Subversion Repositories Projects

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
297 killagreg 1
#include <string.h>
2
#include "printf_P.h"
3
#include "timer0.h"
231 killagreg 4
#include "fat16.h"
5
#include "sdc.h"
297 killagreg 6
#include "uart1.h"
231 killagreg 7
 
8
 
297 killagreg 9
/*
10
FAT16 Drive Layout:
11
Description                                             Offset
12
Volume Boot Sector                                      Start of Partition
13
Fat Tables                                                      Start + # of Reserved Sectors
14
Root Directory Entry                            Start + # of Reserved + (# of Sectors Per FAT * 2)
15
Data Area (Starts with Cluster #2)      Start + # of Reserved + (# of Sectors Per FAT * 2) + ((Maximum Root Directory Entries * 32) / Bytes per Sector)
16
*/
231 killagreg 17
 
18
 
297 killagreg 19
/*
20
________________________________________________________________________________________________________________________________________
231 killagreg 21
 
297 killagreg 22
        Structure of an partition entry
23
________________________________________________________________________________________________________________________________________
231 killagreg 24
 
297 killagreg 25
        Partition Entry is 16 bytes long
26
*/
27
typedef struct
28
{
29
        uint8_t         PartitionState;                         // Current State of Partition (00h=Inactive, 80h=Active)
30
        uint8_t         BeginningHead;                          // Beginning of Partition - Head
31
        uint16_t        BeginningCylSec;                        // Beginning of Partition - Cylinder/Sector (See Below)
32
        uint8_t         Type;                                           // Type of Partition (See List Below)
33
        uint8_t         EndHead;                                        // End of Partition - Head
34
        uint16_t        EndCylSec;                                      // End of Partition - Cylinder/Sector
35
        uint32_t        NoSectorsBeforePartition;       // Number of Sectors between the MBR and the First Sector in the Partition
36
        uint32_t        NoSectorsPartition      ;               // Number of Sectors in the Partition
37
} __attribute__((packed)) PartitionEntry_t;
231 killagreg 38
 
297 killagreg 39
/*
40
Coding of Cylinder/Sector words
231 killagreg 41
 
297 killagreg 42
Cylinder is 10 bits:  [7:0] at [15:8] and [9:8] at [7:6]
43
Sector is 5 bits:  [5:0] at [5:0]
44
*/
231 killagreg 45
 
297 killagreg 46
// Partition Types:
47
#define PART_TYPE_UNKNOWN                       0x00
48
#define PART_TYPE_FAT12                         0x01
49
#define PART_TYPE_XENIX                         0x02
50
#define PART_TYPE_FAT16_ST_32_MB        0x04
51
#define PART_TYPE_EXTDOS                        0x05
52
#define PART_TYPE_FAT16_LT_32_MB        0x06
53
#define PART_TYPE_NTFS                          0x07
54
#define PART_TYPE_FAT32                         0x0B
55
#define PART_TYPE_FAT32LBA                      0x0C
56
#define PART_TYPE_FAT16LBA                      0x0E
57
#define PART_TYPE_EXTDOSLBA                     0x0F
58
#define PART_TYPE_EISA                          0x12
59
#define PART_TYPE_ONTRACK                       0x33
60
#define PART_TYPE_NOVELL                        0x40
61
#define PART_TYPE_DYNAMIC                       0x42
62
#define PART_TYPE_PCIX                          0x4B
63
#define PART_TYPE_LINUX_SWAP            0x82
64
#define PART_TYPE_LINUX_NATIVE          0x83
65
#define PART_TYPE_LINUX_LVM                     0x8E
66
#define PART_TYPE_PHOENIXSAVE           0xA0
67
#define PART_TYPE_FREEBSD                       0xA5
68
#define PART_TYPE_OPENBSD                       0xA6
69
#define PART_TYPE_NETNBSD                       0xA9
70
#define PART_TYPE_CPM                           0xDB
71
#define PART_TYPE_DBFS                          0xE0
72
#define PART_TYPE_BBT                           0xFF
231 killagreg 73
 
74
 
297 killagreg 75
/*
76
________________________________________________________________________________________________________________________________________
231 killagreg 77
 
297 killagreg 78
        Structure of the MasterBootRecord
79
________________________________________________________________________________________________________________________________________
80
 
81
        Master Boot Record is 512 bytes long
82
        The Master Boot Record is the same for pretty much all Operating Systems.
83
        It is located on the first Sector of the Hard Drive, at Cylinder 0, Head 0, Sector 1
84
*/
85
typedef struct
231 killagreg 86
{
297 killagreg 87
        uint8_t                         ExecutableCode[446];    // 446 bytes for machine start code
88
        PartitionEntry_t        PartitionEntry1;                // 16 bytes for partition entry 1
89
        PartitionEntry_t        PartitionEntry2;                // 16 bytes for partition entry 2
90
        PartitionEntry_t        PartitionEntry3;                // 16 bytes for partition entry 3
91
        PartitionEntry_t        PartitionEntry4;                // 16 bytes for partition entry 4
92
        uint16_t                        ExecutableMarker;               // BIOS-Signature (0x55 0xAA)
93
} __attribute__((packed)) MBR_Entry_t;
231 killagreg 94
 
95
 
297 killagreg 96
/*
97
________________________________________________________________________________________________________________________________________
231 killagreg 98
 
297 killagreg 99
        Structure of the VolumeBootRecord
100
________________________________________________________________________________________________________________________________________
231 killagreg 101
 
297 killagreg 102
        The Volume Boot Record is 512 bytes long
103
        This information is located in the first sector of every partition.
104
*/
105
typedef struct
106
{
107
        uint8_t         JumpCode[3];                    // Jump Code + NOP
108
        int8_t          OEMName[8];                             // OEM Name
109
        uint16_t        BytesPerSector;                 // Bytes Per Sector
110
        uint8_t         SectorsPerCluster;              // Sectors Per Cluster
111
        uint16_t        ReservedSectors;                // Reserved Sectors
112
        uint8_t         NoFATCopies;                    // Number of Copies of FAT
113
        uint16_t        MaxRootEntries;                 // Maximum Root Directory Entries
114
        uint16_t        NoSectorsInPartSml32MB; // Number of Sectors in Partition Smaller than 32 MB
115
        uint8_t         MediaDescriptor;                // Media Descriptor (0xF8 for Hard Disks)
116
        uint16_t        SectorsPerFAT;                  // Sectors Per FAT
117
        uint16_t        SectorsPerTrack;                // Sectors Per Track
118
        uint16_t        NoHeads;                                // Number of Heads
119
        uint32_t        NoHiddenSectors;                // Number of Hidden Sectors     in Partition
120
        uint32_t        NoSectors;                              // Number of Sectors in Partition
121
        uint16_t        DriveNo;                                // Logical Drive Number of Partition
122
        uint8_t         ExtendedSig;                    // Extended Signature (0x29)
123
        uint32_t        SerialNo;                               // Serial Number of the Partition
124
        int8_t          VolumeName[11];                 // Volume Name of the Partititon
125
        int8_t          FATName[8];                             // FAT Name (FAT16)
126
        uint8_t         ExecutableCode[446];    // 446 bytes for machine start code
127
        uint16_t        ExecutableMarker;               // Executable Marker (0x55 0xAA)
128
} __attribute__((packed)) VBR_Entry_t;
231 killagreg 129
 
130
 
131
 
297 killagreg 132
/*
133
________________________________________________________________________________________________________________________________________
134
 
135
        Structure of an directory entry
136
________________________________________________________________________________________________________________________________________
137
 
138
        Directory entry is 32 bytes.
139
*/
140
typedef struct
231 killagreg 141
{
297 killagreg 142
        int8_t          Name[8];                                        // 8 bytes name, padded with spaces.
143
        uint8_t         Extension[3];                           // 3 bytes extension, padded with spaces.
144
        uint8_t         Attribute;                                      // attribute of the directory entry (unused,archive,read-only,system,directory,volume)
145
        uint8_t         Reserved[10];                           // reserved bytes within the directory entry.
146
        uint32_t        DateTime;                                       // date and time of last write access to the file or directory.
147
        uint16_t        StartCluster;                           // first cluster of the file or directory.
148
        uint32_t        Size;                                           // size of the file or directory in bytes.
149
}  __attribute__((packed)) DirEntry_t;
231 killagreg 150
 
297 killagreg 151
#define SLOT_EMPTY              0x00    // slot has never been used
152
#define SLOT_E5                 0x05    // the real value is 0xe5
153
#define SLOT_DELETED            0xE5    // file in this slot deleted
231 killagreg 154
 
297 killagreg 155
#define ATTR_NONE               0x00    // normal file
156
#define ATTR_READONLY           0x01    // file is readonly
157
#define ATTR_HIDDEN                     0x02    // file is hidden
158
#define ATTR_SYSTEM                     0x04    // file is a system file
159
#define ATTR_VOLUMELABEL        0x08    // entry is a volume label
160
#define ATTR_LONG_FILENAME      0x0F    // this is a long filename entry
161
#define ATTR_SUBDIRECTORY       0x10    // entry is a directory name
162
#define ATTR_ARCHIVE            0x20    // file is new or modified
231 killagreg 163
 
164
 
297 killagreg 165
/*
166
________________________________________________________________________________________________________________________________________
231 killagreg 167
 
297 killagreg 168
        Structure of an entry within the fileallocationtable.
169
________________________________________________________________________________________________________________________________________
170
*/
171
typedef struct
172
{
173
        uint16_t  NextCluster;                          // the next cluster of the file.
174
} __attribute__((packed)) Fat16Entry_t;
231 killagreg 175
 
297 killagreg 176
// secial fat entries
177
#define FAT16_CLUSTER_FREE                      0x0000
178
#define FAT16_CLUSTER_RESERVED          0x0001
179
#define FAT16_CLUSTER_USED_MIN          0x0002
180
#define FAT16_CLUSTER_USED_MAX          0xFFEF
181
#define FAT16_CLUSTER_ROOTDIR_MIN       0xFFF0
182
#define FAT16_CLUSTER_ROOTDIR_MAX       0xFFF6
183
#define FAT16_CLUSTER_BAD                       0xFFF7
184
#define FAT16_CLUSTER_LAST_MIN          0xFFF8
185
#define FAT16_CLUSTER_LAST_MAX          0xFFFF
231 killagreg 186
 
297 killagreg 187
/*****************************************************************************************************************************************/
188
/*                                                                                                                                                                                                                                                                               */
189
/*      Global variables needed for read- or write-acces to the FAT16- filesystem.                                                                                                                       */
190
/*                                                                                                                                                                                                                                                                               */
191
/*****************************************************************************************************************************************/
231 killagreg 192
 
297 killagreg 193
#define MBR_SECTOR                                      0x00    // the masterboot record is located in sector 0.
194
#define DIRENTRY_SIZE                           32              //bytes
195
#define DIRENTRIES_PER_SECTOR           BYTES_PER_SECTOR/DIRENTRY_SIZE
196
#define FAT16_BYTES                                     2
197
#define FAT16_ENTRIES_PER_SECTOR        BYTES_PER_SECTOR/FAT16_BYTES
198
 
199
#define FSTATE_UNUSED   0
200
#define FSTATE_USED             1
201
 
202
typedef struct
231 killagreg 203
{
297 killagreg 204
        uint8_t         IsValid;                                // 0 means invalid, else valid
205
        uint8_t         SectorsPerCluster;              // how many sectors does a cluster contain?
206
        uint8_t         FatCopies;                              // Numbers of copies of the FAT
207
        uint16_t        MaxRootEntries;                 // Possible number of entries in the root directory.
208
        uint16_t        SectorsPerFat;                  // how many sectors does a fat16 contain?
209
        uint32_t        FirstFatSector;                 // sector of the start of the fat
210
        uint32_t        FirstRootDirSector;             // sector of the rootdirectory
211
        uint32_t        FirstDataSector;                // sector of the first cluster containing data (cluster2).
212
        uint32_t        LastDataSector;                 // the last data sector of the partition
213
} Partition_t;
231 killagreg 214
 
297 killagreg 215
Partition_t     Partition;                                      // Structure holds partition information
231 killagreg 216
 
297 killagreg 217
File_t FilePointer[FILE_MAX_OPEN];      // Allocate Memmoryspace for each filepointer used.
231 killagreg 218
 
219
 
297 killagreg 220
/****************************************************************************************************************************************/
221
/*      Function:               FileDateTime(DateTime_t *);                                                                                                                                                                                     */
222
/*                                                                                                                                                                                                                                                                              */
223
/*      Description:    This function calculates the DOS date time from a pointer to a time structure.                                                                          */
224
/*                                                                                                                                                                                                                                                                              */
225
/*      Returnvalue:    Returns the DOS date time.                                                                                                                                                                                      */
226
/****************************************************************************************************************************************/
227
 
228
uint32_t FileDateTime(DateTime_t * pTimeStruct)
231 killagreg 229
{
297 killagreg 230
        uint32_t datetime = 0;
231
        if((pTimeStruct == 0) || !(pTimeStruct->Valid)) return datetime;
232
 
233
        datetime |= (0x0000007FL & (uint32_t)(pTimeStruct->Year - 1980))<<25; // set year
234
        datetime |= (0x0000000FL & (uint32_t)(pTimeStruct->Month))<<21; // set month
235
        datetime |= (0x0000001FL & (uint32_t)(pTimeStruct->Day))<<16;
236
        datetime |= (0x0000001FL & (uint32_t)(pTimeStruct->Hour))<<11;
237
        datetime |= (0x0000003FL & (uint32_t)(pTimeStruct->Min))<<5;
238
        datetime |= (0x0000001FL & (uint32_t)(pTimeStruct->Sec/2));
239
        return datetime;
231 killagreg 240
}
241
 
242
 
297 killagreg 243
/****************************************************************************************************************************************/
244
/*      Function:               LockFilePointer();                                                                                                                                                                                                      */
245
/*                                                                                                                                                                                                                                                                              */
246
/*      Description:    This function trys to lock a free file pointer.                                                                                                                                         */
247
/*                                                                                                                                                                                                                                                                              */
248
/*      Returnvalue:    Returns the Filepointer on success or 0.                                                                                                                                                        */
249
/****************************************************************************************************************************************/
250
File_t * LockFilePointer(void)
231 killagreg 251
{
297 killagreg 252
        uint8_t i;
253
        File_t * File = 0;
254
        for(i = 0; i < FILE_MAX_OPEN; i++)
231 killagreg 255
        {
297 killagreg 256
                if(FilePointer[i].State == FSTATE_UNUSED)               // found an unused one
231 killagreg 257
                {
297 killagreg 258
                        File = &FilePointer[i];                                         // set pointer to that entry
259
                        FilePointer[i].State = FSTATE_USED;                     // mark it as used
260
                        break;
231 killagreg 261
                }
262
        }
297 killagreg 263
        return(File);
231 killagreg 264
}
265
 
297 killagreg 266
/****************************************************************************************************************************************/
267
/*      Function:               UnlockFilePointer(file_t *);                                                                                                                                                                            */
268
/*                                                                                                                                                                                                                                                                              */
269
/*      Description:    This function trys to unlock a file pointer.                                                                                                                                            */
270
/*                                                                                                                                                                                                                                                                              */
271
/*      Returnvalue:    Returns 1 if file pointer was freed else 0.                                                                                                                                                     */
272
/****************************************************************************************************************************************/
273
uint8_t UnlockFilePointer(File_t * file)
231 killagreg 274
{
297 killagreg 275
        uint8_t cnt;
276
        if(file == NULL) return(0);
277
        for(cnt = 0; cnt < FILE_MAX_OPEN; cnt++)
231 killagreg 278
        {
297 killagreg 279
                if(&FilePointer[cnt] == file)                                           // filepointer to be freed found?
231 killagreg 280
                {
297 killagreg 281
                        file->State = FSTATE_UNUSED;
282
                        file->FirstSectorOfFirstCluster = 0;                    // Sectorpointer to the first sector of the first datacluster of the file.
283
                        file->FirstSectorOfCurrCluster  = 0;
284
                        file->SectorOfCurrCluster               = 0;                    // Pointer to the cluster which is edited at the moment.
285
                        file->SectorOfCurrCluster               = 0;                    // The sector which is edited at the moment (cluster_pointer + sector_index).
286
                        file->ByteOfCurrSector                  = 0;                    // The bytelocation within the current sector (cluster_pointer + sector_index + byte_index).
287
                        file->Mode                                              = 0;                    // mode of fileoperation (read,write)
288
                        file->Size                                              = 0;                    // the size of the opend file in bytes.
289
                        file->Position                                  = 0;                    // pointer to a character within the file 0 < fileposition < filesize
290
                        file->SectorInCache                     = 0;                    // the last sector read, wich is still in the sectorbuffer.
291
                        file->DirectorySector                   = 0;                    // the sectorposition where the directoryentry has been made.
292
                        file->DirectoryIndex                    = 0;                    // the index to the directoryentry within the specified sector.
293
                        file->Attribute                                 = 0;                    // the attribute of the file opened.
294
                        file = NULL;
295
                        return(1);
231 killagreg 296
                }
297
        }
297 killagreg 298
        return(0);
299
}
231 killagreg 300
 
297 killagreg 301
/****************************************************************************************************************************************/
302
/*      Function:               SeperateDirName(int8_t*, int8_t*);                                                                                                                                                                              */
303
/*                                                                                                                                                                                                                                                                              */
304
/*      Description:    This function seperates the first dirname from filepath and brings them                                                                                         */
305
/*                                      into the needed format ('test.txt' -> 'TEST    TXT')                                                                                                                            */
306
/*                                      The subpath is the pointer to the remaining substring if the filepath                                                                                           */
307
/*                                                                                                                                                                                                                                                                              */
308
/*      Returnvalue:    Return NULL on error or pointer to subpath                                                                                                                                                                                                      */
309
/****************************************************************************************************************************************/
310
int8_t* SeperateDirName(const int8_t *filepath, int8_t *dirname)
231 killagreg 311
{
297 killagreg 312
        int8_t* subpath = NULL;
313
        uint8_t readpointer     = 0;
314
        uint8_t writepointer = 0;
231 killagreg 315
 
297 killagreg 316
        // search subpath from beginning of filepath
317
        subpath = NULL;
318
        readpointer     = 0;
319
        if(filepath[0] == '/') readpointer = 1; // ignore first '/'
320
        while(subpath == NULL)  // search the filepath until a subpath was found.
231 killagreg 321
        {
297 killagreg 322
                if(((filepath[readpointer] == 0) || (filepath[readpointer] == '/')))    // if '/' found or end of filepath reached
323
                {
324
                        subpath = (int8_t*)&filepath[readpointer];                              // store the position of the first "/" found after the beginning of the filenpath
325
                }
326
                readpointer++;
231 killagreg 327
        }
328
 
297 killagreg 329
        // clear dirname with spaces
330
        dirname[11] = 0; // terminate dirname
331
        for(writepointer = 0; writepointer < 11; writepointer++) dirname[writepointer] = ' ';
332
        writepointer = 0;
333
        // start seperating the dirname from the filepath.
334
        readpointer = 0;
335
        if(filepath[0] == '/') readpointer = 1; // ignore first '/'
336
        while( &filepath[readpointer] < subpath)
231 killagreg 337
        {
297 killagreg 338
                if(writepointer >= 11) return(NULL);            // dirname to long
339
                if(filepath[readpointer] == '.')                        // seperating dirname and extension.
231 killagreg 340
                {
297 killagreg 341
                        if(writepointer <= 8)
231 killagreg 342
                        {
297 killagreg 343
                                readpointer++;                                          // next character in filename
344
                                writepointer = 8;                                       // jump to start of extension
231 killagreg 345
                        }
297 killagreg 346
                        else return(NULL);                                              // dirbasename to long
347
                }
348
                else
349
                {
350
                        if((0x60 < filepath[readpointer]) && (filepath[readpointer] < 0x7B))
351
                        {
352
                                dirname[writepointer] = (filepath[readpointer] - 0x20);                                 // all characters must be upper case.
353
                        }
231 killagreg 354
                        else
355
                        {
297 killagreg 356
                                dirname[writepointer] = filepath[readpointer];
231 killagreg 357
                        }
297 killagreg 358
                        readpointer++;
359
                        writepointer++;
231 killagreg 360
                }
361
        }
297 killagreg 362
        return(subpath);
231 killagreg 363
}
364
 
365
 
297 killagreg 366
/**************************************************************************************************************************************+*/
367
/*      Function:       Fat16ClusterToSector( uint16_t cluster);                                                                                                                                                                                */
368
/*                                                                                                                                                                                                                                                                              */
369
/*      Description:    This function converts a cluster number given by the fat to the corresponding                                                                           */
370
/*                                      sector that points to the start of the data area that is represented by the cluster number.                                                     */
371
/*                                                                                                                                                                                                                                                                              */
372
/*      Returnvalue: The sector number with the data area of the given cluster                                                                                                                          */
373
/****************************************************************************************************************************************/
374
uint32_t        Fat16ClusterToSector(uint16_t cluster)
231 killagreg 375
{
297 killagreg 376
        if(!Partition.IsValid) return 0;
377
        if (cluster < 2) cluster = 2; // the 0. and 1. cluster in the fat are used for the media descriptor
378
        return ( (cluster - 2) * Partition.SectorsPerCluster) + Partition.FirstDataSector; // the first data sector     is represented by the 2nd cluster
379
}
231 killagreg 380
 
297 killagreg 381
/****************************************************************************************************************************************/
382
/*      Function:       SectorToFat16Cluster( uint32_t sector);                                                                                                                                                                         */
383
/*                                                                                                                                                                                                                                                                              */
384
/*      Description:    This function converts a given sector number given to the corresponding                                                                                         */
385
/*                                      cluster number in the fat that represents this data area.                                                                                                                       */
386
/*                                                                                                                                                                                                                                                                              */
387
/*      Returnvalue: The cluster number representing the data area of the sector.                                                                                                                       */
388
/****************************************************************************************************************************************/
389
uint16_t        SectorToFat16Cluster(uint32_t sector)
390
{
391
        if(!Partition.IsValid) return 0;
392
        return ((uint16_t)((sector - Partition.FirstDataSector) / Partition.SectorsPerCluster) + 2);
393
}
394
 
395
 
396
/****************************************************************************************************************************************/
397
/*      Function:       Fat16_Deinit(void);                                                                                                                                                                                                             */
398
/*                                                                                                                                                                                                                                                                              */
399
/*      Description:    This function uninitializes the fat 16 api                                                                                                                                                      */
400
/*                                                                                                                                                                                                                                                                              */
401
/*      Returnvalue: The function returns "0" on success                                                                                                                                                                        */
402
/****************************************************************************************************************************************/
403
uint8_t Fat16_Deinit(void)
404
{
405
        int16_t returnvalue = 0;
406
        uint8_t cnt;
407
        // declare the filepointers as unused.
408
        for(cnt = 0; cnt < FILE_MAX_OPEN; cnt++)
231 killagreg 409
        {
297 killagreg 410
                if(FilePointer[cnt].State == FSTATE_USED)
231 killagreg 411
                {
297 killagreg 412
                        returnvalue += fclose_(&FilePointer[cnt]); // try to close open file pointers
231 killagreg 413
                }
414
 
415
        }
297 killagreg 416
        SDC_Deinit();                   // uninitialize interface to sd-card
417
        Partition.IsValid = 0;  // mark data in partition structure as invalid
418
        return(returnvalue);
231 killagreg 419
}
420
 
297 killagreg 421
/****************************************************************************************************************************************/
422
/*      Function:               Fat16_Init(void);                                                                                                                                                                                                       */
423
/*                                                                                                                                                                                                                                                                          */
424
/*      Description:    This function reads the Masterbootrecord and finds the position of the Volumebootrecord, the FAT and the Rootdir    */
425
/*                                      and stores the information in global variables.                                                                                                                                     */
426
/*                                                                                                                                                                                                                                                                          */
427
/*      Returnvalue:    The function returns "0" if the filesystem is initialized.                                                                                                                      */
428
/****************************************************************************************************************************************/
429
uint8_t Fat16_Init(void)
231 killagreg 430
{
297 killagreg 431
    uint8_t     cnt     = 0;
432
        uint32_t        partitionfirstsector;
433
        VBR_Entry_t *VBR;
434
        MBR_Entry_t *MBR;
435
        File_t *file;
436
        uint8_t result = 0;
231 killagreg 437
 
297 killagreg 438
        printf("\r\n FAT16 init...");
439
        Partition.IsValid = 0;
440
 
441
        // declare the filepointers as unused.
442
        for(cnt = 0; cnt < FILE_MAX_OPEN; cnt++)
231 killagreg 443
        {
297 killagreg 444
                FilePointer[cnt].State = FSTATE_UNUSED;
231 killagreg 445
        }
297 killagreg 446
        // set current file pinter to first position in list
447
        file = &FilePointer[0];
231 killagreg 448
 
297 killagreg 449
        // try to initialise the sd-card.
450
        if(SD_SUCCESS != SDC_Init())
231 killagreg 451
        {
297 killagreg 452
                printf("SD-Card could not be initialized.");
453
                result = 1;
454
                goto end;
231 killagreg 455
        }
297 killagreg 456
 
457
        // SD-Card is initialized successfully
458
        if(SD_SUCCESS != SDC_GetSector((uint32_t)MBR_SECTOR,file->Cache))       // Read the MasterBootRecord
231 killagreg 459
        {
297 killagreg 460
                printf("Error reading the MBR.");
461
                result = 2;
462
                goto end;
463
        }
464
        MBR = (MBR_Entry_t *)file->Cache;                                               // Enter the MBR using the structure MBR_Entry_t.
465
        if((MBR->PartitionEntry1.Type == PART_TYPE_FAT16_ST_32_MB) ||
466
           (MBR->PartitionEntry1.Type == PART_TYPE_FAT16_LT_32_MB) ||
467
           (MBR->PartitionEntry1.Type == PART_TYPE_FAT16LBA))
468
        {
469
                // get sector offset 1st partition
470
                partitionfirstsector = MBR->PartitionEntry1.NoSectorsBeforePartition;
471
                // Start of Partition is the Volume Boot Sector
472
                if(SD_SUCCESS != SDC_GetSector(partitionfirstsector,file->Cache)) // Read the volume boot record
231 killagreg 473
                {
297 killagreg 474
                        printf("Error reading the VBR.");
475
                        result = 3;
476
                        goto end;
231 killagreg 477
                }
478
        }
297 killagreg 479
        else  // maybe the medium has no partition assuming sector 0 is the vbr
480
        {
481
                partitionfirstsector = 0;
482
        }
231 killagreg 483
 
297 killagreg 484
        VBR = (VBR_Entry_t *) file->Cache;                                              // Enter the VBR using the structure VBR_Entry_t.
485
        if(VBR->BytesPerSector != BYTES_PER_SECTOR)
486
        {
487
                printf("VBR: Sector size not supported.");
488
                result = 4;
489
                goto end;
490
        }
491
        Partition.SectorsPerCluster             = VBR->SectorsPerCluster;                       // Number of sectors per cluster. Depends on the memorysize of the sd-card.
492
        Partition.FatCopies                     = VBR->NoFATCopies;                                     // Number of fatcopies.
493
        Partition.MaxRootEntries                = VBR->MaxRootEntries;                          // How many Entries are possible in the rootdirectory (FAT16 allows max. 512 entries).
494
        Partition.SectorsPerFat                 = VBR->SectorsPerFAT;                           // The number of sectors per FAT.
231 killagreg 495
 
297 killagreg 496
        /* Calculate the sectorpositon of the FAT, the Rootdirectory and the first Datacluster. */
497
        // Calculate the position of the FileAllocationTable:
498
        // Start + # of Reserved Sectors
499
        Partition.FirstFatSector        =   (uint32_t)(partitionfirstsector + (uint32_t)(VBR->ReservedSectors));
500
        // Calculate the position of the Rootdirectory:
501
        // Start + # of Reserved Sectors + (# of Sectors Per FAT * # of FAT Copies)
502
        Partition.FirstRootDirSector    =   Partition.FirstFatSector + (uint32_t)((uint32_t)Partition.SectorsPerFat*(uint32_t)Partition.FatCopies);
503
        // Calculate the position of the first datacluster:
504
        // Start + # of Reserved + (# of Sectors Per FAT * # of FAT Copies) + ((Maximum Root Directory Entries * 32) / Bytes per Sector)
505
        Partition.FirstDataSector       =   Partition.FirstRootDirSector + (uint32_t)(Partition.MaxRootEntries>>4);  // assuming 512 Byte Per Sector
506
        // Calculate the last data sector
507
        if(VBR->NoSectors == 0)
231 killagreg 508
        {
297 killagreg 509
                printf("VBR: Bad number of sectors.");
510
                result = 5;
511
                goto end;
231 killagreg 512
        }
297 killagreg 513
        Partition.LastDataSector = Partition.FirstDataSector + VBR->NoSectors - 1;
514
        // check for FAT16 in VBR of first partition
515
        if(!((VBR->FATName[0]=='F') && (VBR->FATName[1]=='A') && (VBR->FATName[2]=='T') && (VBR->FATName[3]=='1')&&(VBR->FATName[4]=='6')))
516
        {
517
                printf("VBR: Partition ist not FAT16 type.");
518
                result = 6;
519
                goto end;
520
        }
521
        Partition.IsValid = 1; // mark data in partition structure as valid
522
        result = 0;
523
        end:
524
        if(result != 0) Fat16_Deinit();
525
        else printf(" ...ok");
526
        return(result);
231 killagreg 527
}
528
 
333 killagreg 529
/****************************************************************************************************************************************/
530
/*      Function:       Fat16_IsValid(void);                                                                                                                                                                                                            */
531
/*                                                                                                                                                                                                                                                                              */
532
/*      Description:    This function return the Fat 15 filesystem state                                                                                                                                                        */
533
/*                                                                                                                                                                                                                                                                              */
534
/*      Returnvalue: The function returns "1" on success                                                                                                                                                                        */
535
/****************************************************************************************************************************************/
536
uint8_t Fat16_IsValid(void)
537
{
538
        return(Partition.IsValid);
539
}
231 killagreg 540
 
297 killagreg 541
/****************************************************************************************************************************************/
542
/* Function:    ClearCurrCluster(File_t*);                                                                                                                                                                                      */
543
/*                                                                                                                                                                                                                                                                              */
544
/* Description: This function fills the current cluster with 0.                                                                                                                                                 */
545
/*                                                                                                                                                                                                                                                                              */
546
/* Returnvalue: The function returns 1 on success else 0.                                                                                                                                                               */
547
/****************************************************************************************************************************************/
548
uint8_t ClearCurrCluster(File_t * file)
231 killagreg 549
{
297 killagreg 550
        uint8_t retvalue = 1;
551
        uint32_t i;
231 killagreg 552
 
297 killagreg 553
        if((!Partition.IsValid) || (file == NULL)) return(0);
554
 
555
        for(i = 0; i < BYTES_PER_SECTOR; i++) file->Cache[i] = 0; // clear file cache
556
        for(i = 0; i < Partition.SectorsPerCluster; i++)
231 killagreg 557
        {
297 killagreg 558
                file->SectorInCache = file->FirstSectorOfCurrCluster + i;
559
                if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))
231 killagreg 560
                {
297 killagreg 561
                        Fat16_Deinit();
562
                        retvalue = 0;
231 killagreg 563
                }
564
        }
297 killagreg 565
        return(retvalue);
231 killagreg 566
}
567
 
297 killagreg 568
/*****************************************************************************************************************************************/
569
/* Function:    GetNextCluster(File_t* );                                                                                                                                                                                        */
570
/*                                                                                                                                                                                                                                                                               */
571
/* Description: This function finds the next datacluster of the file specified with File *File.                                                                                  */
572
/*                                                                                                                                                                                                                                                                               */
573
/* Returnvalue: The function returns the next cluster or 0 if the last cluster has already reached.                                                                                                      */
574
/*****************************************************************************************************************************************/
575
uint16_t GetNextCluster(File_t * file)
231 killagreg 576
{
297 killagreg 577
        uint16_t cluster = 0;
578
        uint32_t fat_byte_offset, sector, byte;
579
        Fat16Entry_t * fat;
231 killagreg 580
 
297 killagreg 581
        if((!Partition.IsValid) || (file == NULL)) return(cluster);
582
        // if sector is within the data area
583
        if((Partition.FirstDataSector <= file->FirstSectorOfCurrCluster)&& (file->FirstSectorOfCurrCluster <= Partition.LastDataSector))
231 killagreg 584
        {
297 killagreg 585
                // determine current file cluster
586
                cluster = SectorToFat16Cluster(file->FirstSectorOfCurrCluster);
587
                // calculate byte offset in the fat for corresponding entry
588
                fat_byte_offset = ((uint32_t)cluster)<<1; // two FAT bytes (16 bits) for every cluster
589
                // calculate the sector that contains the current cluster within the fat
590
                sector = Partition.FirstFatSector + ( fat_byte_offset / BYTES_PER_SECTOR);
591
                // calculate byte offset of the current cluster within that fat sector
592
                byte = fat_byte_offset % BYTES_PER_SECTOR;
593
                // read this sector to the file cache
594
                if(file->SectorInCache != sector)
231 killagreg 595
                {
297 killagreg 596
                        file->SectorInCache = sector;                                           // update sector stored in buffer
597
                        if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))       // read sector from sd-card
598
                        {
599
                                Fat16_Deinit();
600
                                return (cluster);
601
                        }
231 killagreg 602
                }
297 killagreg 603
                // read the next cluster from cache
604
                fat = (Fat16Entry_t *)(&(file->Cache[byte]));
605
                cluster = fat->NextCluster;
606
                // if last cluster fat entry
607
                if(FAT16_CLUSTER_LAST_MIN <= cluster)
608
                {
609
                         cluster = 0;
610
                }
231 killagreg 611
                else
612
                {
297 killagreg 613
                        file->FirstSectorOfCurrCluster = Fat16ClusterToSector(cluster);
614
                        file->SectorOfCurrCluster = 0;
615
                        file->ByteOfCurrSector = 0;
231 killagreg 616
                }
617
        }
297 killagreg 618
        return(cluster);
231 killagreg 619
}
620
 
621
 
297 killagreg 622
/****************************************************************************************************************************************/
623
/* Function:    FindNextFreeCluster(File_t *);                                                                                                                                                                          */
624
/*                                                                                                                                                                                                                                                                              */
625
/* Description: This function looks in the fat to find the next free cluster                                                                                                                    */
626
/*                                                                                                                                                                                                                                                                              */
627
/* Returnvalue: The function returns the cluster number of the next free cluster found within the fat.                                                                  */
628
/****************************************************************************************************************************************/
629
uint16_t FindNextFreeCluster(File_t *file)
231 killagreg 630
{
297 killagreg 631
        uint32_t fat_sector;                            // current sector within the fat relative to the first sector of the fat.
632
        uint32_t curr_sector;                           // current sector
633
        uint16_t fat_entry;                                     // index to an fatentry within the actual sector (256 fatentries are possible within one sector).
634
        uint16_t free_cluster = 0;                      // next free cluster number.
635
        Fat16Entry_t * fat;
231 killagreg 636
 
297 killagreg 637
        if((!Partition.IsValid) || (file == NULL)) return(0);
231 killagreg 638
 
297 killagreg 639
        // start searching for an empty cluster at the beginning of the fat.
640
        fat_sector = 0;
641
        do
231 killagreg 642
        {
297 killagreg 643
                curr_sector = Partition.FirstFatSector + fat_sector;    // calculate sector to read
644
                file->SectorInCache = curr_sector;                                              // upate the sector number of file cache.
645
                if( SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))              // read sector of fat from sd-card.
646
                {
647
                        Fat16_Deinit();
648
                        return(free_cluster);
649
                }
231 killagreg 650
 
297 killagreg 651
                fat = (Fat16Entry_t *)file->Cache;                                              // set fat pointer to file cache
231 killagreg 652
 
297 killagreg 653
                for(fat_entry = 0; fat_entry < FAT16_ENTRIES_PER_SECTOR; fat_entry++)                                           // look for an free cluster at all entries in this sector of the fat.
231 killagreg 654
                {
297 killagreg 655
                        if(fat[fat_entry].NextCluster == FAT16_CLUSTER_FREE)            // empty cluster found!!
656
                        {
657
                                fat[fat_entry].NextCluster = FAT16_CLUSTER_LAST_MAX;    // mark this fat-entry as used
658
                                if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))               // and save the sector at the sd-card.
659
                                {
660
                                        Fat16_Deinit();
661
                                        return(free_cluster);
662
                                }
663
                                free_cluster = (uint16_t)(fat_sector * FAT16_ENTRIES_PER_SECTOR + (uint32_t)fat_entry);
664
                                fat_entry = FAT16_ENTRIES_PER_SECTOR;                                   // terminate the search for a free cluster in this sector.
665
                        }
231 killagreg 666
                }
297 killagreg 667
                fat_sector++;                                                                                                   // continue the search in next fat sector
668
        // repeat until the end of the fat is  reached and no free cluster has been found so far
669
        }while((fat_sector < Partition.SectorsPerFat) && (!free_cluster));
670
        return(free_cluster);
231 killagreg 671
}
672
 
673
 
297 killagreg 674
/****************************************************************************************************************************************************/
675
/* Function:    int16_t fseek_(File_t *, int32_t *, uint8_t)                                                                                                                                                                                                            */
676
/*                                                                                                                                                                                                                                                                                                      */
677
/* Description: This function sets the pointer of the stream relative to the position                                                                                                                           */
678
/*                              specified by origin (SEEK_SET, SEEK_CUR, SEEK_END)                                                                                                                                                                      */
679
/* Returnvalue: Is 1 if seek was successful                                                                                                                                                                                                                                                                     */
680
/****************************************************************************************************************************************************/
317 killagreg 681
int16_t fseek_(File_t * const file, int32_t offset, int16_t origin)
231 killagreg 682
{
297 killagreg 683
        int32_t         fposition       = 0;
684
        int16_t         retvalue        = 1;
231 killagreg 685
 
297 killagreg 686
        if((!Partition.IsValid) || (file == NULL)) return(0);
687
        switch(origin)
231 killagreg 688
        {
297 killagreg 689
                case SEEK_SET:                          // Fileposition relative to the beginning of the file.
690
                        fposition = 0;
691
                        break;
692
                case SEEK_END:                          // Fileposition relative to the end of the file.
693
                        fposition = (int32_t)file->Size;
694
                        break;
695
                case SEEK_CUR:                          // Fileposition relative to the current position of the file.
696
                default:
697
                        fposition = file->Position;
698
                        break;
699
        }
700
 
701
        fposition += offset;
702
 
703
        if((fposition >= 0) && (fposition <= (int32_t)file->Size))              // is the pointer still within the file?
704
        {
705
                // reset file position to start of the file
706
                file->FirstSectorOfCurrCluster = file->FirstSectorOfFirstCluster;
707
                file->SectorOfCurrCluster       = 0;
708
                file->ByteOfCurrSector          = 0;
709
                file->Position                          = 0;
710
 
711
                while(file->Position < fposition)       // repeat until the current position is less than target
231 killagreg 712
                {
297 killagreg 713
                        file->Position++;                               // increment file position
714
                        file->ByteOfCurrSector++;               // next byte in current sector
715
                        if(file->ByteOfCurrSector >= BYTES_PER_SECTOR)
231 killagreg 716
                        {
297 killagreg 717
                                file->ByteOfCurrSector = 0;                                                                             // reading at the beginning of new sector.
718
                                file->SectorOfCurrCluster++;                                                                    // continue reading in next sector
719
                                if(file->SectorOfCurrCluster >= Partition.SectorsPerCluster)    // if end of cluster is reached, the next datacluster has to be searched in the FAT.
720
                                {
721
                                        if(GetNextCluster(file))                                                                        // Sets the clusterpointer of the file to the next datacluster.
722
                                        {
723
                                                file->SectorOfCurrCluster = 0;
724
                                        }
725
                                        else // the last cluster was allready reached
726
                                        {
727
                                                file->SectorOfCurrCluster--;                                                    // jump back to the ast sector in the last cluster
728
                                                file->ByteOfCurrSector = BYTES_PER_SECTOR;                              // set ByteOfCurrSector one byte over sector end
729
                                        }
730
                                }
231 killagreg 731
                        }
732
                }
733
        }
297 killagreg 734
        if(file->Position == fposition) retvalue = 0;
735
        return(retvalue);
231 killagreg 736
}
737
 
738
 
297 killagreg 739
/****************************************************************************************************************************************/
740
/* Function:    uint16_t DeleteClusterChain(File *file);                                                                                                                                                                                */
741
/*                                                                                                                                                                                                                                                                              */
742
/* Description: This function trances along a cluster chain in the fat and frees all clusters visited.                                                                  */
743
/*                                                                                                                                                                                                                                                                              */
744
/****************************************************************************************************************************************/
745
uint8_t DeleteClusterChain(uint16_t StartCluster)
231 killagreg 746
{
297 killagreg 747
        uint16_t cluster;
748
        uint32_t fat_byte_offset, sector, byte;
749
        Fat16Entry_t * fat;
750
        uint8_t buffer[BYTES_PER_SECTOR];
751
        uint32_t sector_in_buffer = 0;
752
        uint8_t repeat = 0;
231 killagreg 753
 
297 killagreg 754
        if(!Partition.IsValid) return 0;
231 killagreg 755
 
297 killagreg 756
        cluster = StartCluster; // init chain trace
757
        // calculate byte offset in the fat for corresponding entry
758
        fat_byte_offset = ((uint32_t)cluster)<<1; // two FAT bytes (16 bits) for every cluster
759
        // calculate the sector that contains the current cluster within the fat
760
        sector = Partition.FirstFatSector + ( fat_byte_offset / BYTES_PER_SECTOR);
761
        // calculate byte offset of the current cluster within that fat sector
762
        byte = fat_byte_offset % BYTES_PER_SECTOR;
763
        do
764
        {
765
                if(sector != sector_in_buffer)
766
                {
767
                        // read this sector to buffer
768
                        sector_in_buffer = sector;
769
                        if(SD_SUCCESS != SDC_GetSector(sector_in_buffer, buffer)) return 0;     // read sector from sd-card
770
                }
771
                // read the next cluster from cache
772
                fat = (Fat16Entry_t *)(&(buffer[byte]));
773
                cluster = fat->NextCluster;
774
                if((FAT16_CLUSTER_USED_MIN <= cluster) && (cluster <= FAT16_CLUSTER_USED_MAX) ) repeat = 1;
775
                else repeat = 0;
231 killagreg 776
 
297 killagreg 777
                fat->NextCluster =      FAT16_CLUSTER_FREE; // mark current cluster as free
778
                // calculate byte offset in the fat for corresponding entry
779
                fat_byte_offset = ((uint32_t)cluster)<<1; // two FAT bytes (16 bits) for every cluster
780
                // calculate the sector that contains the current cluster within the fat
781
                sector = Partition.FirstFatSector + ( fat_byte_offset / BYTES_PER_SECTOR);
782
                // calculate byte offset of the current cluster within that fat sector
783
                byte = fat_byte_offset % BYTES_PER_SECTOR;
784
                // if new sector is not the sector in buffer or the last cluster in the chain was traced
785
                if((sector != sector_in_buffer) || !repeat)
786
                {       // write sector in buffer
787
                        if(SD_SUCCESS != SDC_PutSector(sector_in_buffer,buffer)) return 0;
788
                }
789
        }
790
        while(repeat);
231 killagreg 791
 
297 killagreg 792
        return 1;
231 killagreg 793
}
794
 
795
 
297 killagreg 796
/****************************************************************************************************************************************/
797
/* Function:    uint16_t AppendCluster(File *file);                                                                                                                                                                                     */
798
/*                                                                                                                                                                                                                                                                              */
799
/* Description: This function looks in the fat to find the next free cluster and appends it to the file.                                                                */
800
/*                                                                                                                                                                                                                                                                              */
801
/* Returnvalue: The function returns the appened cluster number or 0 of no cluster was appended.                                                                                                                                                */
802
/****************************************************************************************************************************************/
803
uint16_t AppendCluster(File_t *file)
231 killagreg 804
{
297 killagreg 805
        uint16_t last_cluster, new_cluster = 0;
806
        uint32_t fat_byte_offset, sector, byte;
807
        Fat16Entry_t * fat;
231 killagreg 808
 
297 killagreg 809
        if((!Partition.IsValid) || (file == NULL)) return(new_cluster);
231 killagreg 810
 
297 killagreg 811
        new_cluster = FindNextFreeCluster(file);        // the next free cluster found on the disk.
812
        if(new_cluster)
813
        {       // A free cluster was found and can be added to the end of the file.
814
                fseek_(file, 0, SEEK_END);                                                                                                      // jump to the end of the file
815
                last_cluster = SectorToFat16Cluster(file->FirstSectorOfCurrCluster);            // determine current file cluster
816
                fat_byte_offset = ((uint32_t)last_cluster)<<1;
817
                sector = Partition.FirstFatSector + ( fat_byte_offset / BYTES_PER_SECTOR);
818
                byte = fat_byte_offset % BYTES_PER_SECTOR;
231 killagreg 819
 
297 killagreg 820
                if(file->SectorInCache != sector)
231 killagreg 821
                {
297 killagreg 822
                        file->SectorInCache = sector;                                           // update sector stored in buffer
823
                        if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))       // read sector from sd-card
824
                        {
825
                                Fat16_Deinit();
826
                                return(0);
827
                        }
231 killagreg 828
                }
297 killagreg 829
                fat = (Fat16Entry_t *)(&(file->Cache[byte]));
830
                fat->NextCluster = new_cluster;                                                 // append the free cluster to the end of the file in the FAT.
831
                if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))               // save the modified sector to the FAT.
231 killagreg 832
                {
297 killagreg 833
                        Fat16_Deinit();
834
                        return(0);
231 killagreg 835
                }
297 killagreg 836
                file->FirstSectorOfCurrCluster = Fat16ClusterToSector(new_cluster);
837
                file->SectorOfCurrCluster = 0;
838
                file->ByteOfCurrSector = 0;
231 killagreg 839
        }
297 killagreg 840
        return(new_cluster);
231 killagreg 841
}
842
 
297 killagreg 843
/****************************************************************************************************************************************************/
844
/* Function:    DirectoryEntryExist(int8_t *, uint8_t, uint8_t, File_t *)                                                                                                                                                                                       */
845
/*                                                                                                                                                                                                                                                                                                      */
846
/* Description: This function searches all possible dir entries until the file or directory is found or the end of the directory is reached                     */
847
/*                                                                                                                                                                                                                                                                                                      */
848
/* Returnvalue: This function returns 1 if the directory entry specified was found.                                                                                                                                     */
849
/****************************************************************************************************************************************************/
850
uint8_t DirectoryEntryExist(int8_t *dirname, uint8_t attribfilter, uint8_t attribmask, File_t *file)
851
{
852
        uint32_t        dir_sector, max_dir_sector, curr_sector;
853
        uint16_t        dir_entry = 0;
231 killagreg 854
 
297 killagreg 855
        uint16_t        end_of_directory_not_reached = 0;
856
        uint8_t         i = 0;
857
        uint8_t         direntry_exist = 0;
858
        DirEntry_t * dir;
231 killagreg 859
 
297 killagreg 860
        // if incomming pointers are useless return immediatly
861
        if((!Partition.IsValid) || (file == NULL) || (dirname == NULL)) return(direntry_exist);
231 killagreg 862
 
297 killagreg 863
        // dir entries can be searched only in filesclusters that have
864
        // a corresponding dir entry with adir-flag set in its attribute
865
        // or direct within the root directory area
231 killagreg 866
 
297 killagreg 867
        file->FirstSectorOfFirstCluster = 0;
868
        // no current directory exist therefore assume searching in the root
869
        if(file->DirectorySector == 0)
870
        {
871
                max_dir_sector = (Partition.MaxRootEntries * DIRENTRY_SIZE)/BYTES_PER_SECTOR;
872
                file->FirstSectorOfFirstCluster = Partition.FirstRootDirSector;
873
        }
874
        // within the root directory area we can read sectors sequentially until the end of this area
875
        else if((Partition.FirstRootDirSector <= file->DirectorySector) && (file->DirectorySector < Partition.FirstDataSector))
876
        {
877
                max_dir_sector = (Partition.MaxRootEntries * DIRENTRY_SIZE)/BYTES_PER_SECTOR;
878
        }
879
        // within the data clusters we can read sectors sequentially only within the cluster
880
        else if((Partition.FirstDataSector <= file->DirectorySector) && (file->DirectorySector <= Partition.LastDataSector))
881
        {
882
                max_dir_sector = Partition.SectorsPerCluster;                           // limit max secters before next cluster
883
        }
884
        else return (direntry_exist); // bad sector range for directory sector of the file
885
        // if search area is not defined yet
886
        if(file->FirstSectorOfFirstCluster == 0)
887
        {
888
                // check if the directory entry of current file is existent and has the dir-flag set
889
                file->SectorInCache = file->DirectorySector;                            // update the sector number of file cache.
890
                if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read in the sector.
891
                {
892
                        Fat16_Deinit();
893
                        return(direntry_exist);
894
                }
895
                dir = (DirEntry_t *)file->Cache;                                                        // set pointer to directory
896
                switch((uint8_t)dir[file->DirectoryIndex].Name[0])                                      // check if current directory exist
897
                {
898
                        case SLOT_EMPTY:
899
                        case SLOT_DELETED:
900
                                // the directrory pointer of this file points to a deleted or not existen directory
901
                                // therefore no file or subdirectory can be created
902
                                return (direntry_exist);
903
                                break;
904
                        default:        // and is a real directory
905
                                if((dir[file->DirectoryIndex].Attribute & ATTR_SUBDIRECTORY) != ATTR_SUBDIRECTORY)
906
                                {       // current file is not a directory therefore no file or subdirectory can be created here
907
                                        return (direntry_exist);
908
                                }
909
                                break;
910
                }
911
                file->FirstSectorOfFirstCluster = Fat16ClusterToSector(dir[file->DirectoryIndex].StartCluster);
912
        }
231 killagreg 913
 
297 killagreg 914
        // update current file data area position to start of first cluster
915
        file->FirstSectorOfCurrCluster  = file->FirstSectorOfFirstCluster;
916
        file->SectorOfCurrCluster               = 0;
917
        file->ByteOfCurrSector                  = 0;
231 killagreg 918
 
297 killagreg 919
        do // loop over all data clusters of the current directory entry
920
        {
921
                dir_sector = 0; // reset sector counter within a new cluster
922
                do // loop over all sectors of a cluster or all sectors of the root directory
923
                {
924
                        curr_sector = file->FirstSectorOfCurrCluster + dir_sector;      // calculate sector number
925
                        file->SectorInCache = curr_sector;                                                      // upate the sector number of file cache.
926
                        if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read the sector
927
                        {
928
                                Fat16_Deinit();
929
                                return(direntry_exist);
930
                        }
931
                        dir = (DirEntry_t *)file->Cache;                                                        // set pointer to directory
932
                        // search all directory entries within that sector
933
                        for(dir_entry = 0; dir_entry < DIRENTRIES_PER_SECTOR; dir_entry++)
934
                        {   // check for existing dir entry
935
                                switch((uint8_t)dir[dir_entry].Name[0])
936
                                {
937
                                        case SLOT_EMPTY:
938
                                        case SLOT_DELETED:
939
                                                // ignore empty or deleted dir entries
940
                                                break;
941
                                        default:
942
                                                // if existing check attributes before names are compared will safe performance
943
                                                if ((dir[dir_entry].Attribute & attribmask) != attribfilter) break; // attribute must match
944
                                                // then compare the name to the giveb dirname (first 11 characters include 8 chars of basename and 3 chars extension.)
945
                                                i = 0;
946
                                                while((i < 11) && (dir[dir_entry].Name[i] == dirname[i])) i++;
947
                                                if (i < 10) break; // names does not match
948
                                                // if dirname and attribute have matched
949
                                                file->Attribute = dir[dir_entry].Attribute; // store attribute of found dir entry
950
                                                file->FirstSectorOfFirstCluster = Fat16ClusterToSector(dir[dir_entry].StartCluster); // set sector of first data cluster
951
                                                file->FirstSectorOfCurrCluster = file->FirstSectorOfFirstCluster;
952
                                                file->SectorOfCurrCluster = 0;
953
                                                file->ByteOfCurrSector = 0;
954
                                                file->DirectorySector = curr_sector; // current sector
955
                                                file->DirectoryIndex  = dir_entry; // current direntry in current sector
956
                                                file->Size = dir[dir_entry].Size;
957
                                                direntry_exist = 1; // mark as found
958
                                                dir_entry = DIRENTRIES_PER_SECTOR;      // stop for-loop
959
                                } // end of first byte of name check
960
                        }
961
                        dir_sector++; // search next sector
962
                // stop if we reached the end of the cluster or the end of the root dir
963
                }while((dir_sector < max_dir_sector) && (!direntry_exist));
231 killagreg 964
 
297 killagreg 965
                // if we are seaching in the data area and the file not found in this cluster so take next cluster.
966
                if(!direntry_exist && ( Partition.FirstDataSector <= file->FirstSectorOfCurrCluster))
967
                {
968
                        end_of_directory_not_reached = GetNextCluster(file);  // updates File->FirstSectorOfCurrCluster
969
                }
970
        }while((end_of_directory_not_reached) && (!direntry_exist)); // repeat until a next cluster exist an no
971
        return(direntry_exist);
231 killagreg 972
}
973
 
974
 
297 killagreg 975
/****************************************************************************************************************************************/
976
/*      Function:               CreateDirectoryEntry(int8_t *, uint16_t, File_t *)                                                                                                                                                      */
977
/*                                                                                                                                                                                                                                                                              */
978
/*      Description:    This function looks for the next free position in the directory and creates an entry.                                                           */
979
/*                                      The type of an directory entry is specified by the file attribute.                                                                                                      */
980
/*                                                                                                                                                                                                                                                                              */
981
/*      Returnvalue:    Return 0 on error                                                                                                                                                                                                       */
982
/****************************************************************************************************************************************/
983
uint8_t CreateDirectoryEntry(int8_t *dirname, uint8_t attrib, File_t *file)
231 killagreg 984
{
297 killagreg 985
        uint32_t        dir_sector, max_dir_sector, curr_sector;
986
        uint16_t        dir_entry       = 0;
987
        uint16_t        subdircluster, dircluster = 0;
988
        uint16_t        end_of_directory_not_reached = 0;
989
        uint8_t         i                       = 0;
990
        uint8_t         retvalue        = 0;
991
        DirEntry_t*     dir;
231 killagreg 992
 
297 killagreg 993
        if((!Partition.IsValid) || (file == NULL) || (dirname == NULL)) return (retvalue);
994
        // It is not checked here that the dir entry that should be created is already existent!
231 killagreg 995
 
297 killagreg 996
        // Dir entries can be created only in file-clusters that have
997
        // the dir-flag set in its attribute or within the root directory
231 killagreg 998
 
297 killagreg 999
        file->FirstSectorOfFirstCluster = 0;
1000
        // no current directory exist therefore assume creating in the root
1001
        if(file->DirectorySector == 0)
231 killagreg 1002
        {
297 killagreg 1003
                max_dir_sector = (Partition.MaxRootEntries * DIRENTRY_SIZE)/BYTES_PER_SECTOR;
1004
                dircluster = 0;
1005
                file->FirstSectorOfFirstCluster = Partition.FirstRootDirSector;
1006
        }
1007
        // within the root directory area we can read sectors sequentially until the end of this area
1008
        else if((Partition.FirstRootDirSector <= file->DirectorySector) && (file->DirectorySector < Partition.FirstDataSector))
1009
        {
1010
                max_dir_sector = (Partition.MaxRootEntries * DIRENTRY_SIZE)/BYTES_PER_SECTOR;
1011
        }
1012
        // within the data clusters we can read sectors sequentially only within the cluster
1013
        else if((Partition.FirstDataSector <= file->DirectorySector) && (file->DirectorySector <= Partition.LastDataSector))
1014
        {
1015
                max_dir_sector = Partition.SectorsPerCluster;
1016
        }
1017
        else return (retvalue); // bad sector range for directory sector of the file
1018
        // if search area is not defined yet
1019
        if(file->FirstSectorOfFirstCluster == 0)
1020
        {
1021
            // check if the directory entry of current file is existent and has the dir-flag set
1022
                file->SectorInCache = file->DirectorySector;                            // update the sector number of file cache.
1023
                if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read in the sector.
1024
                {
1025
                        Fat16_Deinit();
1026
                        return(retvalue);
1027
                }
1028
                dir = (DirEntry_t *)file->Cache;                                                        // set pointer to directory
1029
                switch((uint8_t)dir[file->DirectoryIndex].Name[0])                                      // check if current directory exist
1030
                {
1031
                        case SLOT_EMPTY:
1032
                        case SLOT_DELETED:
1033
                                return (retvalue);
1034
                                break;
1035
                        default:        // and is a real directory
1036
                                if((dir[file->DirectoryIndex].Attribute & ATTR_SUBDIRECTORY) != ATTR_SUBDIRECTORY)
1037
                                {       // current file is not a directory therefore no file or subdirectory can be created here
1038
                                        return (retvalue);
1039
                                }
1040
                                break;
1041
                }
1042
                dircluster = dir[file->DirectoryIndex].StartCluster;
1043
                file->FirstSectorOfFirstCluster = Fat16ClusterToSector(dircluster);
1044
        }
231 killagreg 1045
 
297 killagreg 1046
        subdircluster = FindNextFreeCluster(file);      // get the next free cluster on the disk and mark it as used.
1047
        if(subdircluster)
1048
        {
1049
                file->FirstSectorOfCurrCluster  = file->FirstSectorOfFirstCluster;
1050
                file->SectorOfCurrCluster               = 0;
1051
                do // loop over all clusters of current directory
1052
                {
1053
                        dir_sector = 0; // reset sector counter within a new cluster
1054
                        do // loop over all sectors of a cluster or all sectors of the root directory
231 killagreg 1055
                        {
297 killagreg 1056
                                curr_sector = file->FirstSectorOfCurrCluster + dir_sector;      // calculate sector number
1057
                                file->SectorInCache = curr_sector;                                                      // upate the sector number of file cache.
1058
                                if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read in the sector.
231 killagreg 1059
                                {
297 killagreg 1060
                                        Fat16_Deinit();
1061
                                        return(retvalue);
231 killagreg 1062
                                }
297 killagreg 1063
                                dir = (DirEntry_t *)file->Cache;                                                        // set pointer to directory
1064
                                // search all directory entries of a sector
1065
                                for(dir_entry = 0; dir_entry < DIRENTRIES_PER_SECTOR; dir_entry++)
1066
                                {       // check if current direntry is available
1067
                                        if(((uint8_t)dir[dir_entry].Name[0] == SLOT_EMPTY) || ((uint8_t)dir[dir_entry].Name[0] == SLOT_DELETED))
1068
                                        {       // a free direntry was found
1069
                                                for(i = 0; i < 11; i++) dir[dir_entry].Name[i] = dirname[i];            // Set dir name
1070
                                                dir[dir_entry].Attribute    = attrib;                                                           // Set the attribute of the new directoryentry.
1071
                                                dir[dir_entry].StartCluster = subdircluster;                                            // copy the location of the first datacluster to the directoryentry.
1072
                                                dir[dir_entry].DateTime         = FileDateTime(&SystemTime);                    // set date/time
1073
                                                dir[dir_entry].Size             = 0;                                                                    // the new createted file has no content yet.
1074
                                                if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))       // write back to card
1075
                                                {
1076
                                                        Fat16_Deinit();
1077
                                                        return(retvalue);
1078
                                                }
1079
                                                file->FirstSectorOfFirstCluster = Fat16ClusterToSector(subdircluster);  // Calculate absolute sectorposition of first datacluster.
1080
                                                file->FirstSectorOfCurrCluster  = file->FirstSectorOfFirstCluster;      // Start reading the file with the first sector of the first datacluster.
1081
                                                file->SectorOfCurrCluster               = 0;                                                            // reset sector of cureen cluster
1082
                                                file->ByteOfCurrSector                  = 0;                                                            // reset the byte location within the current sector
1083
                                                file->Attribute                                 = attrib;                                               // set file attribute to dir attribute
1084
                                                file->Size                                              = 0;                                                        // new file has no size
1085
                                                file->DirectorySector                   = curr_sector;
1086
                                                file->DirectoryIndex                    = dir_entry;
1087
                                                if((attrib & ATTR_SUBDIRECTORY) == ATTR_SUBDIRECTORY)                           // if a new directory was created then initilize the data area
1088
                                                {
1089
                                                        ClearCurrCluster(file); // fill cluster with zeros
1090
                                                        file->SectorInCache = file->FirstSectorOfFirstCluster;
1091
                                                        if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read in the sector.
1092
                                                        {
1093
                                                                Fat16_Deinit();
1094
                                                                return(retvalue);
1095
                                                        }
1096
                                                        dir = (DirEntry_t *)file->Cache;
1097
                                                        // create direntry "." to current dir
1098
                                                        dir[0].Name[0] = 0x2E;
1099
                                                        for(i = 1; i < 11; i++) dir[0].Name[i] = ' ';
1100
                                                        dir[0].Attribute = ATTR_SUBDIRECTORY;
1101
                                                        dir[0].StartCluster = subdircluster;
1102
                                                        dir[0].DateTime = 0;
1103
                                                        dir[0].Size = 0;
1104
                                                        // create direntry ".." to the upper dir
1105
                                                        dir[1].Name[0] = 0x2E;
1106
                                                        dir[1].Name[1] = 0x2E;
1107
                                                        for(i = 2; i < 11; i++) dir[1].Name[i] = ' ';
1108
                                                        dir[1].Attribute = ATTR_SUBDIRECTORY;
1109
                                                        dir[1].StartCluster = dircluster;
1110
                                                        dir[1].DateTime = 0;
1111
                                                        dir[1].Size = 0;
1112
                                                        if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))// read in the sector.
1113
                                                        {
1114
                                                                Fat16_Deinit();
1115
                                                                return(retvalue);
1116
                                                        }
1117
                                                }
1118
                                                retvalue = 1;
1119
                                                dir_entry = DIRENTRIES_PER_SECTOR;      // stop for-loop
1120
                                        }
1121
                                }
1122
                                dir_sector++; // search next sector
1123
                        // stop if we reached the end of the cluster or the end of the root dir
1124
                        }while((dir_sector < max_dir_sector) && (!retvalue));
1125
 
1126
                        // if we are seaching in the data area and the file not found in this cluster so take next cluster.
1127
                        if(!retvalue && ( Partition.FirstDataSector <= file->FirstSectorOfCurrCluster))
231 killagreg 1128
                        {
297 killagreg 1129
                                end_of_directory_not_reached = GetNextCluster(file);  // updates File->FirstSectorOfCurrCluster
231 killagreg 1130
                        }
297 killagreg 1131
                }while((end_of_directory_not_reached) && (!retvalue));
1132
                // Perhaps we are at the end of the last cluster of a directory file an have no free direntry found.
1133
                // Then we would need to add a cluster to that file and create the new direntry there.
1134
                // This code is not implemented yet, because its occurs only if more that 32*32=1024 direntries are
1135
                // within a subdirectory of root.
231 killagreg 1136
        }
297 killagreg 1137
        return(retvalue);       // return 1 if file has been created otherwise return 0.
231 killagreg 1138
}
1139
 
297 killagreg 1140
/********************************************************************************************************************************************/
1141
/*      Function:               FileExist(const int8_t* filename, uint8_t attribfilter, uint8_t attribmask, File_t *file);                                                                                      */
1142
/*                                                                                                                                                                                                                                                                                      */
1143
/*      Description:    This function looks for the specified file including its subdirectories beginning                                                                               */
1144
/*                                      in the rootdirectory of the drive. If the file is found the Filepointer properties are                                                                  */
1145
/*                                      updated.                                                                                                                                                                                                                                */
1146
/*                                                                                                                                                                                                                                                                                      */
1147
/*      Returnvalue:    1 if file is found else 0.                                                                                                                                                                                              */
1148
/********************************************************************************************************************************************/
1149
uint8_t FileExist(const int8_t* filename, const uint8_t attribfilter, const uint8_t attribmask, File_t *file)
231 killagreg 1150
{
297 killagreg 1151
        int8_t* path = 0;
1152
        int8_t* subpath = 0;
1153
        uint8_t af, am, file_exist = 0;
1154
        int8_t  dirname[12]; // 8+3 + temination character
231 killagreg 1155
 
297 killagreg 1156
        // if incomming pointers are useless return immediatly
1157
        if ((filename == NULL) || (file == NULL) || (!Partition.IsValid)) return 0;
231 killagreg 1158
 
297 killagreg 1159
        // trace along the filepath
1160
        path = (int8_t*)filename;                                                               // start a the beginning of the filename string
1161
        file->DirectorySector = 0;                                                              // start at RootDirectory with file search
1162
        file->DirectoryIndex = 0;
1163
        // as long as the file was not found and the remaining path is not empty
1164
        while((*path != 0) && !file_exist)
1165
        {       // separate dirname and subpath from filepath string
1166
                subpath = SeperateDirName(path, dirname);
1167
                if(subpath != NULL)
231 killagreg 1168
                {
297 killagreg 1169
                        if(*subpath == 0)
1170
                        {       // empty subpath indicates last element of dir chain
1171
                                af = attribfilter;
1172
                                am = attribmask;
1173
                        }
1174
                        else  // it must be a subdirectory and no volume label
231 killagreg 1175
                        {
297 killagreg 1176
                                af = ATTR_SUBDIRECTORY;
1177
                                am = ATTR_SUBDIRECTORY|ATTR_VOLUMELABEL;
1178
                        }
1179
                        if(!DirectoryEntryExist(dirname, af, am, file))
1180
                        {
1181
                                return (file_exist); // subdirectory does not exist
1182
                        }
1183
                        else
1184
                        {
1185
                                if (*subpath == 0)
231 killagreg 1186
                                {
297 killagreg 1187
                                        file_exist = 1; // last element of path chain was found with the given attribute filter
231 killagreg 1188
                                }
1189
                        }
1190
                }
297 killagreg 1191
                else // error seperating the subpath
231 killagreg 1192
                {
297 killagreg 1193
                        return file_exist; // bad subdir format
231 killagreg 1194
                }
297 killagreg 1195
                path = subpath;
1196
                subpath = 0;
231 killagreg 1197
        }
297 killagreg 1198
        return (file_exist);
231 killagreg 1199
}
1200
 
1201
 
297 killagreg 1202
/********************************************************************************************************************************************/
1203
/*      Function:               FileCreate(const s8* filename, u8 attrib, File_t *file);                                                                                                                                */
1204
/*                                                                                                                                                                                                                                                                                      */
1205
/*      Description:    This function looks for the specified file including its subdirectories beginning                                                                               */
1206
/*                                      in the rootdirectory of the partition. If the file is found the Filepointer properties are                                                              */
1207
/*                                      updated. If file or its subdirectories are not found they will be created                                                                                               */
1208
/*                                                                                                                                                                                                                                                                                      */
1209
/*      Returnvalue:    1 if file was created else 0.                                                                                                                                                                                   */
1210
/********************************************************************************************************************************************/
1211
uint8_t FileCreate(const int8_t* filename, const uint8_t attrib, File_t *file)
231 killagreg 1212
{
297 killagreg 1213
        int8_t *path = 0;
1214
        int8_t *subpath = 0;
1215
        uint8_t af, am, file_created = 0;
1216
        int8_t dirname[12];
231 killagreg 1217
 
297 killagreg 1218
        // if incomming pointers are useless return immediatly
1219
        if ((filename == NULL) || (file == NULL) || (!Partition.IsValid)) return 0;
231 killagreg 1220
 
297 killagreg 1221
        // trace along the filepath
1222
        path = (int8_t*)filename;                                                                       // start a the beginning of the filename string
1223
        file->DirectorySector = 0;                                                              // start at RootDirectory with file search
1224
        file->DirectoryIndex = 0;
1225
        // as long as the file was not created and the remaining file path is not empty
1226
        while((*path != 0) && !file_created)
1227
        {   // separate dirname and subpath from filepath string
1228
                subpath = SeperateDirName(path, dirname);
1229
                if(subpath != NULL)
231 killagreg 1230
                {
297 killagreg 1231
                        if(*subpath == 0)
1232
                        {       // empty subpath indicates last element of dir chain
1233
                                af = ATTR_NONE;
1234
                                am = ATTR_SUBDIRECTORY|ATTR_VOLUMELABEL;  // any file that is no subdir or volume label
1235
                        }
1236
                        else  // it must be a subdirectory and no volume label
231 killagreg 1237
                        {
297 killagreg 1238
                                af = ATTR_SUBDIRECTORY;
1239
                                am = ATTR_SUBDIRECTORY|ATTR_VOLUMELABEL;
231 killagreg 1240
                        }
297 killagreg 1241
                        if(!DirectoryEntryExist(dirname, af, am, file)) // if subdir or file is not existent
1242
                        {  // try to create subdir or file
1243
                                if(*subpath == 0) af = attrib; // if last element in dir chain take the given attribute
1244
                                if(!CreateDirectoryEntry(dirname, af, file))
1245
                                {       // could not be created
1246
                                        return(file_created);
231 killagreg 1247
                                }
297 killagreg 1248
                                else if (*subpath == 0) file_created = 1; // last element of path chain was created
231 killagreg 1249
                        }
1250
                }
297 killagreg 1251
                else // error seperating the subpath
231 killagreg 1252
                {
297 killagreg 1253
                        return file_created; // bad subdir format
231 killagreg 1254
                }
297 killagreg 1255
                path = subpath;
1256
                subpath = 0;
231 killagreg 1257
        }
297 killagreg 1258
        return (file_created);
231 killagreg 1259
}
1260
 
1261
 
297 killagreg 1262
/********************************************************************************************************************************************/
1263
/*      Function:               File_t * fopen_(int8_t* filename, int8_t mode);                                                                                                                                                                 */
1264
/*                                                                                                                                                                                                                                                                                      */
1265
/*      Description:    This function looks for the specified file in the rootdirectory of the drive. If the file is found the number of the    */
1266
/*                                      corrosponding filepointer is returned. Only modes 'r' (reading) and 'a' append are implemented yet.                                             */
1267
/*                                                                                                                                                                                                                                                                                      */
1268
/*      Returnvalue:    The filepointer to the file or 0 if faild.                                                                                                                                                              */
1269
/********************************************************************************************************************************************/
317 killagreg 1270
File_t * fopen_(int8_t * const filename, const int8_t mode)
231 killagreg 1271
{
297 killagreg 1272
        File_t *file    = 0;
231 killagreg 1273
 
297 killagreg 1274
        if((!Partition.IsValid) || (filename == 0)) return(file);
1275
 
1276
        // Look for an unused filepointer in the file pointer list?
1277
        file = LockFilePointer();
1278
        // if no unused file pointer was found return 0
1279
        if(file == NULL) return(file);
1280
 
1281
        // now we have found a free filepointer and claimed it
1282
        // so let initiate its property values
1283
        file->FirstSectorOfFirstCluster = 0;            // Sectorpointer to the first sector of the first datacluster of the file.
1284
        file->FirstSectorOfCurrCluster  = 0;            // Pointer to the cluster which is edited at the moment.
1285
        file->SectorOfCurrCluster               = 0;            // The sector which is edited at the moment (cluster_pointer + sector_index).
1286
        file->ByteOfCurrSector                  = 0;            // The bytelocation within the current sector (cluster_pointer + sector_index + byte_index).
1287
        file->Mode                                              = mode;         // mode of fileoperation (read,write)
1288
        file->Size                                              = 0;            // the size of the opened file in bytes.
1289
        file->Position                                  = 0;            // pointer to a byte within the file 0 < fileposition < filesize
1290
        file->SectorInCache                             = 0;            // the last sector read, wich is still in the sectorbuffer.
1291
        file->DirectorySector                   = 0;            // the sectorposition where the directoryentry has been made.
1292
        file->DirectoryIndex                    = 0;            // the index to the directoryentry within the specified sector.
1293
        file->Attribute                                 = 0;            // the attribute of the file opened.
1294
 
1295
        // check if a real file (no directory) to the given filename exist
1296
        if(FileExist(filename, ATTR_NONE, ATTR_SUBDIRECTORY|ATTR_VOLUMELABEL, file))
1297
        {  // file exist
1298
                switch(mode)  // check mode
231 killagreg 1299
                {
297 killagreg 1300
                        case 'a':       // if mode is: append to file
1301
                                if((file->Attribute & ATTR_READONLY) == ATTR_READONLY)
1302
                                {       // file is marked as readonly --> do not open this file
1303
                                        fclose_(file);
1304
                                        file = NULL;
1305
                                }
1306
                                else
1307
                                {       // file is not marked as read only --> goto end of file
1308
                                        fseek_(file, 0, SEEK_END);              // point to the end of the file
1309
                                }
1310
                                break;
1311
                        case 'w':       // if mode is: write to file
1312
                                if((file->Attribute & ATTR_READONLY) == ATTR_READONLY)
1313
                                {       // file is marked as readonly --> do not open this file
1314
                                        fclose_(file);
1315
                                        file = NULL;
1316
                                }
1317
                                else
1318
                                {       // file is not marked as read only --> goto start of file
1319
                                        // free all clusters of that file
1320
                                        DeleteClusterChain(SectorToFat16Cluster(file->FirstSectorOfFirstCluster));
1321
                                        // mar an empy cluster as the last one and store the corresponding sector
1322
                                        file->FirstSectorOfFirstCluster = Fat16ClusterToSector(FindNextFreeCluster(file));
1323
                                        file->FirstSectorOfCurrCluster = file->FirstSectorOfFirstCluster;
1324
                                        file->SectorOfCurrCluster = 0;
1325
                                        file->ByteOfCurrSector = 0;
1326
                                        file->Size = 0;
1327
                                        file->Position = 0;
1328
                                        fseek_(file, 0, SEEK_SET);
1329
                                }
1330
                                break;
1331
                        case 'r':       // if mode is: read from file
1332
                                // goto end of file
1333
                                fseek_(file, 0, SEEK_SET);
1334
                                break;
1335
                        default: // other modes are not supported
1336
                                fclose_(file);
1337
                                file = NULL;
231 killagreg 1338
                        break;
1339
                }
297 killagreg 1340
                return(file);
231 killagreg 1341
        }
297 killagreg 1342
        else // file does not exist
231 killagreg 1343
        {
297 killagreg 1344
                switch(mode)  // check mode
231 killagreg 1345
                {
297 killagreg 1346
                        case 'a':
1347
                        case 'w': // if mode is write or append
1348
                                // try to create the file
1349
                                if(!FileCreate(filename, ATTR_ARCHIVE, file))
1350
                                { // if it could not be created
1351
                                        fclose_(file);
1352
                                        file = NULL;
1353
                                }
1354
                                break;
1355
                        case 'r': // else opened for 'r'
1356
                        default:  // of unsupported mode
1357
                                fclose_(file);
1358
                                file = NULL;
1359
                                break;
231 killagreg 1360
                }
297 killagreg 1361
                return(file);
231 killagreg 1362
        }
297 killagreg 1363
        // we should never come to this point
1364
        fclose_(file);
1365
        file = NULL;
1366
        return(file);
231 killagreg 1367
}
1368
 
297 killagreg 1369
/****************************************************************************************************************************************************/
1370
/* Function:    fflush_(File *);                                                                                                                                                                                                                                        */
1371
/*                                                                                                                                                                                                                                                                                                      */
1372
/* Description: This function writes the data already in the buffer but not yet written to the file.                                                                                            */
1373
/*                                                                                                                                                                                                                                                                                                      */
1374
/* Returnvalue: 0 on success EOF on error                                                                                                                                                                                                                       */
1375
/****************************************************************************************************************************************************/
317 killagreg 1376
int16_t fflush_(File_t * const file)
297 killagreg 1377
{
1378
        DirEntry_t *dir;
231 killagreg 1379
 
297 killagreg 1380
        if((file == NULL) || (!Partition.IsValid)) return (EOF);
231 killagreg 1381
 
297 killagreg 1382
        switch(file->Mode)
1383
        {
1384
                case 'a':
1385
                case 'w':
1386
                        if(file->ByteOfCurrSector > 0)                                                                          // has data been added to the file?
1387
                        {
1388
                                if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))// save the data still in the buffer
1389
                                {
1390
                                        Fat16_Deinit();
1391
                                        return(EOF);
1392
                                }
1393
                        }
1394
                        file->SectorInCache     = file->DirectorySector;
1395
                        if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))                                       // read the directory entry for this file.
1396
                        {
1397
                                Fat16_Deinit();
1398
                                return(EOF);
1399
                        }
231 killagreg 1400
 
297 killagreg 1401
                        dir = (DirEntry_t *)file->Cache;
1402
                        dir[file->DirectoryIndex].Size = file->Size;                                            // update file size
1403
                        dir[file->DirectoryIndex].DateTime = FileDateTime(&SystemTime);         // update date time
1404
                        if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))       // write back to sd-card
1405
                        {
1406
                                Fat16_Deinit();
1407
                                return(EOF);
1408
                        }
1409
                        break;
1410
                case 'r':
1411
                default:
1412
                        return(EOF);
1413
                        break;
231 killagreg 1414
 
297 killagreg 1415
        }
1416
        return(0);
231 killagreg 1417
}
1418
 
297 killagreg 1419
/****************************************************************************************************************************************/
1420
/*      Function:               fclose_(File *file);                                                                                                                                                                                            */
1421
/*                                                                                                                                                                                                                                                                              */
1422
/*      Description:    This function closes the open file by writing the remaining data                                                                                                        */
1423
/*                                      from the buffer to the device and entering the filesize in the directory entry.                                                                         */
1424
/*                                                                                                                                                                                                                                                                              */
1425
/*      Returnvalue:    0 on success EOF on error                                                                                                                                                                                       */
1426
/****************************************************************************************************************************************/
1427
int16_t fclose_(File_t *file)
1428
{
1429
        int16_t returnvalue = EOF;
231 killagreg 1430
 
297 killagreg 1431
        if(file == NULL) return(returnvalue);
1432
        returnvalue = fflush_(file);
1433
        UnlockFilePointer(file);
1434
        return(returnvalue);
1435
}
231 killagreg 1436
 
297 killagreg 1437
/********************************************************************************************************************************************/
1438
/*      Function:               fgetc_(File *file);                                                                                                                                                                                                             */
1439
/*                                                                                                                                                                                                                                                                                      */
1440
/*      Description:    This function reads and returns one character from the specified file. Is the end of the actual sector reached the              */
1441
/*                                      next sector of the cluster is read. If the last sector of the cluster read the next cluster will be searched in FAT.    */
1442
/*                                                                                                                                                                                                                                                                                      */
1443
/*      Returnvalue:    The function returns the character read from the specified memorylocation as u8 casted to s16 or EOF.                                   */
1444
/********************************************************************************************************************************************/
317 killagreg 1445
int16_t fgetc_(File_t * const file)
231 killagreg 1446
{
297 killagreg 1447
        int16_t c = EOF;
1448
        uint32_t curr_sector;
231 killagreg 1449
 
297 killagreg 1450
        if( (!Partition.IsValid) || (file == NULL)) return(c);
1451
        // if the end of the file is not reached, get the next character.
1452
        if((0 < file->Size) && ((file->Position+1) < file->Size) )
231 killagreg 1453
        {
297 killagreg 1454
                curr_sector  = file->FirstSectorOfCurrCluster;          // calculate the sector of the next character to be read.
1455
                curr_sector += file->SectorOfCurrCluster;
231 killagreg 1456
 
297 killagreg 1457
                if(file->SectorInCache != curr_sector)
231 killagreg 1458
                {
297 killagreg 1459
                        file->SectorInCache = curr_sector;
1460
                        if(SD_SUCCESS != SDC_GetSector(file->SectorInCache,file->Cache))
1461
                        {
1462
                                Fat16_Deinit();
1463
                                return(c);
1464
                        }
231 killagreg 1465
                }
297 killagreg 1466
                c = (int16_t) file->Cache[file->ByteOfCurrSector];
1467
                file->Position++;                                                                       // increment file position
1468
                file->ByteOfCurrSector++;                                                       // goto next byte in sector
1469
                if(file->ByteOfCurrSector >= BYTES_PER_SECTOR)          // if end of sector
231 killagreg 1470
                {
297 killagreg 1471
                        file->ByteOfCurrSector = 0;                                             //  reset byte location
1472
                        file->SectorOfCurrCluster++;                                    //      next sector
1473
                        if(file->SectorOfCurrCluster >= Partition.SectorsPerCluster)    // if end of cluster is reached, the next datacluster has to be searched in the FAT.
231 killagreg 1474
                        {
297 killagreg 1475
 
1476
                                if(GetNextCluster(file))                                                                                // Sets the clusterpointer of the file to the next datacluster.
231 killagreg 1477
                                {
297 killagreg 1478
                                        file->SectorOfCurrCluster = 0;                                                          // start reading new cluster at first sector of the cluster.
231 killagreg 1479
                                }
297 killagreg 1480
                                else // the last cluster was allready reached
1481
                                {
1482
                                        file->SectorOfCurrCluster--;                                                    // jump back to the last sector in the last cluster
1483
                                        file->ByteOfCurrSector = BYTES_PER_SECTOR;                              // set ByteOfCurrSector one byte over sector end
1484
                                }
231 killagreg 1485
                        }
1486
                }
1487
        }
297 killagreg 1488
        return(c);
231 killagreg 1489
}
1490
 
297 killagreg 1491
/********************************************************************************************************************************************/
1492
/*      Function:               fputc_( const s8 c, File *file);                                                                                                                                                                                */
1493
/*                                                                                                                                                                                                                                                                                      */
1494
/*      Description:    This function writes a byte to the specified file and takes care of writing the necessary FAT- Entries.                                 */
1495
/*                                      next sector of the cluster is read. If the last sector of the cluster read the next cluster will be searched in FAT.    */
1496
/*                                                                                                                                                                                                                                                                                      */
1497
/*      Returnvalue:    The function returns the character written to the stream or EOF on error.                                                                                               */
1498
/********************************************************************************************************************************************/
317 killagreg 1499
int16_t fputc_(const int8_t c, File_t * const file)
231 killagreg 1500
{
297 killagreg 1501
        uint32_t curr_sector  = 0;
231 killagreg 1502
 
297 killagreg 1503
        if((!Partition.IsValid) || (file == NULL)) return(EOF);
231 killagreg 1504
 
297 killagreg 1505
        // If file position equals to file size, then the end of file has reached.
1506
        // In this chase it has to be checked that the ByteOfCurrSector is BYTES_PER_SECTOR
1507
        // and a new cluster should be appended.
1508
        if((file->Position >= file->Size) && (file->ByteOfCurrSector >= BYTES_PER_SECTOR))
1509
        {
1510
                if(!AppendCluster(file)) return(EOF);
1511
        }
231 killagreg 1512
 
297 killagreg 1513
        curr_sector  = file->FirstSectorOfCurrCluster;
1514
        curr_sector += file->SectorOfCurrCluster;
1515
        if(file->SectorInCache != curr_sector)
1516
        {
1517
                file->SectorInCache = curr_sector;
1518
                if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))
1519
                {
1520
                        Fat16_Deinit();
1521
                        return(EOF);
1522
                }
1523
        }
231 killagreg 1524
 
297 killagreg 1525
        file->Cache[file->ByteOfCurrSector] = (uint8_t)c;                       // write databyte into the buffer. The byte will be written to the device at once
1526
        if(file->Size == file->Position) file->Size++;          // a character has been written to the file so the size is incremented only when the character has been added at the end of the file.
1527
        file->Position++;                                                                       // the actual positon within the file.
1528
        file->ByteOfCurrSector++;                                                       // goto next byte in sector
1529
        if(file->ByteOfCurrSector >= BYTES_PER_SECTOR)          // if the end of this sector is reached yet
1530
        {       // save the sector to the sd-card
1531
                if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))
231 killagreg 1532
                {
297 killagreg 1533
                        Fat16_Deinit();
1534
                        return(EOF);
1535
                }
1536
                file->ByteOfCurrSector = 0;                                             //  reset byte location
1537
                file->SectorOfCurrCluster++;                                    //      next sector
1538
                if(file->SectorOfCurrCluster >= Partition.SectorsPerCluster)// if end of cluster is reached, the next datacluster has to be searched in the FAT.
1539
                {
1540
                        if(!GetNextCluster(file))                                                               // Sets the clusterpointer of the file to the next datacluster.
1541
                        { // if current cluster was the last cluster of the file
1542
                                if(!AppendCluster(file))                                                // append a new and free cluster at the end of the file.
231 killagreg 1543
                                {
297 killagreg 1544
                                        file->SectorOfCurrCluster--;                            // jump back to last sector of last cluster
1545
                                        file->ByteOfCurrSector = BYTES_PER_SECTOR;      // set byte location to 1 byte over sector len
1546
                                        return(EOF);
231 killagreg 1547
                                }
1548
                        }
297 killagreg 1549
                        else // next cluster
231 killagreg 1550
                        {
297 killagreg 1551
                                file->SectorOfCurrCluster = 0;                                                  // start reading new cluster at first sector of the cluster.
231 killagreg 1552
                        }
1553
                }
1554
        }
297 killagreg 1555
        return(0);
231 killagreg 1556
}
1557
 
1558
 
297 killagreg 1559
/****************************************************************************************************************************************/
1560
/*      Function:               fread_(void *buffer, uint32_t size, uint32_t count, File *File);                                                                                                                                */
1561
/*                                                                                                                                                                                                                                                                              */
1562
/*      Description:    This function reads count objects of the specified size                                                                                                                         */
1563
/*                                      from the actual position of the file to the specified buffer.                                                                                                           */
1564
/*                                                                                                                                                                                                                                                                              */
1565
/*      Returnvalue:    The function returns the number of objects (not bytes) read from the file.                                                                                      */
1566
/****************************************************************************************************************************************/
317 killagreg 1567
uint32_t fread_(void * const buffer, uint32_t size, uint32_t count, File_t * const file)
297 killagreg 1568
{
1569
        uint32_t object_cnt     = 0;                                                                                    // count the number of objects read from the file.
1570
        uint32_t object_size = 0;                                                                                       // count the number of bytes read from the actual object.
1571
        uint8_t *pbuff          = 0;                                                                                    // a pointer to the actual bufferposition.
1572
        uint8_t success      = 1;                                                                                       // no error occured during read operation to the file.
1573
        int16_t c;
231 killagreg 1574
 
297 killagreg 1575
        if((!Partition.IsValid) || (file == NULL) || (buffer == NULL)) return(0);
231 killagreg 1576
 
297 killagreg 1577
        pbuff = (uint8_t *) buffer;                                                                                     // cast the void pointer to an u8 *
231 killagreg 1578
 
297 killagreg 1579
        while((object_cnt < count) && success)
231 killagreg 1580
        {
297 killagreg 1581
                object_size = size;
1582
                while((size > 0) && success)
1583
                {
1584
                        c = fgetc_(file);
1585
                        if(c != EOF)
1586
                        {
1587
                                *pbuff = (uint8_t)c;                                                                    // read a byte from the buffer to the opened file.
1588
                                pbuff++;
1589
                                size--;
1590
                        }
1591
                        else // error or end of file reached
1592
                        {
1593
                                success = 0;
1594
                        }
1595
                }
1596
                if(success) object_cnt++;
231 killagreg 1597
        }
297 killagreg 1598
        return(object_cnt);                                                                                             // return the number of objects succesfully read from the file
231 killagreg 1599
}
1600
 
1601
 
297 killagreg 1602
/****************************************************************************************************************************************/
1603
/*      Function:               fwrite_(void *buffer, uint32_t size, uint32_t count, File *file);                                                                                                                               */
1604
/*                                                                                                                                                                                                                                                                              */
1605
/*      Description:    This function writes count objects of the specified size                                                                                                                        */
1606
/*                                      from the buffer pointer to the actual position in the file.                                                                                                                     */
1607
/*                                                                                                                                                                                                                                                                              */
1608
/*      Returnvalue:    The function returns the number of objects (not bytes) read from the file.                                                                                      */
1609
/****************************************************************************************************************************************/
317 killagreg 1610
uint32_t fwrite_(void * const buffer, uint32_t size, uint32_t count, File_t * const file)
231 killagreg 1611
{
297 killagreg 1612
        uint32_t object_cnt     = 0;                                                                                                            // count the number of objects written to the file.
1613
        uint32_t object_size = 0;                                                                                                               // count the number of bytes written from the actual object.
1614
        uint8_t *pbuff      = 0;                                                                                                                // a pointer to the actual bufferposition.
1615
        uint8_t success      = 1;                                                                                                               // no error occured during write operation to the file.
1616
        int16_t c;
231 killagreg 1617
 
297 killagreg 1618
        if((!Partition.IsValid) || (file == NULL) || (buffer == NULL)) return(0);
231 killagreg 1619
 
297 killagreg 1620
        pbuff = (uint8_t *) buffer;                                                                                                             // cast the void pointer to an u8 *
231 killagreg 1621
 
297 killagreg 1622
        while((object_cnt < count) && success)
231 killagreg 1623
        {
297 killagreg 1624
                object_size = size;
1625
                while((size > 0) && success)
231 killagreg 1626
                {
297 killagreg 1627
                        c = fputc_(*pbuff, file);                                                                               // write a byte from the buffer to the opened file.
1628
                        if(c != EOF)
231 killagreg 1629
                        {
297 killagreg 1630
                                pbuff++;
1631
                                size--;
231 killagreg 1632
                        }
297 killagreg 1633
                        else
231 killagreg 1634
                        {
297 killagreg 1635
                                success = 0;
231 killagreg 1636
                        }
1637
                }
297 killagreg 1638
                if(success) object_cnt++;
231 killagreg 1639
        }
1640
 
297 killagreg 1641
        return(object_cnt);                                                                                                                             // return the number of objects succesfully written to the file
231 killagreg 1642
}
1643
 
1644
 
297 killagreg 1645
/****************************************************************************************************************************************/
1646
/*      Function:               fputs_(const int8_t *string, File_t *File);                                                                                                                                                             */
1647
/*                                                                                                                                                                                                                                                                              */
1648
/*      Description:    This function writes a string to the specified file.                                                                                                                            */
1649
/*                                                                                                                                                                                                                                                                              */
1650
/*      Returnvalue:    The function returns a no negative value or EOF on error.                                                                                                                       */
1651
/****************************************************************************************************************************************/
317 killagreg 1652
int16_t fputs_(int8_t * const string, File_t * const file)
231 killagreg 1653
{
297 killagreg 1654
        uint8_t i=0;
1655
        int16_t c = 0;
231 killagreg 1656
 
297 killagreg 1657
        if((!Partition.IsValid) || (file == NULL) || (string == NULL)) return(0);
231 killagreg 1658
 
297 killagreg 1659
        while((string[i] != 0)&& (c != EOF))
231 killagreg 1660
        {
297 killagreg 1661
                c = fputc_(string[i], file);
1662
                i++;
231 killagreg 1663
        }
297 killagreg 1664
        return(c);
231 killagreg 1665
}
1666
 
297 killagreg 1667
/****************************************************************************************************************************************/
1668
/*      Function:               fgets_(int8 *, int16_t , File_t *);                                                                                                                                                                             */
1669
/*                                                                                                                                                                                                                                                                              */
1670
/*      Description:    This function reads a string from the file to the specifies string.                                                                                             */
1671
/*                                                                                                                                                                                                                                                                              */
1672
/*      Returnvalue:    A pointer to the string read from the file or 0 on error.                                                                                                                       */
1673
/****************************************************************************************************************************************/
317 killagreg 1674
int8_t * fgets_(int8_t * const string, int16_t length, File_t * const file)
231 killagreg 1675
{
317 killagreg 1676
        int8_t *pbuff;
1677
        int16_t c = 0, bytecount;
231 killagreg 1678
 
317 killagreg 1679
        if((!Partition.IsValid) || (file == NULL) || (string == NULL) || (length > 1)) return (0);
297 killagreg 1680
        pbuff = string;
317 killagreg 1681
        bytecount = length;
1682
        while(bytecount > 1)                                                    // read the count-1 characters from the file to the string.
231 killagreg 1683
        {
317 killagreg 1684
                c = fgetc_(file);                                                       // read a character from the opened file.
297 killagreg 1685
                switch(c)
1686
                {
1687
                        case 0x0A:
317 killagreg 1688
                                *pbuff = 0;                                                     // set string terminator
1689
                                return(string);                                         // stop loop
297 killagreg 1690
                                break;
231 killagreg 1691
 
297 killagreg 1692
                        case EOF:
317 killagreg 1693
                                *pbuff = 0;                                                     // set string terminator
1694
                                return(0);
1695
                        default:
1696
                                *pbuff++ = (int8_t)c;                           // copy byte to string
1697
                                bytecount--;
297 killagreg 1698
                                break;
231 killagreg 1699
                }
1700
        }
317 killagreg 1701
        *pbuff = 0;
297 killagreg 1702
        return(string);
1703
}
231 killagreg 1704
 
297 killagreg 1705
/****************************************************************************************************************************************/
1706
/*      Function:               fexist_(const int8_t*);                                                                                                                                                                                                 */
1707
/*                                                                                                                                                                                                                                                                              */
1708
/*      Description:    This function checks if a file already exist.                                                                                                                                           */
1709
/*                                                                                                                                                                                                                                                                              */
1710
/*      Returnvalue:    1 if the file exist else 0.                                                                                                                                                                                     */
1711
/****************************************************************************************************************************************/
318 killagreg 1712
uint8_t fexist_(int8_t* const filename)
297 killagreg 1713
{
1714
        uint8_t exist = 0;
1715
        File_t *file = 0;
1716
        file = LockFilePointer();
1717
        exist = FileExist(filename, ATTR_NONE, ATTR_SUBDIRECTORY|ATTR_VOLUMELABEL, file);
1718
        UnlockFilePointer(file);
1719
        return(exist);
231 killagreg 1720
}
1721
 
297 killagreg 1722
/****************************************************************************************************************************************/
1723
/*      Function:               feof_(File_t *File);                                                                                                                                                                                            */
1724
/*                                                                                                                                                                                                                                                                              */
1725
/*      Description:    This function checks wether the end of the file has been reached.                                                                                                                                               */
1726
/*                                                                                                                                                                                                                                                                              */
1727
/*      Returnvalue:    0 if the end of the file was not reached otherwise 1.                                                                                                                                                                           */
1728
/****************************************************************************************************************************************/
1729
uint8_t feof_(File_t *file)
231 killagreg 1730
{
297 killagreg 1731
        if(((file->Position)+1) < (file->Size))
231 killagreg 1732
        {
297 killagreg 1733
                return(0);
231 killagreg 1734
        }
297 killagreg 1735
        else
1736
        {
1737
                return(1);
1738
        }
1739
}
231 killagreg 1740
 
1741