"FAT32.mpas" unit, details.



This unit "Fat32.mpas" enables you to handle SD/MMC/CF cards and IDE harddisks formatted in Fat32. It can handle subdirectories and long filenames. At this moment it can only be used with the P18Fxxx PIC range and the P24F range, the stack is too deep to run it on a P12 or P16 PIC.
It uses as less as possible ram: the same sectorbuffer is used for the different Fat32 activities.


Table of contents:
Overview of Features
Particularities
The Unit Interface
Usage Templates for SPI, CF and IDE

Overview of features

Particularities

Unit Interface

unit Fat32;

//----------------------------------------------------------------------------//
//        ---> Only for P18 and P24 PIC's (stack too deep) <---               //
//----------------------------------------------------------------------------//

//interface

// -----------------------------------------------------------------------------
// --------------------- Routine to be defined externally ----------------------
// -----------------------------------------------------------------------------

function Fat32_Dev_Read_Sector (Sector: DWord; var Buffer: array[512] of byte): boolean; external; // returns true when successfull
function Fat32_Dev_Write_Sector(Sector: DWord; var Buffer: array[512] of byte): boolean; external; // returns true when successfull
     
// -----------------------------------------------------------------------------
     
const LongFnLength  = 255; // size of a long filename
      
type TLongFileName  = string[LongFnLength];
     TShortFileName = string[12]; // size of a short filename
     
     TFat32DirItem  =
     record
       FileName      : TLongFileName;  // longfilename if "LongFileNamePresent" is true, else "FileName" (short FileName)
       ShortFileName : TShortFileName; // short filename
       FileAttr      : byte;           // file attributes
       FileSize      : DWord;          // FileSize in bytes
       FindDirEntry  : DWord;          // for internal usage only
     end;
     
// -------------------------------------------------------------------------------------------------
// ---- This variable contains the result of Fat32_FindFirst/Fat32_FindNext calls ----------
var   Fat32_DirItem        : TFat32DirItem;
// -------------------------------------------------------------------------------------------------
    
const // file attribute constants to be used in "Fat32_FindFirst", Fat32_FindNext" and "Fat32_FileExists"
      faAnyFile   = $00;
      faReadOnly  = $01; // bit 0  in the attributes byte
      faHidden    = $02; // bit 1
      faSysFile   = $04; // bit 2
      faVolumeId  = $08; // bit 3
      faDirectory = $10; // bit 4
      faArchive   = $20; // bit 5
      faFile      = $40; // bit 6, not directory, not volumeId
      faCreate    = $80; // bit 7, special attribute to create files
      
      // File attribute Characters for e.g. the directory files
      Fat32_Attrs : string[6] = 'RHSVDA'; // be carefull: mirrored! ("R" is bit 0 in the attributes, "H" is bit 1 etc...)
      

// -----------------------------------------------------------------------------
//                           Basic Routines
// -----------------------------------------------------------------------------
    

function Fat32_Init: boolean;
// initialises the Fat32 filesystem, reads in the basic card/disk data (Fat boot record)
// returns true if success, false on failure
// IMPORTANT: ---> "mmc_Init" (or equivalent) must be done (with success) before this routine can be called! <---


function Fat32_QuickFormat(var VolumeLabel: string[11]): boolean;
// This routine deletes all files and directories and creates a new root directory.
// Returns true if Success, otherwise false
// Also re-inits the Fat32 system (call to Fat32_Init)
//------------------------------------------------------------------------------
// IMPORTANT: this routine only Quick -->RE<-- formats the card/disk.
// ---> It should have been initially formatted on a PC! <--- ,
// the MMC/SD/CF card or disk should already contain a valid Fat boot Record
//------------------------------------------------------------------------------

procedure Fat32_VolumeLabel(var _Label: string);
// Returns the Fat32 Volume Label in "_Label"
// "Fat32_Init" must have been executed with success before this procedure can be used

function Fat32_Assign(var LongFn: TLongFileName; file_cre_attr: byte): boolean;
// Opens a file with name "LongFn" and returns true on success.
// Only files can be opened, no directories, VolumeId's etc...
// The file is created (if not already existing) provided "file_cre_attr" contains "faCreate".
// The Filepointer (points to the next byte to be read or written) is set to zero.

procedure Fat32_Close;
// Closes the currently assigned file (flushes the databuffer etc...)
// !!! ---> Always to be called when finishing using a file, except
//     when using a swapfile
//     or "Fat32_Flush" was called after the last write action  <---! !!!

procedure Fat32_Reset(var _Size: DWord);
// Resets the filepointer of the currently assigned file to zero (first byte of the file).
// Upon exit, "_Size" holds the filesize in bytes.

procedure Fat32_Append;
// Sets the filepointer of the currently assigned file to the next place after its last byte

procedure Fat32_Rewrite;
// Discards the content of the currently assigned file (as if it was newly created),
// sets its filesize and FilePointer to 0.

function Fat32_Rename(var OldName, NewName: TLongFileName): boolean;
// Renames the file named "OldName" to "NewName" in the current directory.
// Returns "true" if successful, else "false" (e.g. "OldName" does not exists or "NewName" already exists)
// Attention! !!! this function closes first the currently open file !!!

procedure Fat32_Flush;
// Writes the sectorbuffer of the currently assigned file to the card/disk (if necessary), and
// also writes the (changed) filesize to its directory entry (if necessary).
// Calling this function writes all info as if the file closes, but keeps the file open
// for further access.

procedure Fat32_Seek(Position: DWord);
// Sets the filepointer of the currently open file to "Position".
// If "Position" is outside the file, then it becomes the same as with "Append"

function Fat32_FilePointer: DWord;
// Returns the filepointer value of the currently open file
// The filepointer is the bytenumber in the file that will be read from or written to next.

function Fat32_EOF: boolean;
// Returns true on an end-of-file condition: the filepointer is outside the file
// During "appending" data EOF is always true.

function Fat32_Get_File_Size: DWord;
// Returns the FileSize in bytes of the currently assigned file

function Fat32_Get_File_Size_Sectors: DWord;
// Returns the FileSize of the currently assigned file in Sectors

procedure Fat32_Get_File_Date(var Year: word; var Month: byte; var Day: byte; var Hours: byte; var Mins: byte);
// Gets the "Creation" date and time of the currently assigned file

procedure Fat32_Set_File_Date(Year: word; Month: byte; Day: byte; Hours: byte; Mins: byte);
// Sets the "Creation" date and time of the currently assigned file

procedure Fat32_Get_File_Date_Modified(var Year: word; var Month: byte; var Day: byte; var Hours: byte; var Mins: byte);
// Gets the "Last Modified" date and time of the currently assigned file

procedure Fat32_Set_File_Date_Modified(Year: word; Month: byte; Day: byte; Hours: byte; Mins: byte);
// Sets the "Last Modified" date and time of the currently assigned file

function Fat32_GetAttr: byte;
// returns the attributes of the currently assigned file

procedure Fat32_SetAttr(Attr: byte);
// sets the attributes of the currently assigned file

procedure Fat32_ClearArchiveAttr;
// clears the archive attribute of the currently assigned file

procedure Fat32_SetArchiveAttr;
// Sets the archive attribute of the currently assigned file

procedure Fat32_Read(var _Data: byte);
// Reads 1 byte out of the currently assigned file into "_Data".
// On exit, the CurrentFilePointer points to the next byte in the file to be read

function Fat32_ReadBuffer(var Buffer: array[4096] of byte; DataLen: Word): word;
// Reads at most "DataLen" bytes out of the currently assigned file into "Buffer"
// Upon exit, the CurrentFilePointer points to the next byte in the file to be read
// Returns the actual number of bytes read (reading beyond EOF is not done)

function Fat32_Read_File_Sector(SectorNumber: DWord; var Buffer: array[512] of byte): boolean;
// Reads a whole sector from the the currently assigned file into "Buffer"
// the logical sectornumber is given by "SectorNumber" (0.. filesize in sectors)
// The file's "filepointer" does not change.

function Fat32_Replace_File_Sector(SectorNumber: DWord; var Buffer: array[512] of byte): boolean;
// Writes a whole sector from "Buffer" to the the currently assigned file,
// the logical sectornumber is given by "SectorNumber" (0.. filesize in sectors)
// The file's "filepointer" does not change.
// Attention!  Make sure the sector written to belongs to the open file! (so, 0 >= SectorNumber < filesize in sectors)

procedure Fat32_Write(_Data: byte);
// Writes 1 byte ("_Data") to the currently assigned file.
// Upon exit, the CurrentFilePointer points to the next byte in the file to be written

procedure Fat32_Write_Const_Buffer(const _Data: ^byte; Len: word);
// writes "Len" bytes out of "_Data" (constant data) to the currently open file at position "CurrentFilePointer"
// Afterwards CurrentFilePointer points to the next byte in the file to be written
// Usage: xxx_Fat32_Write_Const_Buffer(@Constant, NrofConstantbytes);

procedure Fat32_WriteBuffer(var Buffer: array[4096] of byte; DataLen: Word);
// Writes "DataLen" bytes out of "Buffer" to the currently open file at position "CurrentFilePointer"
// Afterwards CurrentFilePointer points to the next byte in the file to be written

procedure Fat32_WriteText(var S: string[4095]);
// Writes string "S" to the currently open file at position "CurrentFilePointer",
// no CR LF written after the string
// Afterwards CurrentFilePointer points to the next byte in the file to be written

procedure Fat32_WriteLine(var S: string[4095]);
// Writes string "S" to the currently open file at position "CurrentFilePointer",
// CR LF additionally written after the string
// Afterwards CurrentFilePointer points to the next byte in the file to be written

procedure Fat32_Write_Sector(var Buffer: array[512] of byte);
// Writes 512 bytes out of "Buffer" to the currently open file at position "CurrentFilePointer"
// Afterwards "CurrentFilePointer" points to the next byte in the file to be written.
// Attention: "CurrentFilePointer" mod 512 must be zero (so, at a sector boundary) when "Fat32_Write_Sector" is called!!!!

function Fat32_Delete(var Mame: TLongFileName): boolean;
// Deletes file with "Name"
// Returns true if Success, else false
// Attention! !!! this function closes first the currently open file !!!

procedure Fat32_Delete_Files;
// Deletes all "Files" in the current directory
// The directories in the current are not deleted

function Fat32_ChDir(var LongFn: TLongFileName): boolean;
// Changes directory to "LongFn" from within the current directory
// No backslashes allowed in "LongFn" (no multiple dirlevels)
// Returns true if Success, else false
// Attention! !!! this function closes first the currently open file !!!
// "Prevdir" can be used afterwards to return to the original directory (the one before "ChDir")

function Fat32_ChDir_FP(var LongFn: TLongFileName): boolean;
// Changes directory to "LongFn"
// Multiple dirlevels allowed, e.g. "\Directory1\Directory2",
//   but: the different parts of the path themselves can not be longer than 128 bytes!
// Returns true if Success, else false
// Attention! !!! this function closes first the currently open file !!!
// "Prevdir" can be used afterwards to return to the original directory (the one before "ChDir_FP")

procedure Fat32_PushDir;
// The current directory's start cluster is stored for "PopDir"

procedure Fat32_PopDir;
// The current directory is changed back to the directory wherein the last "PushDir" was executed

procedure Fat32_PrevDir;
// The current directory is changed back to the previously selected directory before the current one

function Fat32_MkDir(var LongFn: TLongFileName): boolean;
// Creates a directory inside the current one if it not already exists
// No backslashes allowed in "LongFn" (no multiple dirlevels)
// Returns true if success (the directory was created or existed already)
// Attention! !!! this function closes first the currently open file !!!

function Fat32_MkDir_ChDir(var LongFn: TLongFileName): boolean;
// Makes a directory and changes the current directory to it.
// (same as subsequent "MkDir" and "ChDir"

function Fat32_RmDir(var LongFn: TLongFileName): boolean;
// Deletes a directory within the current one.
// No backslashes allowed in "LongFn" (no multiple dirlevels)
// Returns true if success (the directory was removed or it did not exist already)
// Make sure the directory is empty (except for the '.' and '..' files), otherwise lost clusters will occur
// Attention! !!! this function closes first the currently open file !!!

function Fat32_RmDir_All(var Fn: string): boolean;
// Deletes directory "Fn" - and all of its files, including subdirectories and all of their files - from the current directory.
// No backslashes allowed in "LongFn" (no multiple dirlevels)
// Returns true if success (the directory was removed or it did not exist already)
// Attention! !!! this function closes first the currently open file !!!

function Fat32_Delete_All: boolean;
// Empties the current directory: all files and subdirs are removed.
// Returns true if success (the all flies and directories were removed or it did not exist already)
// Attention! !!! this function closes first the currently open file !!!

procedure Fat32_Curdir(var CurrentDir: TLongFileName);
// Returns the name of the current directory in "CurrentDir".
// Attention! !!! this function closes first the currently open file !!!
// Attention: the actual variable used as CurrentDir must be (at least) of type string[255]!!!

procedure Fat32_Curdir_FP(var CurrentDir: TLongFileName);
// Returns the full path of the current directory in "CurrentDir".
// Attention! !!! this function closes first the currently open file !!!
// Attention: the actual variable used as CurrentDir must be (at least) of type string[255]!!!

procedure Fat32_CleanDir;
// "Cleans" the current directory file: deletes the unused entries at the end, which
// makes it unnecessary to search through them when e.g. testing a file's existance.
// Enhances speed when creating new files, after other files have been deleted (direntries became free)
// Attention! !!! this function closes first the currently open file !!!

procedure Fat32_DefragDir;
// "Defragments" the current directory file: deletes the unused entries "holes" in the directory, which
// makes it unnecessary to search through them when e.g. testing a file's existance.
// Enhances speed when creating new files, after other files have been deleted (direntries became free)
// Does also a "CleanDir"
// Attention! !!! this function closes first the currently open file !!!

function Fat32_FindFirst(FileAttr: byte): boolean;
// Returns true if the routine finds the first file/directory (if any) and puts the result in "Fat32_DirItem".
// Only the current directory is searched.
// If no first file/directory present then the procedure returns false.
// To be called before "Fat32_FindNext" is used.

function Fat32_FindNext(FileAttr: byte): boolean;
// Returns true if the routine finds a next file/directory (if any) and puts the result in "Fat32_DirItem".
// Only the current directory is searched.
// If no next file/directory present then the procedure returns false.
// Not to be called without a previous call to "Fat32_FindFirst"

function Fat32_FindFirst_FN(var LongFN: TLongFileName; FAttr: byte): boolean;
// Same as "Fat32_FindFirst" but with filename ("LongFN") included in the search criteria.
// Allowed wildcard constructions in "LongFn":
// - "FileName.Ext" : Finds only the file/directory with the filename exactly equal to LongFn
// - "*.*"          : Finds any file/directory (= same as "Fat32_FindFirst")
// - "File*.E*:     : Finds all files/directories of which the filename starts with "File" and the
//                    extension starts with "E".
//                    Attention: The "*" can only be used to make the --> tail <-- of the filename or extension "don't care".
// - "FileN?me.E?t  : Finds all files/directories with the same name as LongFn, except the positions holding "?"
//                    which are don't care. "?" only represents 1 character!
// If "LongFn" has no dot ('.') in it, only files/directories with no extension are found

function Fat32_FindNext_FN(var LongFN: TLongFileName; FAttr: byte): boolean;
// Same as "Fat32_FindNext" but with filename ("LongFN") included in the search criteria.
// Allowed wildcard constructions in "LongFn": see "Fat32_FindFirst_FN"

function Fat32_FileExists(var LongFn: TLongFileName; FAttr: byte): boolean;
// returns true if file with name "LongFn" and attribute "FAttr" exists
// No backslashes allowed in "LongFn" (no multiple dirlevels)

function Fat32_Get_Swap_File(NoSectors: dword; var filename : TLongFileName; Attr : byte) : Dword;
{ - This function is used to create a Fat32 file of fixed size (NoSectors sectors) on the MMC/SD media,
    with consequtive sectors, making it possible to use direct sector read/write in the file without using the FAT32 filesystem any further.
  - The function returns the number of the start sector for the newly created swap file, if there was enough free space
    on the MMC/SD/CF card or disk to create file of required size, 0 otherwise.
  - Attention!!! If a file with specified name already exists on the media, it will be emptied, and a attempt will be made to re-use its space on the card/disk.
  - No need to "close" the file after it was created and written to with this function (the file is not open anyway from the filesystem's point of view).
  - Afterwards the swap file can also be opened like a normal file with "Fat32_Assign".
}

// -----------------------------------------------------------------------------
//                           Additional Routines
// -----------------------------------------------------------------------------

procedure Fat32_MakeDirFile(var DirFileName: TLongFileName);
// Makes a text file which holds the directory info
// (e.g. names and sizes of files present) of the current directory

procedure Fat32_MakeDirFileHtm(var DirFileName: TLongFileName);
// Makes a html file which holds the directory info
// (e.g. names and sizes of files present) of the current directory

procedure Fat32_CopyFile(var SourceFileName: string; var DestinationFileName: string);
// Copies file with name "SourceFileName" to a file with name "DestinationFileName"
// Attention! !!! this function closes first the currently open files

function Fat32_FileCount(var Names: string[255]; Attr: byte): DWord;
// Count the number of files in the current directory of which the filename is in "Names"
// and the attributes comply with "Attr"
// "Names" is a comma separated list of ambiguous (wildcard) filesnames, like '*.txt, *.log, File*.*',
//    for the allowed wildcard constructions in the filenames: see "Fat32_FindFirst_FN".
// "FAttr" is any of the filetypes defined in unit "Fat32.mpas"
//
// Attention:
//  * upon exit "Names" is an empty string!
//  * the separate untrimmed filenames in "names" should not be longer than 30 characters

function Fat32_TotalSpace: DWord;
// Gives the total space in bytes on the Fat32 formatted card.
// xxx_Fat32_Init has to be called first.
// Only applicable with cards spaces <= 4 GB

function Fat32_FreeSpace: DWord;
// Gives the free space in bytes on the Fat32 formatted card.
// xxx_Fat32_Init has to be called first.
// Only applicable with cards spaces <= 4 GB

function Fat32_UsedSpace: DWord;
// Gives the used space in bytes on the Fat32 formatted card.
// xxx_Fat32_Init has to be called first.
// Only applicable with cards spaces <= 4 GB

function Fat32_TotalSpace_KB: DWord;
// Gives the total space in Kilobytes on the Fat32 formatted card.
// xxx_Fat32_Init has to be called first.

function Fat32_FreeSpace_KB: DWord;
// Gives the free space in Kilobytes on the Fat32 formatted card.
// xxx_Fat32_Init has to be called first.

function Fat32_UsedSpace_KB: DWord;
// Gives the used space in Kilobytes on the Fat32 formatted card.
// xxx_Fat32_Init has to be called first.

function Fat32_TotalSpace_MB: DWord;
// Gives the total space in Megabytes (rounded down) on the Fat32 formatted card.
// xxx_Fat32_Init has to be called first.

function Fat32_FreeSpace_MB: DWord;
// Gives the free space in Megabytes (rounded down) on the Fat32 formatted card.
// xxx_Fat32_Init has to be called first.

function Fat32_UsedSpace_MB: DWord;
// Gives the used space in Megabytes (rounded down) on the Fat32 formatted card.
// xxx_Fat32_Init has to be called first.

function Fat32_TotalSpace_GB: real;
// Gives the total space in Gigabytes on the Fat32 formatted card.
// xxx_Fat32_Init has to be called first.

function Fat32_FreeSpace_GB: real;
// Gives the free space in Gigabytes on the Fat32 formatted card.
// xxx_Fat32_Init has to be called first.

function Fat32_UsedSpace_GB: real;
// Gives the used space in Gigabytes on the Fat32 formatted card.
// xxx_Fat32_Init has to be called first.

// --------------------------------------------------------------------------------------------------

implementation

Usage Templates

SPI (SD/MMC) usage template
Compact Flash (CF) usage template
Harddisk (IDE) usage template
-------------------------------------------