diff options
| author | Glenn Ruben Bakke <glennbakke@gmail.com> | 2017-02-07 22:27:32 +0100 |
|---|---|---|
| committer | Glenn Ruben Bakke <glennbakke@gmail.com> | 2017-02-07 22:27:32 +0100 |
| commit | 122d0430db4d103dfb8bc9958b7df4d9803038c8 (patch) | |
| tree | 856ac0d4950b0154cc6aae8cf022fd29b2402073 /extmod | |
| parent | 723943abde3e9de5e14ee40df5e0d5fe25352c97 (diff) | |
| parent | 4cf7fd151e98a3d842eb5c9428545cb67ddd57ee (diff) | |
Merge branch 'nrf52' into nrf5_no_sdk
Diffstat (limited to 'extmod')
| -rw-r--r-- | extmod/fsusermount.c | 209 | ||||
| -rw-r--r-- | extmod/machine_pulse.c | 6 | ||||
| -rw-r--r-- | extmod/machine_signal.c | 114 | ||||
| -rw-r--r-- | extmod/machine_signal.h (renamed from extmod/vfs_fat_file.h) | 15 | ||||
| -rw-r--r-- | extmod/machine_spi.c | 6 | ||||
| -rw-r--r-- | extmod/modframebuf.c | 71 | ||||
| -rw-r--r-- | extmod/modlwip.c | 1 | ||||
| -rw-r--r-- | extmod/vfs.c | 309 | ||||
| -rw-r--r-- | extmod/vfs.h | 80 | ||||
| -rw-r--r-- | extmod/vfs_fat.c | 199 | ||||
| -rw-r--r-- | extmod/vfs_fat.h (renamed from extmod/fsusermount.h) | 26 | ||||
| -rw-r--r-- | extmod/vfs_fat_diskio.c | 59 | ||||
| -rw-r--r-- | extmod/vfs_fat_ffconf.c | 82 | ||||
| -rw-r--r-- | extmod/vfs_fat_file.c | 28 | ||||
| -rw-r--r-- | extmod/vfs_fat_misc.c | 40 | ||||
| -rw-r--r-- | extmod/vfs_reader.c (renamed from extmod/vfs_fat_reader.c) | 72 |
16 files changed, 806 insertions, 511 deletions
diff --git a/extmod/fsusermount.c b/extmod/fsusermount.c deleted file mode 100644 index 5882aba99..000000000 --- a/extmod/fsusermount.c +++ /dev/null @@ -1,209 +0,0 @@ -/* - * This file is part of the Micro Python project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2014 Damien P. George - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "py/mpconfig.h" -#if MICROPY_FSUSERMOUNT -#include <string.h> -#include <errno.h> - -#include "py/nlr.h" -#include "py/runtime.h" -#include "py/mperrno.h" -#include "lib/fatfs/ff.h" -#include "extmod/fsusermount.h" - -fs_user_mount_t *fatfs_mount_mkfs(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args, bool mkfs) { - static const mp_arg_t allowed_args[] = { - { MP_QSTR_readonly, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, - { MP_QSTR_mkfs, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, - }; - - // parse args - mp_obj_t device = pos_args[0]; - mp_obj_t mount_point = pos_args[1]; - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 2, pos_args + 2, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - // get the mount point - mp_uint_t mnt_len; - const char *mnt_str = mp_obj_str_get_data(mount_point, &mnt_len); - - if (device == mp_const_none) { - // umount - FRESULT res = FR_NO_FILESYSTEM; - 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")); - } - return NULL; - } else { - // mount - 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 = 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); - mp_load_method_maybe(device, MP_QSTR_writeblocks, vfs->writeblocks); - 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->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); - mp_load_method(device, MP_QSTR_count, vfs->u.old.count); - } - - // Read-only device indicated by writeblocks[0] == MP_OBJ_NULL. - // User can specify read-only device by: - // 1. readonly=True keyword argument - // 2. nonexistent writeblocks method (then writeblocks[0] == MP_OBJ_NULL already) - if (args[0].u_bool) { - vfs->writeblocks[0] = MP_OBJ_NULL; - } - - // Register the vfs object so that it can be found by the FatFS driver using - // ff_get_ldnumber. We don't register it any earlier than this point in case there - // is an exception, in which case there would remain a partially mounted device. - MP_STATE_PORT(fs_user_mount)[i] = vfs; - - // mount the block device (if mkfs, only pre-mount) - FRESULT res = f_mount(&vfs->fatfs, vfs->str, !mkfs); - // check the result - if (res == FR_OK) { - if (mkfs) { - goto mkfs; - } - } else if (res == FR_NO_FILESYSTEM && args[1].u_bool) { -mkfs: - res = f_mkfs(vfs->str, 1, 0); - if (res != FR_OK) { -mkfs_error: - MP_STATE_PORT(fs_user_mount)[i] = NULL; - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "can't mkfs")); - } - if (mkfs) { - // If requested to only mkfs, unmount pre-mounted device - res = f_mount(NULL, vfs->str, 0); - if (res != FR_OK) { - goto mkfs_error; - } - MP_STATE_PORT(fs_user_mount)[i] = NULL; - return NULL; - } - } else { - MP_STATE_PORT(fs_user_mount)[i] = NULL; - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "can't mount")); - } - - /* - if (vfs->writeblocks[0] == MP_OBJ_NULL) { - printf("mounted read-only"); - } else { - printf("mounted read-write"); - } - DWORD nclst; - FATFS *fatfs; - f_getfree(vfs->str, &nclst, &fatfs); - printf(" on %s with %u bytes free\n", vfs->str, (uint)(nclst * fatfs->csize * 512)); - */ - return vfs; - } -} - -STATIC mp_obj_t fatfs_mount(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - fatfs_mount_mkfs(n_args, pos_args, kw_args, false); - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_KW(fsuser_mount_obj, 2, fatfs_mount); - -mp_obj_t fatfs_umount(mp_obj_t bdev_or_path_in) { - 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); - 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 (vfs != NULL && !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 (vfs != NULL && bdev_or_path_in == vfs->readblocks[1]) { - break; - } - } - } - - if (i == MP_ARRAY_SIZE(MP_STATE_PORT(fs_user_mount))) { - mp_raise_OSError(MP_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; -} -MP_DEFINE_CONST_FUN_OBJ_1(fsuser_umount_obj, fatfs_umount); - -STATIC mp_obj_t fatfs_mkfs(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - fatfs_mount_mkfs(n_args, pos_args, kw_args, true); - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_KW(fsuser_mkfs_obj, 2, fatfs_mkfs); - -#endif // MICROPY_FSUSERMOUNT diff --git a/extmod/machine_pulse.c b/extmod/machine_pulse.c index b2a78d72e..5f837479d 100644 --- a/extmod/machine_pulse.c +++ b/extmod/machine_pulse.c @@ -34,7 +34,7 @@ mp_uint_t machine_time_pulse_us(mp_hal_pin_obj_t pin, int pulse_level, mp_uint_t mp_uint_t start = mp_hal_ticks_us(); while (mp_hal_pin_read(pin) != pulse_level) { if ((mp_uint_t)(mp_hal_ticks_us() - start) >= timeout_us) { - return (mp_uint_t)-1; + return (mp_uint_t)-2; } } start = mp_hal_ticks_us(); @@ -57,9 +57,7 @@ STATIC mp_obj_t machine_time_pulse_us_(size_t n_args, const mp_obj_t *args) { timeout_us = mp_obj_get_int(args[2]); } mp_uint_t us = machine_time_pulse_us(pin, level, timeout_us); - if (us == (mp_uint_t)-1) { - mp_raise_OSError(MP_ETIMEDOUT); - } + // May return -1 or -2 in case of timeout return mp_obj_new_int(us); } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(machine_time_pulse_us_obj, 2, 3, machine_time_pulse_us_); diff --git a/extmod/machine_signal.c b/extmod/machine_signal.c new file mode 100644 index 000000000..fb179c438 --- /dev/null +++ b/extmod/machine_signal.c @@ -0,0 +1,114 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mpconfig.h" +#if MICROPY_PY_MACHINE + +#include "py/obj.h" +#include "py/runtime.h" +#include "extmod/virtpin.h" +#include "extmod/machine_signal.h" + +// Signal class + +typedef struct _machine_signal_t { + mp_obj_base_t base; + mp_obj_t pin; + bool inverted; +} machine_signal_t; + +STATIC mp_obj_t signal_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + enum { ARG_pin, ARG_inverted }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_OBJ | MP_ARG_REQUIRED }, + { MP_QSTR_inverted, MP_ARG_BOOL, {.u_bool = false} }, + }; + + mp_arg_val_t parsed_args[MP_ARRAY_SIZE(allowed_args)]; + + mp_arg_parse_all_kw_array(n_args, n_kw, args, MP_ARRAY_SIZE(allowed_args), allowed_args, parsed_args); + + machine_signal_t *o = m_new_obj(machine_signal_t); + o->base.type = type; + o->pin = parsed_args[ARG_pin].u_obj; + o->inverted = parsed_args[ARG_inverted].u_bool; + return MP_OBJ_FROM_PTR(o); +} + +STATIC mp_uint_t signal_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { + (void)errcode; + machine_signal_t *self = MP_OBJ_TO_PTR(self_in); + + switch (request) { + case MP_PIN_READ: { + return mp_virtual_pin_read(self->pin) ^ self->inverted; + } + case MP_PIN_WRITE: { + mp_virtual_pin_write(self->pin, arg ^ self->inverted); + return 0; + } + } + return -1; +} + +// fast method for getting/setting signal value +STATIC mp_obj_t signal_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 0, 1, false); + if (n_args == 0) { + // get pin + return MP_OBJ_NEW_SMALL_INT(mp_virtual_pin_read(self_in)); + } else { + // set pin + mp_virtual_pin_write(self_in, mp_obj_is_true(args[0])); + return mp_const_none; + } +} + +STATIC mp_obj_t signal_value(size_t n_args, const mp_obj_t *args) { + return signal_call(args[0], n_args - 1, 0, args + 1); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(signal_value_obj, 1, 2, signal_value); + +STATIC const mp_rom_map_elem_t signal_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&signal_value_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(signal_locals_dict, signal_locals_dict_table); + +STATIC const mp_pin_p_t signal_pin_p = { + .ioctl = signal_ioctl, +}; + +const mp_obj_type_t machine_signal_type = { + { &mp_type_type }, + .name = MP_QSTR_Signal, + .make_new = signal_make_new, + .call = signal_call, + .protocol = &signal_pin_p, + .locals_dict = (void*)&signal_locals_dict, +}; + +#endif // MICROPY_PY_MACHINE diff --git a/extmod/vfs_fat_file.h b/extmod/machine_signal.h index 5c271b6ee..7f88cbaa8 100644 --- a/extmod/vfs_fat_file.h +++ b/extmod/machine_signal.h @@ -1,9 +1,9 @@ /* - * This file is part of the Micro Python project, http://micropython.org/ + * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) * - * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2017 Paul Sokolovsky * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,9 +24,12 @@ * THE SOFTWARE. */ -extern const byte fresult_to_errno_table[20]; -mp_obj_t fatfs_builtin_open(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kwargs); -MP_DECLARE_CONST_FUN_OBJ_KW(mp_builtin_open_obj); +#ifndef __MICROPY_INCLUDED_EXTMOD_MACHINE_SIGNAL_H__ +#define __MICROPY_INCLUDED_EXTMOD_MACHINE_SIGNAL_H__ -mp_obj_t fat_vfs_listdir(const char *path, bool is_str_type); +#include "py/obj.h" + +extern const mp_obj_type_t machine_signal_type; + +#endif // __MICROPY_INCLUDED_EXTMOD_MACHINE_SIGNAL_H__ diff --git a/extmod/machine_spi.c b/extmod/machine_spi.c index 6e7678498..a67d294ba 100644 --- a/extmod/machine_spi.c +++ b/extmod/machine_spi.c @@ -90,12 +90,6 @@ void mp_machine_soft_spi_transfer(mp_obj_base_t *self_in, size_t len, const uint if (dest != NULL) { dest[i] = data_in; } - - // Some ports need a regular callback, but probably we don't need - // to do this every byte, or even at all. - #ifdef MICROPY_EVENT_POLL_HOOK - MICROPY_EVENT_POLL_HOOK; - #endif } } diff --git a/extmod/modframebuf.c b/extmod/modframebuf.c index 93d4922c9..792a3a7fa 100644 --- a/extmod/modframebuf.c +++ b/extmod/modframebuf.c @@ -97,13 +97,66 @@ STATIC void rgb565_fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w, i } } +// Functions for GS4_HMSB format + +STATIC void gs4_hmsb_setpixel(const mp_obj_framebuf_t *fb, int x, int y, uint32_t col) { + uint8_t *pixel = &((uint8_t*)fb->buf)[(x + y * fb->stride) >> 1]; + + if (x % 2) { + *pixel = ((uint8_t)col & 0x0f) | (*pixel & 0xf0); + } else { + *pixel = ((uint8_t)col << 4) | (*pixel & 0x0f); + } +} + +STATIC uint32_t gs4_hmsb_getpixel(const mp_obj_framebuf_t *fb, int x, int y) { + if (x % 2) { + return ((uint8_t*)fb->buf)[(x + y * fb->stride) >> 1] & 0x0f; + } + + return ((uint8_t*)fb->buf)[(x + y * fb->stride) >> 1] >> 4; +} + +STATIC void gs4_hmsb_fill_rect(const mp_obj_framebuf_t *fb, int x, int y, int w, int h, uint32_t col) { + col &= 0x0f; + uint8_t *pixel_pair = &((uint8_t*)fb->buf)[(x + y * fb->stride) >> 1]; + uint8_t col_shifted_left = col << 4; + uint8_t colored_pixel_pair = col_shifted_left | col; + int pixel_count_till_next_line = (fb->stride - w) >> 1; + bool odd_x = (x % 2 == 1); + + while (h--) { + int ww = w; + + if (odd_x && ww > 0) { + *pixel_pair = (*pixel_pair & 0xf0) | col; + pixel_pair++; + ww--; + } + + memset(pixel_pair, colored_pixel_pair, ww >> 1); + pixel_pair += ww >> 1; + + if (ww % 2) { + *pixel_pair = col_shifted_left | (*pixel_pair & 0x0f); + if (!odd_x) { + pixel_pair++; + } + } + + pixel_pair += pixel_count_till_next_line; + } +} + // constants for formats -#define FRAMEBUF_MVLSB (0) -#define FRAMEBUF_RGB565 (1) +#define FRAMEBUF_MVLSB (0) +#define FRAMEBUF_RGB565 (1) +#define FRAMEBUF_GS4_HMSB (2) STATIC mp_framebuf_p_t formats[] = { [FRAMEBUF_MVLSB] = {mvlsb_setpixel, mvlsb_getpixel, mvlsb_fill_rect}, [FRAMEBUF_RGB565] = {rgb565_setpixel, rgb565_getpixel, rgb565_fill_rect}, + [FRAMEBUF_GS4_HMSB] = {gs4_hmsb_setpixel, gs4_hmsb_getpixel, gs4_hmsb_fill_rect}, }; static inline void setpixel(const mp_obj_framebuf_t *fb, int x, int y, uint32_t color) { @@ -152,6 +205,7 @@ STATIC mp_obj_t framebuf_make_new(const mp_obj_type_t *type, size_t n_args, size switch (o->format) { case FRAMEBUF_MVLSB: case FRAMEBUF_RGB565: + case FRAMEBUF_GS4_HMSB: break; default: nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, @@ -302,9 +356,13 @@ STATIC mp_obj_t framebuf_line(size_t n_args, const mp_obj_t *args) { mp_int_t e = 2 * dy - dx; for (mp_int_t i = 0; i < dx; ++i) { if (steep) { - setpixel(self, y1, x1, col); + if (0 <= y1 && y1 < self->width && 0 <= x1 && x1 < self->height) { + setpixel(self, y1, x1, col); + } } else { - setpixel(self, x1, y1, col); + if (0 <= x1 && x1 < self->width && 0 <= y1 && y1 < self->height) { + setpixel(self, x1, y1, col); + } } while (e >= 0) { y1 += sy; @@ -314,7 +372,9 @@ STATIC mp_obj_t framebuf_line(size_t n_args, const mp_obj_t *args) { e += 2 * dy; } - setpixel(self, x2, y2, col); + if (0 <= x2 && x2 < self->width && 0 <= y2 && y2 < self->height) { + setpixel(self, x2, y2, col); + } return mp_const_none; } @@ -484,6 +544,7 @@ STATIC const mp_rom_map_elem_t framebuf_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_FrameBuffer1), MP_ROM_PTR(&legacy_framebuffer1_obj) }, { MP_ROM_QSTR(MP_QSTR_MVLSB), MP_OBJ_NEW_SMALL_INT(FRAMEBUF_MVLSB) }, { MP_ROM_QSTR(MP_QSTR_RGB565), MP_OBJ_NEW_SMALL_INT(FRAMEBUF_RGB565) }, + { MP_ROM_QSTR(MP_QSTR_GS4_HMSB), MP_OBJ_NEW_SMALL_INT(FRAMEBUF_GS4_HMSB) }, }; STATIC MP_DEFINE_CONST_DICT(framebuf_module_globals, framebuf_module_globals_table); diff --git a/extmod/modlwip.c b/extmod/modlwip.c index 62699bd41..0f2a6c64b 100644 --- a/extmod/modlwip.c +++ b/extmod/modlwip.c @@ -1172,6 +1172,7 @@ STATIC const mp_map_elem_t lwip_socket_locals_dict_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_makefile), (mp_obj_t)&lwip_socket_makefile_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_read), (mp_obj_t)&mp_stream_read_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_readinto), (mp_obj_t)&mp_stream_readinto_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_readline), (mp_obj_t)&mp_stream_unbuffered_readline_obj}, { MP_OBJ_NEW_QSTR(MP_QSTR_write), (mp_obj_t)&mp_stream_write_obj }, }; diff --git a/extmod/vfs.c b/extmod/vfs.c new file mode 100644 index 000000000..1eb26acf1 --- /dev/null +++ b/extmod/vfs.c @@ -0,0 +1,309 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include <stdint.h> +#include <string.h> + +#include "py/runtime.h" +#include "py/objstr.h" +#include "py/mperrno.h" +#include "extmod/vfs.h" + +#if MICROPY_VFS + +#if MICROPY_VFS_FAT +#include "extmod/vfs_fat.h" +#endif + +// path is the path to lookup and *path_out holds the path within the VFS +// object (starts with / if an absolute path). +// Returns MP_VFS_ROOT for root dir (and then path_out is undefined) and +// MP_VFS_NONE for path not found. +mp_vfs_mount_t *mp_vfs_lookup_path(const char *path, const char **path_out) { + if (path[0] == '/' && path[1] == 0) { + return MP_VFS_ROOT; + } else if (MP_STATE_VM(vfs_cur) == MP_VFS_ROOT) { + // in root dir + if (path[0] == 0) { + return MP_VFS_ROOT; + } + } else if (*path != '/') { + // a relative path within a mounted device + *path_out = path; + return MP_STATE_VM(vfs_cur); + } + + for (mp_vfs_mount_t *vfs = MP_STATE_VM(vfs_mount_table); vfs != NULL; vfs = vfs->next) { + if (strncmp(path, vfs->str, vfs->len) == 0) { + if (path[vfs->len] == '/') { + *path_out = path + vfs->len; + return vfs; + } else if (path[vfs->len] == '\0') { + *path_out = "/"; + return vfs; + } + } + } + + // mount point not found + return MP_VFS_NONE; +} + +// Version of mp_vfs_lookup_path that takes and returns uPy string objects. +STATIC mp_vfs_mount_t *lookup_path(mp_obj_t path_in, mp_obj_t *path_out) { + const char *path = mp_obj_str_get_str(path_in); + const char *p_out; + mp_vfs_mount_t *vfs = mp_vfs_lookup_path(path, &p_out); + if (vfs != MP_VFS_NONE && vfs != MP_VFS_ROOT) { + *path_out = mp_obj_new_str_of_type(mp_obj_get_type(path_in), + (const byte*)p_out, strlen(p_out)); + } + return vfs; +} + +STATIC mp_obj_t mp_vfs_proxy_call(mp_vfs_mount_t *vfs, qstr meth_name, size_t n_args, const mp_obj_t *args) { + if (vfs == MP_VFS_NONE) { + // mount point not found + mp_raise_OSError(MP_ENODEV); + } + if (vfs == MP_VFS_ROOT) { + // can't do operation on root dir + mp_raise_OSError(MP_EPERM); + } + mp_obj_t meth[n_args + 2]; + mp_load_method(vfs->obj, meth_name, meth); + if (args != NULL) { + memcpy(meth + 2, args, n_args * sizeof(*args)); + } + return mp_call_method_n_kw(n_args, 0, meth); +} + +mp_import_stat_t mp_vfs_import_stat(const char *path) { + const char *path_out; + mp_vfs_mount_t *vfs = mp_vfs_lookup_path(path, &path_out); + if (vfs == MP_VFS_NONE || vfs == MP_VFS_ROOT) { + return MP_IMPORT_STAT_NO_EXIST; + } + #if MICROPY_VFS_FAT + // fast paths for known VFS types + if (mp_obj_get_type(vfs->obj) == &mp_fat_vfs_type) { + return fat_vfs_import_stat(MP_OBJ_TO_PTR(vfs->obj), path_out); + } + #endif + // TODO delegate to vfs.stat() method + return MP_IMPORT_STAT_NO_EXIST; +} + +mp_obj_t mp_vfs_mount(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_readonly, ARG_mkfs }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_readonly, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_false} }, + { MP_QSTR_mkfs, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_false} }, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 2, pos_args + 2, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // get the mount point + mp_uint_t mnt_len; + const char *mnt_str = mp_obj_str_get_data(pos_args[1], &mnt_len); + + // create new object + mp_vfs_mount_t *vfs = m_new_obj(mp_vfs_mount_t); + vfs->str = mnt_str; + vfs->len = mnt_len; + vfs->obj = pos_args[0]; + vfs->next = NULL; + + // call the underlying object to do any mounting operation + mp_vfs_proxy_call(vfs, MP_QSTR_mount, 2, (mp_obj_t*)&args); + + // check that the destination mount point is unused + const char *path_out; + if (mp_vfs_lookup_path(mp_obj_str_get_str(pos_args[1]), &path_out) != MP_VFS_NONE) { + mp_raise_OSError(MP_EPERM); + } + + // insert the vfs into the mount table + mp_vfs_mount_t **vfsp = &MP_STATE_VM(vfs_mount_table); + while (*vfsp != NULL) { + vfsp = &(*vfsp)->next; + } + *vfsp = vfs; + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(mp_vfs_mount_obj, 2, mp_vfs_mount); + +mp_obj_t mp_vfs_umount(mp_obj_t mnt_in) { + // remove vfs from the mount table + mp_vfs_mount_t *vfs = NULL; + mp_uint_t mnt_len; + const char *mnt_str = NULL; + if (MP_OBJ_IS_STR(mnt_in)) { + mnt_str = mp_obj_str_get_data(mnt_in, &mnt_len); + } + for (mp_vfs_mount_t **vfsp = &MP_STATE_VM(vfs_mount_table); *vfsp != NULL; vfsp = &(*vfsp)->next) { + if ((mnt_str != NULL && !memcmp(mnt_str, (*vfsp)->str, mnt_len + 1)) || (*vfsp)->obj == mnt_in) { + vfs = *vfsp; + *vfsp = (*vfsp)->next; + break; + } + } + + if (vfs == NULL) { + mp_raise_OSError(MP_EINVAL); + } + + // if we unmounted the current device then set current to root + if (MP_STATE_VM(vfs_cur) == vfs) { + MP_STATE_VM(vfs_cur) = MP_VFS_ROOT; + } + + // call the underlying object to do any unmounting operation + mp_vfs_proxy_call(vfs, MP_QSTR_umount, 0, NULL); + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(mp_vfs_umount_obj, mp_vfs_umount); + +mp_obj_t mp_vfs_open(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_file, ARG_mode, ARG_encoding }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_file, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, + { MP_QSTR_mode, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_QSTR(MP_QSTR_r)} }, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_vfs_mount_t *vfs = lookup_path((mp_obj_t)args[ARG_file].u_rom_obj, &args[ARG_file].u_obj); + return mp_vfs_proxy_call(vfs, MP_QSTR_open, 2, (mp_obj_t*)&args); +} +MP_DEFINE_CONST_FUN_OBJ_KW(mp_vfs_open_obj, 0, mp_vfs_open); + +mp_obj_t mp_vfs_chdir(mp_obj_t path_in) { + mp_obj_t path_out; + mp_vfs_mount_t *vfs = lookup_path(path_in, &path_out); + if (vfs != MP_VFS_ROOT) { + mp_vfs_proxy_call(vfs, MP_QSTR_chdir, 1, &path_out); + } + MP_STATE_VM(vfs_cur) = vfs; + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(mp_vfs_chdir_obj, mp_vfs_chdir); + +mp_obj_t mp_vfs_getcwd(void) { + if (MP_STATE_VM(vfs_cur) == MP_VFS_ROOT) { + return MP_OBJ_NEW_QSTR(MP_QSTR__slash_); + } + mp_obj_t cwd_o = mp_vfs_proxy_call(MP_STATE_VM(vfs_cur), MP_QSTR_getcwd, 0, NULL); + const char *cwd = mp_obj_str_get_str(cwd_o); + vstr_t vstr; + vstr_init(&vstr, MP_STATE_VM(vfs_cur)->len + strlen(cwd) + 1); + vstr_add_strn(&vstr, MP_STATE_VM(vfs_cur)->str, MP_STATE_VM(vfs_cur)->len); + if (!(cwd[0] == '/' && cwd[1] == 0)) { + vstr_add_str(&vstr, cwd); + } + return mp_obj_new_str_from_vstr(&mp_type_str, &vstr); +} +MP_DEFINE_CONST_FUN_OBJ_0(mp_vfs_getcwd_obj, mp_vfs_getcwd); + +mp_obj_t mp_vfs_listdir(size_t n_args, const mp_obj_t *args) { + mp_obj_t path_in; + if (n_args == 1) { + path_in = args[0]; + } else { + path_in = MP_OBJ_NEW_QSTR(MP_QSTR_); + } + + mp_obj_t path_out; + mp_vfs_mount_t *vfs = lookup_path(path_in, &path_out); + + if (vfs == MP_VFS_ROOT) { + // list the root directory + mp_obj_t dir_list = mp_obj_new_list(0, NULL); + for (vfs = MP_STATE_VM(vfs_mount_table); vfs != NULL; vfs = vfs->next) { + mp_obj_list_append(dir_list, mp_obj_new_str_of_type(mp_obj_get_type(path_in), + (const byte*)vfs->str + 1, vfs->len - 1)); + } + return dir_list; + } + + return mp_vfs_proxy_call(vfs, MP_QSTR_listdir, 1, &path_out); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_vfs_listdir_obj, 0, 1, mp_vfs_listdir); + +mp_obj_t mp_vfs_mkdir(mp_obj_t path_in) { + mp_obj_t path_out; + mp_vfs_mount_t *vfs = lookup_path(path_in, &path_out); + return mp_vfs_proxy_call(vfs, MP_QSTR_mkdir, 1, &path_out); +} +MP_DEFINE_CONST_FUN_OBJ_1(mp_vfs_mkdir_obj, mp_vfs_mkdir); + +mp_obj_t mp_vfs_remove(mp_obj_t path_in) { + mp_obj_t path_out; + mp_vfs_mount_t *vfs = lookup_path(path_in, &path_out); + return mp_vfs_proxy_call(vfs, MP_QSTR_remove, 1, &path_out); +} +MP_DEFINE_CONST_FUN_OBJ_1(mp_vfs_remove_obj, mp_vfs_remove); + +mp_obj_t mp_vfs_rename(mp_obj_t old_path_in, mp_obj_t new_path_in) { + mp_obj_t args[2]; + mp_vfs_mount_t *old_vfs = lookup_path(old_path_in, &args[0]); + mp_vfs_mount_t *new_vfs = lookup_path(new_path_in, &args[1]); + if (old_vfs != new_vfs) { + // can't rename across filesystems + mp_raise_OSError(MP_EPERM); + } + return mp_vfs_proxy_call(old_vfs, MP_QSTR_rename, 2, args); +} +MP_DEFINE_CONST_FUN_OBJ_2(mp_vfs_rename_obj, mp_vfs_rename); + +mp_obj_t mp_vfs_rmdir(mp_obj_t path_in) { + mp_obj_t path_out; + mp_vfs_mount_t *vfs = lookup_path(path_in, &path_out); + return mp_vfs_proxy_call(vfs, MP_QSTR_rmdir, 1, &path_out); +} +MP_DEFINE_CONST_FUN_OBJ_1(mp_vfs_rmdir_obj, mp_vfs_rmdir); + +mp_obj_t mp_vfs_stat(mp_obj_t path_in) { + mp_obj_t path_out; + mp_vfs_mount_t *vfs = lookup_path(path_in, &path_out); + return mp_vfs_proxy_call(vfs, MP_QSTR_stat, 1, &path_out); +} +MP_DEFINE_CONST_FUN_OBJ_1(mp_vfs_stat_obj, mp_vfs_stat); + +mp_obj_t mp_vfs_statvfs(mp_obj_t path_in) { + mp_obj_t path_out; + mp_vfs_mount_t *vfs = lookup_path(path_in, &path_out); + return mp_vfs_proxy_call(vfs, MP_QSTR_statvfs, 1, &path_out); +} +MP_DEFINE_CONST_FUN_OBJ_1(mp_vfs_statvfs_obj, mp_vfs_statvfs); + +#endif // MICROPY_VFS diff --git a/extmod/vfs.h b/extmod/vfs.h new file mode 100644 index 000000000..4a1c225a0 --- /dev/null +++ b/extmod/vfs.h @@ -0,0 +1,80 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_EXTMOD_VFS_H +#define MICROPY_INCLUDED_EXTMOD_VFS_H + +#include "py/lexer.h" +#include "py/obj.h" + +// return values of mp_vfs_lookup_path +// ROOT is 0 so that the default current directory is the root directory +#define MP_VFS_NONE ((mp_vfs_mount_t*)1) +#define MP_VFS_ROOT ((mp_vfs_mount_t*)0) + +// constants for block protocol ioctl +#define BP_IOCTL_INIT (1) +#define BP_IOCTL_DEINIT (2) +#define BP_IOCTL_SYNC (3) +#define BP_IOCTL_SEC_COUNT (4) +#define BP_IOCTL_SEC_SIZE (5) + +typedef struct _mp_vfs_mount_t { + const char *str; // mount point with leading / + size_t len; + mp_obj_t obj; + struct _mp_vfs_mount_t *next; +} mp_vfs_mount_t; + +mp_vfs_mount_t *mp_vfs_lookup_path(const char *path, const char **path_out); +mp_import_stat_t mp_vfs_import_stat(const char *path); +mp_obj_t mp_vfs_mount(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +mp_obj_t mp_vfs_umount(mp_obj_t mnt_in); +mp_obj_t mp_vfs_open(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +mp_obj_t mp_vfs_chdir(mp_obj_t path_in); +mp_obj_t mp_vfs_getcwd(void); +mp_obj_t mp_vfs_listdir(size_t n_args, const mp_obj_t *args); +mp_obj_t mp_vfs_mkdir(mp_obj_t path_in); +mp_obj_t mp_vfs_remove(mp_obj_t path_in); +mp_obj_t mp_vfs_rename(mp_obj_t old_path_in, mp_obj_t new_path_in); +mp_obj_t mp_vfs_rmdir(mp_obj_t path_in); +mp_obj_t mp_vfs_stat(mp_obj_t path_in); +mp_obj_t mp_vfs_statvfs(mp_obj_t path_in); + +MP_DECLARE_CONST_FUN_OBJ_KW(mp_vfs_mount_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_vfs_umount_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(mp_vfs_open_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_vfs_chdir_obj); +MP_DECLARE_CONST_FUN_OBJ_0(mp_vfs_getcwd_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_vfs_listdir_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_vfs_mkdir_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_vfs_remove_obj); +MP_DECLARE_CONST_FUN_OBJ_2(mp_vfs_rename_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_vfs_rmdir_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_vfs_stat_obj); +MP_DECLARE_CONST_FUN_OBJ_1(mp_vfs_statvfs_obj); + +#endif // MICROPY_INCLUDED_EXTMOD_VFS_H diff --git a/extmod/vfs_fat.c b/extmod/vfs_fat.c index bd88bcf1b..82dd312b8 100644 --- a/extmod/vfs_fat.c +++ b/extmod/vfs_fat.c @@ -28,40 +28,73 @@ #include "py/mpconfig.h" #if MICROPY_VFS_FAT +#if !MICROPY_VFS +#error "with MICROPY_VFS_FAT enabled, must also enable MICROPY_VFS" +#endif + #include <string.h> #include "py/nlr.h" #include "py/runtime.h" #include "py/mperrno.h" -#include "lib/fatfs/ff.h" -#include "lib/fatfs/diskio.h" -#include "extmod/vfs_fat_file.h" -#include "extmod/fsusermount.h" -#include "timeutils.h" +#include "lib/oofatfs/ff.h" +#include "extmod/vfs_fat.h" +#include "lib/timeutils/timeutils.h" + +#if _MAX_SS == _MIN_SS +#define SECSIZE(fs) (_MIN_SS) +#else +#define SECSIZE(fs) ((fs)->ssize) +#endif #define mp_obj_fat_vfs_t fs_user_mount_t STATIC mp_obj_t fat_vfs_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { - mp_arg_check_num(n_args, n_kw, 2, 2, false); - mp_obj_fat_vfs_t *vfs = fatfs_mount_mkfs(n_args, args, (mp_map_t*)&mp_const_empty_map, false); + mp_arg_check_num(n_args, n_kw, 1, 1, false); + + // create new object + fs_user_mount_t *vfs = m_new_obj(fs_user_mount_t); vfs->base.type = type; + vfs->flags = FSUSER_FREE_OBJ; + vfs->str = NULL; + vfs->len = 0; + vfs->fatfs.drv = vfs; + + // load block protocol methods + mp_load_method(args[0], MP_QSTR_readblocks, vfs->readblocks); + mp_load_method_maybe(args[0], MP_QSTR_writeblocks, vfs->writeblocks); + mp_load_method_maybe(args[0], MP_QSTR_ioctl, vfs->u.ioctl); + if (vfs->u.ioctl[0] != MP_OBJ_NULL) { + // device supports new block protocol, so indicate it + vfs->flags |= FSUSER_HAVE_IOCTL; + } else { + // no ioctl method, so assume the device uses the old block protocol + mp_load_method_maybe(args[0], MP_QSTR_sync, vfs->u.old.sync); + mp_load_method(args[0], MP_QSTR_count, vfs->u.old.count); + } + return MP_OBJ_FROM_PTR(vfs); } STATIC mp_obj_t fat_vfs_mkfs(mp_obj_t bdev_in) { - mp_obj_t args[] = {bdev_in, MP_OBJ_NEW_QSTR(MP_QSTR_mkfs)}; - fatfs_mount_mkfs(2, args, (mp_map_t*)&mp_const_empty_map, true); + // create new object + fs_user_mount_t *vfs = MP_OBJ_TO_PTR(fat_vfs_make_new(&mp_fat_vfs_type, 1, 0, &bdev_in)); + + // make the filesystem + uint8_t working_buf[_MAX_SS]; + FRESULT res = f_mkfs(&vfs->fatfs, FM_FAT | FM_SFD, 0, working_buf, sizeof(working_buf)); + if (res != FR_OK) { + mp_raise_OSError(fresult_to_errno_table[res]); + } + return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(fat_vfs_mkfs_fun_obj, fat_vfs_mkfs); STATIC MP_DEFINE_CONST_STATICMETHOD_OBJ(fat_vfs_mkfs_obj, MP_ROM_PTR(&fat_vfs_mkfs_fun_obj)); -STATIC mp_obj_t fat_vfs_open(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { - // Skip self - return fatfs_builtin_open(n_args - 1, args + 1, kwargs); -} -MP_DEFINE_CONST_FUN_OBJ_KW(fat_vfs_open_obj, 2, fat_vfs_open); +STATIC MP_DEFINE_CONST_FUN_OBJ_3(fat_vfs_open_obj, fatfs_builtin_open_self); STATIC mp_obj_t fat_vfs_listdir_func(size_t n_args, const mp_obj_t *args) { + mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(args[0]); bool is_str_type = true; const char *path; if (n_args == 2) { @@ -73,19 +106,16 @@ STATIC mp_obj_t fat_vfs_listdir_func(size_t n_args, const mp_obj_t *args) { path = ""; } - return fat_vfs_listdir(path, is_str_type); + return fat_vfs_listdir2(self, path, is_str_type); } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(fat_vfs_listdir_obj, 1, 2, fat_vfs_listdir_func); -STATIC mp_obj_t fat_vfs_remove_internal(mp_obj_t path_in, mp_int_t attr) { +STATIC mp_obj_t fat_vfs_remove_internal(mp_obj_t vfs_in, mp_obj_t path_in, mp_int_t attr) { + mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(vfs_in); const char *path = mp_obj_str_get_str(path_in); FILINFO fno; -#if _USE_LFN - fno.lfname = NULL; - fno.lfsize = 0; -#endif - FRESULT res = f_stat(path, &fno); + FRESULT res = f_stat(&self->fatfs, path, &fno); if (res != FR_OK) { mp_raise_OSError(fresult_to_errno_table[res]); @@ -93,7 +123,7 @@ STATIC mp_obj_t fat_vfs_remove_internal(mp_obj_t path_in, mp_int_t attr) { // check if path is a file or directory if ((fno.fattrib & AM_DIR) == attr) { - res = f_unlink(path); + res = f_unlink(&self->fatfs, path); if (res != FR_OK) { mp_raise_OSError(fresult_to_errno_table[res]); @@ -105,27 +135,25 @@ STATIC mp_obj_t fat_vfs_remove_internal(mp_obj_t path_in, mp_int_t attr) { } STATIC mp_obj_t fat_vfs_remove(mp_obj_t vfs_in, mp_obj_t path_in) { - (void)vfs_in; - return fat_vfs_remove_internal(path_in, 0); // 0 == file attribute + return fat_vfs_remove_internal(vfs_in, path_in, 0); // 0 == file attribute } STATIC MP_DEFINE_CONST_FUN_OBJ_2(fat_vfs_remove_obj, fat_vfs_remove); STATIC mp_obj_t fat_vfs_rmdir(mp_obj_t vfs_in, mp_obj_t path_in) { - (void) vfs_in; - return fat_vfs_remove_internal(path_in, AM_DIR); + return fat_vfs_remove_internal(vfs_in, path_in, AM_DIR); } STATIC MP_DEFINE_CONST_FUN_OBJ_2(fat_vfs_rmdir_obj, fat_vfs_rmdir); STATIC mp_obj_t fat_vfs_rename(mp_obj_t vfs_in, mp_obj_t path_in, mp_obj_t path_out) { - (void)vfs_in; + mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(vfs_in); const char *old_path = mp_obj_str_get_str(path_in); const char *new_path = mp_obj_str_get_str(path_out); - FRESULT res = f_rename(old_path, new_path); + FRESULT res = f_rename(&self->fatfs, old_path, new_path); if (res == FR_EXIST) { // if new_path exists then try removing it (but only if it's a file) - fat_vfs_remove_internal(path_out, 0); // 0 == file attribute + fat_vfs_remove_internal(vfs_in, path_out, 0); // 0 == file attribute // try to rename again - res = f_rename(old_path, new_path); + res = f_rename(&self->fatfs, old_path, new_path); } if (res == FR_OK) { return mp_const_none; @@ -137,9 +165,9 @@ STATIC mp_obj_t fat_vfs_rename(mp_obj_t vfs_in, mp_obj_t path_in, mp_obj_t path_ STATIC MP_DEFINE_CONST_FUN_OBJ_3(fat_vfs_rename_obj, fat_vfs_rename); STATIC mp_obj_t fat_vfs_mkdir(mp_obj_t vfs_in, mp_obj_t path_o) { - (void)vfs_in; + mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(vfs_in); const char *path = mp_obj_str_get_str(path_o); - FRESULT res = f_mkdir(path); + FRESULT res = f_mkdir(&self->fatfs, path); if (res == FR_OK) { return mp_const_none; } else { @@ -150,15 +178,11 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(fat_vfs_mkdir_obj, fat_vfs_mkdir); /// Change current directory. STATIC mp_obj_t fat_vfs_chdir(mp_obj_t vfs_in, mp_obj_t path_in) { - (void)vfs_in; + mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(vfs_in); const char *path; path = mp_obj_str_get_str(path_in); - FRESULT res = f_chdrive(path); - - if (res == FR_OK) { - res = f_chdir(path); - } + FRESULT res = f_chdir(&self->fatfs, path); if (res != FR_OK) { mp_raise_OSError(fresult_to_errno_table[res]); @@ -170,71 +194,31 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(fat_vfs_chdir_obj, fat_vfs_chdir); /// Get the current directory. STATIC mp_obj_t fat_vfs_getcwd(mp_obj_t vfs_in) { - (void)vfs_in; + mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(vfs_in); char buf[MICROPY_ALLOC_PATH_MAX + 1]; - FRESULT res = f_getcwd(buf, sizeof buf); - + FRESULT res = f_getcwd(&self->fatfs, buf, sizeof(buf)); if (res != FR_OK) { mp_raise_OSError(fresult_to_errno_table[res]); } - return mp_obj_new_str(buf, strlen(buf), false); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(fat_vfs_getcwd_obj, fat_vfs_getcwd); -// Checks for path equality, ignoring trailing slashes: -// path_equal(/, /) -> true -// second argument must be in canonical form (meaning no trailing slash, unless it's just /) -STATIC bool path_equal(const char *path, const char *path_canonical) { - while (*path_canonical != '\0' && *path == *path_canonical) { - ++path; - ++path_canonical; - } - if (*path_canonical != '\0') { - return false; - } - while (*path == '/') { - ++path; - } - return *path == '\0'; -} - /// \function stat(path) /// Get the status of a file or directory. STATIC mp_obj_t fat_vfs_stat(mp_obj_t vfs_in, mp_obj_t path_in) { - (void)vfs_in; + mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(vfs_in); const char *path = mp_obj_str_get_str(path_in); FILINFO fno; -#if _USE_LFN - fno.lfname = NULL; - fno.lfsize = 0; -#endif - FRESULT res; - - if (path_equal(path, "/")) { + if (path[0] == 0 || (path[0] == '/' && path[1] == 0)) { // stat root directory fno.fsize = 0; fno.fdate = 0x2821; // Jan 1, 2000 fno.ftime = 0; fno.fattrib = AM_DIR; } else { - 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 = 0x2821; // Jan 1, 2000 - fno.ftime = 0; - fno.fattrib = AM_DIR; - res = FR_OK; - } - } - if (res == FR_NO_PATH) { - // stat normal file - res = f_stat(path, &fno); - } + FRESULT res = f_stat(&self->fatfs, path, &fno); if (res != FR_OK) { mp_raise_OSError(fresult_to_errno_table[res]); } @@ -272,19 +256,19 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(fat_vfs_stat_obj, fat_vfs_stat); // Get the status of a VFS. STATIC mp_obj_t fat_vfs_statvfs(mp_obj_t vfs_in, mp_obj_t path_in) { - (void)vfs_in; - const char *path = mp_obj_str_get_str(path_in); + mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(vfs_in); + (void)path_in; - FATFS *fatfs; DWORD nclst; - FRESULT res = f_getfree(path, &nclst, &fatfs); + FATFS *fatfs = &self->fatfs; + FRESULT res = f_getfree(fatfs, &nclst); if (FR_OK != res) { mp_raise_OSError(fresult_to_errno_table[res]); } mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL)); - t->items[0] = MP_OBJ_NEW_SMALL_INT(fatfs->csize * fatfs->ssize); // f_bsize + t->items[0] = MP_OBJ_NEW_SMALL_INT(fatfs->csize * SECSIZE(fatfs)); // f_bsize t->items[1] = t->items[0]; // f_frsize t->items[2] = MP_OBJ_NEW_SMALL_INT((fatfs->n_fatent - 2) * fatfs->csize); // f_blocks t->items[3] = MP_OBJ_NEW_SMALL_INT(nclst); // f_bfree @@ -299,12 +283,42 @@ STATIC mp_obj_t fat_vfs_statvfs(mp_obj_t vfs_in, mp_obj_t path_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_2(fat_vfs_statvfs_obj, fat_vfs_statvfs); -// Unmount the filesystem -STATIC mp_obj_t fat_vfs_umount(mp_obj_t vfs_in) { - fatfs_umount(((fs_user_mount_t *)vfs_in)->readblocks[1]); +STATIC mp_obj_t vfs_fat_mount(mp_obj_t self_in, mp_obj_t readonly, mp_obj_t mkfs) { + fs_user_mount_t *self = MP_OBJ_TO_PTR(self_in); + + // Read-only device indicated by writeblocks[0] == MP_OBJ_NULL. + // User can specify read-only device by: + // 1. readonly=True keyword argument + // 2. nonexistent writeblocks method (then writeblocks[0] == MP_OBJ_NULL already) + if (mp_obj_is_true(readonly)) { + self->writeblocks[0] = MP_OBJ_NULL; + } + + // mount the block device + FRESULT res = f_mount(&self->fatfs); + + // check if we need to make the filesystem + if (res == FR_NO_FILESYSTEM && mp_obj_is_true(mkfs)) { + uint8_t working_buf[_MAX_SS]; + res = f_mkfs(&self->fatfs, FM_FAT | FM_SFD, 0, working_buf, sizeof(working_buf)); + } + if (res != FR_OK) { + mp_raise_OSError(fresult_to_errno_table[res]); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(vfs_fat_mount_obj, vfs_fat_mount); + +STATIC mp_obj_t vfs_fat_umount(mp_obj_t self_in) { + fs_user_mount_t *self = MP_OBJ_TO_PTR(self_in); + FRESULT res = f_umount(&self->fatfs); + if (res != FR_OK) { + mp_raise_OSError(fresult_to_errno_table[res]); + } return mp_const_none; } -STATIC MP_DEFINE_CONST_FUN_OBJ_1(fat_vfs_umount_obj, fat_vfs_umount); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(fat_vfs_umount_obj, vfs_fat_umount); STATIC const mp_rom_map_elem_t fat_vfs_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_mkfs), MP_ROM_PTR(&fat_vfs_mkfs_obj) }, @@ -318,6 +332,7 @@ STATIC const mp_rom_map_elem_t fat_vfs_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_rename), MP_ROM_PTR(&fat_vfs_rename_obj) }, { MP_ROM_QSTR(MP_QSTR_stat), MP_ROM_PTR(&fat_vfs_stat_obj) }, { MP_ROM_QSTR(MP_QSTR_statvfs), MP_ROM_PTR(&fat_vfs_statvfs_obj) }, + { MP_ROM_QSTR(MP_QSTR_mount), MP_ROM_PTR(&vfs_fat_mount_obj) }, { MP_ROM_QSTR(MP_QSTR_umount), MP_ROM_PTR(&fat_vfs_umount_obj) }, }; STATIC MP_DEFINE_CONST_DICT(fat_vfs_locals_dict, fat_vfs_locals_dict_table); diff --git a/extmod/fsusermount.h b/extmod/vfs_fat.h index af6867d23..a5e3c604b 100644 --- a/extmod/fsusermount.h +++ b/extmod/vfs_fat.h @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2014 Damien P. George + * Copyright (c) 2013, 2014 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,18 +24,16 @@ * THE SOFTWARE. */ +#include "py/lexer.h" +#include "py/obj.h" +#include "lib/oofatfs/ff.h" +#include "extmod/vfs.h" + // 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 -// constants for block protocol ioctl -#define BP_IOCTL_INIT (1) -#define BP_IOCTL_DEINIT (2) -#define BP_IOCTL_SYNC (3) -#define BP_IOCTL_SEC_COUNT (4) -#define BP_IOCTL_SEC_SIZE (5) - typedef struct _fs_user_mount_t { mp_obj_base_t base; const char *str; @@ -54,9 +52,11 @@ typedef struct _fs_user_mount_t { FATFS fatfs; } fs_user_mount_t; -fs_user_mount_t *fatfs_mount_mkfs(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args, bool mkfs); -mp_obj_t fatfs_umount(mp_obj_t bdev_or_path_in); +extern const byte fresult_to_errno_table[20]; +extern const mp_obj_type_t mp_fat_vfs_type; + +mp_import_stat_t fat_vfs_import_stat(struct _fs_user_mount_t *vfs, const char *path); +mp_obj_t fatfs_builtin_open_self(mp_obj_t self_in, mp_obj_t path, mp_obj_t mode); +MP_DECLARE_CONST_FUN_OBJ_KW(mp_builtin_open_obj); -MP_DECLARE_CONST_FUN_OBJ_KW(fsuser_mount_obj); -MP_DECLARE_CONST_FUN_OBJ_1(fsuser_umount_obj); -MP_DECLARE_CONST_FUN_OBJ_KW(fsuser_mkfs_obj); +mp_obj_t fat_vfs_listdir2(struct _fs_user_mount_t *vfs, const char *path, bool is_str_type); diff --git a/extmod/vfs_fat_diskio.c b/extmod/vfs_fat_diskio.c index 3f1902b2e..7efcc22f2 100644 --- a/extmod/vfs_fat_diskio.c +++ b/extmod/vfs_fat_diskio.c @@ -28,7 +28,7 @@ */ #include "py/mpconfig.h" -#if MICROPY_FSUSERMOUNT +#if MICROPY_VFS #include <stdint.h> #include <stdio.h> @@ -36,9 +36,9 @@ #include "py/mphal.h" #include "py/runtime.h" -#include "lib/fatfs/ff.h" /* FatFs lower layer API */ -#include "lib/fatfs/diskio.h" /* FatFs lower layer API */ -#include "extmod/fsusermount.h" +#include "lib/oofatfs/ff.h" +#include "lib/oofatfs/diskio.h" +#include "extmod/vfs_fat.h" #if _MAX_SS == _MIN_SS #define SECSIZE(fs) (_MIN_SS) @@ -46,20 +46,18 @@ #define SECSIZE(fs) ((fs)->ssize) #endif -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; - } +typedef void *bdev_t; +STATIC fs_user_mount_t *disk_get_device(void *bdev) { + return (fs_user_mount_t*)bdev; } /*-----------------------------------------------------------------------*/ /* Initialize a Drive */ /*-----------------------------------------------------------------------*/ +STATIC DSTATUS disk_initialize ( - BYTE pdrv /* Physical drive nmuber (0..) */ + bdev_t pdrv /* Physical drive nmuber (0..) */ ) { fs_user_mount_t *vfs = disk_get_device(pdrv); @@ -89,8 +87,9 @@ DSTATUS disk_initialize ( /* Get Disk Status */ /*-----------------------------------------------------------------------*/ +STATIC DSTATUS disk_status ( - BYTE pdrv /* Physical drive nmuber (0..) */ + bdev_t pdrv /* Physical drive nmuber (0..) */ ) { fs_user_mount_t *vfs = disk_get_device(pdrv); @@ -110,7 +109,7 @@ DSTATUS disk_status ( /*-----------------------------------------------------------------------*/ DRESULT disk_read ( - BYTE pdrv, /* Physical drive nmuber (0..) */ + bdev_t pdrv, /* Physical drive nmuber (0..) */ BYTE *buff, /* Data buffer to store read data */ DWORD sector, /* Sector address (LBA) */ UINT count /* Number of sectors to read (1..128) */ @@ -140,9 +139,8 @@ DRESULT disk_read ( /* Write Sector(s) */ /*-----------------------------------------------------------------------*/ -#if _USE_WRITE DRESULT disk_write ( - BYTE pdrv, /* Physical drive nmuber (0..) */ + bdev_t pdrv, /* Physical drive nmuber (0..) */ const BYTE *buff, /* Data to be written */ DWORD sector, /* Sector address (LBA) */ UINT count /* Number of sectors to write (1..128) */ @@ -172,16 +170,14 @@ DRESULT disk_write ( return RES_OK; } -#endif /*-----------------------------------------------------------------------*/ /* Miscellaneous Functions */ /*-----------------------------------------------------------------------*/ -#if _USE_IOCTL DRESULT disk_ioctl ( - BYTE pdrv, /* Physical drive nmuber (0..) */ + bdev_t pdrv, /* Physical drive nmuber (0..) */ BYTE cmd, /* Control code */ void *buff /* Buffer to send/receive control data */ ) @@ -218,6 +214,10 @@ DRESULT disk_ioctl ( } else { *((WORD*)buff) = mp_obj_get_int(ret); } + #if _MAX_SS != _MIN_SS + // need to store ssize because we use it in disk_read/disk_write + vfs->fatfs.ssize = *((WORD*)buff); + #endif return RES_OK; } @@ -225,6 +225,14 @@ DRESULT disk_ioctl ( *((DWORD*)buff) = 1; // erase block size in units of sector size return RES_OK; + case IOCTL_INIT: + *((DSTATUS*)buff) = disk_initialize(pdrv); + return RES_OK; + + case IOCTL_STATUS: + *((DSTATUS*)buff) = disk_status(pdrv); + return RES_OK; + default: return RES_PARERR; } @@ -245,17 +253,28 @@ DRESULT disk_ioctl ( case GET_SECTOR_SIZE: *((WORD*)buff) = 512; // old protocol had fixed sector size + #if _MAX_SS != _MIN_SS + // need to store ssize because we use it in disk_read/disk_write + vfs->fatfs.ssize = 512; + #endif return RES_OK; case GET_BLOCK_SIZE: *((DWORD*)buff) = 1; // erase block size in units of sector size return RES_OK; + case IOCTL_INIT: + *((DSTATUS*)buff) = disk_initialize(pdrv); + return RES_OK; + + case IOCTL_STATUS: + *((DSTATUS*)buff) = disk_status(pdrv); + return RES_OK; + default: return RES_PARERR; } } } -#endif -#endif // MICROPY_FSUSERMOUNT +#endif // MICROPY_VFS diff --git a/extmod/vfs_fat_ffconf.c b/extmod/vfs_fat_ffconf.c deleted file mode 100644 index f8935af75..000000000 --- a/extmod/vfs_fat_ffconf.c +++ /dev/null @@ -1,82 +0,0 @@ -/* - * This file is part of the Micro Python project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2013, 2014 Damien P. George - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "py/mpconfig.h" -#if MICROPY_FSUSERMOUNT - -#include <string.h> - -#include "py/mpstate.h" -#include "lib/fatfs/ff.h" -#include "lib/fatfs/ffconf.h" -#include "lib/fatfs/diskio.h" -#include "extmod/fsusermount.h" - -STATIC bool check_path(const TCHAR **path, const char *mount_point_str, mp_uint_t mount_point_len) { - if (strncmp(*path, mount_point_str, mount_point_len) == 0) { - if ((*path)[mount_point_len] == '/') { - *path += mount_point_len; - return true; - } else if ((*path)[mount_point_len] == '\0') { - *path = "/"; - return true; - } - } - return false; -} - -// "path" is the path to lookup; will advance this pointer beyond the volume name. -// Returns logical drive number (-1 means invalid path). -int ff_get_ldnumber (const TCHAR **path) { - if (!(*path)) { - return -1; - } - - if (**path != '/') { - #if _FS_RPATH - return ff_CurrVol; - #else - return -1; - #endif - } - - 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) { - fs_user_mount_t *vfs = MP_STATE_PORT(fs_user_mount)[vol]; - memcpy(*dest, vfs->str, vfs->len); - *dest += vfs->len; -} - -#endif // MICROPY_FSUSERMOUNT diff --git a/extmod/vfs_fat_file.c b/extmod/vfs_fat_file.c index 77848b5a5..62da23f94 100644 --- a/extmod/vfs_fat_file.c +++ b/extmod/vfs_fat_file.c @@ -25,9 +25,7 @@ */ #include "py/mpconfig.h" -// *_ADHOC part is for cc3200 port which doesn't use general uPy -// infrastructure and instead duplicates code. TODO: Resolve. -#if MICROPY_FSUSERMOUNT || MICROPY_FSUSERMOUNT_ADHOC +#if MICROPY_VFS #include <stdio.h> #include <errno.h> @@ -36,8 +34,8 @@ #include "py/runtime.h" #include "py/stream.h" #include "py/mperrno.h" -#include "lib/fatfs/ff.h" -#include "extmod/vfs_fat_file.h" +#include "lib/oofatfs/ff.h" +#include "extmod/vfs_fat.h" #if MICROPY_VFS_FAT #define mp_type_fileio fatfs_type_fileio @@ -112,7 +110,7 @@ STATIC mp_uint_t file_obj_write(mp_obj_t self_in, const void *buf, mp_uint_t siz STATIC mp_obj_t file_obj_close(mp_obj_t self_in) { pyb_file_obj_t *self = MP_OBJ_TO_PTR(self_in); // if fs==NULL then the file is closed and in that case this method is a no-op - if (self->fp.fs != NULL) { + if (self->fp.obj.fs != NULL) { FRESULT res = f_close(&self->fp); if (res != FR_OK) { mp_raise_OSError(fresult_to_errno_table[res]); @@ -178,7 +176,7 @@ STATIC const mp_arg_t file_open_args[] = { }; #define FILE_OPEN_NUM_ARGS MP_ARRAY_SIZE(file_open_args) -STATIC mp_obj_t file_open(const mp_obj_type_t *type, mp_arg_val_t *args) { +STATIC mp_obj_t file_open(fs_user_mount_t *vfs, const mp_obj_type_t *type, mp_arg_val_t *args) { int mode = 0; const char *mode_s = mp_obj_str_get_str(args[1].u_obj); // TODO make sure only one of r, w, x, a, and b, t are specified @@ -214,7 +212,8 @@ STATIC mp_obj_t file_open(const mp_obj_type_t *type, mp_arg_val_t *args) { o->base.type = type; const char *fname = mp_obj_str_get_str(args[0].u_obj); - FRESULT res = f_open(&o->fp, fname, mode); + assert(vfs != NULL); + FRESULT res = f_open(&vfs->fatfs, &o->fp, fname, mode); if (res != FR_OK) { m_del_obj(pyb_file_obj_t, o); mp_raise_OSError(fresult_to_errno_table[res]); @@ -231,7 +230,7 @@ STATIC mp_obj_t file_open(const mp_obj_type_t *type, mp_arg_val_t *args) { STATIC mp_obj_t file_obj_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { mp_arg_val_t arg_vals[FILE_OPEN_NUM_ARGS]; mp_arg_parse_all_kw_array(n_args, n_kw, args, FILE_OPEN_NUM_ARGS, file_open_args, arg_vals); - return file_open(type, arg_vals); + return file_open(NULL, type, arg_vals); } // TODO gc hook to close the file if not already closed @@ -291,11 +290,14 @@ const mp_obj_type_t mp_type_textio = { }; // Factory function for I/O stream classes -mp_obj_t fatfs_builtin_open(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { +mp_obj_t fatfs_builtin_open_self(mp_obj_t self_in, mp_obj_t path, mp_obj_t mode) { // TODO: analyze buffering args and instantiate appropriate type + fs_user_mount_t *self = MP_OBJ_TO_PTR(self_in); mp_arg_val_t arg_vals[FILE_OPEN_NUM_ARGS]; - mp_arg_parse_all(n_args, args, kwargs, FILE_OPEN_NUM_ARGS, file_open_args, arg_vals); - return file_open(&mp_type_textio, arg_vals); + arg_vals[0].u_obj = path; + arg_vals[1].u_obj = mode; + arg_vals[2].u_obj = mp_const_none; + return file_open(self, &mp_type_textio, arg_vals); } -#endif // MICROPY_FSUSERMOUNT +#endif // MICROPY_VFS diff --git a/extmod/vfs_fat_misc.c b/extmod/vfs_fat_misc.c index d3507a85f..19db99c7f 100644 --- a/extmod/vfs_fat_misc.c +++ b/extmod/vfs_fat_misc.c @@ -25,34 +25,23 @@ */ #include "py/mpconfig.h" -// *_ADHOC part is for cc3200 port which doesn't use general uPy -// infrastructure and instead duplicates code. TODO: Resolve. -#if MICROPY_VFS_FAT || MICROPY_FSUSERMOUNT || MICROPY_FSUSERMOUNT_ADHOC +#if MICROPY_VFS_FAT #include <string.h> #include "py/nlr.h" #include "py/runtime.h" -#include "lib/fatfs/ff.h" -#include "lib/fatfs/diskio.h" -#include "extmod/vfs_fat_file.h" -#include "extmod/fsusermount.h" +#include "lib/oofatfs/ff.h" +#include "extmod/vfs_fat.h" #include "py/lexer.h" -#if _USE_LFN -STATIC char lfn[_MAX_LFN + 1]; /* Buffer to store the LFN */ -#endif - // TODO: actually, the core function should be ilistdir() -mp_obj_t fat_vfs_listdir(const char *path, bool is_str_type) { + +mp_obj_t fat_vfs_listdir2(fs_user_mount_t *vfs, const char *path, bool is_str_type) { FRESULT res; FILINFO fno; - DIR dir; -#if _USE_LFN - fno.lfname = lfn; - fno.lfsize = sizeof lfn; -#endif + FF_DIR dir; - res = f_opendir(&dir, path); /* Open the directory */ + res = f_opendir(&vfs->fatfs, &dir, path); if (res != FR_OK) { mp_raise_OSError(fresult_to_errno_table[res]); } @@ -65,11 +54,7 @@ mp_obj_t fat_vfs_listdir(const char *path, bool is_str_type) { if (fno.fname[0] == '.' && fno.fname[1] == 0) continue; /* Ignore . entry */ if (fno.fname[0] == '.' && fno.fname[1] == '.' && fno.fname[2] == 0) continue; /* Ignore .. entry */ -#if _USE_LFN - char *fn = *fno.lfname ? fno.lfname : fno.fname; -#else char *fn = fno.fname; -#endif /* if (fno.fattrib & AM_DIR) { @@ -96,15 +81,10 @@ mp_obj_t fat_vfs_listdir(const char *path, bool is_str_type) { return dir_list; } -mp_import_stat_t fat_vfs_import_stat(const char *path); - -mp_import_stat_t fat_vfs_import_stat(const char *path) { +mp_import_stat_t fat_vfs_import_stat(fs_user_mount_t *vfs, const char *path) { FILINFO fno; -#if _USE_LFN - fno.lfname = NULL; - fno.lfsize = 0; -#endif - FRESULT res = f_stat(path, &fno); + assert(vfs != NULL); + FRESULT res = f_stat(&vfs->fatfs, path, &fno); if (res == FR_OK) { if ((fno.fattrib & AM_DIR) != 0) { return MP_IMPORT_STAT_DIR; diff --git a/extmod/vfs_fat_reader.c b/extmod/vfs_reader.c index 7a00f18de..9509582d2 100644 --- a/extmod/vfs_fat_reader.c +++ b/extmod/vfs_reader.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2013-2016 Damien P. George + * Copyright (c) 2013-2017 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -25,64 +25,74 @@ */ #include <stdio.h> -#include <assert.h> +#include <string.h> -#include "py/mperrno.h" +#include "py/nlr.h" +#include "py/stream.h" #include "py/reader.h" +#include "extmod/vfs.h" -#if MICROPY_READER_FATFS +#if MICROPY_READER_VFS -#include "lib/fatfs/ff.h" -#include "extmod/vfs_fat_file.h" - -typedef struct _mp_reader_fatfs_t { - FIL fp; +typedef struct _mp_reader_vfs_t { + mp_obj_t file; uint16_t len; uint16_t pos; - byte buf[20]; -} mp_reader_fatfs_t; + byte buf[24]; +} mp_reader_vfs_t; -STATIC mp_uint_t mp_reader_fatfs_readbyte(void *data) { - mp_reader_fatfs_t *reader = (mp_reader_fatfs_t*)data; +STATIC mp_uint_t mp_reader_vfs_readbyte(void *data) { + mp_reader_vfs_t *reader = (mp_reader_vfs_t*)data; if (reader->pos >= reader->len) { if (reader->len < sizeof(reader->buf)) { return MP_READER_EOF; } else { - UINT n; - f_read(&reader->fp, reader->buf, sizeof(reader->buf), &n); - if (n == 0) { + int errcode; + reader->len = mp_stream_rw(reader->file, reader->buf, sizeof(reader->buf), + &errcode, MP_STREAM_RW_READ | MP_STREAM_RW_ONCE); + if (errcode != 0) { + // TODO handle errors properly + return MP_READER_EOF; + } + if (reader->len == 0) { return MP_READER_EOF; } - reader->len = n; reader->pos = 0; } } return reader->buf[reader->pos++]; } -STATIC void mp_reader_fatfs_close(void *data) { - mp_reader_fatfs_t *reader = (mp_reader_fatfs_t*)data; - f_close(&reader->fp); - m_del_obj(mp_reader_fatfs_t, reader); +STATIC void mp_reader_vfs_close(void *data) { + mp_reader_vfs_t *reader = (mp_reader_vfs_t*)data; + mp_stream_close(reader->file); + m_del_obj(mp_reader_vfs_t, reader); } int mp_reader_new_file(mp_reader_t *reader, const char *filename) { - mp_reader_fatfs_t *rf = m_new_obj_maybe(mp_reader_fatfs_t); + mp_reader_vfs_t *rf = m_new_obj_maybe(mp_reader_vfs_t); if (rf == NULL) { return MP_ENOMEM; } - FRESULT res = f_open(&rf->fp, filename, FA_READ); - if (res != FR_OK) { - return fresult_to_errno_table[res]; + // TODO we really should just let this function raise a uPy exception + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + mp_obj_t arg = mp_obj_new_str(filename, strlen(filename), false); + rf->file = mp_vfs_open(1, &arg, (mp_map_t*)&mp_const_empty_map); + int errcode; + rf->len = mp_stream_rw(rf->file, rf->buf, sizeof(rf->buf), &errcode, MP_STREAM_RW_READ | MP_STREAM_RW_ONCE); + nlr_pop(); + if (errcode != 0) { + return errcode; + } + } else { + return MP_ENOENT; // assume error was "file not found" } - UINT n; - f_read(&rf->fp, rf->buf, sizeof(rf->buf), &n); - rf->len = n; rf->pos = 0; reader->data = rf; - reader->readbyte = mp_reader_fatfs_readbyte; - reader->close = mp_reader_fatfs_close; + reader->readbyte = mp_reader_vfs_readbyte; + reader->close = mp_reader_vfs_close; return 0; // success } -#endif +#endif // MICROPY_READER_VFS |
