Difference between revisions of "Documents/PHAT"

From Nutwiki
Jump to: navigation, search
(Created page with "<div id="content"> = PHAT File System = PHAT is then name of the FAT12, FAT16 and FAT32 compatible file system provided by Nut/OS. Currently this is still alpha code and may...")
 
(No difference)

Latest revision as of 08:57, 13 July 2017

PHAT File System

PHAT is then name of the FAT12, FAT16 and FAT32 compatible file system provided by Nut/OS. Currently this is still alpha code and may not work as expected. Beside the fact, that it will probably contain a lot of bugs, the following known problems and limitations exist:

  • Tested on Ethernut 3 (ARM7) only.
  • Long filenames (VFAT) are not yet supported.
  • Only a single sector buffer is used.
  • Deleting large files is sometimes extremly slow or seems to fail completely.
  • Possibly fails to change back to the root directory. At least this problem appears with the ftpd sample.
  • After deleting directories with files using the ftpd sample, running ckdisk or similar tools results in lost+found fragments.
  • Write protections are ignored.

The max. performance with MMC cards on Ethernut 3 is 128 kBytes/s for writing and 350 kBytes/s for reading.

Prerequisites

In most cases you need to update the programmable logic on Ethernut 3 to [[../../arc/enut30dnpl5.zip|NPL Version 5]]. Check [[../hardware/enut3/nplupgrd.html|Ethernut 3 NPL Version]] about how to do this.

Nut/OS 4.2.1 or later is required.

Nut/OS File System History

Since the very early days Nut/OS came with a lowest-end read-only file system called UROM, which is still in use. It actually had been a quick hack to support HTTP requests in the first place.

Later on Michael Fischer added a FAT file system, which had been successfully used for ATA harddisk and CDROMs with ATAPI interface. Unfortunately it was also read-only and no file system with write access existed over a long period.

Several contributors published other file systems for Nut/OS, like
Xflash by Michael Fischer or
[[../../../arc/df-SPIFlashFileSystemWeb_ver111.zip|SPIFlashFileSystem]] by Dusan Ferbas.
Unfortunately no developer with write access to the source code repository added the code to the distribution.

Not too long ago, the PNUT file system had been introduced. It was the first officially released driver with write access and its main purpose is to offer an easy to use high level access to banked memory. Though, as it uses RAM, all stored information is gone after cycling the power supply.

An interesting idea had been contributed by Maarten van Heesch, named XPNUT. It creates a copy of the PNUT file system in a serial flash chip. Upon initialization, the flashed copy is transfered back to RAM.

Using PHAT

The modularity of Nut/OS requires to register all drivers that will be used by the application. Calling NutRegisterDevice() with a pointer to the NUTDEVICE information structure of the device we want to use creates a reference to the device driver. When the application is later linked to the Nut/OS libraries, then the driver code of the referenced devices is added to the final binary that runs on the target board. Drivers, which are not registered, will not be part of the binary image. This is true for hardware drivers as well as file system drivers, as Nut/OS handles both in a similar way.

The PHAT file system does not directly access the hardware. It needs a block device driver attached to it, which provides the low level block read and write access. At the time of this writing only one block device driver is available, which supports Multimedia and SD Cards in SPI mode.

Here's how an application registers the PHAT file system and the block device driver.

#include <dev/nplmmc.h>
#include <fs/phatfs.h>

/* Register the PHAT file system. */
if (NutRegisterDevice(&devPhat0, 0, 0)) {
    /* Handle error */
}
/* Register the MMC block device. */
if (NutRegisterDevice(&devNplMmc0, 0, 0)) {
    /* Handle error */
}

After the drivers had been successfully registered, the application can take the next step: Mounting a volume. From here on we forget about any NUTDEVICE structure. As soon as the device is registered, Nut/OS knows its name, which is stored inside the NUTDEVICE structure. Application code uses this name instead of the NUTDEVICE structure itself. The idea behind this is, that coming versions will completely ban the NUTDEVICE structure from application code and a special initialization module will be used to register the correct devices.

Mass storage devices may contain more than one volume, also known as partitions. Thus, the application must specify three items to mount a volume:

  1. The block device to use.
  2. The volume to mount.
  3. The file system to use.

Nut/OS doesn't offer a mount() API call. Instead _open() is used and the required items are packed into a path.

#include <stdio.h>
#include <fcntl.h>

int hvol;

/* Mount partition. */
if ((hvol = _open("MMC0:1/PHAT0", _O_RDWR | _O_BINARY)) == -1) {
    /* Handle error */
}

This mounts the first partition ("1") on the MMC device ("MMC0") and uses the PHAT file system ("PHAT0") to access the volume. Obviously Nut/OS is prepared to provide multiple MMC devices ("MMC1", "MMC2"...) and to mount several PHAT volumes ("PHAT1", "PHAT2"...) concurrently. Note, that the first partition is "1". Partition "0" is a special case and will mount the first primary partition that is marked active. We may even use the shortest form

hvol = _open("MMC0:", _O_RDWR | _O_BINARY);

which will mount the first active primary partition, using the first file system driver that Nut/OS can find among all registered devices. However, the order of the list of file system drivers is undocumented. Thus, when using the short form, only one file system driver should have been registered. The value returned by _open() can be used later to unmount the volume. Again there is no specific call available and _close() is used instead.

_close(hvol);

After a volume has been successfully mounted, standard I/O calls can be used to access its contents, typically files and directories. As there is no support right now for a current working path, applications have to specify the full path including the name of the file system in front. The following sample opens a file for write access, writes a simple text line to it and close the file afterwards. If the file doesn't exist, it will be created.

#include <stdio.h>

FILE *fp;

fp = fopen("PHAT0:/simple.txt", "w");
fprintf(fp, "First line in this file\n");
fclose(fp);

Special functions are provided to read directories, namely opendir(), readdir() and closedir().

New subdirectories can be created with mkdir() and existing subdirectories may be removed by calling rmdir().

FTP Server Sample

When compiling app/ftpd/ftpserv.c for Ethernut 3, then the PHAT file system is used by default. A precompiled binary is included in [[../../arc/ftpd-phat.zip|this archive]].

PHAT Driver Internals

Buffering

The driver is prepared to handle its own sector buffers. However, in the current version it uses the single sector buffer provided by the block device driver.

The single buffer makes any kind of write access very slow. However, read access times are acceptable and using the buffer of the block device driver allows to create minimal systems with ATA interfaces, which share address and/or data bus with I/O ports and do not allow to access external memory during ATA transfers. Such a candidate would be an ATmega128 CPU with IDE CDROM or harddisk, where the sector buffer is located in the on-chip RAM.

Anyway, later versions of the PHAT driver will probably have to use a more advanced buffering.

Driver Modules

Compared the other Nut/OS drivers the PHAT file system driver is quite large and split into several source code modules.

  • phatfs.c
    Contains the device structure devPhat0, the main driver routines, as well as cluster allocation routines. The device structure has the following format:
    struct _NUTDEVICE {
        NUTDEVICE *dev_next;
        u_char dev_name[9];
        u_char dev_type;
        uptr_t dev_base;
        u_char dev_irq;
        void *dev_icb;
        void *dev_dcb;
        int (*dev_init) (NUTDEVICE *);
        int (*dev_ioctl) (NUTDEVICE *, int, void *);
        int (*dev_read) (NUTFILE *, void *, int);
        int (*dev_write) (NUTFILE *, CONST void *, int);
        int (*dev_write_P) (NUTFILE *, PGM_P, int);
        NUTFILE * (*dev_open) (NUTDEVICE *, CONST char *, int, int);
        int (*dev_close) (NUTFILE *);
        long (*dev_size) (NUTFILE *);
    };

    The same structure is used in Nut/OS for all kind of devices.

    • dev_next
      points to the next device. All registered devices are linked by this pointer, which is NULL for the last device.
    • dev_name
      stores the symbolic name of the device.
    • dev_type
      contains the type of the interface, which this driver provides. For file systems the type IFTYP_FS is used.
    • dev_base and dev_irq
      are not used by file system drivers.
    • dev_icb
      is used by the PHAT device to store the NUTFILE handle of the associated block device.
    • dev_dcb
      is used by the PHAT device to store the pointer to its volume information structure (see below).


    The remaining structure elements contain pointers to the basic file system functions.

    • dev_init, points to PhatInit
      Applications need to register the file system driver with NutRegisterDevice(&devPhat0, 0, 0), which in turn calls this routine.
    • dev_open, points to PhatFileOpen
      This low level routine opens a file and is called by the C runtime library functions like _open(). In addition to open normal files, it is used by the module phatdir.c to open directories
    • dev_close, points to PhatFileClose
      Closes a normal file or directory, which had been previously opened by PhatFileOpen().
    • dev_read, points to PhatFileRead
      Reads data from a file or directory previously opened by PhatFileOpen().
    • dev_write, points to PhatFileWrite
      Writes data to a file or directory previously opened by PhatFileOpen().
    • dev_ioctl, points to PhatIOCtl
      • FS_STATUS
        Queries the status of a directory entry. Used by the C runtime function stat().
      • FS_DIR_CREATE
        Creates a subdirectory entry. Used by the C runtime function mkdir().
      • FS_DIR_REMOVE
        Deletes a subdirectory entry. Used by the C runtime function rmdir().
      • FS_DIR_OPEN
        Opens a directory. Used by the C runtime function opendir().
      • FS_DIR_CLOSE
        Closes a directory. Used by the C runtime function closedir().
      • FS_DIR_READ
        Reads the next entry of a previously opened directory. Used by the C runtime function readdir().
      • FS_FILE_STATUS
        Queries the status of a previously opened file. Not implemented.
      • FS_FILE_DELETE
        Deletes a file. Used by the C runtime function unlink().
      • FS_FILE_SEEK
        Sets a file pointer. Used by the C runtime function _seek().
      • FS_RENAME
        Renames a file. Implemented, but currently not used.
      • FS_VOL_MOUNT
        Mounts a FAT volume. This function is called by the block device driver.
      • FS_VOL_UNMOUNT
        Unmounts a FAT volume. This function is called by the block device driver.
  • phatvol.c
    This modules contains the routines to mount and unmount a volume.
    struct _PHATVOL {
        int vol_type;
        u_long vol_numfree;
        u_long vol_nxtfree;
        u_char *vol_buf;
        u_long vol_bufsect;
        int vol_bufdirty;
        u_int vol_sectsz;
        u_int vol_clustsz;
        u_long vol_tabsz;
        u_long vol_tab_sect[2];
        u_int vol_rootsz;
        u_long vol_root_sect;
        u_long vol_root_clust;
        u_long vol_last_clust;
        u_long vol_data_sect;
    };
  • phatdir.c
    Contains routines to create, remove, rename, search, read and update directory entries.
  • phat12.c
    phat16.c
    phat32.c
    These modules contain FAT12, FAT16 or FAT32 specific routines to set, query and release cluster links.
  • phatio.c
    The routines in this modules are used to load or unload sector buffers. Currently the PHAT driver doesn't provide its own buffering but uses the (single) buffer of the block device.
  • phatutil.c
    Contains various helper routines.
  • phatdbg.c
    Useful routines for debugging the file system driver.