VFS FileSystem

Requirements

No specific requirement. This example should run without issue on GAP9 EVK.

Description

This example shows you how to use VFS on GAP9 with mram or external flash.

# Boot from JTAG
cmake -B build
cmake --build buil -j -t run

Code

/*
 * Copyright (C) 2017 ETH Zurich, University of Bologna and GreenWaves Technologies
 * All rights reserved.
 *
 * This software may be modified and distributed under the terms
 * of the BSD license.  See the LICENSE file for details.
 *
 */

#include "pmsis.h"
#include "bsp/bsp.h"
#include "bsp/flash_partition_v2.h"
#include "bsp/vfs.h"

#define TOTAL_SIZE  ( 16384 )
#define BUFF_SIZE   ( 1024 )

static PI_L2 char buff[2][BUFF_SIZE];
static pi_fs_file_t *file[2];
static pi_fs_file_t *tx_file[2];

static PI_L2 char check_buff[BUFF_SIZE];

static int32_t exec_reads()
{
    printf("exec read test\n");

	int32_t size0 = file[0]->size;
	int32_t size1 = file[1]->size;
	int32_t rd_size0, rd_size1;
    uint32_t index0 = 0;
    uint32_t index1 = 0;

	do{
		if (size0 > BUFF_SIZE)
			rd_size0 = BUFF_SIZE;
		else
			rd_size0 = size0;

		if (size1 > BUFF_SIZE)
			rd_size1 = BUFF_SIZE;
		else
			rd_size1 = size1;

		pi_fs_read(file[0], buff[0], rd_size0);
		pi_fs_read(file[1], buff[1], rd_size1);

		size0 -= rd_size0;
		size1 -= rd_size1;

		for (int32_t i=0; i<rd_size0; i++)
		{
			unsigned char expected;
			expected = (index0%128) & 0x7f;
			if (expected != buff[0][i])
			{
				printf("Error, buffer: %d, index: %d, expected: 0x%x, read: 0x%x\n", 0, i, expected, buff[0][i]);
				return -6;
			}
			index0 ++;
		}

		for (int32_t i=0; i<rd_size1; i++)
		{
			unsigned char expected;
			expected = (index1 %128) | 0x80;
			if (expected != buff[1][i])
			{
				printf("Error, buffer: %d, index: %d, expected: 0x%x, read: 0x%x\n", 1, i, expected, buff[1][i]);
				return -6;
			}
			index1 ++;
		}

	} while(size0 && size1);
	index0 = 0;
	index1 = 0;

	return 0;
}

static int exec_tests_lfs()
{

    for(int i=0; i<(TOTAL_SIZE/BUFF_SIZE); i++)
    {
        pi_vfs_read(file[0], buff[0], BUFF_SIZE);
        pi_vfs_write(tx_file[0], buff[0], BUFF_SIZE);
        pi_vfs_read(file[1], buff[1], BUFF_SIZE);
        pi_vfs_write(tx_file[1], buff[1], BUFF_SIZE);
    }

    return 0;
}

#if (CONFIG_VFS_VERSION == 2)
int test_vfs_ls(pi_vfs_part_t *vfs, char* url)
#else
int test_vfs_ls(pi_vfs_t *vfs, char* url)
#endif
{
    pi_vfs_file_t* dir;

    dir = pi_vfs_dir_open(vfs, url);
    if(dir==NULL)
        return -1;
    printf("fs dir opened\n");

    pi_vfs_info_t info;
    while (true) {
#if (CONFIG_VFS_VERSION == 2)
        int res = pi_vfs_dir_read(vfs, &info);
#else
        int res = pi_vfs_dir_read(dir, &info);
#endif
        if (res < 0) {
            printf("dir read failed\n");
            return res;
        }

        if (res == 0) {
            break;
        }

        switch (info.file_type) {
            case PI_FS_TYPE_REG: printf("reg "); break;
            case PI_FS_TYPE_DIR: printf("dir "); break;
            default:             printf("?   "); break;
        }

        static const char *prefixes[] = {"", "K", "M", "G"};
        for (int i = sizeof(prefixes)/sizeof(prefixes[0])-1; i >= 0; i--) {
            if ((int)info.size >= (1 << 10*i)-1) {
                printf("%*u%sB ", 4-(i != 0), info.size >> 10*i, prefixes[i]);
                break;
            }
        }

        printf("%s\n", info.name);
    }

#if (CONFIG_VFS_VERSION == 2)
    pi_vfs_dir_close(vfs);
#else
    pi_vfs_dir_close(dir);
#endif

    return 0;
}

#if (CONFIG_VFS_VERSION == 2)
int test_lfs(pi_vfs_part_t *vfs)
#else
int test_lfs(pi_vfs_t *vfs)
#endif
{
    int err = 0;
    pi_vfs_file_t *vfile[2];
    pi_vfs_file_t *tx_vfile[2];

    err += test_vfs_ls(vfs, "/");

    //This is a debug function to print the content of a folder.
    printf("List Dir: /\n");
    pi_vfs_ls(vfs, "/");
    printf("\n\n\n");
    printf("List Dir: /files\n");
    pi_vfs_ls(vfs, "/files/");
    printf("\n\n\n");

    //Create a new directory
    printf("Creating Directory: \"/new_dir\"\n");
    pi_vfs_mkdir(vfs, "/new_dir");

    // Print to see that has been properly created
    printf("List Dir: /\n");
    pi_vfs_ls(vfs, "/");
    printf("\n\n\n");

    //Copy files in the new folder
    vfile[0] = pi_vfs_open(vfs, STR(FILE0), PI_FS_FLAGS_READ);
    if (vfile[0] == NULL)
    {
        printf("File0 not found\n");
        return -3;
    }

    vfile[1] = pi_vfs_open(vfs, STR(FILE1), PI_FS_FLAGS_READ);
    if (vfile[1] == NULL)
    {
        printf("File1 not found\n");
        return -4;
    }

    tx_vfile[0] = pi_vfs_open(vfs, STR(TX_FILE0), PI_FS_FLAGS_WRITE);
    if (tx_vfile[0] == NULL)
    {
        printf("error when opening tx_file0\n");
        return -3;
    }

    tx_vfile[1] = pi_vfs_open(vfs, STR(TX_FILE1), PI_FS_FLAGS_WRITE);
    if (tx_vfile[1] == NULL)
    {
        printf("error when opening tx_file1\n");
        return -4;
    }

    for(int i=0; i<(TOTAL_SIZE/BUFF_SIZE); i++)
    {
        pi_vfs_read(vfile[0], buff[0], BUFF_SIZE);
        pi_vfs_write(tx_vfile[0], buff[0], BUFF_SIZE);
        pi_vfs_read(vfile[1], buff[1], BUFF_SIZE);
        pi_vfs_write(tx_vfile[1], buff[1], BUFF_SIZE);
    }

    // Close file to wrote data on flash.
    pi_vfs_close(vfile[0]);
    pi_vfs_close(vfile[1]);
    pi_vfs_close(tx_vfile[0]);
    pi_vfs_close(tx_vfile[1]);

    printf("Copying %s  to %s\n",STR(FILE0),STR(TX_FILE0));
    printf("Copying %s  to %s\n",STR(FILE1),STR(TX_FILE1));


    for (int j=0; j<2; j++)
    {

        pi_vfs_file_t *file;

        if (j == 0)
            file = pi_vfs_open(vfs, STR(TX_FILE0), PI_FS_FLAGS_READ);
        else
            file = pi_vfs_open(vfs, STR(TX_FILE1), PI_FS_FLAGS_READ);

        pi_vfs_read(file, check_buff, BUFF_SIZE);

        for (int i=0; i<BUFF_SIZE; i++)
        {
            unsigned char expected;
            if (j == 0)
                expected = i & 0x7f;
            else
                expected = i | 0x80;
            if (expected != check_buff[i])
            {
                printf("Error, buffer: %d, index: %d, expected: 0x%x, read: 0x%x\n", j, i, expected, check_buff[i]);
                return -6;
            }
        }
        pi_vfs_close(file);
    }

    printf("Hooray! copied Files checked correctly!!!\n");

    //Remove copyied files:
    printf("Removing %s\n", STR(TX_FILE0));
    pi_vfs_remove(vfs, STR(TX_FILE0));
    printf("Removing %s\n", STR(TX_FILE1));
    pi_vfs_remove(vfs, STR(TX_FILE1));

    printf("Removing /new_dir\n");
    //Remove Created Directory;
    pi_vfs_remove(vfs, "/new_dir");

    //List all files in the filesystem
    printf("List Dir all FS content:\n");
    printf("\n/\n");
    test_vfs_ls(vfs, "/");
    printf("\n/files/\n");
    test_vfs_ls(vfs, "/files/");
    printf("\n\n\n");

    return err;
}

int main(void)
{
#if (CONFIG_VFS_VERSION == 2)
    pi_device_t my_vfs;
    pi_vfs_conf_t my_vfs_conf;
    pi_vfs_conf_init(&my_vfs_conf);
    pi_open_from_conf(&my_vfs, &my_vfs_conf);
#else
    pi_device_t my_vfs[2];
    pi_vfs_conf_t my_vfs_conf[2];
    pi_vfs_conf_init(&my_vfs_conf[0]);
    pi_vfs_conf_init(&my_vfs_conf[1]);
    pi_open_from_conf(&my_vfs[0], &my_vfs_conf[0]);
    pi_open_from_conf(&my_vfs[1], &my_vfs_conf[1]);
#endif

    /*
     * Test ReadFS mount
     */
    printf("============================\n");
    printf("    Test readFS via VFS\n");
    printf("============================\n");

#if (CONFIG_VFS_VERSION == 2)
    pi_vfs_part_t my_readfs_mram, my_readfs_flash;
    // Dummy ptr. Simply to prevent #ifdef version to pass object to functions
    pi_vfs_part_t *my_readfs_mram_ptr = &my_readfs_mram, *my_readfs_flash_ptr = &my_readfs_flash;
    pi_vfs_part_init(&my_readfs_mram, "readfs_mram", &my_readfs_flash);
    pi_vfs_part_init(&my_readfs_flash, "readfs_flash", NULL);

    int32_t mount_err = pi_vfs_mount(&my_vfs, "app", &my_readfs_mram);
    if (mount_err)
#else
    pi_vfs_t *my_readfs_mram_ptr = (pi_vfs_t *) pi_vfs_mount(&my_vfs[0], "/app/readfs_mram");
    pi_vfs_t *my_readfs_flash_ptr = (pi_vfs_t *) pi_vfs_mount(&my_vfs[1], "/app/readfs_flash");
    if ((my_readfs_mram_ptr == NULL) || (my_readfs_flash_ptr == NULL))
#endif
    {
        printf("mount readfs failed\n");
        return -1;
    }
    file[0] = pi_vfs_open(my_readfs_mram_ptr, "flash_file_0.bin", 0);
    file[1] = pi_vfs_open(my_readfs_flash_ptr, "flash_file_1.bin", 0);
    if (file[0] == NULL || file[1] == NULL)
    {
        printf("file open failed\n");
        return -1;
    }
    printf("files opened\n");

	if (exec_reads())
    {
        printf("read test failed\n");
		return -1;
    }

    pi_vfs_close(file[0]);
    pi_vfs_close(file[1]);
#if (CONFIG_VFS_VERSION == 2)
    pi_vfs_unmount(&my_vfs);
#else
    pi_vfs_unmount(&my_vfs[0]);
    pi_vfs_unmount(&my_vfs[1]);
#endif
    printf("readFS test succeed\n\n");

    /*
     * Test LFS mount
     */
    printf("============================\n");
    printf("    Test LFS via VFS\n");
    printf("============================\n");

#if (CONFIG_VFS_VERSION == 2)
    pi_vfs_part_t my_lfs_mram, my_lfs_flash;
    // Dummy ptr. Simply to prevent #ifdef version to pass object to functions
    pi_vfs_part_t *my_lfs_mram_ptr = &my_lfs_mram, *my_lfs_flash_ptr = &my_lfs_flash;
    pi_vfs_part_init(&my_lfs_mram, "lfs_mram", &my_lfs_flash);
    pi_vfs_part_init(&my_lfs_flash, "lfs_flash", NULL);

    mount_err = pi_vfs_mount(&my_vfs, "app", &my_lfs_mram);
    if (mount_err)
#else
    pi_vfs_t *my_lfs_flash_ptr = (pi_vfs_t *) pi_vfs_mount(&my_vfs[0], "/app/lfs_flash");
    pi_vfs_t *my_lfs_mram_ptr = (pi_vfs_t *) pi_vfs_mount(&my_vfs[1], "/app/lfs_mram");
    if ((my_lfs_mram_ptr == NULL) || (my_lfs_flash_ptr == NULL))
#endif
    {
        printf("mount lfs failed\n");
        return -1;
    }
    printf("lfs mounted via VFS\n");

    test_lfs(my_lfs_flash_ptr);
    test_lfs(my_lfs_mram_ptr);

#if (CONFIG_VFS_VERSION == 2)
    pi_vfs_unmount(&my_vfs);
#else
    pi_vfs_unmount(&my_vfs[0]);
    pi_vfs_unmount(&my_vfs[1]);
#endif
    printf("lfs test succeed\n\n");

    /*
     *  Test dir access and dir read
     */

    printf("============================\n");
    printf("    Test dir load via VFS\n");
    printf("============================\n");

#if (CONFIG_VFS_VERSION == 2)
    pi_vfs_part_t my_root_mram, my_root_flash;
    // Dummy ptr. Simply to prevent #ifdef version to pass object to functions
    pi_vfs_part_t *root_dir_mram_ptr = &my_root_mram, *root_dir_flash_ptr = &my_root_flash;
    pi_vfs_part_init(&my_root_mram, "lfs_flash/", &my_root_flash);
    pi_vfs_part_init(&my_root_flash, "lfs_flash/lfs_file_folder/", NULL);

    mount_err = pi_vfs_mount(&my_vfs, "app", &my_root_mram);
    if (mount_err)
#else
    pi_vfs_file_t *root_dir_flash_ptr = (pi_vfs_file_t *) pi_vfs_mount(&my_vfs[0], "/app/lfs_flash/lfs_file_folder/");
    pi_vfs_file_t *root_dir_mram_ptr = (pi_vfs_file_t *) pi_vfs_mount(&my_vfs[1], "/app/lfs_flash/");
    if ((root_dir_flash_ptr == NULL) || (root_dir_mram_ptr == NULL))
#endif
    {
        printf("mount /app/lfs_flash/files failed\n");
        return -1;
    }
    printf("lfs dir mounted via VFS\n");

    pi_vfs_info_t info;
    // Dump the info for lfs_file_folder in ext-flash
    printf("dump the content in the lfs_file_folder in ext-flash\n");
    while (true) {
        int res = pi_vfs_dir_read(root_dir_flash_ptr, &info);
        if (res < 0) {
            printf("dir read failed\n");
            return res;
        }

        if (res == 0) {
            break;
        }

        switch (info.file_type) {
            case PI_FS_TYPE_REG: printf("reg "); break;
            case PI_FS_TYPE_DIR: printf("dir "); break;
            default:             printf("?   "); break;
        }

        static const char *prefixes[] = {"", "K", "M", "G"};
        for (int i = sizeof(prefixes)/sizeof(prefixes[0])-1; i >= 0; i--) {
            if ((int)info.size >= (1 << 10*i)-1) {
                printf("%*u%sB ", 4-(i != 0), info.size >> 10*i, prefixes[i]);
                break;
            }
        }

        printf("%s\n", info.name);
    }

    // Dump the info for / folder in mram
    printf("dump the content in the / in mram\n");
    while (true) {
        int res = pi_vfs_dir_read(root_dir_mram_ptr, &info);
        if (res < 0) {
            printf("dir read failed\n");
            return res;
        }

        if (res == 0) {
            break;
        }

        switch (info.file_type) {
            case PI_FS_TYPE_REG: printf("reg "); break;
            case PI_FS_TYPE_DIR: printf("dir "); break;
            default:             printf("?   "); break;
        }

        static const char *prefixes[] = {"", "K", "M", "G"};
        for (int i = sizeof(prefixes)/sizeof(prefixes[0])-1; i >= 0; i--) {
            if ((int)info.size >= (1 << 10*i)-1) {
                printf("%*u%sB ", 4-(i != 0), info.size >> 10*i, prefixes[i]);
                break;
            }
        }

        printf("%s\n", info.name);
    }

#if (CONFIG_VFS_VERSION == 2)
    pi_vfs_unmount(&my_vfs);
#else
    pi_vfs_unmount(&my_vfs[0]);
    pi_vfs_unmount(&my_vfs[1]);
#endif
    printf("dir test succeed\n\n");

    printf("Leaving example\n");
    return 0;
}