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).
This commit is contained in:
Damien George 2016-02-10 16:32:57 +00:00
parent 34023eb673
commit b33a770596
12 changed files with 297 additions and 286 deletions

View File

@ -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);

View File

@ -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 {

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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);

View File

@ -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; \

View File

@ -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

View File

@ -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);

View File

@ -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;
}

View File

@ -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);