From 01ac354929ddb6dd704de7cd35fa3de697d2b936 Mon Sep 17 00:00:00 2001 From: Vincent Dupont Date: Wed, 14 Feb 2018 15:07:35 +0100 Subject: [PATCH 1/3] examples: add filesystem example --- examples/filesystem/Makefile | 46 ++++++ examples/filesystem/README.md | 31 ++++ examples/filesystem/main.c | 264 ++++++++++++++++++++++++++++++++++ 3 files changed, 341 insertions(+) create mode 100644 examples/filesystem/Makefile create mode 100644 examples/filesystem/README.md create mode 100644 examples/filesystem/main.c diff --git a/examples/filesystem/Makefile b/examples/filesystem/Makefile new file mode 100644 index 0000000000..640a24a002 --- /dev/null +++ b/examples/filesystem/Makefile @@ -0,0 +1,46 @@ +# name of your application +APPLICATION = filesystem + +# If no BOARD is found in the environment, use this default: +BOARD ?= native + +BOARD_INSUFFICIENT_MEMORY := nucleo32-f031 + +# This has to be the absolute path to the RIOT base directory: +RIOTBASE ?= $(CURDIR)/../.. + +# Comment this out to disable code in RIOT that does safety checking +# which is not needed in a production environment but helps in the +# development process: +DEVELHELP ?= 1 + +# Change this to 0 show compiler invocation lines by default: +QUIET ?= 1 + +# Modules to include: +USEMODULE += shell +USEMODULE += shell_commands +USEMODULE += ps + +# Use MTD (flash layer) +USEMODULE += mtd + +# Use VFS +USEMODULE += vfs + +# Use a file system +USEMODULE += littlefs +# USEMODULE += spiffs +# USEMODULE += fatfs +USEMODULE += constfs +# USEMODULE += devfs + +# Set file systems specific variables +ifneq (,$(filter littlefs, $(USEMODULE))) + CFLAGS += -DVFS_FILE_BUFFER_SIZE=52 -DVFS_DIR_BUFFER_SIZE=44 +else ifneq (,$(filter spiffs, $(USEMODULE))) + SPIFFS_NB_FD ?= 8 + CFLAGS += '-DSPIFFS_FS_FD_SPACE_SIZE=(32 * $(SPIFFS_NB_FD))' +endif + +include $(RIOTBASE)/Makefile.include diff --git a/examples/filesystem/README.md b/examples/filesystem/README.md new file mode 100644 index 0000000000..d42383e743 --- /dev/null +++ b/examples/filesystem/README.md @@ -0,0 +1,31 @@ +# File system usage example + +This is a basic example how to use a file system with RIOT in your embedded application. + +This example shows: + - how to mount/format/unmount a filesystem, with spiffs, littlefs and constfs examples + - how to open/read/write/close a file with and without newlib + +In RIOT, most filesystems use `mtd` as flash interface. So to use this example +you must define `MTD_0`. `MTD_0` is a pointer to a `mtd_dev_t` instance. +This example use `littlefs` as default filesystem on the whole `mtd` device. +A `constfs` filesystem is also demonstrated with two files. + +All the RIOT filesystems are used through the `vfs` interface, and on most platform +they can be accessed transparently with `open/close/read/write/...` functions. +With newlib, `fopen/fclose/fread/fwrite/...` can also be used transparently. + +The following commands are available: + - `format`: should be called the first time only, it will format the `mtd` device +with the comfigured filesystem + - `mount`: mount the filesystem on the configured mount point (default is `/sda` +but it can be configured with `FLASH_MOUNT_POINT` define). The `constfs` filesystem +is mounted automatically when the application starts + - `umount`: unmount `/sda` + - `cat `: similarly to unix `cat` unix command, it prints the given `` on +stdout + - `tee `: similarly to `tee` unix command, it writes `` in `` + +Apart from these commands, the default `vfs` commands can be used, for instance: + - `vfs df`: shows all mountpoints and used/available memory + - `vfs ls `: list files diff --git a/examples/filesystem/main.c b/examples/filesystem/main.c new file mode 100644 index 0000000000..a181b9bb08 --- /dev/null +++ b/examples/filesystem/main.c @@ -0,0 +1,264 @@ +/* + * Copyright (C) 2018 OTA keys S.A. + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup examples + * @{ + * + * @file + * @brief File system usage example application + * + * @author Vincent Dupont + * + * @} + */ + +#include +#include +#include +#include + +#include "shell.h" +#include "board.h" /* MTD_0 is defined in board.h */ + +/* Flash mount point */ +#define FLASH_MOUNT_POINT "/sda" + +/* In this example, MTD_0 is used as mtd interface for littlefs or spiffs */ +/* littlefs and spiffs basic usage are shown */ +#ifdef MTD_0 +/* File system descriptor initialization */ +#if defined(MODULE_LITTLEFS) +/* include file system header for driver */ +#include "fs/littlefs_fs.h" + +/* file system specific descriptor + * for littlefs, some fields can be tweaked to define the size + * of the partition, see header documentation. + * In this example, default behavior will be used, i.e. the entire + * memory will be used (parameters come from mtd) */ +static littlefs_desc_t fs_desc = { + .lock = MUTEX_INIT, +}; + +/* littlefs file system driver will be used */ +#define FS_DRIVER littlefs_file_system + +#elif defined(MODULE_SPIFFS) +/* include file system header */ +#include "fs/spiffs_fs.h" + +/* file system specific descriptor + * as for littlefs, some fields can be changed if needed, + * this example focus on basic usage, i.e. entire memory used */ +static spiffs_desc_t fs_desc = { + .lock = MUTEX_INIT, +}; + +/* spiffs driver will be used */ +#define FS_DRIVER spiffs_file_system +#endif + +/* this structure defines the vfs mount point: + * - fs field is set to the file system driver + * - mount_point field is the mount point name + * - private_data depends on the underlying file system. For both spiffs and + * littlefs, it needs to be a pointer to the file system descriptor */ +static vfs_mount_t flash_mount = { + .fs = &FS_DRIVER, + .mount_point = FLASH_MOUNT_POINT, + .private_data = &fs_desc, +}; +#endif /* MTD_0 */ + +/* constfs example */ +#include "fs/constfs.h" + +#define HELLO_WORLD_CONTENT "Hello World!\n" +#define HELLO_RIOT_CONTENT "Hello RIOT!\n" + +/* this defines two const files in the constfs */ +static constfs_file_t constfs_files[] = { + { + .path = "/hello-world", + .size = sizeof(HELLO_WORLD_CONTENT), + .data = (const uint8_t *)HELLO_WORLD_CONTENT, + }, + { + .path = "/hello-riot", + .size = sizeof(HELLO_RIOT_CONTENT), + .data = (const uint8_t *)HELLO_RIOT_CONTENT, + } +}; + +/* this is the constfs specific descriptor */ +static constfs_t constfs_desc = { + .nfiles = sizeof(constfs_files) / sizeof(constfs_files[0]), + .files = constfs_files, +}; + +/* constfs mount point, as for previous example, it needs a file system driver, + * a mount poinr and private_data is a pointer to the constfs descriptor */ +static vfs_mount_t const_mount = { + .fs = &constfs_file_system, + .mount_point = "/const", + .private_data = &constfs_desc, +}; + +/* Command handlers */ +static int _mount(int argc, char **argv) +{ + (void)argc; + (void)argv; +#if defined(MTD_0) && (defined(MODULE_SPIFFS) || defined(MODULE_LITTLEFS)) + int res = vfs_mount(&flash_mount); + if (res < 0) { + printf("Error while mounting %s...try format\n", FLASH_MOUNT_POINT); + return 1; + } + + printf("%s successfully mounted\n", FLASH_MOUNT_POINT); + return 0; +#else + puts("No external flash file system selected"); + return 1; +#endif +} + +static int _format(int argc, char **argv) +{ + (void)argc; + (void)argv; +#if defined(MTD_0) && (defined(MODULE_SPIFFS) || defined(MODULE_LITTLEFS)) + int res = vfs_format(&flash_mount); + if (res < 0) { + printf("Error while formatting %s\n", FLASH_MOUNT_POINT); + return 1; + } + + printf("%s successfully formatted\n", FLASH_MOUNT_POINT); + return 0; +#else + puts("No external flash file system selected"); + return 1; +#endif +} + +static int _umount(int argc, char **argv) +{ + (void)argc; + (void)argv; +#if defined(MTD_0) && (defined(MODULE_SPIFFS) || defined(MODULE_LITTLEFS)) + int res = vfs_umount(&flash_mount); + if (res < 0) { + printf("Error while unmounting %s\n", FLASH_MOUNT_POINT); + return 1; + } + + printf("%s successfully unmounted\n", FLASH_MOUNT_POINT); + return 0; +#else + puts("No external flash file system selected"); + return 1; +#endif +} + +static int _cat(int argc, char **argv) +{ + if (argc < 2) { + printf("Usage: %s \n", argv[0]); + return 1; + } + /* With newlib, low-level syscalls are plugged to RIOT vfs + * on native, open/read/write/close/... are plugged to RIOT vfs */ +#ifdef MODULE_NEWLIB + FILE *f = fopen(argv[1], "r"); + if (f == NULL) { + printf("file %s does not exist\n", argv[1]); + return 1; + } + char c; + while (fread(&c, 1, 1, f) != 0) { + putchar(c); + } + fclose(f); +#else + int fd = open(argv[1], O_RDONLY); + if (fd < 0) { + printf("file %s does not exist\n", argv[1]); + return 1; + } + char c; + while (read(fd, &c, 1) != 0) { + putchar(c); + } + close(fd); +#endif + return 0; +} + +static int _tee(int argc, char **argv) +{ + if (argc != 3) { + printf("Usage: %s \n", argv[0]); + return 1; + } + +#ifdef MODULE_NEWLIB + FILE *f = fopen(argv[1], "w+"); + if (f == NULL) { + printf("error while trying to create %s\n", argv[1]); + return 1; + } + if (fwrite(argv[2], 1, strlen(argv[2]), f) != strlen(argv[2])) { + puts("Error while writing"); + } + fclose(f); +#else + int fd = open(argv[1], O_RDWR | O_CREAT); + if (fd < 0) { + printf("error while trying to create %s\n", argv[1]); + return 1; + } + if (write(fd, argv[2], strlen(argv[2])) != (ssize_t)strlen(argv[2])) { + puts("Error while writing"); + } + close(fd); +#endif + return 0; +} + +static const shell_command_t shell_commands[] = { + { "mount", "mount flash filesystem", _mount }, + { "format", "format flash file system", _format }, + { "umount", "unmount flash filesystem", _umount }, + { "cat", "print the content of a file", _cat }, + { "tee", "write a string in a file", _tee }, + { NULL, NULL, NULL } +}; + +int main(void) +{ +#if defined(MTD_0) && (defined(MODULE_SPIFFS) || defined(MODULE_LITTLEFS)) + /* spiffs and littlefs need a mtd pointer + * by default the whole memory is used */ + fs_desc.dev = MTD_0; +#endif + int res = vfs_mount(&const_mount); + if (res < 0) { + puts("Error while mounting constfs"); + } + else { + puts("constfs mounted successfully"); + } + + char line_buf[SHELL_DEFAULT_BUFSIZE]; + shell_run(shell_commands, line_buf, SHELL_DEFAULT_BUFSIZE); + + return 0; +} From 0d9badfab5112cdb03bb317623aac2f21ac38dde Mon Sep 17 00:00:00 2001 From: Vincent Dupont Date: Wed, 14 Feb 2018 17:08:02 +0100 Subject: [PATCH 2/3] atmega_common: improve posix_unistd syscalls Add open implementation and improve fcntl with variable arguments --- cpu/atmega_common/posix_unistd.c | 38 ++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/cpu/atmega_common/posix_unistd.c b/cpu/atmega_common/posix_unistd.c index 4d2ece5e29..4e0e736da7 100644 --- a/cpu/atmega_common/posix_unistd.c +++ b/cpu/atmega_common/posix_unistd.c @@ -15,15 +15,44 @@ */ #include +#include #include #include #ifdef MODULE_VFS +#include #include "vfs.h" #elif defined(MODULE_UART_STDIO) #include "uart_stdio.h" #endif +int open(const char *name, int flags, ...) +{ +#ifdef MODULE_VFS + unsigned mode = 0; + + if ((flags & O_CREAT)) { + va_list ap; + va_start(ap, flags); + mode = va_arg(ap, unsigned); + va_end(ap); + } + + int fd = vfs_open(name, flags, mode); + if (fd < 0) { + /* vfs returns negative error codes */ + errno = -fd; + return -1; + } + return fd; +#else + (void)name; + (void)flags; + errno = ENODEV; + return -1; +#endif +} + int close(int fd) { #ifdef MODULE_VFS @@ -58,9 +87,15 @@ off_t lseek(int fd, off_t off, int whence) #endif } -int fcntl(int fd, int cmd, int arg) +int fcntl(int fd, int cmd, ...) { #ifdef MODULE_VFS + unsigned long arg; + va_list ap; + va_start(ap, cmd); + arg = va_arg(ap, unsigned long); + va_end(ap); + int res = vfs_fcntl(fd, cmd, arg); if (res < 0) { errno = -res; @@ -70,7 +105,6 @@ int fcntl(int fd, int cmd, int arg) #else (void)fd; (void)cmd; - (void)arg; errno = ENODEV; return -1; #endif From 7cd7a6cccada2f9d8ae7d431d9dd9c93915b94c8 Mon Sep 17 00:00:00 2001 From: Vincent Dupont Date: Wed, 14 Feb 2018 17:09:11 +0100 Subject: [PATCH 3/3] examples/filesystem: blacklist msp430 boards --- examples/filesystem/Makefile | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/examples/filesystem/Makefile b/examples/filesystem/Makefile index 640a24a002..0e0448e45f 100644 --- a/examples/filesystem/Makefile +++ b/examples/filesystem/Makefile @@ -4,6 +4,16 @@ APPLICATION = filesystem # If no BOARD is found in the environment, use this default: BOARD ?= native +# Blacklisting msp430-based boards, as file syscalls are not supported +BOARD_BLACKLIST := chronos \ + msb-430 \ + msb-430h \ + telosb \ + wsn430-v1_3b \ + wsn430-v1_4 \ + z1 \ + # + BOARD_INSUFFICIENT_MEMORY := nucleo32-f031 # This has to be the absolute path to the RIOT base directory: