--- /dev/null
+/*
+ * Copyright (c) Quectel Wireless Solution, Co., Ltd.All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+
+#include "py/runtime.h"
+#include "py/mperrno.h"
+#include "py/mphal.h"
+#include "py/mpthread.h"
+#include "py/objstr.h"
+#include "extmod/vfs.h"
+#include "extmod/vfs_fat_sdio.h"
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#include "helios_fs.h"
+#include "helios_pin.h"
+
+#if MICROPY_VFS_FAT_SDIO
+
+enum { SDIO_MAKE_ARG_pname};
+
+const mp_arg_t sdio_make_allowed_args[] = {
+ { MP_QSTR_pname, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+};
+
+const char *mp_vfs_sdio_make_path(mp_obj_vfs_sdio_t *self, mp_obj_t path_in) {
+ const char *path = mp_obj_str_get_str(path_in);
+ if (path[0] != '/') {
+ size_t l = vstr_len(&self->cur_dir);
+ if (l > 0) {
+ vstr_add_str(&self->cur_dir, path);
+ path = vstr_null_terminated_str(&self->cur_dir);
+ self->cur_dir.len = l;
+ }
+ }
+
+ return path;
+}
+
+STATIC mp_import_stat_t mp_vfs_sdio_import_stat(void *self_in, const char *path) {
+ mp_obj_vfs_sdio_t *self = self_in;
+ unsigned char isdir = '\0';
+ unsigned int size = 0;
+
+
+ mp_obj_str_t path_obj = { { &mp_type_str }, 0, 0, (const byte *)path };
+ path = mp_vfs_sdio_make_path(self, MP_OBJ_FROM_PTR(&path_obj));
+ char f_path[64] = "";
+
+ sprintf(f_path, "%s%s", "C:", path);
+ QUEC_QPY_SDIO_LOG("FAT SDIO import stat:%s \r\n", f_path);
+
+ int ret = Helios_fat_getstat(f_path, &size, &isdir);
+ if (ret == 0)
+ {
+ if ((uint8_t)isdir == 1)
+ {
+ return MP_IMPORT_STAT_DIR;
+ }
+ else
+ {
+ return MP_IMPORT_STAT_FILE;
+ }
+ }
+
+ return MP_IMPORT_STAT_NO_EXIST;
+}
+static c_callback_t *callback_sd_det = 0;
+
+STATIC mp_obj_t vfs_sdio_sdcard_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 args_parse[MP_ARRAY_SIZE(sdio_make_allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, args, MP_ARRAY_SIZE(sdio_make_allowed_args), sdio_make_allowed_args, args_parse);
+ char *partition_name = (char *)mp_obj_str_get_str(args_parse[SDIO_MAKE_ARG_pname].u_obj);
+ Helios_sdio_device_type_e device_type = HELIOS_SDIO_SDCARD;
+
+ mp_obj_vfs_sdio_t *vfs = m_new_obj(mp_obj_vfs_sdio_t);
+ vfs->base.type = type;
+ vstr_init(&vfs->cur_dir, 16);
+ vstr_add_byte(&vfs->cur_dir, '/');
+
+ if(Helios_fat_device_type_switch(device_type) != 0)
+ {
+ mp_raise_OSError(19);
+ }
+
+ memset(vfs->data, '\0', sizeof(vfs->data));
+ strcpy(vfs->data,partition_name);
+
+ return MP_OBJ_FROM_PTR(vfs);
+}
+
+STATIC mp_obj_t vfs_sdio_emmc_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 args_parse[MP_ARRAY_SIZE(sdio_make_allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, args, MP_ARRAY_SIZE(sdio_make_allowed_args), sdio_make_allowed_args, args_parse);
+ char *partition_name = (char *)mp_obj_str_get_str(args_parse[SDIO_MAKE_ARG_pname].u_obj);
+
+ Helios_sdio_device_type_e device_type = HELIOS_SDIO_EMMC;
+
+ mp_obj_vfs_sdio_t *vfs = m_new_obj(mp_obj_vfs_sdio_t);
+ vfs->base.type = type;
+ vstr_init(&vfs->cur_dir, 16);
+ vstr_add_byte(&vfs->cur_dir, '/');
+
+ if(Helios_fat_device_type_switch(device_type) != 0)
+ {
+ mp_raise_OSError(19);
+ }
+
+ memset(vfs->data, '\0', sizeof(vfs->data));
+ strcpy(vfs->data,partition_name);
+
+ return MP_OBJ_FROM_PTR(vfs);
+}
+
+STATIC mp_obj_t vfs_sdio_mount(mp_obj_t self_in, mp_obj_t readonly, mp_obj_t mkfs) {
+ /*mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in);
+ if (mp_obj_is_true(readonly)) {
+ self->readonly = true;
+ }*/
+ if (mp_obj_is_true(mkfs)) {
+ uint8_t ret =0;
+ ret = Helios_fat_format(ASR_SDIO_SD_VOLUME);
+ if(ret!=0)
+ {
+ mp_raise_ValueError("format fail");
+ }
+ }
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(vfs_sdio_mount_obj, vfs_sdio_mount);
+
+STATIC mp_obj_t vfs_sdio_umount(mp_obj_t self_in) {
+ (void)self_in;
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(vfs_sdio_umount_obj, vfs_sdio_umount);
+
+STATIC mp_obj_t vfs_sdio_open(mp_obj_t self_in, mp_obj_t path_in, mp_obj_t mode_in) {
+ mp_obj_vfs_sdio_t *self = MP_OBJ_TO_PTR(self_in);
+ const char *mode = mp_obj_str_get_str(mode_in);
+ const char *path = mp_obj_str_get_str(path_in);
+
+
+ mp_obj_str_t path_obj = { { &mp_type_str }, 0, 0, (const byte *)path };
+ path = mp_vfs_sdio_make_path(self, MP_OBJ_FROM_PTR(&path_obj));
+ path_obj.data = (const byte *)path;
+
+ return mp_vfs_sdio_file_open(self_in, &mp_type_vfs_sdio_textio, MP_OBJ_FROM_PTR(&path_obj), mode_in);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(vfs_sdio_open_obj, vfs_sdio_open);
+
+STATIC mp_obj_t vfs_sdio_chdir(mp_obj_t self_in, mp_obj_t path_in) {
+ mp_obj_vfs_sdio_t *self = MP_OBJ_TO_PTR(self_in);
+
+ // Check path exists
+ const char *path = mp_vfs_sdio_make_path(self, path_in);
+ if (path[1] != '\0') {
+ // Not at root, check it exists
+ unsigned char isdir = '\0';
+ unsigned int size = 0;
+ char f_path[64] = "";
+
+ sprintf(f_path, "%s%s", "C:", path);
+
+ int ret = Helios_fat_getstat(f_path, &size, &isdir);
+ if ((ret != 0) || (uint8_t)isdir == 0) {
+ mp_raise_OSError(-MP_ENOENT);
+ }
+ }
+
+ // Update cur_dir with new path
+ if (path == vstr_str(&self->cur_dir)) {
+ self->cur_dir.len = strlen(path);
+ } else {
+ vstr_reset(&self->cur_dir);
+ vstr_add_str(&self->cur_dir, path);
+ }
+
+ // If not at root add trailing / to make it easy to build paths
+ // and then normalise the path
+ if (vstr_len(&self->cur_dir) != 1) {
+ vstr_add_byte(&self->cur_dir, '/');
+
+ #define CWD_LEN (vstr_len(&self->cur_dir))
+ size_t to = 1;
+ size_t from = 1;
+ char *cwd = vstr_str(&self->cur_dir);
+ while (from < CWD_LEN) {
+ for (; cwd[from] == '/' && from < CWD_LEN; ++from) {
+ // Scan for the start
+ }
+ if (from > to) {
+ // Found excessive slash chars, squeeze them out
+ vstr_cut_out_bytes(&self->cur_dir, to, from - to);
+ from = to;
+ }
+ for (; cwd[from] != '/' && from < CWD_LEN; ++from) {
+ // Scan for the next /
+ }
+ if ((from - to) == 1 && cwd[to] == '.') {
+ // './', ignore
+ vstr_cut_out_bytes(&self->cur_dir, to, ++from - to);
+ from = to;
+ } else if ((from - to) == 2 && cwd[to] == '.' && cwd[to + 1] == '.') {
+ // '../', skip back
+ if (to > 1) {
+ // Only skip back if not at the tip
+ for (--to; to > 1 && cwd[to - 1] != '/'; --to) {
+ // Skip back
+ }
+ }
+ vstr_cut_out_bytes(&self->cur_dir, to, ++from - to);
+ from = to;
+ } else {
+ // Normal element, keep it and just move the offset
+ to = ++from;
+ }
+ }
+ }
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(vfs_sdio_chdir_obj, vfs_sdio_chdir);
+
+STATIC mp_obj_t vfs_sdio_getcwd(mp_obj_t self_in) {
+ mp_obj_vfs_sdio_t *self = MP_OBJ_TO_PTR(self_in);
+ if (vstr_len(&self->cur_dir) == 1) {
+ return MP_OBJ_NEW_QSTR(MP_QSTR__slash_);
+ } else {
+ // don't include trailing /
+ return mp_obj_new_str(self->cur_dir.buf, self->cur_dir.len - 1);
+ }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(vfs_sdio_getcwd_obj, vfs_sdio_getcwd);
+
+typedef struct _mp_vfs_sdio_ilistdir_it_t {
+ mp_obj_base_t base;
+ mp_fun_1_t iternext;
+ bool is_str;
+ SDIO_DIR dir;
+} mp_vfs_sdio_ilistdir_it_t;
+
+STATIC mp_obj_t vfs_sdio_ilistdir_it_iternext(mp_obj_t self_in) {
+ mp_vfs_sdio_ilistdir_it_t *self = MP_OBJ_TO_PTR(self_in);
+
+ for (;;) {
+ SDIO_FILINFO fno;
+ int res = Helios_fat_dirread(&self->dir, &fno);
+ char *fn = fno.fname;
+ if (res != 0 || fn[0] == 0) {
+ // stop on error or end of dir
+ break;
+ }
+
+ // Note that FatFS already filters . and .., so we don't need to
+
+ // make 4-tuple with info about this entry
+ mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(4, NULL));
+ if (self->is_str) {
+ t->items[0] = mp_obj_new_str(fn, strlen(fn));
+ } else {
+ t->items[0] = mp_obj_new_bytes((const byte *)fn, strlen(fn));
+ }
+ if (fno.fattrib & AM_DIR) {
+ // dir
+ t->items[1] = MP_OBJ_NEW_SMALL_INT(MP_S_IFDIR);
+ } else {
+ // file
+ t->items[1] = MP_OBJ_NEW_SMALL_INT(MP_S_IFREG);
+ }
+ t->items[2] = MP_OBJ_NEW_SMALL_INT(0); // no inode number
+ t->items[3] = mp_obj_new_int_from_uint(fno.fsize);
+
+ return MP_OBJ_FROM_PTR(t);
+ }
+
+ // ignore error because we may be closing a second time
+ Helios_fat_dirclose(&self->dir);
+
+ return MP_OBJ_STOP_ITERATION;
+}
+
+STATIC mp_obj_t vfs_sdio_ilistdir(mp_obj_t self_in, mp_obj_t path_in) {
+ mp_obj_vfs_sdio_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_vfs_sdio_ilistdir_it_t *iter = m_new_obj(mp_vfs_sdio_ilistdir_it_t);
+
+ iter->base.type = &mp_type_polymorph_iter;
+ iter->iternext = vfs_sdio_ilistdir_it_iternext;
+ iter->is_str = mp_obj_get_type(path_in) == &mp_type_str;
+ const char *path = mp_obj_str_get_str(path_in);
+ char f_path[64] = "";
+ int len = 0;
+
+ if (path[0] == '\0') {
+ path = ".";
+ }
+
+ sprintf(f_path, "%s%s", "C:", path);
+
+ //iter->dir = Helios_fat_diropen(f_path);
+ int ret = Helios_fat_diropen(&iter->dir, f_path);
+ if (ret != 0) {
+ mp_raise_OSError(-1);
+ }
+ return MP_OBJ_FROM_PTR(iter);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(vfs_sdio_ilistdir_obj, vfs_sdio_ilistdir);
+
+STATIC mp_obj_t vfs_sdio_mkdir(mp_obj_t self_in, mp_obj_t path_in) {
+ mp_obj_vfs_sdio_t *self = MP_OBJ_TO_PTR(self_in);
+ const char *path = mp_vfs_sdio_make_path(self, path_in);
+ char f_path[64] = "";
+ sprintf(f_path, "%s%s", "C:", path);
+
+ int ret = Helios_fat_makedir(f_path, 0777);
+ if (ret != 0) {
+ mp_raise_OSError(ret);
+ }
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(vfs_sdio_mkdir_obj, vfs_sdio_mkdir);
+
+STATIC mp_obj_t vfs_sdio_remove(mp_obj_t self_in, mp_obj_t path_in) {
+ mp_obj_vfs_sdio_t *self = MP_OBJ_TO_PTR(self_in);
+ const char *path = mp_vfs_sdio_make_path(self, path_in);
+ char f_path[64] = "";
+
+ sprintf(f_path, "%s%s", "C:", path);
+
+ int ret = Helios_fat_remove(f_path);
+ if (ret != 0) {
+ mp_raise_OSError(ret);
+ }
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(vfs_sdio_remove_obj, vfs_sdio_remove);
+
+STATIC mp_obj_t vfs_sdio_rename(mp_obj_t self_in, mp_obj_t old_path_in, mp_obj_t new_path_in) {
+ mp_obj_vfs_sdio_t *self = MP_OBJ_TO_PTR(self_in);
+ const char *old_path = mp_vfs_sdio_make_path(self, old_path_in);
+ const char *new_path = mp_obj_str_get_str(new_path_in);
+ vstr_t path_new;
+ vstr_init(&path_new, vstr_len(&self->cur_dir));
+ if (new_path[0] != '/') {
+ vstr_add_strn(&path_new, vstr_str(&self->cur_dir), vstr_len(&self->cur_dir));
+ }
+ vstr_add_str(&path_new, new_path);
+ char o_path[64] = "";
+ char n_path[64] = "";
+
+ sprintf(o_path, "%s%s", "C:", old_path);
+ sprintf(n_path, "%s%s", "C:", vstr_null_terminated_str(&path_new));
+
+ int ret = Helios_fat_rename(o_path, n_path);
+ vstr_clear(&path_new);
+ if (ret != 0) {
+ mp_raise_OSError(ret);
+ }
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(vfs_sdio_rename_obj, vfs_sdio_rename);
+
+STATIC mp_obj_t vfs_sdio_rmdir(mp_obj_t self_in, mp_obj_t path_in) {
+ mp_obj_vfs_sdio_t *self = MP_OBJ_TO_PTR(self_in);
+ const char *path = mp_vfs_sdio_make_path(self, path_in);
+ char f_path[64] = "";
+
+ sprintf(f_path, "%s%s", "C:", path);
+
+ QUEC_QPY_SDIO_LOG("remove dir %s", f_path);
+
+ int ret = Helios_fat_removedir(f_path);
+ if (ret != 0) {
+ mp_raise_OSError(ret);
+ }
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(vfs_sdio_rmdir_obj, vfs_sdio_rmdir);
+
+STATIC mp_obj_t vfs_sdio_stat(mp_obj_t self_in, mp_obj_t path_in) {
+ int ret;
+ unsigned char isdir = '\0';
+ unsigned int size = 0;
+ mp_obj_vfs_sdio_t *self = MP_OBJ_TO_PTR(self_in);
+ const char *path = mp_vfs_sdio_make_path(self, path_in);
+ char f_path[64] = "";
+
+ sprintf(f_path, "%s%s", "C:", path);
+
+ ret = Helios_fat_getstat(f_path, &size, &isdir);
+ if (ret != 1) {
+ mp_raise_OSError(ret);
+ }
+
+ mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL));
+ t->items[0] = MP_OBJ_NEW_SMALL_INT((uint8_t)isdir == 1 ? MP_S_IFDIR : MP_S_IFREG);// st_mode
+ t->items[1] = MP_OBJ_NEW_SMALL_INT(0);//mp_obj_new_int_from_uint(sb.st_ino);// st_ino
+ t->items[2] = MP_OBJ_NEW_SMALL_INT(0);//mp_obj_new_int_from_uint(sb.st_dev);// st_dev
+ t->items[3] = MP_OBJ_NEW_SMALL_INT(0);//mp_obj_new_int_from_uint(sb.st_nlink);// st_nlink
+ t->items[4] = MP_OBJ_NEW_SMALL_INT(0);//mp_obj_new_int_from_uint(sb.st_uid);// st_uid
+ t->items[5] = MP_OBJ_NEW_SMALL_INT(0);//mp_obj_new_int_from_uint(sb.st_gid);// st_gid
+ t->items[6] = mp_obj_new_int_from_uint(size);// st_size
+ t->items[7] = MP_OBJ_NEW_SMALL_INT(0);//mp_obj_new_int_from_uint(sb.st_atime);// st_atime
+ t->items[8] = MP_OBJ_NEW_SMALL_INT(0);//mp_obj_new_int_from_uint(sb.st_mtime);// st_mtime
+ t->items[9] = MP_OBJ_NEW_SMALL_INT(0);//mp_obj_new_int_from_uint(sb.st_ctime);// st_ctime
+ return MP_OBJ_FROM_PTR(t);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(vfs_sdio_stat_obj, vfs_sdio_stat);
+
+
+STATIC mp_obj_t vfs_sdio_statvfs(mp_obj_t self_in, mp_obj_t path_in) {
+ mp_obj_vfs_sdio_t *self = MP_OBJ_TO_PTR(self_in);
+ int ret;
+ unsigned int fat_total_block = (Helios_fat_gettotal("C:") / 4096);
+ unsigned int fat_free_block = (Helios_fat_getfree("C:") / 4096);
+ const char *path = mp_obj_str_get_str(path_in);
+ char f_path[64] = "";
+
+ sprintf(f_path, "%s%s", "C:", path);
+
+ // if (ret != 0) {
+ // mp_raise_OSError(ret);
+ // }
+
+ mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(10, NULL));
+ t->items[0] = MP_OBJ_NEW_SMALL_INT(4096);// f_bsize
+ t->items[1] = t->items[0];// f_frsize
+ t->items[2] = MP_OBJ_NEW_SMALL_INT(fat_total_block);//MP_OBJ_NEW_SMALL_INT(256);// f_blocks
+ t->items[3] = MP_OBJ_NEW_SMALL_INT(fat_free_block);// f_bfree
+ t->items[4] = t->items[3];// f_bavail
+ t->items[5] = MP_OBJ_NEW_SMALL_INT(0); // f_files
+ t->items[6] = MP_OBJ_NEW_SMALL_INT(0); // f_ffree
+ t->items[7] = MP_OBJ_NEW_SMALL_INT(0); // f_favail
+ t->items[8] = MP_OBJ_NEW_SMALL_INT(0); // f_flags
+ t->items[9] = MP_OBJ_NEW_SMALL_INT(0);
+ return MP_OBJ_FROM_PTR(t);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(vfs_sdio_statvfs_obj, vfs_sdio_statvfs);
+
+STATIC const mp_rom_map_elem_t vfs_sdio_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_mount), MP_ROM_PTR(&vfs_sdio_mount_obj) },
+ { MP_ROM_QSTR(MP_QSTR_umount), MP_ROM_PTR(&vfs_sdio_umount_obj) },
+ { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&vfs_sdio_open_obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_chdir), MP_ROM_PTR(&vfs_sdio_chdir_obj) },
+ { MP_ROM_QSTR(MP_QSTR_getcwd), MP_ROM_PTR(&vfs_sdio_getcwd_obj) },
+ { MP_ROM_QSTR(MP_QSTR_ilistdir), MP_ROM_PTR(&vfs_sdio_ilistdir_obj) },
+ { MP_ROM_QSTR(MP_QSTR_mkdir), MP_ROM_PTR(&vfs_sdio_mkdir_obj) },
+ { MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&vfs_sdio_remove_obj) },
+ { MP_ROM_QSTR(MP_QSTR_rename), MP_ROM_PTR(&vfs_sdio_rename_obj) },
+ { MP_ROM_QSTR(MP_QSTR_rmdir), MP_ROM_PTR(&vfs_sdio_rmdir_obj) },
+ { MP_ROM_QSTR(MP_QSTR_stat), MP_ROM_PTR(&vfs_sdio_stat_obj) },
+ { MP_ROM_QSTR(MP_QSTR_statvfs), MP_ROM_PTR(&vfs_sdio_statvfs_obj) },
+ // { MP_ROM_QSTR(MP_QSTR_set_callback), MP_ROM_PTR(&vfs_sdio_sd_set_callback_obj) },
+ // { MP_ROM_QSTR(MP_QSTR_set_det), MP_ROM_PTR(&vfs_sdio_sd_set_det_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(vfs_sdio_locals_dict, vfs_sdio_locals_dict_table);
+
+STATIC const mp_vfs_proto_t vfs_sdio_proto = {
+ .import_stat = mp_vfs_sdio_import_stat,
+};
+
+const mp_obj_type_t mp_type_vfs_sdio_sd = {
+ { &mp_type_type },
+ .name = MP_QSTR_VfsSd,
+ .make_new = vfs_sdio_sdcard_make_new,
+ .protocol = &vfs_sdio_proto,
+ .locals_dict = (mp_obj_dict_t *)&vfs_sdio_locals_dict,
+};
+
+const mp_obj_type_t mp_type_vfs_sdio_emmc = {
+ { &mp_type_type },
+ .name = MP_QSTR_VfsEmmc,
+ .make_new = vfs_sdio_emmc_make_new,
+ .protocol = &vfs_sdio_proto,
+ .locals_dict = (mp_obj_dict_t *)&vfs_sdio_locals_dict,
+};
+
+#endif // PLAT_ASR_1803s || PLAT_ASR_1803sc
--- /dev/null
+/*
+ * Copyright (c) Quectel Wireless Solution, Co., Ltd.All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _VFS_SDIO_H_
+#define _VFS_SDIO_H_
+
+
+#include "py/lexer.h"
+#include "py/obj.h"
+#include "helios_debug.h"
+
+#if MICROPY_VFS_FAT_SDIO
+
+#if 1
+#define QUEC_QPY_SDIO_LOG(msg, ...) custom_log(QPY_FS_SDIO, msg, ##__VA_ARGS__)
+#else
+#define QUEC_QPY_SDIO_LOG(msg, ...)
+#endif
+
+extern const mp_obj_type_t mp_type_vfs_sdio_emmc;
+extern const mp_obj_type_t mp_type_vfs_sdio_sd;
+extern const mp_obj_type_t mp_type_vfs_sdio_fileio;
+extern const mp_obj_type_t mp_type_vfs_sdio_textio;
+
+
+#define S_IFMT (0170000) /* type of file */
+#define S_IFDIR (0040000) /* directory */
+#define S_IFCHR (0020000) /* character special */
+#define S_IFBLK (0060000) /* block special */
+#define S_IFREG (0100000) /* regular */
+#define S_IFLNK (0120000) /* symbolic link */
+#define S_IFSOCK (0140000) /* socket */
+#define S_IFIFO (0010000) /* fifo */
+
+#define FA_WRITE 0x02
+#define FA_OPEN_EXISTING 0x00
+#define FA_CREATE_NEW 0x04
+#define FA_CREATE_ALWAYS 0x08
+#define FA_OPEN_ALWAYS 0x10
+#define FA_OPEN_APPEND 0x30
+
+/* Fast seek controls (2nd argument of f_lseek) */
+#define CREATE_LINKMAP ((FSIZE_t)0 - 1)
+
+/* Format options (2nd argument of f_mkfs) */
+#define FM_FAT 0x01
+#define FM_FAT32 0x02
+#define FM_EXFAT 0x04
+#define FM_ANY 0x07
+#define FM_SFD 0x08
+
+/* Filesystem type (FATFS.fs_type) */
+#define FS_FAT12 1
+#define FS_FAT16 2
+#define FS_FAT32 3
+#define FS_EXFAT 4
+
+/* File attribute bits for directory entry (FILINFO.fattrib) */
+#define AM_RDO 0x01 /* Read only */
+#define AM_HID 0x02 /* Hidden */
+#define AM_SYS 0x04 /* System */
+#define AM_DIR 0x10 /* Directory */
+#define AM_ARC 0x20 /* Archive */
+
+
+typedef struct
+{
+ unsigned long f_bsize; /* file system block size */
+ unsigned long f_frsize; /* fragment size */
+ unsigned long f_blocks; /* size of fs in f_frsize units */
+ unsigned long f_bfree; /* free blocks in fs */
+ unsigned long f_bavail; /* free blocks avail to non-superuser */
+ unsigned long f_files; /* total file nodes in file system */
+ unsigned long f_ffree; /* free file nodes in fs */
+ unsigned long f_favail; /* avail file nodes in fs */
+ unsigned long f_fsid; /* file system id */
+ unsigned long f_flag; /* mount flags */
+ unsigned long f_namemax; /* maximum length of filenames */
+}qstat_vfs;
+
+typedef struct
+{
+ int d_ino; ///< inode number, file system implementation can use it for any purpose
+ unsigned char d_type; ///< type of file
+ char d_name[256]; ///< file name
+}qdirent;
+
+typedef unsigned char BYTE;
+typedef char TCHAR;
+typedef unsigned long DWORD;
+typedef unsigned short WORD;
+typedef unsigned long long QWORD;
+typedef DWORD LBA_t;
+typedef QWORD FSIZE_t;
+
+typedef struct {
+ void* fs; /* Pointer to the hosting volume of this object */
+ WORD id; /* Hosting volume mount ID */
+ BYTE attr; /* Object attribute */
+ BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous, =3:fragmented in this session, b2:sub-directory stretched) */
+ DWORD sclust; /* Object data start cluster (0:no cluster or root directory) */
+ FSIZE_t objsize; /* Object size (valid when sclust != 0) */
+ DWORD n_cont; /* Size of first fragment - 1 (valid when stat == 3) */
+ DWORD n_frag; /* Size of last fragment needs to be written to FAT (valid when not zero) */
+ DWORD c_scl; /* Containing directory start cluster (valid when sclust != 0) */
+ DWORD c_size; /* b31-b8:Size of containing directory, b7-b0: Chain status (valid when c_scl != 0) */
+ DWORD c_ofs; /* Offset in the containing directory (valid when file object and sclust != 0) */
+} FFOBJID;
+
+typedef struct {
+ FFOBJID obj; /* Object identifier */
+ DWORD dptr; /* Current read/write offset */
+ DWORD clust; /* Current cluster */
+ LBA_t sect; /* Current sector (0:Read operation has terminated) */
+ BYTE* dir; /* Pointer to the directory item in the win[] */
+ BYTE fn[12]; /* SFN (in/out) {body[8],ext[3],status[1]} */
+ DWORD blk_ofs; /* Offset of current entry block being processed (0xFFFFFFFF:Invalid) */
+ const TCHAR* pat; /* Pointer to the name matching pattern */
+} SDIO_DIR;
+
+#define SDIO_FF_LFN_BUF 255
+#define SDIO_FF_SFN_BUF 12
+
+typedef struct {
+ FSIZE_t fsize; /* File size */
+ WORD fdate; /* Modified date */
+ WORD ftime; /* Modified time */
+ BYTE fattrib; /* File attribute */
+ TCHAR altname[SDIO_FF_SFN_BUF + 1];/* Altenative file name */
+ TCHAR fname[SDIO_FF_LFN_BUF + 1]; /* Primary file name */
+} SDIO_FILINFO;
+
+typedef struct _mp_obj_vfs_sdio_t {
+ mp_obj_base_t base;
+ vstr_t cur_dir;
+ vstr_t root;
+ size_t root_len;
+ bool readonly;
+ char data[64];
+} mp_obj_vfs_sdio_t;
+
+mp_obj_t mp_vfs_sdio_file_open(mp_obj_t self_in, const mp_obj_type_t *type, mp_obj_t file_in, mp_obj_t mode_in);
+
+#endif // PLAT_ASR1803S
+
+#endif // _VFS_SDIO_H_
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) Quectel Wireless Solution, Co., Ltd.All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include <stdio.h>
+#include <string.h>
+
+#include "py/mphal.h"
+#include "py/mpthread.h"
+#include "py/runtime.h"
+#include "py/stream.h"
+#include "py/objstr.h"
+#include "extmod/vfs.h"
+#include "extmod/vfs_fat_sdio.h"
+
+#include "helios_fs.h"
+
+#if MICROPY_VFS_FAT_SDIO
+
+#if MICROPY_VFS_FAT
+#include "ff.h"
+#else
+#define FA_READ 0x01
+#define FA_WRITE 0x02
+#define FA_OPEN_EXISTING 0x00
+#define FA_CREATE_NEW 0x04
+#define FA_CREATE_ALWAYS 0x08
+#define FA_OPEN_ALWAYS 0x10
+#define FA_OPEN_APPEND 0x30
+#endif
+
+typedef struct _mp_obj_vfs_sdio_file_t {
+ mp_obj_base_t base;
+ HeliosFILE * fd;
+} mp_obj_vfs_sdio_file_t;
+
+#ifdef MICROPY_CPYTHON_COMPAT
+STATIC void check_fd_is_open(const mp_obj_vfs_sdio_file_t *o) {
+ if (0 >= (unsigned int)o->fd) {
+ mp_raise_ValueError(MP_ERROR_TEXT("I/O operation on closed file"));
+ }
+}
+#else
+#define check_fd_is_open(o)
+#endif
+
+STATIC void vfs_sdio_file_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+ (void)kind;
+ mp_obj_vfs_sdio_file_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_printf(print, "<io.%s %d>", mp_obj_get_type_str(self_in), self->fd);
+}
+
+STATIC mp_obj_t vfs_sdio_file_fileno(mp_obj_t self_in) {
+ mp_obj_vfs_sdio_file_t *self = MP_OBJ_TO_PTR(self_in);
+ check_fd_is_open(self);
+ return MP_OBJ_NEW_SMALL_INT(self->fd);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(vfs_sdio_file_fileno_obj, vfs_sdio_file_fileno);
+
+STATIC mp_obj_t vfs_sdio_file___exit__(size_t n_args, const mp_obj_t *args) {
+ (void)n_args;
+ return mp_stream_close(args[0]);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(vfs_sdio_file___exit___obj, 4, 4, vfs_sdio_file___exit__);
+
+STATIC mp_uint_t vfs_sdio_file_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) {
+ mp_obj_vfs_sdio_file_t *o = MP_OBJ_TO_PTR(o_in);
+ check_fd_is_open(o);
+ int r;
+
+ QUEC_QPY_SDIO_LOG("SDIO read %d with size:%d", o->fd, size);
+ r = Helios_fat_fread(buf, size, 1, o->fd);
+ if(r < 0)
+ {
+ *errcode = -r;
+ return MP_STREAM_ERROR;
+ }
+
+ return (mp_uint_t)r;
+}
+
+STATIC mp_uint_t vfs_sdio_file_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) {
+ mp_obj_vfs_sdio_file_t *o = MP_OBJ_TO_PTR(o_in);
+ check_fd_is_open(o);
+ #if MICROPY_PY_OS_DUPTERM
+ if (o->fd <= STDERR_FILENO) {
+ mp_hal_stdout_tx_strn(buf, size);
+ return size;
+ }
+ #endif
+ int r;
+
+ QUEC_QPY_SDIO_LOG("SDIO write %d with size:%d", o->fd, size);
+ r = Helios_fat_fwrite((void *)buf, size, 1, o->fd);
+ if(r < 0)
+ {
+ *errcode = -r;
+ return MP_STREAM_ERROR;
+ }
+
+ return (mp_uint_t)r;
+}
+
+STATIC mp_uint_t vfs_sdio_file_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) {
+ mp_obj_vfs_sdio_file_t *o = MP_OBJ_TO_PTR(o_in);
+ check_fd_is_open(o);
+ switch (request) {
+ case MP_STREAM_FLUSH: {
+ int res = Helios_fat_fsync((unsigned int)(o->fd));
+
+ if (res != 0) {
+ *errcode = -res;
+ return MP_STREAM_ERROR;
+ }
+
+ return 0;
+ }
+ case MP_STREAM_SEEK: {
+ struct mp_stream_seek_t *s = (struct mp_stream_seek_t *)arg;
+ int res = Helios_fat_fseek(o->fd, s->offset, s->whence);
+ if (res < 0) {
+ *errcode = -res;
+ return MP_STREAM_ERROR;
+ }
+
+ s->offset = res;
+ return 0;
+ }
+ case MP_STREAM_CLOSE:
+ Helios_fat_fclose(o->fd);
+ #ifdef MICROPY_CPYTHON_COMPAT
+ o->fd = NULL;
+ #endif
+ return 0;
+ case MP_STREAM_GET_FILENO:
+ return 0;
+ default:
+ *errcode = 0;
+ return MP_STREAM_ERROR;
+ }
+}
+
+
+mp_obj_t mp_vfs_sdio_file_open(mp_obj_t self_in, const mp_obj_type_t *type, mp_obj_t file_in, mp_obj_t mode_in) {
+ mp_obj_vfs_sdio_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_obj_vfs_sdio_file_t *o = m_new_obj(mp_obj_vfs_sdio_file_t);
+ const char *mode_s = mp_obj_str_get_str(mode_in);
+ const char *fname = mp_obj_str_get_str(file_in);
+ HeliosFILE * fd;
+ char f_path[64] = "";
+ int mode = 0;
+
+ sprintf(f_path, "%s%s", "C:", fname);
+ QUEC_QPY_SDIO_LOG("FAT SDIO import open:%s \r\n", f_path);
+
+ o->base.type = type;
+ while (*mode_s) {
+ switch (*mode_s++) {
+ case 'r':
+ mode |= FA_READ;
+ break;
+ case 'w':
+ mode |= FA_WRITE | FA_CREATE_ALWAYS;
+ break;
+ case 'x':
+ mode |= FA_WRITE | FA_CREATE_NEW;
+ break;
+ case 'a':
+ mode |= FA_WRITE | FA_OPEN_ALWAYS;
+ break;
+ case '+':
+ mode |= FA_READ | FA_WRITE;
+ break;
+ #if MICROPY_PY_IO_FILEIO
+ case 'b':
+ type = &mp_type_vfs_sdio_fileio;
+ break;
+ #endif
+ case 't':
+ type = &mp_type_vfs_sdio_textio;
+ break;
+ }
+ }
+ fd = Helios_fat_fopen(f_path, mode);
+
+ if(0 >= (unsigned int)fd)
+ {
+ mp_raise_OSError(-1);
+ QUEC_QPY_SDIO_LOG("FAT SDIO OPEN ERROR");
+ return mp_const_none;
+ }
+ o->fd = fd;
+
+ return MP_OBJ_FROM_PTR(o);
+}
+
+STATIC mp_obj_t vfs_sdio_file_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
+ enum { ARG_file, ARG_mode };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_file, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_rom_obj = MP_ROM_NONE} },
+ { MP_QSTR_mode, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_QSTR(MP_QSTR_r)} },
+ };
+
+ mp_arg_val_t arg_vals[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, args, MP_ARRAY_SIZE(allowed_args), allowed_args, arg_vals);
+
+ const char *fname = mp_obj_str_get_str(arg_vals[ARG_file].u_obj);
+ const char *p_out;
+ const char *mode_s = mp_obj_str_get_str(arg_vals[ARG_mode].u_obj);
+ mp_vfs_mount_t *vfs = mp_vfs_lookup_path(fname, &p_out);
+ if (vfs != MP_VFS_NONE && vfs != MP_VFS_ROOT) {
+ arg_vals[ARG_file].u_obj = mp_obj_new_str_of_type(mp_obj_get_type(arg_vals[ARG_file].u_obj),
+ (const byte *)p_out, strlen(p_out));
+ }
+
+ if((vfs != MP_VFS_NONE && vfs != MP_VFS_ROOT) && vfs->readonly == MP_VFS_READONIY_ENABLE && vfs_readonly_mode)
+ {
+ if(strcmp(mode_s, "r") && strcmp(mode_s, "rt") && strcmp(mode_s, "rb"))
+ {
+ return mp_obj_new_int(-1);
+ }
+ }
+
+ return mp_vfs_sdio_file_open(vfs->obj, type, arg_vals[ARG_file].u_obj, arg_vals[ARG_mode].u_obj);
+}
+
+
+STATIC const mp_rom_map_elem_t vfs_sdio_rawfile_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_fileno), MP_ROM_PTR(&vfs_sdio_file_fileno_obj) },
+ { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
+ { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
+ { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) },
+ { MP_ROM_QSTR(MP_QSTR_readlines), MP_ROM_PTR(&mp_stream_unbuffered_readlines_obj) },
+ { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
+ { MP_ROM_QSTR(MP_QSTR_seek), MP_ROM_PTR(&mp_stream_seek_obj) },
+ { MP_ROM_QSTR(MP_QSTR_tell), MP_ROM_PTR(&mp_stream_tell_obj) },
+ { MP_ROM_QSTR(MP_QSTR_flush), MP_ROM_PTR(&mp_stream_flush_obj) },
+ { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) },
+ { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&mp_identity_obj) },
+ { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&vfs_sdio_file___exit___obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(vfs_sdio_rawfile_locals_dict, vfs_sdio_rawfile_locals_dict_table);
+
+#if MICROPY_PY_IO_FILEIO
+STATIC const mp_stream_p_t vfs_sdio_fileio_stream_p = {
+ .read = vfs_sdio_file_read,
+ .write = vfs_sdio_file_write,
+ .ioctl = vfs_sdio_file_ioctl,
+};
+
+const mp_obj_type_t mp_type_vfs_sdio_fileio = {
+ { &mp_type_type },
+ .name = MP_QSTR_FileIO,
+ .print = vfs_sdio_file_print,
+ .make_new = vfs_sdio_file_make_new,
+ .getiter = mp_identity_getiter,
+ .iternext = mp_stream_unbuffered_iter,
+ .protocol = &vfs_sdio_fileio_stream_p,
+ .locals_dict = (mp_obj_dict_t *)&vfs_sdio_rawfile_locals_dict,
+};
+#endif
+
+STATIC const mp_stream_p_t vfs_sdio_textio_stream_p = {
+ .read = vfs_sdio_file_read,
+ .write = vfs_sdio_file_write,
+ .ioctl = vfs_sdio_file_ioctl,
+ .is_text = true,
+};
+
+const mp_obj_type_t mp_type_vfs_sdio_textio = {
+ { &mp_type_type },
+ .name = MP_QSTR_TextIOWrapper,
+ .print = vfs_sdio_file_print,
+ .make_new = vfs_sdio_file_make_new,
+ .getiter = mp_identity_getiter,
+ .iternext = mp_stream_unbuffered_iter,
+ .protocol = &vfs_sdio_textio_stream_p,
+ .locals_dict = (mp_obj_dict_t *)&vfs_sdio_rawfile_locals_dict,
+};
+
+/*const mp_obj_vfs_efs_file_t mp_sys_stdin_obj = {{&mp_type_vfs_efs_textio}, STDIN_FILENO};
+const mp_obj_vfs_efs_file_t mp_sys_stdout_obj = {{&mp_type_vfs_efs_textio}, STDOUT_FILENO};
+const mp_obj_vfs_efs_file_t mp_sys_stderr_obj = {{&mp_type_vfs_efs_textio}, STDERR_FILENO};
+*/
+
+#endif // PLAT_ASR_1803s || PLAT_ASR_1803sc
\ No newline at end of file