MicroPython移植(3) : 文件系统和内建对象

文章目录

      • 1.1 文件系统
      • 1.2 内建方法和对象
      • 1.3 使用ampy
      • 1.4 文件相关的常用方法 & 模块

1.1 文件系统

mpy的文件系统为vfs(虚拟文件系统), vfs基于oofatfs库实现, 而oofatfs又是源自开源的fatfs文件系统,即整个vfs是基于fatfs扩展而来. fatfs文件系统原本需要用户移植的文件diskio.c , mpy重新封装了一层vfs_fat*, 一方面为MicroPython 的python module提供实现支持,另一方面也为用户进行porting(hal)层的实现提供了统一的实现入口.用户实现自己的文件系统需要:

  1. 开启VFS 宏支持
#ifndef MICROPY_VFS
#define MICROPY_VFS                 (1)
#endif
#define MICROPY_VFS_FAT             (MICROPY_VFS)

#if MICROPY_VFS
    #define MICROPY_FATFS_RPATH         (2)
    #define MICROPY_FATFS_MAX_SS        (4096)
    #define MICROPY_FATFS_ENABLE_LFN    (1)
#endif
  1. 根据开发板实际的存储设备(SD卡或Flash)实现设备基本的读写和初始化驱动
  2. 根据存储设备驱动接口实现 fs module的对象方法: *readblocks, *writeblocks , *ioctl, 并实现vfs初始化和挂载函数
static bool b_pyb_flash_is_initialised = false;

void pyb_flash_init(void) {
    //ignore
    
    b_pyb_flash_is_initialised = true;
}

uint32_t pyb_flash_get_block_size(void) {
    return XFLASH_BLOCK_SIZE;
}

uint32_t pyb_flash_get_block_count(void) {
    return XFLASH_SIZE/XFLASH_BLOCK_SIZE;
}

void pyb_flash_flush(void) {
    //nothing to do
}

/*
 * dest : buffer ptr to save read data
 * block_num : the start number of block to read ,scope :[0 ~ 1023]
 */
bool pyb_flash_read_block(uint8_t *dest, uint32_t block_num) {
    //ignore
}

/*
 * dest : buffer ptr to save read data
 * block_num : the start number of block to read ,scope :[0 ~ 1023]
 * num_blocks : how many blocks to read
 */
mp_uint_t pyb_flash_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blocks) {
    uint32_t i = 0;
    mp_uint_t ret = 0;
    
    for (i = 0; i < num_blocks; i++) {
        if (!pyb_flash_read_block(dest + i * XFLASH_BLOCK_SIZE, block_num + i)) {
            ret = 1; // error
            break;
        }
    }
    
    return ret; // success
}

/*
 * src : buffer ptr to program data
 * block_num : the start number of block to write ,scope :[0 ~ 1023]
 */
bool pyb_flash_write_block(const uint8_t *src, uint32_t block_num) {
    //ignore
}

/*
 * src : buffer ptr to program data
 * block_num : the start number of block to write ,scope :[0 ~ 1023]
 * num_blocks : how many blocks to write
 */
mp_uint_t pyb_flash_write_blocks(const uint8_t *src, uint32_t block_num, uint32_t num_blocks) {

    for (size_t i = 0; i < num_blocks; i++) {
        if (!pyb_flash_write_block(src + i * XFLASH_BLOCK_SIZE, block_num + i)) {
            return 1; // error
        }
    }
    return 0; // success
}


/******************************************************************************/
// MicroPython bindings

STATIC const mp_obj_base_t pyb_flash_obj = {&pyb_flash_type};

STATIC mp_obj_t pyb_flash_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
    // check arguments
    mp_arg_check_num(n_args, n_kw, 0, 0, false);

    // return singleton object
    return MP_OBJ_FROM_PTR(&pyb_flash_obj);
}

STATIC mp_obj_t pyb_flash_readblocks(mp_obj_t self, mp_obj_t block_num, mp_obj_t buf) {
    mp_buffer_info_t bufinfo;
    mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_WRITE);
    mp_uint_t ret = pyb_flash_read_blocks(bufinfo.buf, mp_obj_get_int(block_num), bufinfo.len / XFLASH_BLOCK_SIZE);
    return MP_OBJ_NEW_SMALL_INT(ret);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_3(pyb_flash_readblocks_obj, pyb_flash_readblocks);

STATIC mp_obj_t pyb_flash_writeblocks(mp_obj_t self, mp_obj_t block_num, mp_obj_t buf) {
    mp_buffer_info_t bufinfo;
    mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_READ);
    mp_uint_t ret = pyb_flash_write_blocks(bufinfo.buf, mp_obj_get_int(block_num), bufinfo.len / XFLASH_BLOCK_SIZE);
    return MP_OBJ_NEW_SMALL_INT(ret);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_3(pyb_flash_writeblocks_obj, pyb_flash_writeblocks);

STATIC mp_obj_t pyb_flash_ioctl(mp_obj_t self, mp_obj_t cmd_in, mp_obj_t arg_in) {
    mp_int_t cmd = mp_obj_get_int(cmd_in);
    switch (cmd) {
        case BP_IOCTL_INIT: 
            pyb_flash_init();
            if(b_pyb_flash_is_initialised){
                return MP_OBJ_NEW_SMALL_INT(0);
            }
            return MP_OBJ_NEW_SMALL_INT(1);
        
        case BP_IOCTL_DEINIT: 
            pyb_flash_flush(); 
            return MP_OBJ_NEW_SMALL_INT(0); // TODO properly
        
        case BP_IOCTL_SYNC: 
            pyb_flash_flush(); 
            return MP_OBJ_NEW_SMALL_INT(0);
        
        case BP_IOCTL_SEC_COUNT: 
            return MP_OBJ_NEW_SMALL_INT(pyb_flash_get_block_count());
            
        case BP_IOCTL_SEC_SIZE: 
            return MP_OBJ_NEW_SMALL_INT(pyb_flash_get_block_size());
            
        default: 
            return mp_const_none;
    }
}
STATIC MP_DEFINE_CONST_FUN_OBJ_3(pyb_flash_ioctl_obj, pyb_flash_ioctl);

STATIC const mp_rom_map_elem_t pyb_flash_locals_dict_table[] = {
    { MP_ROM_QSTR(MP_QSTR_readblocks),      MP_ROM_PTR(&pyb_flash_readblocks_obj) },
    { MP_ROM_QSTR(MP_QSTR_writeblocks),     MP_ROM_PTR(&pyb_flash_writeblocks_obj) },
    { MP_ROM_QSTR(MP_QSTR_ioctl),           MP_ROM_PTR(&pyb_flash_ioctl_obj) },
};

STATIC MP_DEFINE_CONST_DICT(pyb_flash_locals_dict, pyb_flash_locals_dict_table);

const mp_obj_type_t pyb_flash_type = {
    { &mp_type_type },
    .name           = MP_QSTR_Flash,
    .make_new       = pyb_flash_make_new,
    .locals_dict    = (mp_obj_dict_t*)&pyb_flash_locals_dict,
};

//vfs init func
void pyb_flash_init_vfs(fs_user_mount_t *vfs) {
    vfs->base.type      = &mp_fat_vfs_type;
    vfs->flags         |= FSUSER_NATIVE | FSUSER_HAVE_IOCTL;
    vfs->fatfs.drv      = vfs;
    vfs->readblocks[0]  = MP_OBJ_FROM_PTR(&pyb_flash_readblocks_obj);
    vfs->readblocks[1]  = MP_OBJ_FROM_PTR(&pyb_flash_obj);
    vfs->readblocks[2]  = MP_OBJ_FROM_PTR(pyb_flash_read_blocks); // native version
    vfs->writeblocks[0] = MP_OBJ_FROM_PTR(&pyb_flash_writeblocks_obj);
    vfs->writeblocks[1] = MP_OBJ_FROM_PTR(&pyb_flash_obj);
    vfs->writeblocks[2] = MP_OBJ_FROM_PTR(pyb_flash_write_blocks); // native version
    vfs->u.ioctl[0]     = MP_OBJ_FROM_PTR(&pyb_flash_ioctl_obj);
    vfs->u.ioctl[1]     = MP_OBJ_FROM_PTR(&pyb_flash_obj);
}
  1. 根据实际需要,进行fatfs 的各项功能配置 (ffconf.h)

  2. 根据需要开启并实现依赖于文件系统的一些内建方法和module

  3. 系统初始化时候, 注意进行vfs的挂载

  4. 注意事项:

    注意配置存储外设的block大小和ff的FATFS_MAX_SS/FATFS_MIN_SS 一直

    #define MICROPY_FATFS_MAX_SS (4096)

1.2 内建方法和对象

  1. MicroPython 提供了众多的内建方法和内建对象, 定义在文件 objmodule.c
STATIC const mp_rom_map_elem_t mp_builtin_module_table[] = {
    { MP_ROM_QSTR(MP_QSTR___main__), MP_ROM_PTR(&mp_module___main__) },
    { MP_ROM_QSTR(MP_QSTR_builtins), MP_ROM_PTR(&mp_module_builtins) },
    { MP_ROM_QSTR(MP_QSTR_micropython), MP_ROM_PTR(&mp_module_micropython) },

#if MICROPY_PY_IO
    { MP_ROM_QSTR(MP_QSTR_uio), MP_ROM_PTR(&mp_module_io) },
#endif

	....
	
	}

​ 除了标准提供的__ main __ , builtins, micropython 外, 其余对象均使用宏控制,用户根据移植需要进行打开或者关闭即可

  1. 实现 内建的open/stat 方法

    open 方法是micropython 重要的内建方法之一, 在提供的移植模板中, open 方法进行了空实现

    mp_obj_t mp_builtin_open(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) {
        return mp_const_none;
    }
    MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open);
    

    如果移植实现了 vfs 文件系统的移植, 就可以将内建的open方法和vfs 提供的文件系统open方法绑定起来, 以实现使用内建的open方法直接进行文件操作, 与文件系统的open方法绑定后,需要注释掉模板的空实现,避免编译重定义错误。

    内建的stat方法也可以直接和vfs的stat方法绑定

    // use vfs's functions for import stat and builtin open
    #define mp_import_stat              mp_vfs_import_stat
    #define mp_builtin_open             mp_vfs_open
    #define mp_builtin_open_obj         mp_vfs_open_obj
    

1.3 使用ampy

系统开始执行py,需要启用宏控MICROPY_READER_VFS, 使用系统实现的mp_lexer_new_from_file方法

#define MICROPY_READER_VFS 1

  1. 安装ampy

    pip3(pip) install adafruit-ampy
    pip3 install pserial   # 依赖这个包
    
  2. ampy 支持的功能

    ampy --help
    Usage: ampy [OPTIONS] COMMAND [ARGS]...
    
      ampy - Adafruit MicroPython Tool
    
      Ampy is a tool to control MicroPython boards over a serial connection.
      Using ampy you can manipulate files on the board's internal filesystem and
      even run scripts.
    
    Options:
      -p, --port PORT    Name of serial port for connected board.  Can optionally
                         specify with AMPY_PORT environment variable.  [required]
      -b, --baud BAUD    Baud rate for the serial connection (default 115200).
                         Can optionally specify with AMPY_BAUD environment
                         variable.
      -d, --delay DELAY  Delay in seconds before entering RAW MODE (default 0).
                         Can optionally specify with AMPY_DELAY environment
                         variable.
      --version          Show the version and exit.
      --help             Show this message and exit.
    
    Commands:
      get    Retrieve a file from the board.
      ls     List contents of a directory on the board.
      mkdir  Create a directory on the board.
      put    Put a file or folder and its contents on the board.
      reset  Perform soft reset/reboot of the board.
      rm     Remove a file from the board.
      rmdir  Forcefully remove a folder and all its children from the board.
      run    Run a script and print its output.
    
  3. ampy使用举例

    # 使用ls
    >ampy --port COM8 ls /flash
    /flash/3456
    /flash/test.txt
    
    # 传输文件到board
    >ampy --port COM8 put main.py
    
    # 使用ls
    >ampy --port COM8 ls /flash
    /flash/3456
    /flash/main.py
    /flash/test.txt
    
    # 运行板载文件
    >ampy --port COM8 run main.py
    Hello word!   # 从main.py 打印而来
    

1.4 文件相关的常用方法 & 模块

  • dir() : 查看所有已导入的module、对象

  • import X : 导入module

  • dir(module): 查看module的方法、对象

  • import builtins: 导入 所有内建的方法和对象

  • 其他常用module : uos, uio, uio.FileIO (文件对象)

  • 创建和删除文件

    f=open('file.txt', 'wr')
    import uos
    uos.remove('file.txt')
    
  • 文件操作方法

    dir(uio.FileIO)
    
    ['__class__', '__enter__', '__exit__', '__name__', 'close', 'read', 'readinto', 'readline', 'write', '__del__', 'flush', 'readlines', 'seek', 'tell']
    
  • 其他,还可以根据应用需要与MCU的能力, 开启 float,longlong以及数学库等

你可能感兴趣的:(嵌入式,Python,Iot)