📄 fileio.c
字号:
/******************************************************************************
*
* PIC18 C18 Secure Digital and Multimedia Cards Interface
*
******************************************************************************
* FileName: fileio.c
* Dependencies: generic.h
* fileio.h
* sdmmc.h
* string.h
* stdlib.h
* ctype.h
* _FATDefs.h
* Processor: PIC18
* Compiler: C18
* Company: Microchip Technology, Inc.
*
* Author zhouyi 2008.8.11
*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*********************************************************************************/
#include "fileio.h"
#include "sdmmc.h"
#include "generic.h"
#include "string.h"
#include "stdlib.h"
#include "ctype.h"
#include "_FATDefs.h"
// Define arrays for file allocation
#ifndef FAT16_DYNAMIC_MEM
MYFILE gFileArray[FAT16_MAX_FILES_OPEN];
BYTE gFileSlotOpen[FAT16_MAX_FILES_OPEN];
#endif
// DOS directory entry structure
typedef struct __DIRENTRY
{
char DIR_Name[DIR_NAMESIZE]; // Name
char DIR_Extension[DIR_EXTENSION]; // Extension
BYTE DIR_Attr; // Attributes
BYTE DIR_NTRes; // reserved by NT
BYTE DIR_CrtTimeTenth; // millisecond stamp
WORD DIR_CrtTime; // time created
WORD DIR_CrtDate; // date created
WORD DIR_LstAccDate; // Last Access date
WORD DIR_FstClusHI; // high word of this enty's first cluster number
WORD DIR_WrtTime; // last update time
WORD DIR_WrtDate; // last update date
WORD DIR_FstClusLO; // low word of this entry's first cluster number
DWORD DIR_FileSize; // file size in DWORD
}_DIRENTRY;
typedef _DIRENTRY * DIRENTRY;
// directory entry management
#define DIR_ESIZE 32 // size of a directory entry (BYTEs)
#define DIR_NAME 0 // offset of file name
#define DIR_EXT 8 // offset of file extension
#define DIR_ATTRIB 11 // offset of attribute( 00ARSHDV) (BYTE)
#define DIR_TIME 22 // offset of last use time (WORD)
#define DIR_DATE 24 // offset of last use date (WORD)
#define DIR_CLST 26 // offset of first cluster in FAT (WORD)
#define DIR_SIZE 28 // offset of file size (DWORD)
#define DIR_DEL 0xE5 // marker of a deleted entry
#define DIR_EMPTY 0 // marker of last entry in directory
// number of directory entries in one sector
#define DIRENTRIES_PER_SECTOR 0x10
#define RAMwrite( a, f, d) *(a+f) = d
#define RAMread( a, f) *(a+f)
#define RAMreadW( a, f) *(WORD *)(a+f)
#define RAMreadD( a, f) *(DWORD *)(a+f)
extern unsigned char BSR;
MYFILE *gBufferOwner = NULL;
WORD lastClusterRead = 0xFFFF;
// internal errors
#define CE_FAT_EOF 60 // fat attempt to read beyond EOF
#define CE_EOF 61 // reached the end of file
// since we use an address generator, FILE is not actually the cast of what we pass
typedef MYFILE * FILEOBJ;
#define FILEEXTPAGESIZE sizeof(_FILEEXTND)
#define SIZEOF(s,m) ((size_t) sizeof(((s *)0)->m))
// Private functions
WORD FATread( DISK *dsk, WORD ccls);
DIRENTRY Cache_File_Entry( FILEOBJ fo, WORD * curEntry, BYTE ForceRead);
BYTE Fill_File_Object(FILEOBJ fo, WORD *fHandle);
DWORD Cluster2Sector(DISK * disk, WORD cluster);
BYTE FAT_erase_cluster_chain (WORD cluster, DISK * dsk);
WORD FATfindEmptyCluster(FILEOBJ fo);
WORD FATReadQueued( DISK *dsk, WORD ccls);
DIRENTRY LoadDirAttrib(FILEOBJ fo, WORD *fHandle);
void IncrementTimeStamp(DIRENTRY dir);
BYTE FindEmptyEntries(FILEOBJ fo, WORD *fHandle);
BYTE PopulateEntries(FILEOBJ fo, char *name , WORD *fHandle);
CETYPE FILECreateHeadCluster( FILEOBJ fo, WORD *cluster);
BYTE EraseCluster(DISK *disk, WORD cluster);
void FileObjectCopy(FILEOBJ foDest,FILEOBJ foSource);
CETYPE CreateFirstCluster(FILEOBJ fo);
BYTE isShort ( char aChar);
extern BYTE WriteProtectState(void);
BYTE ValidateChars (char * FileName);
BYTE FormatFileName( const char* fileName, char* fN2 );
CETYPE __fread( MYFILE *fo, BYTE * dest, WORD count, WORD *pBytesRead);
CETYPE __fclose(FILEOBJ fo);
CETYPE __fwrite( MYFILE* fo, void * src, WORD count, WORD* pBytesWritten );
CETYPE __fseek (FILEOBJ fo, DWORD offset, BYTE origin);
MYFILE * __fopen (const char * fileName, const char *mode, MYFILE* filePtr );
CETYPE CreateFileEntry(FILEOBJ fo, WORD *fHandle);
CETYPE FILEfind( FILEOBJ foDest, FILEOBJ foCompareTo, BYTE cmd);
BYTE FILEget_next_cluster(FILEOBJ fo, WORD n);
BYTE FILEallocate_new_cluster( FILEOBJ fo);
CETYPE FILEopen (FILEOBJ fo, WORD *fHandle, char type);
CETYPE FILEerase( FILEOBJ fo, WORD *fHandle, BYTE EraseClusters);
/******************************************************************************
* Function: int FAT16Init()
*
* PreCondition: None
*
* Input: None
*
* Output: int: True if initialization successful, otherwise false
*
* Side Effects: None
*
* Overview: Initialize the static memory slots for holding
* file structures; only used when FAT16_DYNAMIC_MEM is
* not defined
*
* Note: None
*****************************************************************************/
unsigned char FAT16Init()
{
char result;
#ifndef FAT16_DYNAMIC_MEM
int fIndex;
for( fIndex = 0; fIndex < FAT16_MAX_FILES_OPEN; fIndex++ )
gFileSlotOpen[fIndex] = TRUE;
//#else
// SRAMInitHeap();
#endif
result = MediaInit();
return result;
// ceer = result;
}
/******************************************************************************
* Function: FILE * my_fopen (const char * fileName, const char * mode)
*
* PreCondition: For read or append mode, file exists
*
* Input: fileName - The name of the file to open (stored in RAM)
* mode - WRITE - Create a new file or replace an existing file
* READ - Read data from an existing file
* APPEND - Append data to an existing file
*
* Output: FILE * - The pointer to the file object
*
* Side Effects: None
*
* Overview: User called file open function (with fileName and mode
* defined in RAM)
*
* Note: None
*****************************************************************************/
MYFILE * my_fopen( const char * fileName, const char *mode )
{
MYFILE* filePtr;
MYFILE* pFile;
int fIndex;
#ifdef FAT16_DYNAMIC_MEM
filePtr = (MYFILE *) FAT16_malloc(sizeof(MYFILE));
#else
filePtr = NULL;
//Pick available file structure
for( fIndex = 0; fIndex < FAT16_MAX_FILES_OPEN; fIndex++ )
{
if( gFileSlotOpen[fIndex] ) //this slot is available
{
gFileSlotOpen[fIndex] = FALSE;
filePtr = &gFileArray[fIndex];
break;
}
}
if( filePtr == NULL )
return NULL; //no file structure slot available
#endif
//try to open the file
pFile = __fopen( fileName, mode, filePtr );
#ifdef FAT16_DYNAMIC_MEM
if( pFile == NULL )
FAT16_free( (unsigned char *)filePtr );
#else
if( pFile == NULL )
gFileSlotOpen[fIndex] = TRUE; //put this slot back to the pool
#endif
return pFile;
}
/******************************************************************************
* Function: CETYPE FILEfind( FILEOBJ foDest, FILEOBJ foCompareTo, BYTE cmd)
*
* PreCondition: DISKmount function has been executed, foCompareTo loaded with
* file name
*
* Input: foDest - FILEOBJ containing information of file found
* foCompareTo - FILEOBJ containing name of file to be found
* cmd - 1 - search for a matching entry
* 2 - search for an empty entry
*
* Output: CE_GOOD - File found
* CE_FILE_NOT_FOUND - File not found
*
* Side Effects: None
*
* Overview: Find a file given a name as passed via foCompareTo, place found in foDest
*
* Note: None
*****************************************************************************/
CETYPE FILEfind( FILEOBJ foDest, FILEOBJ foCompareTo, BYTE cmd)
{
WORD attrib,fHandle = 0; // current entry counter
BYTE state,index; // state of the current object
CETYPE statusB = CE_FILE_NOT_FOUND;
BYTE character,test;
// reset the cluster
foDest->dirccls = foDest->dirclus;
if( Cache_File_Entry(foDest, &fHandle, TRUE) == NULL)
{
statusB = CE_BADCACHEREAD;
}
else
{
// Loop until you reach the end or find the file
while(1)
{
if(statusB!=CE_GOOD)
{
state = Fill_File_Object(foDest, &fHandle);
if(state == NO_MORE)
{
break;
}
}
else
{
break;
}
if(state == FOUND)
{
/* We got something */
// get the attributes
attrib = foDest->attributes;
attrib &= ATTR_MASK;
// see if we are a volume id or hidden, ignore
if((attrib != ATTR_VOLUME) && (attrib & ATTR_HIDDEN) != ATTR_HIDDEN)
{
statusB = CE_GOOD;
character = (BYTE)'m'; // random value
// search for one. if status = TRUE we found one
for(index = 0; (statusB == CE_GOOD) && index < DIR_NAMECOMP; index++)
{
// get the source character
character = foDest->name[index];
// get the destination character
test = foCompareTo->name[index];
if(tolower(character) != tolower(test))
statusB = CE_FILE_NOT_FOUND; // Nope its not a match
}// for loop
} // not dir nor vol
} // not found
else
{
/*** looking for an empty/re-usable entry ***/
if ( cmd == 0)
statusB = CE_GOOD;
} // found or not
// just increment it no matter what happened
fHandle++;
}// while
}
return(statusB);
} // FILEFind
/******************************************************************************
* Function: WORD FATread( DISK *dsk, WORD ccls)
*
* PreCondition: None
*
* Input: dsk - Disk structure
* ccls - Current cluster
*
* Output: 0000 - cluster is empty
* 0FF8 - last cluster in a chain
* 0xxx - next cluster in a chain
* FFFF - FAIL
*
* Side Effects: None
*
* Overview: Reads the content of a cluster link in FAT
*
* Note: None
*****************************************************************************/
WORD FATread( DISK *dsk, WORD ccls)
{
WORD p, c ;
DWORD l;
if( dsk->type != FAT16 )
return CLUSTER_FAIL;
// get address of current cluster in fat
p = ccls;
// cluster = 0xabcd
// packed as: 0 | 1 | 2 | 3 |
// word p 0 1 | 2 3 | 4 5 | 6 7 |..
// cd ab| cd ab| cd ab| cd ab|
l = dsk->fat + (p >> 8 ); // 256 clusters per sector
if ((gBufferOwner != (MYFILE *) 0xAA55) ||
(lastClusterRead != l))
{
// load the fat sector containing the cluster
gBufferOwner = (MYFILE *)0xAA55; //reset buffer owner
if ( !SECTORread( l, dsk->buffer) )
return CLUSTER_FAIL;
lastClusterRead = l;
}
// get the next cluster value
c = RAMreadW( dsk->buffer, ((p & 0xFF)<<1));
// Normalize it so 0xFFFF is an error
if(c >= LAST_CLUSTER_FAT16)
c = LAST_CLUSTER;
return c;
} // FATread
/******************************************************************************
* Function: CETYPE FILEopen (FILEOBJ fo, WORD *fHandle, char type)
*
* PreCondition: FILEfind returns true for read or append, fo contains file data
*
* Input: fo - File to be opened
* fHandle - Location of file
* type - WRITE - Create a new file or replace an existing file
* READ - Read data from an existing file
* APPEND - Append data to an existing file
*
* Output: CE_GOOD - FILEopen successful
* CE_NOT_INIT - Card is not yet initialized because of some error
* CE_FILE_NOT_FOUND - Could not find the file on the card
* CE_BAD_SECTOR_READ - A bad read occured of a sector
*
*
* Side Effects: None
*
* Overview: Opens a file to perform operations on
*
* Note: None
*****************************************************************************/
CETYPE FILEopen (FILEOBJ fo, WORD *fHandle, char type)
{
DISK *dsk; //Disk structure
BYTE r; //Result of search for file
DWORD l; //lba of first sector of first cluster
CETYPE error = CE_GOOD;
dsk = (DISK *)(fo->dsk);
if (dsk->mount == FALSE)
error = CE_NOT_INIT;
else
{
// load the sector
Cache_File_Entry(fo, fHandle, TRUE);
// Fill up the File Object with the information pointed to by fHandle
r = Fill_File_Object(fo, fHandle);
if (r != FOUND)
error = CE_FILE_NOT_FOUND;
else
{
fo->seek = 0; // first byte in file
fo->ccls = fo->cluster; // first cluster
fo->sec = 0; // first sector in the cluster
fo->pos = 0; // first byte in sector/cluster
if ( r == NOT_FOUND)
{
error = CE_FILE_NOT_FOUND;
}
else
{
// Determine the lba of the selected sector and load
l = Cluster2Sector(dsk,fo->ccls);
gBufferOwner = fo;
if ( !SECTORread( l, dsk->buffer))
error = CE_BAD_SECTOR_READ;
} // -- found
fo->Flags.FileWriteEOF = FALSE;
// Set flag for operation type
if (type == 'w' || type == 'a')
{
fo->Flags.write = 1; //write or append
}
else
{
fo->Flags.write = 0; //read
} // -- flags
} // -- r = Found
} // -- Mounted
return (error);
} // -- FILEopen
/******************************************************************************
* Function: CETYPE __fread ( MYFILE *fo, BYTE *pDest, WORD count, WORD *pBytesRead )
*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -