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 QUOTE(name) #name
#define STR(macro) QUOTE(macro)
#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;
}

int test_vfs_ls(pi_vfs_t *vfs,char* url)
{
    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) {
        int res = pi_vfs_dir_read(dir, &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);
    }

    pi_vfs_dir_close(dir);
    return 0;
}

int test_lfs(pi_vfs_t *vfs)
{
    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)
{
    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]);
    my_vfs_conf[1].id = 1;
    pi_open_from_conf(&my_vfs[0], &my_vfs_conf[0]);
    pi_open_from_conf(&my_vfs[1], &my_vfs_conf[1]);

    /*
     * Test Volume mount
     */

    printf("============================\n");
    printf(" Test Volume mount via VFS\n");
    printf("============================\n");
    /* Open volume */
    pi_fpv2_volume_desc_t* test_volume = (pi_fpv2_volume_desc_t *) pi_vfs_mount(&my_vfs[0], "/app");
    if(test_volume == NULL)
    {
        printf("mount app failed\n");
        return -1;
    }
    else
        printf("Volume volume /app has been mounted\n");
    pi_fpv2_volume_dump(test_volume);
    pi_vfs_unmount(&my_vfs[0]);
    printf("Mount volume test done\n");

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

    pi_vfs_t *my_readfs_mram = (pi_vfs_t *) pi_vfs_mount(&my_vfs[0], "/app/readfs_mram");
    pi_vfs_t *my_readfs_flash = (pi_vfs_t *) pi_vfs_mount(&my_vfs[1], "/app/readfs_flash");
    if( my_readfs_mram == NULL ||  my_readfs_flash == NULL )
    {
        printf("mount /app/readfs failed\n");
        return -1;
    }
    file[0] = pi_fs_open(my_readfs_mram->fs, "flash_file_0.bin", 0);
    file[1] = pi_fs_open(my_readfs_flash->fs, "flash_file_1.bin", 0);
    if (file[0] == NULL || file[1] == NULL) 
    {
        printf("file open failed\n");
        return -1;
    }
    else
    {
        printf("files opened\n");
    }

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

    pi_fs_close(file[0]);
    pi_fs_close(file[1]);
    pi_vfs_unmount(&my_vfs[0]);
    pi_vfs_unmount(&my_vfs[1]);
    printf("readFS test succeed\n");
    
    /*
     * Test LFS mount
     */
    printf("============================\n");
    printf("    Test LFS via VFS\n");
    printf("============================\n");

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


    /*
     *  Test dir access and dir read
     */ 

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

    pi_vfs_file_t *root_dir_flash = (pi_vfs_file_t *) pi_vfs_mount(&my_vfs[0], "/app/lfs_flash/lfs_file_folder/");
    pi_vfs_file_t *root_dir_mram = (pi_vfs_file_t *) pi_vfs_mount(&my_vfs[1], "/app/lfs_flash/");
    if(root_dir_flash == NULL || root_dir_mram == NULL)
    {
        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, &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, &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);
    }

    pi_vfs_dir_close(root_dir_flash);
    pi_vfs_dir_close(root_dir_mram);
    pi_vfs_unmount(&my_vfs[0]);
    pi_vfs_unmount(&my_vfs[1]);

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