From b33a7705966a743c5e4c0c3c3bb83e6d97b5e84d Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 10 Feb 2016 16:32:57 +0000 Subject: [PATCH] extmod/fsusermount: Support mounting of multiple block devices. This patch adds support to fsusermount for multiple block devices (instead of just one). The maximum allowed is fixed at compile time by the size of the fs_user_mount array accessed via MP_STATE_PORT, which in turn is set by MICROPY_FATFS_VOLUMES. With this patch, stmhal (which is still tightly coupled to fsusermount) is also modified to support mounting multiple devices And the flash and SD card are now just two block devices that are mounted at start up if they exist (and they have special native code to make them more efficient). --- extmod/fsusermount.c | 68 ++++++--- extmod/fsusermount.h | 9 +- stmhal/diskio.c | 338 +++++++++++++++++------------------------- stmhal/fatfs_port.c | 3 +- stmhal/ffconf.c | 28 ++-- stmhal/main.c | 49 ++++-- stmhal/moduos.c | 52 ++++--- stmhal/mpconfigport.h | 6 +- stmhal/sdcard.c | 12 ++ stmhal/sdcard.h | 3 + stmhal/storage.c | 12 ++ stmhal/storage.h | 3 + 12 files changed, 297 insertions(+), 286 deletions(-) diff --git a/extmod/fsusermount.c b/extmod/fsusermount.c index 441711ae2e..677961ea39 100644 --- a/extmod/fsusermount.c +++ b/extmod/fsusermount.c @@ -53,25 +53,38 @@ STATIC mp_obj_t fatfs_mount_mkfs(mp_uint_t n_args, const mp_obj_t *pos_args, mp_ if (device == mp_const_none) { // umount FRESULT res = FR_NO_FILESYSTEM; - if (MP_STATE_PORT(fs_user_mount) != NULL) { - res = f_mount(NULL, MP_STATE_PORT(fs_user_mount)->str, 0); - m_del_obj(fs_user_mount_t, MP_STATE_PORT(fs_user_mount)); - MP_STATE_PORT(fs_user_mount) = NULL; + for (size_t i = 0; i < MP_ARRAY_SIZE(MP_STATE_PORT(fs_user_mount)); ++i) { + fs_user_mount_t *vfs = MP_STATE_PORT(fs_user_mount)[i]; + if (vfs != NULL && !memcmp(mnt_str, vfs->str, mnt_len + 1)) { + res = f_mount(NULL, vfs->str, 0); + if (vfs->flags & FSUSER_FREE_OBJ) { + m_del_obj(fs_user_mount_t, vfs); + } + MP_STATE_PORT(fs_user_mount)[i] = NULL; + break; + } } if (res != FR_OK) { nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "can't umount")); } } else { // mount - if (MP_STATE_PORT(fs_user_mount) != NULL) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "device already mounted")); + size_t i = 0; + for (; i < MP_ARRAY_SIZE(MP_STATE_PORT(fs_user_mount)); ++i) { + if (MP_STATE_PORT(fs_user_mount)[i] == NULL) { + break; + } + } + if (i == MP_ARRAY_SIZE(MP_STATE_PORT(fs_user_mount))) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "too many devices mounted")); } // create new object fs_user_mount_t *vfs; - MP_STATE_PORT(fs_user_mount) = vfs = m_new_obj(fs_user_mount_t); + MP_STATE_PORT(fs_user_mount)[i] = vfs = m_new_obj(fs_user_mount_t); vfs->str = mnt_str; vfs->len = mnt_len; + vfs->flags = FSUSER_FREE_OBJ; // load block protocol methods mp_load_method(device, MP_QSTR_readblocks, vfs->readblocks); @@ -79,7 +92,7 @@ STATIC mp_obj_t fatfs_mount_mkfs(mp_uint_t n_args, const mp_obj_t *pos_args, mp_ mp_load_method_maybe(device, MP_QSTR_ioctl, vfs->u.ioctl); if (vfs->u.ioctl[0] != MP_OBJ_NULL) { // device supports new block protocol, so indicate it - vfs->u.old.count[1] = MP_OBJ_SENTINEL; + vfs->flags |= FSUSER_HAVE_IOCTL; } else { // no ioctl method, so assume the device uses the old block protocol mp_load_method_maybe(device, MP_QSTR_sync, vfs->u.old.sync); @@ -114,7 +127,7 @@ mkfs_error: if (res != FR_OK) { goto mkfs_error; } - MP_STATE_PORT(fs_user_mount) = NULL; + MP_STATE_PORT(fs_user_mount)[i] = NULL; } } else { nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "can't mount")); @@ -141,30 +154,39 @@ STATIC mp_obj_t fatfs_mount(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t MP_DEFINE_CONST_FUN_OBJ_KW(fsuser_mount_obj, 2, fatfs_mount); STATIC mp_obj_t fatfs_umount(mp_obj_t bdev_or_path_in) { - if (MP_STATE_PORT(fs_user_mount) == NULL) { - goto einval; - } - + size_t i = 0; if (MP_OBJ_IS_STR(bdev_or_path_in)) { mp_uint_t mnt_len; const char *mnt_str = mp_obj_str_get_data(bdev_or_path_in, &mnt_len); - if (memcmp(mnt_str, MP_STATE_PORT(fs_user_mount)->str, mnt_len + 1)) { - goto einval; + for (; i < MP_ARRAY_SIZE(MP_STATE_PORT(fs_user_mount)); ++i) { + fs_user_mount_t *vfs = MP_STATE_PORT(fs_user_mount)[i]; + if (!memcmp(mnt_str, vfs->str, mnt_len + 1)) { + break; + } + } + } else { + for (; i < MP_ARRAY_SIZE(MP_STATE_PORT(fs_user_mount)); ++i) { + fs_user_mount_t *vfs = MP_STATE_PORT(fs_user_mount)[i]; + if (bdev_or_path_in == vfs->readblocks[1]) { + break; + } } - } else if (bdev_or_path_in != MP_STATE_PORT(fs_user_mount)->readblocks[1]) { - goto einval; } - FRESULT res = f_mount(NULL, MP_STATE_PORT(fs_user_mount)->str, 0); - m_del_obj(fs_user_mount_t, MP_STATE_PORT(fs_user_mount)); - MP_STATE_PORT(fs_user_mount) = NULL; + if (i == MP_ARRAY_SIZE(MP_STATE_PORT(fs_user_mount))) { + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(EINVAL))); + } + + fs_user_mount_t *vfs = MP_STATE_PORT(fs_user_mount)[i]; + FRESULT res = f_mount(NULL, vfs->str, 0); + if (vfs->flags & FSUSER_FREE_OBJ) { + m_del_obj(fs_user_mount_t, vfs); + } + MP_STATE_PORT(fs_user_mount)[i] = NULL; if (res != FR_OK) { nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "can't umount")); } return mp_const_none; - -einval: - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(EINVAL))); } MP_DEFINE_CONST_FUN_OBJ_1(fsuser_umount_obj, fatfs_umount); diff --git a/extmod/fsusermount.h b/extmod/fsusermount.h index 0fa353b7ef..3dcd035918 100644 --- a/extmod/fsusermount.h +++ b/extmod/fsusermount.h @@ -24,13 +24,18 @@ * THE SOFTWARE. */ +// these are the values for fs_user_mount_t.flags +#define FSUSER_NATIVE (0x0001) // readblocks[2]/writeblocks[2] contain native func +#define FSUSER_FREE_OBJ (0x0002) // fs_user_mount_t obj should be freed on umount +#define FSUSER_HAVE_IOCTL (0x0004) // new protocol with ioctl + typedef struct _fs_user_mount_t { const char *str; - mp_uint_t len; + uint16_t len; // length of str + uint16_t flags; mp_obj_t readblocks[4]; mp_obj_t writeblocks[4]; // new protocol uses just ioctl, old uses sync (optional) and count - // if ioctl[3]=count[1]=MP_OBJ_SENTINEL then we have the new protocol, else old union { mp_obj_t ioctl[4]; struct { diff --git a/stmhal/diskio.c b/stmhal/diskio.c index 9a4efd1a4d..998729a70d 100644 --- a/stmhal/diskio.c +++ b/stmhal/diskio.c @@ -35,17 +35,23 @@ #include "py/runtime.h" #include "lib/fatfs/ff.h" /* FatFs lower layer API */ #include "lib/fatfs/diskio.h" /* FatFs lower layer API */ -#include "storage.h" -#include "sdcard.h" #include "extmod/fsusermount.h" // constants for block protocol ioctl -//#define BP_IOCTL_INIT (1) // unused +#define BP_IOCTL_INIT (1) //#define BP_IOCTL_DEINIT (2) // unused #define BP_IOCTL_SYNC (3) #define BP_IOCTL_SEC_COUNT (4) #define BP_IOCTL_SEC_SIZE (5) +STATIC fs_user_mount_t *disk_get_device(uint id) { + if (id < MP_ARRAY_SIZE(MP_STATE_PORT(fs_user_mount))) { + return MP_STATE_PORT(fs_user_mount)[id]; + } else { + return NULL; + } +} + /*-----------------------------------------------------------------------*/ /* Initialize a Drive */ /*-----------------------------------------------------------------------*/ @@ -54,33 +60,27 @@ DSTATUS disk_initialize ( BYTE pdrv /* Physical drive nmuber (0..) */ ) { - switch (pdrv) { -#if MICROPY_HW_HAS_FLASH - case PD_FLASH: - storage_init(); - return 0; -#endif - -#if MICROPY_HW_HAS_SDCARD - case PD_SDCARD: - if (!sdcard_power_on()) { - return STA_NODISK; - } - // TODO return STA_PROTECT if SD card is read only - return 0; -#endif - - case PD_USER: - if (MP_STATE_PORT(fs_user_mount) == NULL) { - return STA_NODISK; - } - if (MP_STATE_PORT(fs_user_mount)->writeblocks[0] == MP_OBJ_NULL) { - return STA_PROTECT; - } - return 0; + fs_user_mount_t *vfs = disk_get_device(pdrv); + if (vfs == NULL) { + return STA_NOINIT; } - return STA_NOINIT; + if (vfs->flags & FSUSER_HAVE_IOCTL) { + // new protocol with ioctl; call ioctl(INIT, 0) + vfs->u.ioctl[2] = MP_OBJ_NEW_SMALL_INT(BP_IOCTL_INIT); + vfs->u.ioctl[3] = MP_OBJ_NEW_SMALL_INT(0); // unused + mp_obj_t ret = mp_call_method_n_kw(2, 0, vfs->u.ioctl); + if (MP_OBJ_SMALL_INT_VALUE(ret) != 0) { + // error initialising + return STA_NOINIT; + } + } + + if (vfs->writeblocks[0] == MP_OBJ_NULL) { + return STA_PROTECT; + } else { + return 0; + } } /*-----------------------------------------------------------------------*/ @@ -91,28 +91,16 @@ DSTATUS disk_status ( BYTE pdrv /* Physical drive nmuber (0..) */ ) { - switch (pdrv) { - case PD_FLASH : - // flash is ready - return 0; - -#if MICROPY_HW_HAS_SDCARD - case PD_SDCARD: - // TODO return STA_PROTECT if SD card is read only - return 0; -#endif - - case PD_USER: - if (MP_STATE_PORT(fs_user_mount) == NULL) { - return STA_NODISK; - } - if (MP_STATE_PORT(fs_user_mount)->writeblocks[0] == MP_OBJ_NULL) { - return STA_PROTECT; - } - return 0; + fs_user_mount_t *vfs = disk_get_device(pdrv); + if (vfs == NULL) { + return STA_NOINIT; } - return STA_NOINIT; + if (vfs->writeblocks[0] == MP_OBJ_NULL) { + return STA_PROTECT; + } else { + return 0; + } } /*-----------------------------------------------------------------------*/ @@ -126,37 +114,24 @@ DRESULT disk_read ( UINT count /* Number of sectors to read (1..128) */ ) { - switch (pdrv) { -#if MICROPY_HW_HAS_FLASH - case PD_FLASH: - for (int i = 0; i < count; i++) { - if (!storage_read_block(buff + i * FLASH_BLOCK_SIZE, sector + i)) { - return RES_ERROR; - } - } - return RES_OK; -#endif - -#if MICROPY_HW_HAS_SDCARD - case PD_SDCARD: - if (sdcard_read_blocks(buff, sector, count) != 0) { - return RES_ERROR; - } - return RES_OK; -#endif - - case PD_USER: - if (MP_STATE_PORT(fs_user_mount) == NULL) { - // nothing mounted - return RES_ERROR; - } - MP_STATE_PORT(fs_user_mount)->readblocks[2] = MP_OBJ_NEW_SMALL_INT(sector); - MP_STATE_PORT(fs_user_mount)->readblocks[3] = mp_obj_new_bytearray_by_ref(count * 512, buff); - mp_call_method_n_kw(2, 0, MP_STATE_PORT(fs_user_mount)->readblocks); - return RES_OK; + fs_user_mount_t *vfs = disk_get_device(pdrv); + if (vfs == NULL) { + return RES_PARERR; } - return RES_PARERR; + if (vfs->flags & FSUSER_NATIVE) { + mp_uint_t (*f)(uint8_t*, uint32_t, uint32_t) = (void*)vfs->readblocks[2]; + if (f(buff, sector, count) != 0) { + return RES_ERROR; + } + } else { + vfs->readblocks[2] = MP_OBJ_NEW_SMALL_INT(sector); + vfs->readblocks[3] = mp_obj_new_bytearray_by_ref(count * 512, buff); + mp_call_method_n_kw(2, 0, vfs->readblocks); + // TODO handle error return + } + + return RES_OK; } /*-----------------------------------------------------------------------*/ @@ -171,41 +146,29 @@ DRESULT disk_write ( UINT count /* Number of sectors to write (1..128) */ ) { - switch (pdrv) { -#if MICROPY_HW_HAS_FLASH - case PD_FLASH: - for (int i = 0; i < count; i++) { - if (!storage_write_block(buff + i * FLASH_BLOCK_SIZE, sector + i)) { - return RES_ERROR; - } - } - return RES_OK; -#endif - -#if MICROPY_HW_HAS_SDCARD - case PD_SDCARD: - if (sdcard_write_blocks(buff, sector, count) != 0) { - return RES_ERROR; - } - return RES_OK; -#endif - - case PD_USER: - if (MP_STATE_PORT(fs_user_mount) == NULL) { - // nothing mounted - return RES_ERROR; - } - if (MP_STATE_PORT(fs_user_mount)->writeblocks[0] == MP_OBJ_NULL) { - // read-only block device - return RES_ERROR; - } - MP_STATE_PORT(fs_user_mount)->writeblocks[2] = MP_OBJ_NEW_SMALL_INT(sector); - MP_STATE_PORT(fs_user_mount)->writeblocks[3] = mp_obj_new_bytearray_by_ref(count * 512, (void*)buff); - mp_call_method_n_kw(2, 0, MP_STATE_PORT(fs_user_mount)->writeblocks); - return RES_OK; + fs_user_mount_t *vfs = disk_get_device(pdrv); + if (vfs == NULL) { + return RES_PARERR; } - return RES_PARERR; + if (vfs->writeblocks[0] == MP_OBJ_NULL) { + // read-only block device + return RES_WRPRT; + } + + if (vfs->flags & FSUSER_NATIVE) { + mp_uint_t (*f)(const uint8_t*, uint32_t, uint32_t) = (void*)vfs->writeblocks[2]; + if (f(buff, sector, count) != 0) { + return RES_ERROR; + } + } else { + vfs->writeblocks[2] = MP_OBJ_NEW_SMALL_INT(sector); + vfs->writeblocks[3] = mp_obj_new_bytearray_by_ref(count * 512, (void*)buff); + mp_call_method_n_kw(2, 0, vfs->writeblocks); + // TODO handle error return + } + + return RES_OK; } #endif @@ -221,100 +184,69 @@ DRESULT disk_ioctl ( void *buff /* Buffer to send/receive control data */ ) { - switch (pdrv) { -#if MICROPY_HW_HAS_FLASH - case PD_FLASH: - switch (cmd) { - case CTRL_SYNC: - storage_flush(); - return RES_OK; - - case GET_BLOCK_SIZE: - *((DWORD*)buff) = 1; // high-level sector erase size in units of the small (512) block size - return RES_OK; - } - break; -#endif - -#if MICROPY_HW_HAS_SDCARD - case PD_SDCARD: - switch (cmd) { - case CTRL_SYNC: - return RES_OK; - - case GET_BLOCK_SIZE: - *((DWORD*)buff) = 1; // high-level sector erase size in units of the small (512) block size - return RES_OK; - } - break; -#endif - - case PD_USER: { - fs_user_mount_t *vfs = MP_STATE_PORT(fs_user_mount); - if (vfs == NULL) { - // nothing mounted - return RES_ERROR; - } - if (vfs->u.old.count[1] == MP_OBJ_SENTINEL) { - // new protocol with ioctl - switch (cmd) { - case CTRL_SYNC: - vfs->u.ioctl[2] = MP_OBJ_NEW_SMALL_INT(BP_IOCTL_SYNC); - vfs->u.ioctl[3] = MP_OBJ_NEW_SMALL_INT(0); // unused - mp_call_method_n_kw(2, 0, vfs->u.ioctl); - vfs->u.ioctl[3] = MP_OBJ_SENTINEL; // indicate new protocol - return RES_OK; - - case GET_SECTOR_COUNT: { - vfs->u.ioctl[2] = MP_OBJ_NEW_SMALL_INT(BP_IOCTL_SEC_COUNT); - vfs->u.ioctl[3] = MP_OBJ_NEW_SMALL_INT(0); // unused - mp_obj_t ret = mp_call_method_n_kw(2, 0, vfs->u.ioctl); - *((DWORD*)buff) = mp_obj_get_int(ret); - vfs->u.ioctl[3] = MP_OBJ_SENTINEL; // indicate new protocol - return RES_OK; - } - - case GET_SECTOR_SIZE: { - vfs->u.ioctl[2] = MP_OBJ_NEW_SMALL_INT(BP_IOCTL_SEC_SIZE); - vfs->u.ioctl[3] = MP_OBJ_NEW_SMALL_INT(0); // unused - mp_obj_t ret = mp_call_method_n_kw(2, 0, vfs->u.ioctl); - *((WORD*)buff) = mp_obj_get_int(ret); - vfs->u.ioctl[3] = MP_OBJ_SENTINEL; // indicate new protocol - return RES_OK; - } - - case GET_BLOCK_SIZE: - *((DWORD*)buff) = 1; // erase block size in units of sector size - return RES_OK; - } - } else { - // old protocol with sync and count - switch (cmd) { - case CTRL_SYNC: - if (vfs->u.old.sync[0] != MP_OBJ_NULL) { - mp_call_method_n_kw(0, 0, vfs->u.old.sync); - } - return RES_OK; - - case GET_SECTOR_COUNT: { - mp_obj_t ret = mp_call_method_n_kw(0, 0, vfs->u.old.count); - *((DWORD*)buff) = mp_obj_get_int(ret); - return RES_OK; - } - - case GET_SECTOR_SIZE: - *((WORD*)buff) = 512; // old protocol had fixed sector size - return RES_OK; - - case GET_BLOCK_SIZE: - *((DWORD*)buff) = 1; // erase block size in units of sector size - return RES_OK; - } - } - break; - } + fs_user_mount_t *vfs = disk_get_device(pdrv); + if (vfs == NULL) { + return RES_PARERR; } - return RES_PARERR; + if (vfs->flags & FSUSER_HAVE_IOCTL) { + // new protocol with ioctl + switch (cmd) { + case CTRL_SYNC: + vfs->u.ioctl[2] = MP_OBJ_NEW_SMALL_INT(BP_IOCTL_SYNC); + vfs->u.ioctl[3] = MP_OBJ_NEW_SMALL_INT(0); // unused + mp_call_method_n_kw(2, 0, vfs->u.ioctl); + return RES_OK; + + case GET_SECTOR_COUNT: { + vfs->u.ioctl[2] = MP_OBJ_NEW_SMALL_INT(BP_IOCTL_SEC_COUNT); + vfs->u.ioctl[3] = MP_OBJ_NEW_SMALL_INT(0); // unused + mp_obj_t ret = mp_call_method_n_kw(2, 0, vfs->u.ioctl); + *((DWORD*)buff) = mp_obj_get_int(ret); + return RES_OK; + } + + case GET_SECTOR_SIZE: { + vfs->u.ioctl[2] = MP_OBJ_NEW_SMALL_INT(BP_IOCTL_SEC_SIZE); + vfs->u.ioctl[3] = MP_OBJ_NEW_SMALL_INT(0); // unused + mp_obj_t ret = mp_call_method_n_kw(2, 0, vfs->u.ioctl); + *((WORD*)buff) = mp_obj_get_int(ret); + return RES_OK; + } + + case GET_BLOCK_SIZE: + *((DWORD*)buff) = 1; // erase block size in units of sector size + return RES_OK; + + default: + return RES_PARERR; + } + } else { + // old protocol with sync and count + switch (cmd) { + case CTRL_SYNC: + if (vfs->u.old.sync[0] != MP_OBJ_NULL) { + mp_call_method_n_kw(0, 0, vfs->u.old.sync); + } + return RES_OK; + + case GET_SECTOR_COUNT: { + mp_obj_t ret = mp_call_method_n_kw(0, 0, vfs->u.old.count); + *((DWORD*)buff) = mp_obj_get_int(ret); + return RES_OK; + } + + case GET_SECTOR_SIZE: + *((WORD*)buff) = 512; // old protocol had fixed sector size + return RES_OK; + + case GET_BLOCK_SIZE: + *((DWORD*)buff) = 1; // erase block size in units of sector size + return RES_OK; + + default: + return RES_PARERR; + } + } } #endif diff --git a/stmhal/fatfs_port.c b/stmhal/fatfs_port.c index a1435eaa3f..421ceddbaf 100644 --- a/stmhal/fatfs_port.c +++ b/stmhal/fatfs_port.c @@ -30,10 +30,11 @@ #include "lib/fatfs/diskio.h" /* FatFs lower layer API */ #include "rtc.h" -const PARTITION VolToPart[] = { +const PARTITION VolToPart[MICROPY_FATFS_VOLUMES] = { {0, 1}, // Logical drive 0 ==> Physical drive 0, 1st partition {1, 0}, // Logical drive 1 ==> Physical drive 1 (auto detection) {2, 0}, // Logical drive 2 ==> Physical drive 2 (auto detection) + {3, 0}, // Logical drive 3 ==> Physical drive 3 (auto detection) /* {0, 2}, // Logical drive 2 ==> Physical drive 0, 2nd partition {0, 3}, // Logical drive 3 ==> Physical drive 0, 3rd partition diff --git a/stmhal/ffconf.c b/stmhal/ffconf.c index 74336310a7..6cd140f227 100644 --- a/stmhal/ffconf.c +++ b/stmhal/ffconf.c @@ -60,26 +60,18 @@ int ff_get_ldnumber (const TCHAR **path) { #endif } - if (check_path(path, "/flash", 6)) { - return PD_FLASH; - } else if (check_path(path, "/sd", 3)) { - return PD_SDCARD; - } else if (MP_STATE_PORT(fs_user_mount) != NULL && check_path(path, MP_STATE_PORT(fs_user_mount)->str, MP_STATE_PORT(fs_user_mount)->len)) { - return PD_USER; - } else { - return -1; + for (size_t i = 0; i < MP_ARRAY_SIZE(MP_STATE_PORT(fs_user_mount)); ++i) { + fs_user_mount_t *vfs = MP_STATE_PORT(fs_user_mount)[i]; + if (vfs != NULL && check_path(path, vfs->str, vfs->len)) { + return i; + } } + + return -1; } void ff_get_volname(BYTE vol, TCHAR **dest) { - if (vol == PD_FLASH) { - memcpy(*dest, "/flash", 6); - *dest += 6; - } else if (vol == PD_SDCARD) { - memcpy(*dest, "/sd", 3); - *dest += 3; - } else { - memcpy(*dest, MP_STATE_PORT(fs_user_mount)->str, MP_STATE_PORT(fs_user_mount)->len); - *dest += MP_STATE_PORT(fs_user_mount)->len; - } + fs_user_mount_t *vfs = MP_STATE_PORT(fs_user_mount)[vol]; + memcpy(*dest, vfs->str, vfs->len); + *dest += vfs->len; } diff --git a/stmhal/main.c b/stmhal/main.c index 882de6e1a4..02dcc76174 100644 --- a/stmhal/main.c +++ b/stmhal/main.c @@ -38,6 +38,7 @@ #include "lib/utils/pyexec.h" #include "lib/fatfs/ff.h" +#include "extmod/fsusermount.h" #include "systick.h" #include "pendsv.h" @@ -64,10 +65,7 @@ void SystemClock_Config(void); -static FATFS fatfs0; -#if MICROPY_HW_HAS_SDCARD -static FATFS fatfs1; -#endif +fs_user_mount_t fs_user_mount_flash; void flash_error(int n) { for (int i = 0; i < n; i++) { @@ -169,8 +167,18 @@ static const char fresh_readme_txt[] = // we don't make this function static because it needs a lot of stack and we // want it to be executed without using stack within main() function void init_flash_fs(uint reset_mode) { + // init the vfs object + fs_user_mount_t *vfs = &fs_user_mount_flash; + vfs->str = "/flash"; + vfs->len = 6; + vfs->flags = 0; + pyb_flash_init_vfs(vfs); + + // put the flash device in slot 0 (it will be unused at this point) + MP_STATE_PORT(fs_user_mount)[0] = vfs; + // try to mount the flash - FRESULT res = f_mount(&fatfs0, "/flash", 1); + FRESULT res = f_mount(&vfs->fatfs, vfs->str, 1); if (reset_mode == 3 || res == FR_NO_FILESYSTEM) { // no filesystem, or asked to reset it, so create a fresh one @@ -183,7 +191,9 @@ void init_flash_fs(uint reset_mode) { if (res == FR_OK) { // success creating fresh LFS } else { - __fatal_error("could not create LFS"); + printf("PYB: can't create flash filesystem\n"); + MP_STATE_PORT(fs_user_mount)[0] = NULL; + return; } // set label @@ -213,7 +223,9 @@ void init_flash_fs(uint reset_mode) { } else if (res == FR_OK) { // mount sucessful } else { - __fatal_error("could not access LFS"); + printf("PYB: can't mount flash\n"); + MP_STATE_PORT(fs_user_mount)[0] = NULL; + return; } // The current directory is used as the boot up directory. @@ -448,6 +460,9 @@ soft_reset: mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_flash_slash_lib)); mp_obj_list_init(mp_sys_argv, 0); + // zero out the pointers to the mounted devices + memset(MP_STATE_PORT(fs_user_mount), 0, sizeof(MP_STATE_PORT(fs_user_mount))); + // Initialise low-level sub-systems. Here we need to very basic things like // zeroing out memory and resetting any of the sub-systems. Following this // we can run Python scripts (eg boot.py), but anything that is configurable @@ -493,9 +508,24 @@ soft_reset: #if MICROPY_HW_HAS_SDCARD // if an SD card is present then mount it on /sd/ if (sdcard_is_present()) { - FRESULT res = f_mount(&fatfs1, "/sd", 1); + // create vfs object + fs_user_mount_t *vfs = m_new_obj_maybe(fs_user_mount_t); + if (vfs == NULL) { + goto no_mem_for_sd; + } + vfs->str = "/sd"; + vfs->len = 3; + vfs->flags = FSUSER_FREE_OBJ; + sdcard_init_vfs(vfs); + + // put the sd device in slot 1 (it will be unused at this point) + MP_STATE_PORT(fs_user_mount)[1] = vfs; + + FRESULT res = f_mount(&vfs->fatfs, vfs->str, 1); if (res != FR_OK) { - printf("[SD] could not mount SD card\n"); + printf("PYB: can't mount SD card\n"); + MP_STATE_PORT(fs_user_mount)[1] = NULL; + m_del_obj(fs_user_mount_t, vfs); } else { // TODO these should go before the /flash entries in the path mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_sd)); @@ -517,6 +547,7 @@ soft_reset: f_chdrive("/sd"); } } + no_mem_for_sd:; } #endif diff --git a/stmhal/moduos.c b/stmhal/moduos.c index cb2a73c116..293fbabafc 100644 --- a/stmhal/moduos.c +++ b/stmhal/moduos.c @@ -58,15 +58,6 @@ static char lfn[_MAX_LFN + 1]; /* Buffer to store the LFN */ #endif -STATIC bool sd_in_root(void) { -#if MICROPY_HW_HAS_SDCARD - // TODO this is not the correct logic to check for /sd - return sdcard_is_present(); -#else - return false; -#endif -} - STATIC const qstr os_uname_info_fields[] = { MP_QSTR_sysname, MP_QSTR_nodename, MP_QSTR_release, MP_QSTR_version, MP_QSTR_machine @@ -144,12 +135,11 @@ STATIC mp_obj_t os_listdir(mp_uint_t n_args, const mp_obj_t *args) { // "hack" to list root directory if (path[0] == '/' && path[1] == '\0') { mp_obj_t dir_list = mp_obj_new_list(0, NULL); - mp_obj_list_append(dir_list, MP_OBJ_NEW_QSTR(MP_QSTR_flash)); - if (sd_in_root()) { - mp_obj_list_append(dir_list, MP_OBJ_NEW_QSTR(MP_QSTR_sd)); - } - if (MP_STATE_PORT(fs_user_mount) != NULL) { - mp_obj_list_append(dir_list, mp_obj_new_str(MP_STATE_PORT(fs_user_mount)->str + 1, MP_STATE_PORT(fs_user_mount)->len - 1, false)); + for (size_t i = 0; i < MP_ARRAY_SIZE(MP_STATE_PORT(fs_user_mount)); ++i) { + fs_user_mount_t *vfs = MP_STATE_PORT(fs_user_mount)[i]; + if (vfs != NULL) { + mp_obj_list_append(dir_list, mp_obj_new_str(vfs->str + 1, vfs->len - 1, false)); + } } return dir_list; } @@ -298,21 +288,32 @@ STATIC mp_obj_t os_stat(mp_obj_t path_in) { #endif FRESULT res; - if (path_equal(path, "/") || path_equal(path, "/flash") || path_equal(path, "/sd")) { - // stat built-in directory - if (path[1] == 's' && !sd_in_root()) { - // no /sd directory - res = FR_NO_PATH; - goto error; - } + if (path_equal(path, "/")) { + // stat root directory fno.fsize = 0; fno.fdate = 0; fno.ftime = 0; fno.fattrib = AM_DIR; } else { - res = f_stat(path, &fno); + res = FR_NO_PATH; + for (size_t i = 0; i < MP_ARRAY_SIZE(MP_STATE_PORT(fs_user_mount)); ++i) { + fs_user_mount_t *vfs = MP_STATE_PORT(fs_user_mount)[i]; + if (vfs != NULL && path_equal(path, vfs->str)) { + // stat mounted device directory + fno.fsize = 0; + fno.fdate = 0; + fno.ftime = 0; + fno.fattrib = AM_DIR; + res = FR_OK; + } + } + if (res == FR_NO_PATH) { + // stat normal file + res = f_stat(path, &fno); + } if (res != FR_OK) { - goto error; + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, + MP_OBJ_NEW_SMALL_INT(fresult_to_errno_table[res]))); } } @@ -343,9 +344,6 @@ STATIC mp_obj_t os_stat(mp_obj_t path_in) { t->items[9] = MP_OBJ_NEW_SMALL_INT(seconds); // st_ctime return t; - -error: - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(fresult_to_errno_table[res]))); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(os_stat_obj, os_stat); diff --git a/stmhal/mpconfigport.h b/stmhal/mpconfigport.h index cea8a3ecb4..8d12397361 100644 --- a/stmhal/mpconfigport.h +++ b/stmhal/mpconfigport.h @@ -53,7 +53,7 @@ #define MICROPY_FATFS_LFN_CODE_PAGE (437) /* 1=SFN/ANSI 437=LFN/U.S.(OEM) */ #define MICROPY_FATFS_USE_LABEL (1) #define MICROPY_FATFS_RPATH (2) -#define MICROPY_FATFS_VOLUMES (3) +#define MICROPY_FATFS_VOLUMES (4) #define MICROPY_FATFS_MULTI_PARTITION (1) #define MICROPY_FSUSERMOUNT (1) @@ -183,8 +183,8 @@ extern const struct _mp_obj_module_t mp_module_network; /* pointers to all CAN objects (if they have been created) */ \ struct _pyb_can_obj_t *pyb_can_obj_all[2]; \ \ - /* for user-mountable block device */ \ - struct _fs_user_mount_t *fs_user_mount; \ + /* for user-mountable block device (max fixed at compile time) */ \ + struct _fs_user_mount_t *fs_user_mount[MICROPY_FATFS_VOLUMES]; \ \ /* list of registered NICs */ \ mp_obj_list_t mod_network_nic_list; \ diff --git a/stmhal/sdcard.c b/stmhal/sdcard.c index fb480bbec8..ae96de953f 100644 --- a/stmhal/sdcard.c +++ b/stmhal/sdcard.c @@ -424,4 +424,16 @@ const mp_obj_type_t pyb_sdcard_type = { .locals_dict = (mp_obj_t)&pyb_sdcard_locals_dict, }; +void sdcard_init_vfs(fs_user_mount_t *vfs) { + vfs->flags |= FSUSER_NATIVE | FSUSER_HAVE_IOCTL; + vfs->readblocks[0] = (mp_obj_t)&pyb_sdcard_readblocks_obj; + vfs->readblocks[1] = (mp_obj_t)&pyb_sdcard_obj; + vfs->readblocks[2] = (mp_obj_t)sdcard_read_blocks; // native version + vfs->writeblocks[0] = (mp_obj_t)&pyb_sdcard_writeblocks_obj; + vfs->writeblocks[1] = (mp_obj_t)&pyb_sdcard_obj; + vfs->writeblocks[2] = (mp_obj_t)sdcard_write_blocks; // native version + vfs->u.ioctl[0] = (mp_obj_t)&pyb_sdcard_ioctl_obj; + vfs->u.ioctl[1] = (mp_obj_t)&pyb_sdcard_obj; +} + #endif // MICROPY_HW_HAS_SDCARD diff --git a/stmhal/sdcard.h b/stmhal/sdcard.h index 06ca5ef1b3..ccc24927e5 100644 --- a/stmhal/sdcard.h +++ b/stmhal/sdcard.h @@ -39,3 +39,6 @@ mp_uint_t sdcard_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t n extern const struct _mp_obj_type_t pyb_sdcard_type; extern const struct _mp_obj_base_t pyb_sdcard_obj; + +struct _fs_user_mount_t; +void sdcard_init_vfs(struct _fs_user_mount_t *vfs); diff --git a/stmhal/storage.c b/stmhal/storage.c index 7bd55a2b20..f6075c43c4 100644 --- a/stmhal/storage.c +++ b/stmhal/storage.c @@ -387,3 +387,15 @@ const mp_obj_type_t pyb_flash_type = { .make_new = pyb_flash_make_new, .locals_dict = (mp_obj_t)&pyb_flash_locals_dict, }; + +void pyb_flash_init_vfs(fs_user_mount_t *vfs) { + vfs->flags |= FSUSER_NATIVE | FSUSER_HAVE_IOCTL; + vfs->readblocks[0] = (mp_obj_t)&pyb_flash_readblocks_obj; + vfs->readblocks[1] = (mp_obj_t)&pyb_flash_obj; + vfs->readblocks[2] = (mp_obj_t)storage_read_blocks; // native version + vfs->writeblocks[0] = (mp_obj_t)&pyb_flash_writeblocks_obj; + vfs->writeblocks[1] = (mp_obj_t)&pyb_flash_obj; + vfs->writeblocks[2] = (mp_obj_t)storage_write_blocks; // native version + vfs->u.ioctl[0] = (mp_obj_t)&pyb_flash_ioctl_obj; + vfs->u.ioctl[1] = (mp_obj_t)&pyb_flash_obj; +} diff --git a/stmhal/storage.h b/stmhal/storage.h index 30aa483095..4d3de77eda 100644 --- a/stmhal/storage.h +++ b/stmhal/storage.h @@ -42,3 +42,6 @@ mp_uint_t storage_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_bl mp_uint_t storage_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t num_blocks); extern const struct _mp_obj_type_t pyb_flash_type; + +struct _fs_user_mount_t; +void pyb_flash_init_vfs(struct _fs_user_mount_t *vfs);