summaryrefslogtreecommitdiff
path: root/extmod
diff options
context:
space:
mode:
Diffstat (limited to 'extmod')
-rw-r--r--extmod/fsusermount.c209
-rw-r--r--extmod/machine_pulse.c6
-rw-r--r--extmod/machine_signal.c114
-rw-r--r--extmod/machine_signal.h (renamed from extmod/vfs_fat_file.h)15
-rw-r--r--extmod/machine_spi.c6
-rw-r--r--extmod/modframebuf.c71
-rw-r--r--extmod/modlwip.c1
-rw-r--r--extmod/vfs.c309
-rw-r--r--extmod/vfs.h80
-rw-r--r--extmod/vfs_fat.c199
-rw-r--r--extmod/vfs_fat.h (renamed from extmod/fsusermount.h)26
-rw-r--r--extmod/vfs_fat_diskio.c59
-rw-r--r--extmod/vfs_fat_ffconf.c82
-rw-r--r--extmod/vfs_fat_file.c28
-rw-r--r--extmod/vfs_fat_misc.c40
-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