Subversion Repositories NaviCtrl

Rev

Rev 308 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 ingob 1
/*#######################################################################################*/
2
/* !!! THIS IS NOT FREE SOFTWARE !!!                                                     */
3
/*#######################################################################################*/
4
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
5
// + Copyright (c) 2008 Ingo Busker, Holger Buss
171 ingob 6
// + Nur für den privaten Gebrauch / NON-COMMERCIAL USE ONLY
1 ingob 7
// + FOR NON COMMERCIAL USE ONLY
8
// + www.MikroKopter.com
9
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
88 killagreg 10
// + Es gilt für das gesamte Projekt (Hardware, Software, Binärfiles, Sourcecode und Dokumentation),
11
// + dass eine Nutzung (auch auszugsweise) nur für den privaten (nicht-kommerziellen) Gebrauch zulässig ist.
12
// + Sollten direkte oder indirekte kommerzielle Absichten verfolgt werden, ist mit uns (info@mikrokopter.de) Kontakt
13
// + bzgl. der Nutzungsbedingungen aufzunehmen.
1 ingob 14
// + Eine kommerzielle Nutzung ist z.B.Verkauf von MikroKoptern, Bestückung und Verkauf von Platinen oder Bausätzen,
15
// + Verkauf von Luftbildaufnahmen, usw.
16
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
88 killagreg 17
// + Werden Teile des Quellcodes (mit oder ohne Modifikation) weiterverwendet oder veröffentlicht,
1 ingob 18
// + unterliegen sie auch diesen Nutzungsbedingungen und diese Nutzungsbedingungen incl. Copyright müssen dann beiliegen
19
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
20
// + Sollte die Software (auch auszugesweise) oder sonstige Informationen des MikroKopter-Projekts
21
// + auf anderen Webseiten oder sonstigen Medien veröffentlicht werden, muss unsere Webseite "http://www.mikrokopter.de"
22
// + eindeutig als Ursprung verlinkt werden
23
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
24
// + Keine Gewähr auf Fehlerfreiheit, Vollständigkeit oder Funktion
25
// + Benutzung auf eigene Gefahr
26
// + Wir übernehmen keinerlei Haftung für direkte oder indirekte Personen- oder Sachschäden
27
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
171 ingob 28
// + Die Portierung oder Nutzung der Software (oder Teile davon) auf andere Systeme (ausser der Hardware von www.mikrokopter.de) ist nur
1 ingob 29
// + mit unserer Zustimmung zulässig
30
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
31
// + Die Funktion printf_P() unterliegt ihrer eigenen Lizenz und ist hiervon nicht betroffen
32
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
88 killagreg 33
// + Redistributions of source code (with or without modifications) must retain the above copyright notice,
1 ingob 34
// + this list of conditions and the following disclaimer.
35
// +   * Neither the name of the copyright holders nor the names of contributors may be used to endorse or promote products derived
36
// +     from this software without specific prior written permission.
88 killagreg 37
// +   * The use of this project (hardware, software, binary files, sources and documentation) is only permitted
1 ingob 38
// +     for non-commercial use (directly or indirectly)
88 killagreg 39
// +     Commercial use (for excample: selling of MikroKopters, selling of PCBs, assembly, ...) is only permitted
1 ingob 40
// +     with our written permission
88 killagreg 41
// +   * If sources or documentations are redistributet on other webpages, out webpage (http://www.MikroKopter.de) must be
42
// +     clearly linked as origin
171 ingob 43
// +   * porting the sources to other systems or using the software on other systems (except hardware from www.mikrokopter.de) is not allowed
1 ingob 44
//
45
// +  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
46
// +  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47
// +  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48
// +  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
49
// +  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
50
// +  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
51
// +  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
52
// +  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
53
// +  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
54
// +  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
88 killagreg 55
// +  POSSIBILITY OF SUCH DAMAGE.
1 ingob 56
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
41 ingob 57
#include <stdio.h>
58
#include "91x_lib.h"
119 killagreg 59
#include "timer1.h"
41 ingob 60
#include "fat16.h"
61
#include "sdc.h"
62
#include "uart1.h"
1 ingob 63
 
64
//________________________________________________________________________________________________________________________________________
88 killagreg 65
// Module name:                 fat16.c
1 ingob 66
// Compiler used:               avr-gcc 3.4.5
211 killagreg 67
// Last Modifikation:   20.03.2010
68
// Version:                             2.10
88 killagreg 69
// Authors:                             Stephan Busker & Gregor Stobrawa
41 ingob 70
// Description:                 Source files for FAT16 implementation with read and write-access
71
//                                              Copyright (C) 2008 Stephan Busker & Gregor Stobrawa
1 ingob 72
//........................................................................................................................................
41 ingob 73
// Functions:                   extern s16              Fat16_Init(void);
88 killagreg 74
//                                              extern s16              Fat16_Deinit(void);
211 killagreg 75
//                                              extern s8*              FAT16_GetVolumeLabel(void);
41 ingob 76
//                                              extern File_t * fopen_(const u8 *filename, const s8 mode);
77
//                                              extern s16              fclose_(File_t *File);
211 killagreg 78
//                                              extern u8               fexist_(s8 * const filename);
41 ingob 79
//                                              extern s16              fflush_(File_t *File);
80
//                                              extern s16      fseek_(File_t *File, s32 offset, s16 origin);
81
//                                              extern s16              fgetc_(File_t *File);
82
//                                              extern s16              fputc_(u8 c, File_t *File);
88 killagreg 83
//                                              extern u32              fread_(void *buffer, u32 size, u32 count, File_t *File);
41 ingob 84
//                                              extern u32              fwrite_(void *buffer, u32 size, u32 count, File_t *File);
85
//                                              extern s16              fputs_(const u8 *string, File_t *File);
86
//                                              extern u8 *     fgets_(u8 *string, s16 length, File_t *File);
211 killagreg 87
//                                              extern u8               feof_(File_t * const file);
1 ingob 88
//........................................................................................................................................
41 ingob 89
// ext. functions:              extern SD_Result_t SDC_Init(void;)
90
//                                              extern SD_Result_t SDC_Deinit(void);
88 killagreg 91
//                      extern SD_Result_t SDC_GetSector (u32,u8 *);
41 ingob 92
//                                              extern SD_Result_t SDC_PutSector (u32,u8 *);
1 ingob 93
//........................................................................................................................................
94
//
95
// URL:                                 www.Mikro-Control.de
96
// mailto:                              stephan.busker@mikro-control.de
97
//________________________________________________________________________________________________________________________________________
98
 
41 ingob 99
/*
100
FAT16 Drive Layout:
101
Description                                             Offset
102
Volume Boot Sector                                      Start of Partition
103
Fat Tables                                                      Start + # of Reserved Sectors
104
Root Directory Entry                            Start + # of Reserved + (# of Sectors Per FAT * 2)
105
Data Area (Starts with Cluster #2)      Start + # of Reserved + (# of Sectors Per FAT * 2) + ((Maximum Root Directory Entries * 32) / Bytes per Sector)
106
*/
1 ingob 107
 
108
 
41 ingob 109
/*
110
________________________________________________________________________________________________________________________________________
88 killagreg 111
 
112
        Structure of an partition entry
41 ingob 113
________________________________________________________________________________________________________________________________________
1 ingob 114
 
41 ingob 115
        Partition Entry is 16 bytes long
116
*/
117
typedef struct
118
{
119
        u8      PartitionState;                         // Current State of Partition (00h=Inactive, 80h=Active)
120
        u8      BeginningHead;                          // Beginning of Partition - Head
121
        u16     BeginningCylSec;                        // Beginning of Partition - Cylinder/Sector (See Below)
122
        u8      Type;                                           // Type of Partition (See List Below)
123
        u8      EndHead;                                        // End of Partition - Head
124
        u16     EndCylSec;                                      // End of Partition - Cylinder/Sector
125
        u32     NoSectorsBeforePartition;       // Number of Sectors between the MBR and the First Sector in the Partition
126
        u32     NoSectorsPartition      ;               // Number of Sectors in the Partition
88 killagreg 127
} __attribute__((packed)) PartitionEntry_t;
1 ingob 128
 
41 ingob 129
/*
130
Coding of Cylinder/Sector words
1 ingob 131
 
41 ingob 132
Cylinder is 10 bits:  [7:0] at [15:8] and [9:8] at [7:6]
88 killagreg 133
Sector is 5 bits:  [5:0] at [5:0]
41 ingob 134
*/
1 ingob 135
 
41 ingob 136
// Partition Types:
137
#define PART_TYPE_UNKNOWN                       0x00
138
#define PART_TYPE_FAT12                         0x01
139
#define PART_TYPE_XENIX                         0x02
140
#define PART_TYPE_FAT16_ST_32_MB        0x04
141
#define PART_TYPE_EXTDOS                        0x05
142
#define PART_TYPE_FAT16_LT_32_MB        0x06
143
#define PART_TYPE_NTFS                          0x07
144
#define PART_TYPE_FAT32                         0x0B
145
#define PART_TYPE_FAT32LBA                      0x0C
146
#define PART_TYPE_FAT16LBA                      0x0E
147
#define PART_TYPE_EXTDOSLBA                     0x0F
148
#define PART_TYPE_EISA                          0x12
149
#define PART_TYPE_ONTRACK                       0x33
150
#define PART_TYPE_NOVELL                        0x40
151
#define PART_TYPE_DYNAMIC                       0x42
152
#define PART_TYPE_PCIX                          0x4B
153
#define PART_TYPE_LINUX_SWAP            0x82
154
#define PART_TYPE_LINUX_NATIVE          0x83
155
#define PART_TYPE_LINUX_LVM                     0x8E
156
#define PART_TYPE_PHOENIXSAVE           0xA0
157
#define PART_TYPE_FREEBSD                       0xA5
158
#define PART_TYPE_OPENBSD                       0xA6
159
#define PART_TYPE_NETNBSD                       0xA9
160
#define PART_TYPE_CPM                           0xDB
161
#define PART_TYPE_DBFS                          0xE0
162
#define PART_TYPE_BBT                           0xFF
1 ingob 163
 
164
 
41 ingob 165
/*
166
________________________________________________________________________________________________________________________________________
88 killagreg 167
 
168
        Structure of the MasterBootRecord
41 ingob 169
________________________________________________________________________________________________________________________________________
1 ingob 170
 
41 ingob 171
        Master Boot Record is 512 bytes long
172
        The Master Boot Record is the same for pretty much all Operating Systems.
173
        It is located on the first Sector of the Hard Drive, at Cylinder 0, Head 0, Sector 1
174
*/
175
typedef struct
176
{
88 killagreg 177
        u8                              ExecutableCode[446];    // 446 bytes for machine start code
178
        PartitionEntry_t        PartitionEntry1;                // 16 bytes for partition entry 1
179
        PartitionEntry_t        PartitionEntry2;                // 16 bytes for partition entry 2
180
        PartitionEntry_t        PartitionEntry3;                // 16 bytes for partition entry 3
181
        PartitionEntry_t        PartitionEntry4;                // 16 bytes for partition entry 4
182
        u16                                     ExecutableMarker;               // BIOS-Signature (0x55 0xAA)
183
} __attribute__((packed)) MBR_Entry_t;
1 ingob 184
 
185
 
41 ingob 186
/*
187
________________________________________________________________________________________________________________________________________
88 killagreg 188
 
189
        Structure of the VolumeBootRecord
41 ingob 190
________________________________________________________________________________________________________________________________________
24 StephanB 191
 
41 ingob 192
        The Volume Boot Record is 512 bytes long
193
        This information is located in the first sector of every partition.
194
*/
195
typedef struct
196
{
197
        u8  JumpCode[3];                        // Jump Code + NOP
88 killagreg 198
        s8  OEMName[8];                         // OEM Name
41 ingob 199
        u16 BytesPerSector;                     // Bytes Per Sector
200
        u8  SectorsPerCluster;          // Sectors Per Cluster
201
        u16 ReservedSectors;            // Reserved Sectors
202
        u8  NoFATCopies;                        // Number of Copies of FAT
88 killagreg 203
        u16 MaxRootEntries;                     // Maximum Root Directory Entries
41 ingob 204
        u16 NoSectorsInPartSml32MB;     // Number of Sectors in Partition Smaller than 32 MB
205
        u8  MediaDescriptor;            // Media Descriptor (0xF8 for Hard Disks)
206
        u16 SectorsPerFAT;                      // Sectors Per FAT
207
        u16 SectorsPerTrack;            // Sectors Per Track
208
        u16 NoHeads;                            // Number of Heads
209
        u32 NoHiddenSectors;            // Number of Hidden Sectors     in Partition
210
        u32 NoSectors;                          // Number of Sectors in Partition
211
        u16     DriveNo;                                // Logical Drive Number of Partition
212
        u8  ExtendedSig;                        // Extended Signature (0x29)
213
        u32 SerialNo;                           // Serial Number of the Partition
214
        s8  VolumeName[11];                     // Volume Name of the Partititon
215
        s8  FATName[8];                         // FAT Name (FAT16)
88 killagreg 216
        u8  ExecutableCode[446];        // 446 bytes for machine start code
217
        u16 ExecutableMarker;           // Executable Marker (0x55 0xAA)
218
} __attribute__((packed)) VBR_Entry_t;
1 ingob 219
 
220
 
221
 
41 ingob 222
/*
223
________________________________________________________________________________________________________________________________________
224
 
88 killagreg 225
        Structure of an directory entry
41 ingob 226
________________________________________________________________________________________________________________________________________
227
 
228
        Directory entry is 32 bytes.
229
*/
230
typedef struct
1 ingob 231
{
41 ingob 232
        s8      Name[8];                                        // 8 bytes name, padded with spaces.
233
        u8      Extension[3];                           // 3 bytes extension, padded with spaces.
234
        u8      Attribute;                                      // attribute of the directory entry (unused,archive,read-only,system,directory,volume)
211 killagreg 235
        u8  Res1;                                               // should be zero
236
        u8  CreationTime10ms;                   // subsecond resolution of creation time
237
        u16 CreationTime;                               // Time of creation h:m:s
238
        u16 CreationDate;                               // Date of creation Y.M.D
239
        u16 LastAccessDate;             // The date where the file was last accessed
240
        u8      Res2[2];                                    // should be zero
241
        u16 ModTime;                                    // date of last write access
242
        u16 ModDate;                                    // date of last write access to the file or directory.
41 ingob 243
        u16 StartCluster;                               // first cluster of the file or directory.
244
        u32 Size;                                               // size of the file or directory in bytes.
245
}  __attribute__((packed)) DirEntry_t;
1 ingob 246
 
41 ingob 247
#define SLOT_EMPTY              0x00    // slot has never been used
248
#define SLOT_E5                 0x05    // the real value is 0xe5
249
#define SLOT_DELETED            0xE5    // file in this slot deleted
1 ingob 250
 
41 ingob 251
#define ATTR_NONE               0x00    // normal file
252
#define ATTR_READONLY           0x01    // file is readonly
253
#define ATTR_HIDDEN                     0x02    // file is hidden
254
#define ATTR_SYSTEM                     0x04    // file is a system file
255
#define ATTR_VOLUMELABEL        0x08    // entry is a volume label
256
#define ATTR_LONG_FILENAME      0x0F    // this is a long filename entry
257
#define ATTR_SUBDIRECTORY       0x10    // entry is a directory name
258
#define ATTR_ARCHIVE            0x20    // file is new or modified
24 StephanB 259
 
260
 
41 ingob 261
/*
262
________________________________________________________________________________________________________________________________________
88 killagreg 263
 
264
        Structure of an entry within the fileallocationtable.
41 ingob 265
________________________________________________________________________________________________________________________________________
266
*/
267
typedef struct
268
{
269
        u16  NextCluster;                               // the next cluster of the file.
270
} __attribute__((packed)) Fat16Entry_t;
1 ingob 271
 
41 ingob 272
// secial fat entries
273
#define FAT16_CLUSTER_FREE                      0x0000
274
#define FAT16_CLUSTER_RESERVED          0x0001
275
#define FAT16_CLUSTER_USED_MIN          0x0002
276
#define FAT16_CLUSTER_USED_MAX          0xFFEF
277
#define FAT16_CLUSTER_ROOTDIR_MIN       0xFFF0
278
#define FAT16_CLUSTER_ROOTDIR_MAX       0xFFF6
279
#define FAT16_CLUSTER_BAD                       0xFFF7
280
#define FAT16_CLUSTER_LAST_MIN          0xFFF8
281
#define FAT16_CLUSTER_LAST_MAX          0xFFFF
282
 
88 killagreg 283
/*****************************************************************************************************************************************/
41 ingob 284
/*                                                                                                                                                                                                                                                                               */
285
/*      Global variables needed for read- or write-acces to the FAT16- filesystem.                                                                                                                       */
286
/*                                                                                                                                                                                                                                                                               */
287
/*****************************************************************************************************************************************/
288
 
289
#define MBR_SECTOR                                      0x00    // the masterboot record is located in sector 0.
290
#define DIRENTRY_SIZE                           32              //bytes
291
#define DIRENTRIES_PER_SECTOR           BYTES_PER_SECTOR/DIRENTRY_SIZE
292
#define FAT16_BYTES                                     2
293
#define FAT16_ENTRIES_PER_SECTOR        BYTES_PER_SECTOR/FAT16_BYTES
294
 
211 killagreg 295
#define SECTOR_UNDEFINED        0x00000000L
296
#define CLUSTER_UNDEFINED       0x0000
297
 
88 killagreg 298
#define FSTATE_UNUSED   0
41 ingob 299
#define FSTATE_USED             1
300
 
301
typedef struct
1 ingob 302
{
41 ingob 303
        u8      IsValid;                                // 0 means invalid, else valid
304
        u8      SectorsPerCluster;              // how many sectors does a cluster contain?
305
        u8      FatCopies;                              // Numbers of copies of the FAT
306
        u16     MaxRootEntries;                 // Possible number of entries in the root directory.
307
        u16     SectorsPerFat;                  // how many sectors does a fat16 contain?
308
        u32 FirstFatSector;                     // sector of the start of the fat
309
        u32 FirstRootDirSector;         // sector of the rootdirectory
310
        u32 FirstDataSector;            // sector of the first cluster containing data (cluster2).
311
        u32 LastDataSector;                     // the last data sector of the partition
210 killagreg 312
        u8 VolumeLabel[12];                     // the volume label
41 ingob 313
} Partition_t;
1 ingob 314
 
41 ingob 315
Partition_t     Partition;                                      // Structure holds partition information
1 ingob 316
 
41 ingob 317
File_t FilePointer[FILE_MAX_OPEN];      // Allocate Memmoryspace for each filepointer used.
1 ingob 318
 
41 ingob 319
 
320
/****************************************************************************************************************************************/
211 killagreg 321
/*      Function:               FileDate(DateTime_t *);                                                                                                                                                                                         */
41 ingob 322
/*                                                                                                                                                                                                                                                                              */
211 killagreg 323
/*      Description:    This function calculates the DOS date from a pointer to a time structure.                                                                                       */
41 ingob 324
/*                                                                                                                                                                                                                                                                              */
211 killagreg 325
/*      Returnvalue:    Returns the DOS date.                                                                                                                                                                                           */
41 ingob 326
/****************************************************************************************************************************************/
211 killagreg 327
u16 FileDate(DateTime_t * pTimeStruct)
328
{
329
        u16 date = 0;
330
        if(pTimeStruct == NULL)   return date;
331
        if(!(pTimeStruct->Valid)) return date;
41 ingob 332
 
211 killagreg 333
        date |= (0x007F & (u16)(pTimeStruct->Year - 1980))<<9; // set year
334
        date |= (0x000F & (u16)(pTimeStruct->Month))<<5; // set month
335
        date |= (0x001F & (u16)(pTimeStruct->Day));
336
        return date;
337
}
338
 
339
/****************************************************************************************************************************************/
340
/*      Function:               FileTime(DateTime_t *);                                                                                                                                                                                         */
341
/*                                                                                                                                                                                                                                                                              */
342
/*      Description:    This function calculates the DOS time from a pointer to a time structure.                                                                                       */
343
/*                                                                                                                                                                                                                                                                              */
344
/*      Returnvalue:    Returns the DOS time.                                                                                                                                                                                           */
345
/****************************************************************************************************************************************/
346
 
347
u16 FileTime(DateTime_t * pTimeStruct)
1 ingob 348
{
211 killagreg 349
        u16 time = 0;
350
        if(pTimeStruct == NULL)   return time;
351
        if(!(pTimeStruct->Valid)) return time;
24 StephanB 352
 
211 killagreg 353
        time |= (0x001F & (u16)(pTimeStruct->Hour))<<11;
354
        time |= (0x003F & (u16)(pTimeStruct->Min))<<5;
355
        time |= (0x001F & (u16)(pTimeStruct->Sec/2));
356
        return time;
1 ingob 357
}
358
 
41 ingob 359
/****************************************************************************************************************************************/
360
/*      Function:               LockFilePointer();                                                                                                                                                                                                      */
361
/*                                                                                                                                                                                                                                                                              */
362
/*      Description:    This function trys to lock a free file pointer.                                                                                                                                         */
363
/*                                                                                                                                                                                                                                                                              */
364
/*      Returnvalue:    Returns the Filepointer on success or 0.                                                                                                                                                        */
365
/****************************************************************************************************************************************/
366
File_t * LockFilePointer(void)
1 ingob 367
{
41 ingob 368
        u8 i;
369
        File_t * File = 0;
370
        for(i = 0; i < FILE_MAX_OPEN; i++)
1 ingob 371
        {
88 killagreg 372
                if(FilePointer[i].State == FSTATE_UNUSED)               // found an unused one
1 ingob 373
                {
88 killagreg 374
                        File = &FilePointer[i];                                         // set pointer to that entry
41 ingob 375
                        FilePointer[i].State = FSTATE_USED;                     // mark it as used
376
                        break;
1 ingob 377
                }
41 ingob 378
        }
379
        return(File);
1 ingob 380
}
381
 
41 ingob 382
/****************************************************************************************************************************************/
383
/*      Function:               UnlockFilePointer(file_t *);                                                                                                                                                                            */
384
/*                                                                                                                                                                                                                                                                              */
385
/*      Description:    This function trys to unlock a file pointer.                                                                                                                                            */
386
/*                                                                                                                                                                                                                                                                              */
387
/*      Returnvalue:    Returns 1 if file pointer was freed else 0.                                                                                                                                                     */
388
/****************************************************************************************************************************************/
389
u8 UnlockFilePointer(File_t * file)
1 ingob 390
{
41 ingob 391
        u8 cnt;
392
        if(file == NULL) return(0);
393
        for(cnt = 0; cnt < FILE_MAX_OPEN; cnt++)
1 ingob 394
        {
41 ingob 395
                if(&FilePointer[cnt] == file)                                           // filepointer to be freed found?
1 ingob 396
                {
88 killagreg 397
                        file->State = FSTATE_UNUSED;
211 killagreg 398
                        file->FirstSectorOfFirstCluster = SECTOR_UNDEFINED;                     // Sectorpointer to the first sector of the first datacluster of the file.
399
                        file->FirstSectorOfCurrCluster  = SECTOR_UNDEFINED;                     // Pointer to the cluster which is edited at the moment.
41 ingob 400
                        file->SectorOfCurrCluster               = 0;                    // The sector which is edited at the moment (cluster_pointer + sector_index).
401
                        file->ByteOfCurrSector                  = 0;                    // The bytelocation within the current sector (cluster_pointer + sector_index + byte_index).
402
                        file->Mode                                              = 0;                    // mode of fileoperation (read,write)
403
                        file->Size                                              = 0;                    // the size of the opend file in bytes.
404
                        file->Position                                  = 0;                    // pointer to a character within the file 0 < fileposition < filesize
211 killagreg 405
                        file->SectorInCache                     = SECTOR_UNDEFINED;                     // the last sector read, wich is still in the sectorbuffer.
406
                        file->DirectorySector                   = SECTOR_UNDEFINED;                     // the sectorposition where the directoryentry has been made.
41 ingob 407
                        file->DirectoryIndex                    = 0;                    // the index to the directoryentry within the specified sector.
408
                        file->Attribute                                 = 0;                    // the attribute of the file opened.
88 killagreg 409
                        file = NULL;
41 ingob 410
                        return(1);
1 ingob 411
                }
41 ingob 412
        }
413
        return(0);
414
}
1 ingob 415
 
41 ingob 416
/****************************************************************************************************************************************/
417
/*      Function:               SeperateDirName(s8*, s8*);                                                                                                                                                                              */
418
/*                                                                                                                                                                                                                                                                              */
419
/*      Description:    This function seperates the first dirname from filepath and brings them                                                                                         */
420
/*                                      into the needed format ('test.txt' -> 'TEST    TXT')                                                                                                                            */
210 killagreg 421
/*                                      The subpath is the pointer to the remaining substring of the filepath                                                                                           */
41 ingob 422
/*                                                                                                                                                                                                                                                                              */
423
/*      Returnvalue:    Return NULL on error or pointer to subpath                                                                                                                                                                                                      */
424
/****************************************************************************************************************************************/
425
s8* SeperateDirName(const s8 *filepath, s8 *dirname)
426
{
427
        s8* subpath = NULL;
428
        u8 readpointer  = 0;
429
        u8 writepointer = 0;
1 ingob 430
 
88 killagreg 431
        // search subpath from beginning of filepath
41 ingob 432
        subpath = NULL;
433
        readpointer     = 0;
434
        if(filepath[0] == '/') readpointer = 1; // ignore first '/'
88 killagreg 435
        while(subpath == NULL)  // search the filepath until a subpath was found.
1 ingob 436
        {
88 killagreg 437
                if(((filepath[readpointer] == 0) || (filepath[readpointer] == '/')))    // if '/' found or end of filepath reached
438
                {
41 ingob 439
                        subpath = (s8*)&filepath[readpointer];                          // store the position of the first "/" found after the beginning of the filenpath
440
                }
441
                readpointer++;
442
        }
1 ingob 443
 
41 ingob 444
        // clear dirname with spaces
445
        dirname[11] = 0; // terminate dirname
446
        for(writepointer = 0; writepointer < 11; writepointer++) dirname[writepointer] = ' ';
447
        writepointer = 0;
448
        // start seperating the dirname from the filepath.
449
        readpointer = 0;
450
        if(filepath[0] == '/') readpointer = 1; // ignore first '/'
451
        while( &filepath[readpointer] < subpath)
1 ingob 452
        {
41 ingob 453
                if(writepointer >= 11) return(NULL);            // dirname to long
454
                if(filepath[readpointer] == '.')                        // seperating dirname and extension.
1 ingob 455
                {
41 ingob 456
                        if(writepointer <= 8)
1 ingob 457
                        {
41 ingob 458
                                readpointer++;                                          // next character in filename
459
                                writepointer = 8;                                       // jump to start of extension
1 ingob 460
                        }
88 killagreg 461
                        else return(NULL);                                              // dirbasename to long
41 ingob 462
                }
463
                else
464
                {
465
                        if((0x60 < filepath[readpointer]) && (filepath[readpointer] < 0x7B))
466
                        {
467
                                dirname[writepointer] = (filepath[readpointer] - 0x20);                                 // all characters must be upper case.
468
                        }
1 ingob 469
                        else
470
                        {
41 ingob 471
                                dirname[writepointer] = filepath[readpointer];
88 killagreg 472
                        }
41 ingob 473
                        readpointer++;
474
                        writepointer++;
1 ingob 475
                }
41 ingob 476
        }
88 killagreg 477
        return(subpath);
1 ingob 478
}
479
 
480
 
41 ingob 481
/**************************************************************************************************************************************+*/
482
/*      Function:       Fat16ClusterToSector( u16 cluster);                                                                                                                                                                             */
483
/*                                                                                                                                                                                                                                                                              */
484
/*      Description:    This function converts a cluster number given by the fat to the corresponding                                                                           */
485
/*                                      sector that points to the start of the data area that is represented by the cluster number.                                                     */
486
/*                                                                                                                                                                                                                                                                              */
487
/*      Returnvalue: The sector number with the data area of the given cluster                                                                                                                          */
488
/****************************************************************************************************************************************/
489
u32     Fat16ClusterToSector(u16 cluster)
490
{
211 killagreg 491
        if(!Partition.IsValid) return SECTOR_UNDEFINED;
218 killagreg 492
        if ((cluster < 2) || (cluster == CLUSTER_UNDEFINED))
211 killagreg 493
        {
494
                return SECTOR_UNDEFINED;
495
        }
496
        else
497
        {
498
                return ( (cluster - 2) * Partition.SectorsPerCluster) + Partition.FirstDataSector; // the first data sector     is represented by the 2nd cluster
499
        }
41 ingob 500
}
501
 
502
/****************************************************************************************************************************************/
503
/*      Function:       SectorToFat16Cluster( u32 sector);                                                                                                                                                                              */
504
/*                                                                                                                                                                                                                                                                              */
505
/*      Description:    This function converts a given sector number given to the corresponding                                                                                         */
506
/*                                      cluster number in the fat that represents this data area.                                                                                                                       */
507
/*                                                                                                                                                                                                                                                                              */
508
/*      Returnvalue: The cluster number representing the data area of the sector.                                                                                                                       */
509
/****************************************************************************************************************************************/
510
u16     SectorToFat16Cluster(u32 sector)
511
{
211 killagreg 512
        if(!Partition.IsValid) return CLUSTER_UNDEFINED;
513
        if((sector == SECTOR_UNDEFINED) || (sector < Partition.FirstDataSector)) return CLUSTER_UNDEFINED;
514
        else return ((u16)((sector - Partition.FirstDataSector) / Partition.SectorsPerCluster) + 2);
41 ingob 515
}
516
 
517
 
518
/****************************************************************************************************************************************/
210 killagreg 519
/*      Function:       Fat16_IsValid(void);                                                                                                                                                                                                    */
90 killagreg 520
/*                                                                                                                                                                                                                                                                              */
210 killagreg 521
/*      Description:    This function return the Fat 16 filesystem state                                                                                                                                        */
90 killagreg 522
/*                                                                                                                                                                                                                                                                              */
523
/*      Returnvalue: The function returns "1" on success                                                                                                                                                                        */
524
/****************************************************************************************************************************************/
525
u8 Fat16_IsValid(void)
526
{
527
        return(Partition.IsValid);
528
}
529
 
530
/****************************************************************************************************************************************/
41 ingob 531
/*      Function:       Fat16_Deinit(void);                                                                                                                                                                                                             */
532
/*                                                                                                                                                                                                                                                                              */
533
/*      Description:    This function uninitializes the fat 16 api                                                                                                                                                      */
534
/*                                                                                                                                                                                                                                                                              */
535
/*      Returnvalue: The function returns "0" on success                                                                                                                                                                        */
536
/****************************************************************************************************************************************/
537
u8 Fat16_Deinit(void)
538
{
539
        s16 returnvalue = 0;
540
        u8 cnt;
146 killagreg 541
 
542
        UART1_PutString("\r\n FAT16 deinit...");
41 ingob 543
        // declare the filepointers as unused.
544
        for(cnt = 0; cnt < FILE_MAX_OPEN; cnt++)
1 ingob 545
        {
41 ingob 546
                if(FilePointer[cnt].State == FSTATE_USED)
1 ingob 547
                {
41 ingob 548
                        returnvalue += fclose_(&FilePointer[cnt]); // try to close open file pointers
1 ingob 549
                }
211 killagreg 550
                else UnlockFilePointer(&FilePointer[cnt]);
88 killagreg 551
 
1 ingob 552
        }
41 ingob 553
        SDC_Deinit();                   // uninitialize interface to sd-card
554
        Partition.IsValid = 0;  // mark data in partition structure as invalid
210 killagreg 555
        Partition.VolumeLabel[0]='\0';
146 killagreg 556
        UART1_PutString("ok");
41 ingob 557
        return(returnvalue);
1 ingob 558
}
559
 
41 ingob 560
/****************************************************************************************************************************************/
561
/*      Function:               Fat16_Init(void);                                                                                                                                                                                                       */
562
/*                                                                                                                                                                                                                                                                          */
563
/*      Description:    This function reads the Masterbootrecord and finds the position of the Volumebootrecord, the FAT and the Rootdir    */
564
/*                                      and stores the information in global variables.                                                                                                                                     */
565
/*                                                                                                                                                                                                                                                                          */
566
/*      Returnvalue:    The function returns "0" if the filesystem is initialized.                                                                                                                      */
567
/****************************************************************************************************************************************/
568
u8 Fat16_Init(void)
88 killagreg 569
{
41 ingob 570
    u8  cnt     = 0;
571
        u32     partitionfirstsector;
88 killagreg 572
        VBR_Entry_t *VBR;
41 ingob 573
        MBR_Entry_t *MBR;
574
        File_t *file;
575
        u8 result = 0;
1 ingob 576
 
110 killagreg 577
        UART1_PutString("\r\n FAT16 init...");
41 ingob 578
        Partition.IsValid = 0;
579
 
580
        // declare the filepointers as unused.
581
        for(cnt = 0; cnt < FILE_MAX_OPEN; cnt++)
1 ingob 582
        {
211 killagreg 583
                UnlockFilePointer(&FilePointer[cnt]);
1 ingob 584
        }
41 ingob 585
        // set current file pinter to first position in list
88 killagreg 586
        file = &FilePointer[0];
587
 
211 killagreg 588
        // try to initialize the sd-card.
88 killagreg 589
        if(SD_SUCCESS != SDC_Init())
590
        {
110 killagreg 591
                UART1_PutString("SD-Card could not be initialized.");
41 ingob 592
                result = 1;
88 killagreg 593
                goto end;
41 ingob 594
        }
1 ingob 595
 
41 ingob 596
        // SD-Card is initialized successfully
597
        if(SD_SUCCESS != SDC_GetSector((u32)MBR_SECTOR,file->Cache))    // Read the MasterBootRecord
1 ingob 598
        {
110 killagreg 599
                UART1_PutString("Error reading the MBR.");
41 ingob 600
                result = 2;
88 killagreg 601
                goto end;
1 ingob 602
        }
41 ingob 603
        MBR = (MBR_Entry_t *)file->Cache;                                               // Enter the MBR using the structure MBR_Entry_t.
88 killagreg 604
        if((MBR->PartitionEntry1.Type == PART_TYPE_FAT16_ST_32_MB) ||
41 ingob 605
           (MBR->PartitionEntry1.Type == PART_TYPE_FAT16_LT_32_MB) ||
606
           (MBR->PartitionEntry1.Type == PART_TYPE_FAT16LBA))
1 ingob 607
        {
41 ingob 608
                // get sector offset 1st partition
609
                partitionfirstsector = MBR->PartitionEntry1.NoSectorsBeforePartition;
610
                // Start of Partition is the Volume Boot Sector
611
                if(SD_SUCCESS != SDC_GetSector(partitionfirstsector,file->Cache)) // Read the volume boot record
1 ingob 612
                {
110 killagreg 613
                        UART1_PutString("Error reading the VBR.");
41 ingob 614
                        result = 3;
88 killagreg 615
                        goto end;
616
                }
1 ingob 617
        }
41 ingob 618
        else  // maybe the medium has no partition assuming sector 0 is the vbr
619
        {
620
                partitionfirstsector = 0;
621
        }
88 killagreg 622
 
41 ingob 623
        VBR = (VBR_Entry_t *) file->Cache;                                              // Enter the VBR using the structure VBR_Entry_t.
624
        if(VBR->BytesPerSector != BYTES_PER_SECTOR)
625
        {
110 killagreg 626
                UART1_PutString("VBR: Sector size not supported.");
41 ingob 627
                result = 4;
88 killagreg 628
                goto end;
41 ingob 629
        }
630
        Partition.SectorsPerCluster             = VBR->SectorsPerCluster;                       // Number of sectors per cluster. Depends on the memorysize of the sd-card.
631
        Partition.FatCopies                     = VBR->NoFATCopies;                                     // Number of fatcopies.
632
        Partition.MaxRootEntries                = VBR->MaxRootEntries;                          // How many Entries are possible in the rootdirectory (FAT16 allows max. 512 entries).
210 killagreg 633
        Partition.SectorsPerFat                 = VBR->SectorsPerFAT;                           // The number of sectors per FAT                                // copy volume label
634
        Partition.VolumeLabel[0] = '\0';                                                                        // set string terminator
41 ingob 635
 
636
        /* Calculate the sectorpositon of the FAT, the Rootdirectory and the first Datacluster. */
88 killagreg 637
        // Calculate the position of the FileAllocationTable:
41 ingob 638
        // Start + # of Reserved Sectors
88 killagreg 639
        Partition.FirstFatSector        =   (u32)(partitionfirstsector + (u32)(VBR->ReservedSectors));
640
        // Calculate the position of the Rootdirectory:
641
        // Start + # of Reserved Sectors + (# of Sectors Per FAT * # of FAT Copies)
41 ingob 642
        Partition.FirstRootDirSector    =   Partition.FirstFatSector + (u32)((u32)Partition.SectorsPerFat*(u32)Partition.FatCopies);
643
        // Calculate the position of the first datacluster:
88 killagreg 644
        // Start + # of Reserved + (# of Sectors Per FAT * # of FAT Copies) + ((Maximum Root Directory Entries * 32) / Bytes per Sector)
41 ingob 645
        Partition.FirstDataSector       =   Partition.FirstRootDirSector + (u32)(Partition.MaxRootEntries>>4);  // assuming 512 Byte Per Sector
646
        // Calculate the last data sector
647
        if(VBR->NoSectors == 0)
648
        {
110 killagreg 649
                UART1_PutString("VBR: Bad number of sectors.");
41 ingob 650
                result = 5;
88 killagreg 651
                goto end;
41 ingob 652
        }
653
        Partition.LastDataSector = Partition.FirstDataSector + VBR->NoSectors - 1;
654
        // check for FAT16 in VBR of first partition
655
        if(!((VBR->FATName[0]=='F') && (VBR->FATName[1]=='A') && (VBR->FATName[2]=='T') && (VBR->FATName[3]=='1')&&(VBR->FATName[4]=='6')))
656
        {
110 killagreg 657
                UART1_PutString("VBR: Partition ist not FAT16 type.");
41 ingob 658
                result = 6;
659
                goto end;
660
        }
661
        Partition.IsValid = 1; // mark data in partition structure as valid
662
        result = 0;
663
        end:
664
        if(result != 0) Fat16_Deinit();
110 killagreg 665
        else UART1_PutString("ok");
88 killagreg 666
        return(result);
1 ingob 667
}
668
 
669
 
41 ingob 670
 
671
/****************************************************************************************************************************************/
672
/* Function:    ClearCurrCluster(File_t*);                                                                                                                                                                                      */
673
/*                                                                                                                                                                                                                                                                              */
674
/* Description: This function fills the current cluster with 0.                                                                                                                                                 */
675
/*                                                                                                                                                                                                                                                                              */
676
/* Returnvalue: The function returns 1 on success else 0.                                                                                                                                                               */
677
/****************************************************************************************************************************************/
678
u8 ClearCurrCluster(File_t * file)
1 ingob 679
{
41 ingob 680
        u8 retvalue = 1;
681
        u32 i;
88 killagreg 682
 
41 ingob 683
        if((!Partition.IsValid) || (file == NULL)) return(0);
684
 
685
        for(i = 0; i < BYTES_PER_SECTOR; i++) file->Cache[i] = 0; // clear file cache
211 killagreg 686
        if(file->FirstSectorOfCurrCluster == SECTOR_UNDEFINED) return (0); // nothing to do 
41 ingob 687
        for(i = 0; i < Partition.SectorsPerCluster; i++)
1 ingob 688
        {
41 ingob 689
                file->SectorInCache = file->FirstSectorOfCurrCluster + i;
690
                if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))
691
                {
88 killagreg 692
                        Fat16_Deinit();
41 ingob 693
                        retvalue = 0;
282 killagreg 694
                        return(retvalue);
41 ingob 695
                }
1 ingob 696
        }
88 killagreg 697
        return(retvalue);
1 ingob 698
}
699
 
41 ingob 700
/*****************************************************************************************************************************************/
701
/* Function:    GetNextCluster(File_t* );                                                                                                                                                                                        */
702
/*                                                                                                                                                                                                                                                                               */
703
/* Description: This function finds the next datacluster of the file specified with File *File.                                                                                  */
704
/*                                                                                                                                                                                                                                                                               */
705
/* Returnvalue: The function returns the next cluster or 0 if the last cluster has already reached.                                                                                                      */
706
/*****************************************************************************************************************************************/
707
u16 GetNextCluster(File_t * file)
1 ingob 708
{
211 killagreg 709
        u16 cluster = CLUSTER_UNDEFINED;
41 ingob 710
        u32 fat_byte_offset, sector, byte;
711
        Fat16Entry_t * fat;
88 killagreg 712
 
41 ingob 713
        if((!Partition.IsValid) || (file == NULL)) return(cluster);
211 killagreg 714
        if(file->FirstSectorOfCurrCluster == SECTOR_UNDEFINED) return(cluster);
41 ingob 715
        // if sector is within the data area
716
        if((Partition.FirstDataSector <= file->FirstSectorOfCurrCluster)&& (file->FirstSectorOfCurrCluster <= Partition.LastDataSector))
1 ingob 717
        {
41 ingob 718
                // determine current file cluster
719
                cluster = SectorToFat16Cluster(file->FirstSectorOfCurrCluster);
720
                // calculate byte offset in the fat for corresponding entry
721
                fat_byte_offset = ((u32)cluster)<<1; // two FAT bytes (16 bits) for every cluster
722
                // calculate the sector that contains the current cluster within the fat
723
                sector = Partition.FirstFatSector + ( fat_byte_offset / BYTES_PER_SECTOR);
724
                // calculate byte offset of the current cluster within that fat sector
725
                byte = fat_byte_offset % BYTES_PER_SECTOR;
726
                // read this sector to the file cache
727
                if(file->SectorInCache != sector)
1 ingob 728
                {
41 ingob 729
                        file->SectorInCache = sector;                                           // update sector stored in buffer
730
                        if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))       // read sector from sd-card
24 StephanB 731
                        {
41 ingob 732
                                Fat16_Deinit();
733
                                return (cluster);
88 killagreg 734
                        }
735
                }
41 ingob 736
                // read the next cluster from cache
737
                fat = (Fat16Entry_t *)(&(file->Cache[byte]));
738
                cluster = fat->NextCluster;
211 killagreg 739
                // if no next cluster exist
41 ingob 740
                if(FAT16_CLUSTER_LAST_MIN <= cluster)
741
                {
211 killagreg 742
                         cluster = CLUSTER_UNDEFINED; // next cluster is undefined
1 ingob 743
                }
24 StephanB 744
                else
745
                {
41 ingob 746
                        file->FirstSectorOfCurrCluster = Fat16ClusterToSector(cluster);
747
                        file->SectorOfCurrCluster = 0;
748
                        file->ByteOfCurrSector = 0;
24 StephanB 749
                }
88 killagreg 750
        }
41 ingob 751
        return(cluster);
1 ingob 752
}
753
 
754
 
41 ingob 755
/****************************************************************************************************************************************/
756
/* Function:    FindNextFreeCluster(File_t *);                                                                                                                                                                          */
757
/*                                                                                                                                                                                                                                                                              */
758
/* Description: This function looks in the fat to find the next free cluster                                                                                                                    */
759
/*                                                                                                                                                                                                                                                                              */
760
/* Returnvalue: The function returns the cluster number of the next free cluster found within the fat.                                                                  */
761
/****************************************************************************************************************************************/
762
u16 FindNextFreeCluster(File_t *file)
1 ingob 763
{
41 ingob 764
        u32 fat_sector;                                 // current sector within the fat relative to the first sector of the fat.
765
        u32     curr_sector;                            // current sector
766
        u16     fat_entry;                                      // index to an fatentry within the actual sector (256 fatentries are possible within one sector).
211 killagreg 767
        u16     free_cluster    = CLUSTER_UNDEFINED;    // next free cluster number.
41 ingob 768
        Fat16Entry_t * fat;
88 killagreg 769
 
41 ingob 770
        if((!Partition.IsValid) || (file == NULL)) return(0);
24 StephanB 771
 
41 ingob 772
        // start searching for an empty cluster at the beginning of the fat.
88 killagreg 773
        fat_sector = 0;
774
        do
1 ingob 775
        {
41 ingob 776
                curr_sector = Partition.FirstFatSector + fat_sector;    // calculate sector to read
777
                file->SectorInCache = curr_sector;                                              // upate the sector number of file cache.
778
                if( SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))              // read sector of fat from sd-card.
779
                {
780
                        Fat16_Deinit();
781
                        return(free_cluster);
782
                }
783
 
784
                fat = (Fat16Entry_t *)file->Cache;                                              // set fat pointer to file cache
785
 
88 killagreg 786
                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.
41 ingob 787
                {
788
                        if(fat[fat_entry].NextCluster == FAT16_CLUSTER_FREE)            // empty cluster found!!
88 killagreg 789
                        {
790
                                fat[fat_entry].NextCluster = FAT16_CLUSTER_LAST_MAX;    // mark this fat-entry as used
41 ingob 791
                                if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))               // and save the sector at the sd-card.
792
                                {
793
                                        Fat16_Deinit();
794
                                        return(free_cluster);
795
                                }
88 killagreg 796
                                free_cluster = (u16)(fat_sector * FAT16_ENTRIES_PER_SECTOR + (u32)fat_entry);
41 ingob 797
                                fat_entry = FAT16_ENTRIES_PER_SECTOR;                                   // terminate the search for a free cluster in this sector.
798
                        }
799
                }
800
                fat_sector++;                                                                                                   // continue the search in next fat sector
88 killagreg 801
        // repeat until the end of the fat is  reached and no free cluster has been found so far
41 ingob 802
        }while((fat_sector < Partition.SectorsPerFat) && (!free_cluster));
803
        return(free_cluster);
1 ingob 804
}
805
 
806
 
41 ingob 807
/****************************************************************************************************************************************************/
808
/* Function:    s16 fseek_(File_t *, s32 *, u8)                                                                                                                                                                                                         */
809
/*                                                                                                                                                                                                                                                                                                      */
810
/* Description: This function sets the pointer of the stream relative to the position                                                                                                                           */
811
/*                              specified by origin (SEEK_SET, SEEK_CUR, SEEK_END)                                                                                                                                                                      */
211 killagreg 812
/* Returnvalue: Is 0 if seek was successful                                                                                                                                                                                                                                                                     */
41 ingob 813
/****************************************************************************************************************************************************/
814
s16 fseek_(File_t *file, s32 offset, s16 origin)
1 ingob 815
{
41 ingob 816
        s32             fposition       = 0;
817
        s16     retvalue        = 1;
88 killagreg 818
 
211 killagreg 819
        if((!Partition.IsValid) || (file == NULL)) return(retvalue);
41 ingob 820
        switch(origin)
821
        {
822
                case SEEK_SET:                          // Fileposition relative to the beginning of the file.
88 killagreg 823
                        fposition = 0;
41 ingob 824
                        break;
825
                case SEEK_END:                          // Fileposition relative to the end of the file.
826
                        fposition = (s32)file->Size;
827
                        break;
828
                case SEEK_CUR:                          // Fileposition relative to the current position of the file.
829
                default:
830
                        fposition = file->Position;
831
                        break;
1 ingob 832
        }
41 ingob 833
 
834
        fposition += offset;
835
 
836
        if((fposition >= 0) && (fposition <= (s32)file->Size))          // is the pointer still within the file?
1 ingob 837
        {
41 ingob 838
                // reset file position to start of the file
839
                file->FirstSectorOfCurrCluster = file->FirstSectorOfFirstCluster;
840
                file->SectorOfCurrCluster       = 0;
841
                file->ByteOfCurrSector          = 0;
842
                file->Position                          = 0;
211 killagreg 843
                if(file->FirstSectorOfCurrCluster == SECTOR_UNDEFINED) return(retvalue);
41 ingob 844
                while(file->Position < fposition)       // repeat until the current position is less than target
1 ingob 845
                {
41 ingob 846
                        file->Position++;                               // increment file position
88 killagreg 847
                        file->ByteOfCurrSector++;               // next byte in current sector
848
                        if(file->ByteOfCurrSector >= BYTES_PER_SECTOR)
41 ingob 849
                        {
850
                                file->ByteOfCurrSector = 0;                                                                             // reading at the beginning of new sector.
851
                                file->SectorOfCurrCluster++;                                                                    // continue reading in next sector
852
                                if(file->SectorOfCurrCluster >= Partition.SectorsPerCluster)    // if end of cluster is reached, the next datacluster has to be searched in the FAT.
853
                                {
854
                                        if(GetNextCluster(file))                                                                        // Sets the clusterpointer of the file to the next datacluster.
855
                                        {
88 killagreg 856
                                                file->SectorOfCurrCluster = 0;
41 ingob 857
                                        }
858
                                        else // the last cluster was allready reached
859
                                        {
211 killagreg 860
                                                file->SectorOfCurrCluster--;                                                    // jump back to the last sector in the last cluster
41 ingob 861
                                                file->ByteOfCurrSector = BYTES_PER_SECTOR;                              // set ByteOfCurrSector one byte over sector end
862
                                        }
863
                                }
88 killagreg 864
                        }
865
                }
1 ingob 866
        }
88 killagreg 867
        if(file->Position == fposition) retvalue = 0;
1 ingob 868
        return(retvalue);
869
}
870
 
871
 
41 ingob 872
/****************************************************************************************************************************************/
873
/* Function:    u16 DeleteClusterChain(File *file);                                                                                                                                                                             */
874
/*                                                                                                                                                                                                                                                                              */
875
/* Description: This function trances along a cluster chain in the fat and frees all clusters visited.                                                                  */
876
/*                                                                                                                                                                                                                                                                              */
877
/****************************************************************************************************************************************/
878
u8 DeleteClusterChain(u16 StartCluster)
1 ingob 879
{
88 killagreg 880
        u16 cluster;
41 ingob 881
        u32 fat_byte_offset, sector, byte;
882
        Fat16Entry_t * fat;
883
        u8 buffer[BYTES_PER_SECTOR];
884
        u32 sector_in_buffer = 0;
885
        u8 repeat = 0;
886
 
211 killagreg 887
        if(!Partition.IsValid) return(0);
888
        if(StartCluster == CLUSTER_UNDEFINED) return(0);
210 killagreg 889
        cluster = StartCluster; // init chain trace
211 killagreg 890
        // if start cluster is no real cluster
891
    if(FAT16_CLUSTER_LAST_MIN <= cluster) return 1;
41 ingob 892
 
893
        // calculate byte offset in the fat for corresponding entry
894
        fat_byte_offset = ((u32)cluster)<<1; // two FAT bytes (16 bits) for every cluster
895
        // calculate the sector that contains the current cluster within the fat
896
        sector = Partition.FirstFatSector + ( fat_byte_offset / BYTES_PER_SECTOR);
897
        // calculate byte offset of the current cluster within that fat sector
898
        byte = fat_byte_offset % BYTES_PER_SECTOR;
88 killagreg 899
        do
1 ingob 900
        {
41 ingob 901
                if(sector != sector_in_buffer)
1 ingob 902
                {
41 ingob 903
                        // read this sector to buffer
904
                        sector_in_buffer = sector;
905
                        if(SD_SUCCESS != SDC_GetSector(sector_in_buffer, buffer)) return 0;     // read sector from sd-card
88 killagreg 906
                }
41 ingob 907
                // read the next cluster from cache
908
                fat = (Fat16Entry_t *)(&(buffer[byte]));
909
                cluster = fat->NextCluster;
211 killagreg 910
                fat->NextCluster =      FAT16_CLUSTER_FREE; // mark current cluster as free
911
 
912
                if((FAT16_CLUSTER_USED_MIN <= cluster) && (cluster <= FAT16_CLUSTER_USED_MAX) )
913
                {
914
                        repeat = 1;
915
                        // calculate sector byte and byte offset in the fat for the next cluster
916
                        fat_byte_offset = ((u32)cluster)<<1; // two FAT bytes (16 bits) for every cluster
917
                        // calculate the sector that contains the current cluster within the fat
918
                        sector = Partition.FirstFatSector + ( fat_byte_offset / BYTES_PER_SECTOR);
919
                        // calculate byte offset of the current cluster within that fat sector
920
                        byte = fat_byte_offset % BYTES_PER_SECTOR;
921
                }
41 ingob 922
                else repeat = 0;
923
 
924
                // if new sector is not the sector in buffer or the last cluster in the chain was traced
925
                if((sector != sector_in_buffer) || !repeat)
926
                {       // write sector in buffer
210 killagreg 927
                        if(SD_SUCCESS != SDC_PutSector(sector_in_buffer,buffer))
146 killagreg 928
                        {
929
                                Fat16_Deinit();
211 killagreg 930
                                return(0);
146 killagreg 931
                        }
1 ingob 932
                }
41 ingob 933
        }
934
        while(repeat);
935
 
936
        return 1;
1 ingob 937
}
938
 
939
 
41 ingob 940
/****************************************************************************************************************************************/
941
/* Function:    u16 AppendCluster(File *file);                                                                                                                                                                                  */
942
/*                                                                                                                                                                                                                                                                              */
943
/* Description: This function looks in the fat to find the next free cluster and appends it to the file.                                                                */
944
/*                                                                                                                                                                                                                                                                              */
211 killagreg 945
/* Returnvalue: The function returns the appened cluster number or CLUSTER_UNDEFINED of no cluster was appended.                                                */
41 ingob 946
/****************************************************************************************************************************************/
947
u16 AppendCluster(File_t *file)
1 ingob 948
{
211 killagreg 949
        u16 last_cluster, new_cluster = CLUSTER_UNDEFINED;
41 ingob 950
        u32 fat_byte_offset, sector, byte;
951
        Fat16Entry_t * fat;
88 killagreg 952
 
41 ingob 953
        if((!Partition.IsValid) || (file == NULL)) return(new_cluster);
1 ingob 954
 
41 ingob 955
        new_cluster = FindNextFreeCluster(file);        // the next free cluster found on the disk.
211 killagreg 956
        if(new_cluster != CLUSTER_UNDEFINED)
88 killagreg 957
        {       // A free cluster was found and can be added to the end of the file.
41 ingob 958
                fseek_(file, 0, SEEK_END);                                                                                                      // jump to the end of the file
88 killagreg 959
                last_cluster = SectorToFat16Cluster(file->FirstSectorOfCurrCluster);            // determine current file cluster
211 killagreg 960
                if(last_cluster != CLUSTER_UNDEFINED)
41 ingob 961
                {
211 killagreg 962
                        // update FAT entry of last cluster
963
                        fat_byte_offset = ((u32)last_cluster)<<1;
964
                        sector = Partition.FirstFatSector + ( fat_byte_offset / BYTES_PER_SECTOR);
965
                        byte = fat_byte_offset % BYTES_PER_SECTOR;
966
                        // read the sector containing the last cluster of the file
967
                        if(file->SectorInCache != sector)
41 ingob 968
                        {
211 killagreg 969
                                file->SectorInCache = sector;   // update sector stored in buffer
970
                                if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))       // read sector from sd-card
971
                                {
972
                                        Fat16_Deinit();
973
                                        return(0);
974
                                }
975
                        }
976
                        fat = (Fat16Entry_t *)(&(file->Cache[byte]));
977
                        fat->NextCluster = new_cluster;                                                 // append the free cluster to the end of the file in the FAT.
978
                        if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))               // save the modified sector to the FAT.
979
                        {
41 ingob 980
                                Fat16_Deinit();
211 killagreg 981
                                return(0);
88 killagreg 982
                        }
983
                }
211 killagreg 984
                else // last cluster of the file is undefined
985
                {   // then the new cluster must be the first one of the file
986
                    // and its cluster number must be set in the direntry
987
                        DirEntry_t * dir;
988
                        file->SectorInCache = file->DirectorySector;                            // update the sector number of file cache.
989
                        if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read in the sector.
990
                        {
991
                                Fat16_Deinit();
992
                                return(CLUSTER_UNDEFINED);
993
                        }
994
                        dir = (DirEntry_t *)file->Cache;                                                        // set pointer to directory
995
                        dir[file->DirectoryIndex].Res1 = 0;
996
                        dir[file->DirectoryIndex].Res2[0] = 0;
997
                        dir[file->DirectoryIndex].Res2[1] = 0;
998
                        dir[file->DirectoryIndex].StartCluster = new_cluster;           // update startcluster 
999
                    dir[file->DirectoryIndex].ModTime   = FileTime(&SystemTime);// set time
1000
                        dir[file->DirectoryIndex].ModDate       = FileDate(&SystemTime);// and date of modification
1001
                        dir[file->DirectoryIndex].LastAccessDate = dir[file->DirectoryIndex].ModDate;
1002
                        dir[file->DirectoryIndex].Size          = 0;
1003
                        // write sector containing the direntry
1004
                        if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))
1005
                        {
1006
                                Fat16_Deinit();
1007
                                return(CLUSTER_UNDEFINED);
1008
                        }
1009
                        // update file info     
1010
                        file->FirstSectorOfFirstCluster = Fat16ClusterToSector(new_cluster);
1011
                        file->Size = 0;
1012
                        file->Position = 0;
41 ingob 1013
                }
211 killagreg 1014
                // update file pointes
41 ingob 1015
                file->FirstSectorOfCurrCluster = Fat16ClusterToSector(new_cluster);
1016
                file->SectorOfCurrCluster = 0;
1017
                file->ByteOfCurrSector = 0;
1018
        }
1019
        return(new_cluster);
1 ingob 1020
}
1021
 
41 ingob 1022
/****************************************************************************************************************************************************/
1023
/* Function:    DirectoryEntryExist(s8 *, u8, u8, File_t *)                                                                                                                                                                                     */
1024
/*                                                                                                                                                                                                                                                                                                      */
1025
/* Description: This function searches all possible dir entries until the file or directory is found or the end of the directory is reached                     */
1026
/*                                                                                                                                                                                                                                                                                                      */
1027
/* Returnvalue: This function returns 1 if the directory entry specified was found.                                                                                                                                     */
1028
/****************************************************************************************************************************************************/
1029
u8 DirectoryEntryExist(s8 *dirname, u8 attribfilter, u8 attribmask, File_t *file)
1030
{
1031
        u32             dir_sector, max_dir_sector, curr_sector;
1032
        u16     dir_entry = 0;
24 StephanB 1033
 
41 ingob 1034
        u16     end_of_directory_not_reached = 0;
1035
        u8              i = 0;
1036
        u8      direntry_exist = 0;
1037
        DirEntry_t * dir;
24 StephanB 1038
 
41 ingob 1039
        // if incomming pointers are useless return immediatly
88 killagreg 1040
        if((!Partition.IsValid) || (file == NULL) || (dirname == NULL)) return(direntry_exist);
41 ingob 1041
 
88 killagreg 1042
        // dir entries can be searched only in filesclusters that have
1043
        // a corresponding dir entry with adir-flag set in its attribute
41 ingob 1044
        // or direct within the root directory area
88 killagreg 1045
 
211 killagreg 1046
        file->FirstSectorOfFirstCluster = SECTOR_UNDEFINED;
41 ingob 1047
        // no current directory exist therefore assume searching in the root
211 killagreg 1048
        if(file->DirectorySector == SECTOR_UNDEFINED)
24 StephanB 1049
        {
41 ingob 1050
                max_dir_sector = (Partition.MaxRootEntries * DIRENTRY_SIZE)/BYTES_PER_SECTOR;
1051
                file->FirstSectorOfFirstCluster = Partition.FirstRootDirSector;
1052
        }
1053
        // within the root directory area we can read sectors sequentially until the end of this area
1054
        else if((Partition.FirstRootDirSector <= file->DirectorySector) && (file->DirectorySector < Partition.FirstDataSector))
1055
        {
1056
                max_dir_sector = (Partition.MaxRootEntries * DIRENTRY_SIZE)/BYTES_PER_SECTOR;
1057
        }
88 killagreg 1058
        // within the data clusters we can read sectors sequentially only within the cluster
41 ingob 1059
        else if((Partition.FirstDataSector <= file->DirectorySector) && (file->DirectorySector <= Partition.LastDataSector))
1060
        {
1061
                max_dir_sector = Partition.SectorsPerCluster;                           // limit max secters before next cluster
1062
        }
1063
        else return (direntry_exist); // bad sector range for directory sector of the file
1064
        // if search area is not defined yet
211 killagreg 1065
        if(file->FirstSectorOfFirstCluster == SECTOR_UNDEFINED)
41 ingob 1066
        {
1067
                // check if the directory entry of current file is existent and has the dir-flag set
1068
                file->SectorInCache = file->DirectorySector;                            // update the sector number of file cache.
1069
                if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read in the sector.
24 StephanB 1070
                {
41 ingob 1071
                        Fat16_Deinit();
1072
                        return(direntry_exist);
24 StephanB 1073
                }
41 ingob 1074
                dir = (DirEntry_t *)file->Cache;                                                        // set pointer to directory
211 killagreg 1075
                switch((u8)dir[file->DirectoryIndex].Name[0])                           // check if current directory exist
24 StephanB 1076
                {
41 ingob 1077
                        case SLOT_EMPTY:
1078
                        case SLOT_DELETED:
1079
                                // the directrory pointer of this file points to a deleted or not existen directory
1080
                                // therefore no file or subdirectory can be created
1081
                                return (direntry_exist);
1082
                                break;
88 killagreg 1083
                        default:        // and is a real directory
41 ingob 1084
                                if((dir[file->DirectoryIndex].Attribute & ATTR_SUBDIRECTORY) != ATTR_SUBDIRECTORY)
1085
                                {       // current file is not a directory therefore no file or subdirectory can be created here
1086
                                        return (direntry_exist);
1087
                                }
1088
                                break;
24 StephanB 1089
                }
41 ingob 1090
                file->FirstSectorOfFirstCluster = Fat16ClusterToSector(dir[file->DirectoryIndex].StartCluster);
24 StephanB 1091
        }
1092
 
41 ingob 1093
        // update current file data area position to start of first cluster
88 killagreg 1094
        file->FirstSectorOfCurrCluster  = file->FirstSectorOfFirstCluster;
1095
        file->SectorOfCurrCluster               = 0;
41 ingob 1096
        file->ByteOfCurrSector                  = 0;
24 StephanB 1097
 
41 ingob 1098
        do // loop over all data clusters of the current directory entry
88 killagreg 1099
        {
41 ingob 1100
                dir_sector = 0; // reset sector counter within a new cluster
1101
                do // loop over all sectors of a cluster or all sectors of the root directory
88 killagreg 1102
                {
41 ingob 1103
                        curr_sector = file->FirstSectorOfCurrCluster + dir_sector;      // calculate sector number
1104
                        file->SectorInCache = curr_sector;                                                      // upate the sector number of file cache.
1105
                        if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read the sector
1106
                        {
1107
                                Fat16_Deinit();
88 killagreg 1108
                                return(direntry_exist);
41 ingob 1109
                        }
1110
                        dir = (DirEntry_t *)file->Cache;                                                        // set pointer to directory
1111
                        // search all directory entries within that sector
1112
                        for(dir_entry = 0; dir_entry < DIRENTRIES_PER_SECTOR; dir_entry++)
1113
                        {   // check for existing dir entry
1114
                                switch((u8)dir[dir_entry].Name[0])
1115
                                {
1116
                                        case SLOT_EMPTY:
1117
                                        case SLOT_DELETED:
1118
                                                // ignore empty or deleted dir entries
1119
                                                break;
1120
                                        default:
1121
                                                // if existing check attributes before names are compared will safe performance
1122
                                                if ((dir[dir_entry].Attribute & attribmask) != attribfilter) break; // attribute must match
1123
                                                // then compare the name to the giveb dirname (first 11 characters include 8 chars of basename and 3 chars extension.)
1124
                                                i = 0;
1125
                                                while((i < 11) && (dir[dir_entry].Name[i] == dirname[i])) i++;
1126
                                                if (i < 10) break; // names does not match
1127
                                                // if dirname and attribute have matched
1128
                                                file->Attribute = dir[dir_entry].Attribute; // store attribute of found dir entry
88 killagreg 1129
                                                file->FirstSectorOfFirstCluster = Fat16ClusterToSector(dir[dir_entry].StartCluster); // set sector of first data cluster
41 ingob 1130
                                                file->FirstSectorOfCurrCluster = file->FirstSectorOfFirstCluster;
1131
                                                file->SectorOfCurrCluster = 0;
1132
                                                file->ByteOfCurrSector = 0;
1133
                                                file->DirectorySector = curr_sector; // current sector
1134
                                                file->DirectoryIndex  = dir_entry; // current direntry in current sector
88 killagreg 1135
                                                file->Size = dir[dir_entry].Size;
1136
                                                direntry_exist = 1; // mark as found
1137
                                                dir_entry = DIRENTRIES_PER_SECTOR;      // stop for-loop
41 ingob 1138
                                } // end of first byte of name check
1139
                        }
1140
                        dir_sector++; // search next sector
1141
                // stop if we reached the end of the cluster or the end of the root dir
1142
                }while((dir_sector < max_dir_sector) && (!direntry_exist));
1 ingob 1143
 
41 ingob 1144
                // if we are seaching in the data area and the file not found in this cluster so take next cluster.
88 killagreg 1145
                if(!direntry_exist && ( Partition.FirstDataSector <= file->FirstSectorOfCurrCluster))
41 ingob 1146
                {
1147
                        end_of_directory_not_reached = GetNextCluster(file);  // updates File->FirstSectorOfCurrCluster
1148
                }
1149
        }while((end_of_directory_not_reached) && (!direntry_exist)); // repeat until a next cluster exist an no
1150
        return(direntry_exist);
1 ingob 1151
}
1152
 
1153
 
41 ingob 1154
/****************************************************************************************************************************************/
1155
/*      Function:               CreateDirectoryEntry(s8 *, u16, File_t *)                                                                                                                                                       */
1156
/*                                                                                                                                                                                                                                                                              */
1157
/*      Description:    This function looks for the next free position in the directory and creates an entry.                                                           */
1158
/*                                      The type of an directory entry is specified by the file attribute.                                                                                                      */
1159
/*                                                                                                                                                                                                                                                                              */
1160
/*      Returnvalue:    Return 0 on error                                                                                                                                                                                                       */
1161
/****************************************************************************************************************************************/
1162
u8 CreateDirectoryEntry(s8 *dirname, u8 attrib, File_t *file)
1 ingob 1163
{
41 ingob 1164
        u32 dir_sector, max_dir_sector, curr_sector;
1165
        u16 dir_entry   = 0;
1166
        u16 subdircluster, dircluster = 0;
1167
        u16 end_of_directory_not_reached = 0;
1168
        u8      i                       = 0;
88 killagreg 1169
        u8      retvalue        = 0;
41 ingob 1170
        DirEntry_t *dir;
1171
 
1172
        if((!Partition.IsValid) || (file == NULL) || (dirname == NULL)) return (retvalue);
1173
        // It is not checked here that the dir entry that should be created is already existent!
88 killagreg 1174
 
1175
        // Dir entries can be created only in file-clusters that have
41 ingob 1176
        // the dir-flag set in its attribute or within the root directory
88 killagreg 1177
 
211 killagreg 1178
        file->FirstSectorOfFirstCluster = SECTOR_UNDEFINED;
41 ingob 1179
        // no current directory exist therefore assume creating in the root
211 killagreg 1180
        if(file->DirectorySector == SECTOR_UNDEFINED)
24 StephanB 1181
        {
41 ingob 1182
                max_dir_sector = (Partition.MaxRootEntries * DIRENTRY_SIZE)/BYTES_PER_SECTOR;
1183
                dircluster = 0;
1184
                file->FirstSectorOfFirstCluster = Partition.FirstRootDirSector;
1185
        }
1186
        // within the root directory area we can read sectors sequentially until the end of this area
1187
        else if((Partition.FirstRootDirSector <= file->DirectorySector) && (file->DirectorySector < Partition.FirstDataSector))
1188
        {
1189
                max_dir_sector = (Partition.MaxRootEntries * DIRENTRY_SIZE)/BYTES_PER_SECTOR;
1190
        }
88 killagreg 1191
        // within the data clusters we can read sectors sequentially only within the cluster
41 ingob 1192
        else if((Partition.FirstDataSector <= file->DirectorySector) && (file->DirectorySector <= Partition.LastDataSector))
1193
        {
1194
                max_dir_sector = Partition.SectorsPerCluster;
1195
        }
88 killagreg 1196
        else return (retvalue); // bad sector range for directory sector of the file
41 ingob 1197
        // if search area is not defined yet
211 killagreg 1198
        if(file->FirstSectorOfFirstCluster == SECTOR_UNDEFINED)
41 ingob 1199
        {
1200
            // check if the directory entry of current file is existent and has the dir-flag set
1201
                file->SectorInCache = file->DirectorySector;                            // update the sector number of file cache.
88 killagreg 1202
                if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read in the sector.
41 ingob 1203
                {
1204
                        Fat16_Deinit();
1205
                        return(retvalue);
88 killagreg 1206
                }
41 ingob 1207
                dir = (DirEntry_t *)file->Cache;                                                        // set pointer to directory
218 killagreg 1208
                switch((u8)dir[file->DirectoryIndex].Name[0])                           // check if current directory exist
41 ingob 1209
                {
1210
                        case SLOT_EMPTY:
1211
                        case SLOT_DELETED:
1212
                                return (retvalue);
1213
                                break;
88 killagreg 1214
                        default:        // and is a real directory
41 ingob 1215
                                if((dir[file->DirectoryIndex].Attribute & ATTR_SUBDIRECTORY) != ATTR_SUBDIRECTORY)
1216
                                {       // current file is not a directory therefore no file or subdirectory can be created here
1217
                                        return (retvalue);
1218
                                }
1219
                                break;
1220
                }
1221
                dircluster = dir[file->DirectoryIndex].StartCluster;
88 killagreg 1222
                file->FirstSectorOfFirstCluster = Fat16ClusterToSector(dircluster);
41 ingob 1223
        }
88 killagreg 1224
 
218 killagreg 1225
        // if the new direntry is a subdirectory
1226
        if((attrib & ATTR_SUBDIRECTORY) == ATTR_SUBDIRECTORY)
1227
        {       // get a free clutser for its content
1228
                subdircluster = FindNextFreeCluster(file);      // get the next free cluster on the disk and mark it as used.
1229
        }
1230
        else // a normal file
1231
        {       // has no data cluster after creation
1232
                subdircluster = CLUSTER_UNDEFINED;
1233
        }
1234
 
211 killagreg 1235
        file->FirstSectorOfCurrCluster  = file->FirstSectorOfFirstCluster;
1236
        file->SectorOfCurrCluster               = 0;
1237
        do // loop over all clusters of current directory
41 ingob 1238
        {
211 killagreg 1239
                dir_sector = 0; // reset sector counter within a new cluster
1240
                do // loop over all sectors of a cluster or all sectors of the root directory
88 killagreg 1241
                {
211 killagreg 1242
                        curr_sector = file->FirstSectorOfCurrCluster + dir_sector;      // calculate sector number
1243
                        file->SectorInCache = curr_sector;                                                      // upate the sector number of file cache.
1244
                        if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read in the sector.
1 ingob 1245
                        {
211 killagreg 1246
                                Fat16_Deinit();
1247
                                return(retvalue);
1248
                        }
1249
 
1250
                        dir = (DirEntry_t *)file->Cache;                                                        // set pointer to directory
1251
                        // search all directory entries of a sector
1252
                        for(dir_entry = 0; dir_entry < DIRENTRIES_PER_SECTOR; dir_entry++)
1253
                        {       // check if current direntry is available
1254
                                if(((u8)dir[dir_entry].Name[0] == SLOT_EMPTY) || ((u8)dir[dir_entry].Name[0] == SLOT_DELETED))
1255
                                {       // a free direntry was found
1256
                                        for(i = 0; i < 11; i++) dir[dir_entry].Name[i] = dirname[i];            // Set dir name
1257
                                        dir[dir_entry].Attribute    = attrib;
1258
                                        dir[dir_entry].Res1 = 0;
1259
                                        dir[dir_entry].CreationTime10ms = (u8)(SystemTime.mSec/10);
1260
                                        dir[dir_entry].CreationTime     = FileTime(&SystemTime);
1261
                                        dir[dir_entry].CreationDate     = FileDate(&SystemTime);
1262
                                        dir[dir_entry].LastAccessDate = dir[dir_entry].CreationDate;
1263
                                        dir[dir_entry].Res2[0] = 0;
1264
                                        dir[dir_entry].Res2[1] = 0;
1265
                                        dir[dir_entry].ModTime = dir[dir_entry].CreationTime;
1266
                                        dir[dir_entry].ModDate = dir[dir_entry].CreationDate;
1267
                                        // Set the attribute of the new directoryentry.
1268
                                        dir[dir_entry].StartCluster = subdircluster;                                            // copy the location of the first datacluster to the directoryentry.
1269
                                        dir[dir_entry].Size             = 0;                                                                    // the new createted file has no content yet.
1270
                                        if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))       // write back to card
1271
                                        {
1272
                                                Fat16_Deinit();
1273
                                                return(retvalue);
1274
                                        }
218 killagreg 1275
                                        file->FirstSectorOfFirstCluster = Fat16ClusterToSector(subdircluster);  // Calculate absolute sectorposition of first datacluster.
211 killagreg 1276
                                        file->FirstSectorOfCurrCluster  = file->FirstSectorOfFirstCluster;      // Start reading the file with the first sector of the first datacluster.
1277
                                        file->SectorOfCurrCluster               = 0;                                                            // reset sector of cureen cluster
1278
                                        file->ByteOfCurrSector                  = 0;                                                            // reset the byte location within the current sector
1279
                                        file->Attribute                                 = attrib;                                               // set file attribute to dir attribute
1280
                                        file->Size                                              = 0;                                                        // new file has no size
1281
                                        file->DirectorySector                   = curr_sector;
1282
                                        file->DirectoryIndex                    = dir_entry;
1283
                                        // prepare subdirectory data cluster
1284
                                        if((attrib & ATTR_SUBDIRECTORY) == ATTR_SUBDIRECTORY)                           // if a new directory was created then initilize the data area
1285
                                        {
1286
                                                ClearCurrCluster(file); // fill cluster with zeros
1287
                                                file->SectorInCache = file->FirstSectorOfFirstCluster;
1288
                                                if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read in the sector.
41 ingob 1289
                                                {
211 killagreg 1290
                                                        Fat16_Deinit();
41 ingob 1291
                                                        return(retvalue);
1292
                                                }
211 killagreg 1293
                                                dir = (DirEntry_t *)file->Cache;
1294
                                                // create direntry "." to current dir
1295
                                                dir[0].Name[0] = 0x2E;
1296
                                                for(i = 1; i < 11; i++) dir[0].Name[i] = ' ';
1297
                                                dir[0].Attribute = ATTR_SUBDIRECTORY;
1298
                                                dir[0].StartCluster = subdircluster;
1299
                                                dir[0].Size = 0;
1300
                                                // create direntry ".." to the upper dir
1301
                                                dir[1].Name[0] = 0x2E;
1302
                                                dir[1].Name[1] = 0x2E;
1303
                                                for(i = 2; i < 11; i++) dir[1].Name[i] = ' ';
1304
                                                dir[1].Attribute = ATTR_SUBDIRECTORY;
1305
                                                dir[1].StartCluster = dircluster;
1306
                                                dir[1].Size = 0;
1307
                                                if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))// read in the sector.
88 killagreg 1308
                                                {
211 killagreg 1309
                                                        Fat16_Deinit();
1310
                                                        return(retvalue);
1311
                                                }
1312
                                        }
1313
                                        retvalue = 1;
1314
                                        dir_entry = DIRENTRIES_PER_SECTOR;      // stop for-loop
88 killagreg 1315
                                }
211 killagreg 1316
                        }
1317
                        dir_sector++; // search next sector
1318
                // stop if we reached the end of the cluster or the end of the root dir
1319
                }while((dir_sector < max_dir_sector) && (!retvalue));
88 killagreg 1320
 
211 killagreg 1321
                // if we are seaching in the data area and the file not found in this cluster so take next cluster.
1322
                if(!retvalue && ( Partition.FirstDataSector <= file->FirstSectorOfCurrCluster))
1323
                {
1324
                        end_of_directory_not_reached = GetNextCluster(file);  // updates File->FirstSectorOfCurrCluster
1325
                }
1326
        }while((end_of_directory_not_reached) && (!retvalue));
1327
        // Perhaps we are at the end of the last cluster of a directory file and have no free direntry found.
1328
        // Then we would need to add a cluster to that file and create the new direntry there.
1329
        // This code is not implemented yet, because its occurs only if more that 32*32=1024 direntries are
1330
        // within a subdirectory of root.
1331
 
41 ingob 1332
        return(retvalue);       // return 1 if file has been created otherwise return 0.
1 ingob 1333
}
1334
 
41 ingob 1335
/********************************************************************************************************************************************/
1336
/*      Function:               FileExist(const s8* filename, u8 attribfilter, u8 attribmask, File_t *file);                                                                                    */
1337
/*                                                                                                                                                                                                                                                                                      */
1338
/*      Description:    This function looks for the specified file including its subdirectories beginning                                                                               */
1339
/*                                      in the rootdirectory of the drive. If the file is found the Filepointer properties are                                                                  */
1340
/*                                      updated.                                                                                                                                                                                                                                */
1341
/*                                                                                                                                                                                                                                                                                      */
1342
/*      Returnvalue:    1 if file is found else 0.                                                                                                                                                                                              */
1343
/********************************************************************************************************************************************/
1344
u8 FileExist(const s8* filename, const u8 attribfilter, const u8 attribmask, File_t *file)
1 ingob 1345
{
41 ingob 1346
        s8* path = 0;
1347
        s8* subpath = 0;
1348
        u8 af, am, file_exist = 0;
1349
        s8 dirname[12]; // 8+3 + temination character
1 ingob 1350
 
41 ingob 1351
        // if incomming pointers are useless return immediatly
1352
        if ((filename == NULL) || (file == NULL) || (!Partition.IsValid)) return 0;
1 ingob 1353
 
41 ingob 1354
        // trace along the filepath
1355
        path = (s8*)filename;                                                           // start a the beginning of the filename string
1356
        file->DirectorySector = 0;                                                              // start at RootDirectory with file search
88 killagreg 1357
        file->DirectoryIndex = 0;
41 ingob 1358
        // as long as the file was not found and the remaining path is not empty
1359
        while((*path != 0) && !file_exist)
1360
        {       // separate dirname and subpath from filepath string
1361
                subpath = SeperateDirName(path, dirname);
1362
                if(subpath != NULL)
88 killagreg 1363
                {
1364
                        if(*subpath == 0)
41 ingob 1365
                        {       // empty subpath indicates last element of dir chain
1366
                                af = attribfilter;
1367
                                am = attribmask;
1368
                        }
1369
                        else  // it must be a subdirectory and no volume label
1 ingob 1370
                        {
41 ingob 1371
                                af = ATTR_SUBDIRECTORY;
1372
                                am = ATTR_SUBDIRECTORY|ATTR_VOLUMELABEL;
1373
                        }
1374
                        if(!DirectoryEntryExist(dirname, af, am, file))
1375
                        {
1376
                                return (file_exist); // subdirectory does not exist
1377
                        }
88 killagreg 1378
                        else
1379
                        {
41 ingob 1380
                                if (*subpath == 0)
24 StephanB 1381
                                {
41 ingob 1382
                                        file_exist = 1; // last element of path chain was found with the given attribute filter
24 StephanB 1383
                                }
1 ingob 1384
                        }
1385
                }
41 ingob 1386
                else // error seperating the subpath
1 ingob 1387
                {
41 ingob 1388
                        return file_exist; // bad subdir format
1 ingob 1389
                }
41 ingob 1390
                path = subpath;
1391
                subpath = 0;
1 ingob 1392
        }
41 ingob 1393
        return (file_exist);
1 ingob 1394
}
1395
 
24 StephanB 1396
 
41 ingob 1397
/********************************************************************************************************************************************/
1398
/*      Function:               FileCreate(const s8* filename, u8 attrib, File_t *file);                                                                                                                                */
1399
/*                                                                                                                                                                                                                                                                                      */
1400
/*      Description:    This function looks for the specified file including its subdirectories beginning                                                                               */
1401
/*                                      in the rootdirectory of the partition. If the file is found the Filepointer properties are                                                              */
88 killagreg 1402
/*                                      updated. If file or its subdirectories are not found they will be created                                                                                               */
41 ingob 1403
/*                                                                                                                                                                                                                                                                                      */
1404
/*      Returnvalue:    1 if file was created else 0.                                                                                                                                                                                   */
1405
/********************************************************************************************************************************************/
1406
u8 FileCreate(const s8* filename, const u8 attrib, File_t *file)
1407
{
1408
        s8 *path = 0;
1409
        s8 *subpath = 0;
1410
        u8 af, am, file_created = 0;
1411
        s8 dirname[12];
24 StephanB 1412
 
41 ingob 1413
        // if incomming pointers are useless return immediatly
1414
        if ((filename == NULL) || (file == NULL) || (!Partition.IsValid)) return 0;
1 ingob 1415
 
41 ingob 1416
        // trace along the filepath
1417
        path = (s8*)filename;                                                                   // start a the beginning of the filename string
1418
        file->DirectorySector = 0;                                                              // start at RootDirectory with file search
1419
        file->DirectoryIndex = 0;
1420
        // as long as the file was not created and the remaining file path is not empty
1421
        while((*path != 0) && !file_created)
1422
        {   // separate dirname and subpath from filepath string
1423
                subpath = SeperateDirName(path, dirname);
1424
                if(subpath != NULL)
24 StephanB 1425
                {
88 killagreg 1426
                        if(*subpath == 0)
41 ingob 1427
                        {       // empty subpath indicates last element of dir chain
1428
                                af = ATTR_NONE;
1429
                                am = ATTR_SUBDIRECTORY|ATTR_VOLUMELABEL;  // any file that is no subdir or volume label
24 StephanB 1430
                        }
41 ingob 1431
                        else  // it must be a subdirectory and no volume label
24 StephanB 1432
                        {
41 ingob 1433
                                af = ATTR_SUBDIRECTORY;
1434
                                am = ATTR_SUBDIRECTORY|ATTR_VOLUMELABEL;
24 StephanB 1435
                        }
41 ingob 1436
                        if(!DirectoryEntryExist(dirname, af, am, file)) // if subdir or file is not existent
1437
                        {  // try to create subdir or file
1438
                                if(*subpath == 0) af = attrib; // if last element in dir chain take the given attribute
1439
                                if(!CreateDirectoryEntry(dirname, af, file))
1440
                                {       // could not be created
88 killagreg 1441
                                        return(file_created);
1442
                                }
41 ingob 1443
                                else if (*subpath == 0) file_created = 1; // last element of path chain was created
24 StephanB 1444
                        }
1445
                }
41 ingob 1446
                else // error seperating the subpath
24 StephanB 1447
                {
41 ingob 1448
                        return file_created; // bad subdir format
24 StephanB 1449
                }
41 ingob 1450
                path = subpath;
1451
                subpath = 0;
1452
        }
1453
        return (file_created);
24 StephanB 1454
}
1 ingob 1455
 
24 StephanB 1456
 
41 ingob 1457
/********************************************************************************************************************************************/
1458
/*      Function:               File_t * fopen_(s8* filename, s8 mode);                                                                                                                                                                 */
1459
/*                                                                                                                                                                                                                                                                                      */
1460
/*      Description:    This function looks for the specified file in the rootdirectory of the drive. If the file is found the number of the    */
1461
/*                                      corrosponding filepointer is returned. Only modes 'r' (reading) and 'a' append are implemented yet.                                             */
1462
/*                                                                                                                                                                                                                                                                                      */
1463
/*      Returnvalue:    The filepointer to the file or 0 if faild.                                                                                                                                                              */
1464
/********************************************************************************************************************************************/
89 killagreg 1465
File_t * fopen_(s8 * const filename, const s8 mode)
88 killagreg 1466
{
41 ingob 1467
        File_t *file    = 0;
88 killagreg 1468
 
41 ingob 1469
        if((!Partition.IsValid) || (filename == 0)) return(file);
1470
 
1471
        // Look for an unused filepointer in the file pointer list?
1472
        file = LockFilePointer();
1473
        // if no unused file pointer was found return 0
1474
        if(file == NULL) return(file);
1475
 
1476
        // now we have found a free filepointer and claimed it
1477
        // so let initiate its property values
211 killagreg 1478
        file->FirstSectorOfFirstCluster = SECTOR_UNDEFINED;             // Sectorpointer to the first sector of the first datacluster of the file.
1479
        file->FirstSectorOfCurrCluster  = SECTOR_UNDEFINED;             // Pointer to the cluster which is edited at the moment.
41 ingob 1480
        file->SectorOfCurrCluster               = 0;            // The sector which is edited at the moment (cluster_pointer + sector_index).
1481
        file->ByteOfCurrSector                  = 0;            // The bytelocation within the current sector (cluster_pointer + sector_index + byte_index).
1482
        file->Mode                                              = mode;         // mode of fileoperation (read,write)
1483
        file->Size                                              = 0;            // the size of the opened file in bytes.
1484
        file->Position                                  = 0;            // pointer to a byte within the file 0 < fileposition < filesize
211 killagreg 1485
        file->SectorInCache                             = SECTOR_UNDEFINED;             // the last sector read, wich is still in the sectorbuffer.
1486
        file->DirectorySector                   = SECTOR_UNDEFINED;             // the sectorposition where the directoryentry has been made.
41 ingob 1487
        file->DirectoryIndex                    = 0;            // the index to the directoryentry within the specified sector.
1488
        file->Attribute                                 = 0;            // the attribute of the file opened.
1489
 
1490
        // check if a real file (no directory) to the given filename exist
88 killagreg 1491
        if(FileExist(filename, ATTR_NONE, ATTR_SUBDIRECTORY|ATTR_VOLUMELABEL, file))
41 ingob 1492
        {  // file exist
1493
                switch(mode)  // check mode
1 ingob 1494
                {
41 ingob 1495
                        case 'a':       // if mode is: append to file
1496
                                if((file->Attribute & ATTR_READONLY) == ATTR_READONLY)
1497
                                {       // file is marked as readonly --> do not open this file
1498
                                        fclose_(file);
1499
                                        file = NULL;
1500
                                }
1501
                                else
1502
                                {       // file is not marked as read only --> goto end of file
1503
                                        fseek_(file, 0, SEEK_END);              // point to the end of the file
1504
                                }
1505
                                break;
1506
                        case 'w':       // if mode is: write to file
1507
                                if((file->Attribute & ATTR_READONLY) == ATTR_READONLY)
1508
                                {       // file is marked as readonly --> do not open this file
1509
                                        fclose_(file);
1510
                                        file = NULL;
1511
                                }
1512
                                else
211 killagreg 1513
                                {       // file is not marked as read only
1514
                                        DirEntry_t * dir;
41 ingob 1515
                                        // free all clusters of that file
1516
                                        DeleteClusterChain(SectorToFat16Cluster(file->FirstSectorOfFirstCluster));
211 killagreg 1517
                                        // update directory entry of that file
1518
                                        file->SectorInCache = file->DirectorySector;                            // update the sector number of file cache.
1519
                                        if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read in the sector.
1520
                                        {
1521
                                                Fat16_Deinit();
1522
                                                return(NULL);
1523
                                        }
1524
                                        dir = (DirEntry_t *)file->Cache;                                                                // set pointer to directory
1525
                                    dir[file->DirectoryIndex].ModTime   = FileTime(&SystemTime);        // set modification time
1526
                                        dir[file->DirectoryIndex].ModDate       = FileDate(&SystemTime);        // set modification date
1527
                                        dir[file->DirectoryIndex].LastAccessDate = dir[file->DirectoryIndex].ModDate;
1528
                                        dir[file->DirectoryIndex].StartCluster = CLUSTER_UNDEFINED;             // update startcluster 
1529
                                        dir[file->DirectoryIndex].Size          = 0;
1530
                                        // write sector containing the direntry
1531
                                        if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))
1532
                                        {
1533
                                                Fat16_Deinit();
1534
                                                return(NULL);
1535
                                        }
1536
                                        file->FirstSectorOfFirstCluster = SECTOR_UNDEFINED;
41 ingob 1537
                                        file->FirstSectorOfCurrCluster = file->FirstSectorOfFirstCluster;
1538
                                        file->SectorOfCurrCluster = 0;
1539
                                        file->ByteOfCurrSector = 0;
1540
                                        file->Size = 0;
1541
                                        file->Position = 0;
1542
                                        fseek_(file, 0, SEEK_SET);
1543
                                }
1544
                                break;
1545
                        case 'r':       // if mode is: read from file
88 killagreg 1546
                                // goto end of file
41 ingob 1547
                                fseek_(file, 0, SEEK_SET);
1548
                                break;
1549
                        default: // other modes are not supported
1550
                                fclose_(file);
1551
                                file = NULL;
24 StephanB 1552
                        break;
1 ingob 1553
                }
88 killagreg 1554
                return(file);
1 ingob 1555
        }
41 ingob 1556
        else // file does not exist
1557
        {
1558
                switch(mode)  // check mode
1559
                {
1560
                        case 'a':
1561
                        case 'w': // if mode is write or append
1562
                                // try to create the file
1563
                                if(!FileCreate(filename, ATTR_ARCHIVE, file))
1564
                                { // if it could not be created
1565
                                        fclose_(file);
1566
                                        file = NULL;
1567
                                }
1568
                                break;
1569
                        case 'r': // else opened for 'r'
218 killagreg 1570
                        default:  // if unsupported mode
41 ingob 1571
                                fclose_(file);
1572
                                file = NULL;
88 killagreg 1573
                                break;
41 ingob 1574
                }
88 killagreg 1575
                return(file);
41 ingob 1576
        }
1577
        // we should never come to this point
1578
        fclose_(file);
1579
        file = NULL;
24 StephanB 1580
        return(file);
1581
}
1582
 
41 ingob 1583
/****************************************************************************************************************************************************/
1584
/* Function:    fflush_(File *);                                                                                                                                                                                                                                        */
1585
/*                                                                                                                                                                                                                                                                                                      */
1586
/* Description: This function writes the data already in the buffer but not yet written to the file.                                                                                            */
1587
/*                                                                                                                                                                                                                                                                                                      */
1588
/* Returnvalue: 0 on success EOF on error                                                                                                                                                                                                                       */
1589
/****************************************************************************************************************************************************/
1590
s16     fflush_(File_t *file)
24 StephanB 1591
{
88 killagreg 1592
        DirEntry_t *dir;
1593
 
41 ingob 1594
        if((file == NULL) || (!Partition.IsValid)) return (EOF);
88 killagreg 1595
 
41 ingob 1596
        switch(file->Mode)
24 StephanB 1597
        {
41 ingob 1598
                case 'a':
1599
                case 'w':
88 killagreg 1600
                        if(file->ByteOfCurrSector > 0)                                                                          // has data been added to the file?
41 ingob 1601
                        {
88 killagreg 1602
                                if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))// save the data still in the buffer
41 ingob 1603
                                {
88 killagreg 1604
                                        Fat16_Deinit();
1605
                                        return(EOF);
1606
                                }
41 ingob 1607
                        }
1608
                        file->SectorInCache     = file->DirectorySector;
1609
                        if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))                                       // read the directory entry for this file.
1610
                        {
1611
                                Fat16_Deinit();
88 killagreg 1612
                                return(EOF);
41 ingob 1613
                        }
88 killagreg 1614
 
41 ingob 1615
                        dir = (DirEntry_t *)file->Cache;
211 killagreg 1616
                        // update dile size and modification time & date
1617
                        dir[file->DirectoryIndex].ModTime = FileTime(&SystemTime);
1618
                        dir[file->DirectoryIndex].ModDate = FileDate(&SystemTime);
1619
                        dir[file->DirectoryIndex].LastAccessDate = dir[file->DirectoryIndex].ModDate;
41 ingob 1620
                        dir[file->DirectoryIndex].Size = file->Size;                                            // update file size
1621
                        if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))       // write back to sd-card
1622
                        {
1623
                                Fat16_Deinit();
1624
                                return(EOF);
1625
                        }
1626
                        break;
1627
                case 'r':
1628
                default:
211 killagreg 1629
                        // do nothing!
41 ingob 1630
                        return(EOF);
1631
                        break;
1632
 
24 StephanB 1633
        }
41 ingob 1634
        return(0);
24 StephanB 1635
}
1 ingob 1636
 
41 ingob 1637
/****************************************************************************************************************************************/
1638
/*      Function:               fclose_(File *file);                                                                                                                                                                                            */
1639
/*                                                                                                                                                                                                                                                                              */
1640
/*      Description:    This function closes the open file by writing the remaining data                                                                                                        */
1641
/*                                      from the buffer to the device and entering the filesize in the directory entry.                                                                         */
1642
/*                                                                                                                                                                                                                                                                              */
1643
/*      Returnvalue:    0 on success EOF on error                                                                                                                                                                                       */
1644
/****************************************************************************************************************************************/
1645
s16 fclose_(File_t *file)
24 StephanB 1646
{
41 ingob 1647
        s16 returnvalue = EOF;
24 StephanB 1648
 
41 ingob 1649
        if(file == NULL) return(returnvalue);
1650
        returnvalue = fflush_(file);
1651
        UnlockFilePointer(file);
1652
        return(returnvalue);
24 StephanB 1653
}
1654
 
41 ingob 1655
/********************************************************************************************************************************************/
1656
/*      Function:               fgetc_(File *file);                                                                                                                                                                                                             */
1657
/*                                                                                                                                                                                                                                                                                      */
1658
/*      Description:    This function reads and returns one character from the specified file. Is the end of the actual sector reached the              */
1659
/*                                      next sector of the cluster is read. If the last sector of the cluster read the next cluster will be searched in FAT.    */
1660
/*                                                                                                                                                                                                                                                                                      */
1661
/*      Returnvalue:    The function returns the character read from the specified memorylocation as u8 casted to s16 or EOF.                                   */
1662
/********************************************************************************************************************************************/
1663
s16 fgetc_(File_t *file)
88 killagreg 1664
{
41 ingob 1665
        s16 c = EOF;
1666
        u32 curr_sector;
88 killagreg 1667
 
41 ingob 1668
        if( (!Partition.IsValid) || (file == NULL)) return(c);
1669
        // if the end of the file is not reached, get the next character.
88 killagreg 1670
        if((0 < file->Size) && ((file->Position+1) < file->Size) )
1 ingob 1671
        {
41 ingob 1672
                curr_sector  = file->FirstSectorOfCurrCluster;          // calculate the sector of the next character to be read.
88 killagreg 1673
                curr_sector += file->SectorOfCurrCluster;
1674
 
41 ingob 1675
                if(file->SectorInCache != curr_sector)
1 ingob 1676
                {
41 ingob 1677
                        file->SectorInCache = curr_sector;
1678
                        if(SD_SUCCESS != SDC_GetSector(file->SectorInCache,file->Cache))
1679
                        {
1680
                                Fat16_Deinit();
1681
                                return(c);
88 killagreg 1682
                        }
1683
                }
41 ingob 1684
                c = (s16) file->Cache[file->ByteOfCurrSector];
1685
                file->Position++;                                                                       // increment file position
88 killagreg 1686
                file->ByteOfCurrSector++;                                                       // goto next byte in sector
41 ingob 1687
                if(file->ByteOfCurrSector >= BYTES_PER_SECTOR)          // if end of sector
24 StephanB 1688
                {
41 ingob 1689
                        file->ByteOfCurrSector = 0;                                             //  reset byte location
1690
                        file->SectorOfCurrCluster++;                                    //      next sector
1691
                        if(file->SectorOfCurrCluster >= Partition.SectorsPerCluster)    // if end of cluster is reached, the next datacluster has to be searched in the FAT.
24 StephanB 1692
                        {
88 killagreg 1693
 
41 ingob 1694
                                if(GetNextCluster(file))                                                                                // Sets the clusterpointer of the file to the next datacluster.
24 StephanB 1695
                                {
41 ingob 1696
                                        file->SectorOfCurrCluster = 0;                                                          // start reading new cluster at first sector of the cluster.
1697
                                }
1698
                                else // the last cluster was allready reached
1699
                                {
1700
                                        file->SectorOfCurrCluster--;                                                    // jump back to the last sector in the last cluster
1701
                                        file->ByteOfCurrSector = BYTES_PER_SECTOR;                              // set ByteOfCurrSector one byte over sector end
1702
                                }
1 ingob 1703
                        }
24 StephanB 1704
                }
1705
        }
41 ingob 1706
        return(c);
24 StephanB 1707
}
1708
 
41 ingob 1709
/********************************************************************************************************************************************/
1710
/*      Function:               fputc_( const s8 c, File *file);                                                                                                                                                                                */
1711
/*                                                                                                                                                                                                                                                                                      */
1712
/*      Description:    This function writes a byte to the specified file and takes care of writing the necessary FAT- Entries.                                 */
1713
/*                                      next sector of the cluster is read. If the last sector of the cluster read the next cluster will be searched in FAT.    */
1714
/*                                                                                                                                                                                                                                                                                      */
1715
/*      Returnvalue:    The function returns the character written to the stream or EOF on error.                                                                                               */
1716
/********************************************************************************************************************************************/
1717
s16 fputc_(const s8 c, File_t *file)
88 killagreg 1718
{
41 ingob 1719
        u32 curr_sector  = 0;
88 killagreg 1720
 
41 ingob 1721
        if((!Partition.IsValid) || (file == NULL)) return(EOF);
211 killagreg 1722
        switch(file->Mode)
41 ingob 1723
        {
211 killagreg 1724
                case 'w':
1725
                case 'a':
1726
                        // If file position equals to file size, then the end of file has been reached.
1727
                        // In this case it has to be checked that the ByteOfCurrSector is BYTES_PER_SECTOR
1728
                        // and a new cluster should be appended.
1729
                        // If the first sector of first cluster is unvalid, then the file claims no data clusters 
1730
                        // and size should be zero, therefore append a new Cluster too.
1731
                        if(((file->Position >= file->Size) && (file->ByteOfCurrSector >= BYTES_PER_SECTOR)) || (file->FirstSectorOfFirstCluster == SECTOR_UNDEFINED))
1732
                        {
1733
                                if(CLUSTER_UNDEFINED == AppendCluster(file)) return(EOF);
1734
                        }
1735
 
1736
                        curr_sector  = file->FirstSectorOfCurrCluster;
1737
                        curr_sector += file->SectorOfCurrCluster;
1738
                        if(file->SectorInCache != curr_sector)
1739
                        {
1740
                                file->SectorInCache = curr_sector;
1741
                                if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))
24 StephanB 1742
                                {
211 killagreg 1743
                                        Fat16_Deinit();
1744
                                        return(EOF);
24 StephanB 1745
                                }
1 ingob 1746
                        }
211 killagreg 1747
 
1748
                        file->Cache[file->ByteOfCurrSector] = (u8)c;            // write databyte into the buffer. The byte will be written to the device at once
1749
                        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.
1750
                        file->Position++;                                                                       // the actual positon within the file.
1751
                        file->ByteOfCurrSector++;                                                       // goto next byte in sector
1752
                        if(file->ByteOfCurrSector >= BYTES_PER_SECTOR)          // if the end of this sector is reached yet
1753
                        {       // save the sector to the sd-card
1754
                                if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))
1755
                                {
1756
                                        Fat16_Deinit();
1757
                                        return(EOF);
1758
                                }
1759
                                file->ByteOfCurrSector = 0;                                             //  reset byte location
1760
                                file->SectorOfCurrCluster++;                                    //      next sector
1761
                                if(file->SectorOfCurrCluster >= Partition.SectorsPerCluster)// if end of cluster is reached, the next datacluster has to be searched in the FAT.
1762
                                {
1763
                                        if(!GetNextCluster(file))                                                               // Sets the clusterpointer of the file to the next datacluster.
1764
                                        { // if current cluster was the last cluster of the file
1765
                                                if(!AppendCluster(file))                                                // append a new and free cluster at the end of the file.
1766
                                                {
1767
                                                        file->SectorOfCurrCluster--;                            // jump back to last sector of last cluster
1768
                                                        file->ByteOfCurrSector = BYTES_PER_SECTOR;      // set byte location to 1 byte over sector len
1769
                                                        return(EOF);
1770
                                                }
1771
                                        }
1772
                                        else // next cluster
1773
                                        {
1774
                                                file->SectorOfCurrCluster = 0;                                                  // start reading new cluster at first sector of the cluster.
1775
                                        }
1776
                                }
88 killagreg 1777
                        }
211 killagreg 1778
                        break;
1779
                case 'r':
1780
                default:
1781
                        return(EOF);
1782
                        break;
1783
        } // EOF switch(file->Mode)
41 ingob 1784
        return(0);
24 StephanB 1785
}
1786
 
1787
 
41 ingob 1788
/****************************************************************************************************************************************/
1789
/*      Function:               fread_(void *buffer, s32 size, s32 count, File *File);                                                                                                                          */
1790
/*                                                                                                                                                                                                                                                                              */
1791
/*      Description:    This function reads count objects of the specified size                                                                                                                         */
1792
/*                                      from the actual position of the file to the specified buffer.                                                                                                           */
1793
/*                                                                                                                                                                                                                                                                              */
1794
/*      Returnvalue:    The function returns the number of objects (not bytes) read from the file.                                                                                      */
1795
/****************************************************************************************************************************************/
1796
u32 fread_(void *buffer, u32 size, u32 count, File_t *file)
1797
{
1798
        u32 object_cnt  = 0;                                                                                    // count the number of objects read from the file.
1799
        u32 object_size = 0;                                                                                    // count the number of bytes read from the actual object.
1800
        u8 *pbuff       = 0;                                                                                    // a pointer to the actual bufferposition.
1801
        u8 success      = 1;                                                                                    // no error occured during read operation to the file.
88 killagreg 1802
        s16 c;
24 StephanB 1803
 
41 ingob 1804
        if((!Partition.IsValid) || (file == NULL) || (buffer == NULL)) return(0);
24 StephanB 1805
 
41 ingob 1806
        pbuff = (u8 *) buffer;                                                                                  // cast the void pointer to an u8 *
88 killagreg 1807
 
41 ingob 1808
        while((object_cnt < count) && success)
24 StephanB 1809
        {
41 ingob 1810
                object_size = size;
1811
                while((size > 0) && success)
1812
                {
1813
                        c = fgetc_(file);
1814
                        if(c != EOF)
1815
                        {
1816
                                *pbuff = (u8)c;                                                                         // read a byte from the buffer to the opened file.
1817
                                pbuff++;
1818
                                size--;
1819
                        }
1820
                        else // error or end of file reached
1821
                        {
88 killagreg 1822
                                success = 0;
41 ingob 1823
                        }
1824
                }
1825
                if(success) object_cnt++;
88 killagreg 1826
        }
41 ingob 1827
        return(object_cnt);                                                                                             // return the number of objects succesfully read from the file
1 ingob 1828
}
1829
 
24 StephanB 1830
 
41 ingob 1831
/****************************************************************************************************************************************/
1832
/*      Function:               fwrite_(void *buffer, s32 size, s32 count, File *file);                                                                                                                         */
1833
/*                                                                                                                                                                                                                                                                              */
1834
/*      Description:    This function writes count objects of the specified size                                                                                                                        */
1835
/*                                      from the buffer pointer to the actual position in the file.                                                                                                                     */
1836
/*                                                                                                                                                                                                                                                                              */
1837
/*      Returnvalue:    The function returns the number of objects (not bytes) read from the file.                                                                                      */
1838
/****************************************************************************************************************************************/
1839
u32 fwrite_(void *buffer, u32 size, u32 count, File_t *file)
1 ingob 1840
{
41 ingob 1841
        u32 object_cnt  = 0;                                                                                                            // count the number of objects written to the file.
1842
        u32 object_size = 0;                                                                                                            // count the number of bytes written from the actual object.
1843
        u8 *pbuff           = 0;                                                                                                                // a pointer to the actual bufferposition.
1844
        u8 success      = 1;                                                                                                            // no error occured during write operation to the file.
88 killagreg 1845
        s16 c;
24 StephanB 1846
 
41 ingob 1847
        if((!Partition.IsValid) || (file == NULL) || (buffer == NULL)) return(0);
211 killagreg 1848
        if(file->Mode == 'r') return (0); // opened read only
41 ingob 1849
        pbuff = (u8 *) buffer;                                                                                                          // cast the void pointer to an u8 *
88 killagreg 1850
 
41 ingob 1851
        while((object_cnt < count) && success)
1 ingob 1852
        {
41 ingob 1853
                object_size = size;
1854
                while((size > 0) && success)
1 ingob 1855
                {
41 ingob 1856
                        c = fputc_(*pbuff, file);                                                                               // write a byte from the buffer to the opened file.
1857
                        if(c != EOF)
24 StephanB 1858
                        {
41 ingob 1859
                                pbuff++;
1860
                                size--;
24 StephanB 1861
                        }
41 ingob 1862
                        else
24 StephanB 1863
                        {
41 ingob 1864
                                success = 0;
24 StephanB 1865
                        }
1 ingob 1866
                }
41 ingob 1867
                if(success) object_cnt++;
88 killagreg 1868
        }
1869
 
41 ingob 1870
        return(object_cnt);                                                                                                                             // return the number of objects succesfully written to the file
88 killagreg 1871
}
1 ingob 1872
 
24 StephanB 1873
 
41 ingob 1874
/****************************************************************************************************************************************/
1875
/*      Function:               fputs_(const s8 *string, File_t *File);                                                                                                                                                         */
1876
/*                                                                                                                                                                                                                                                                              */
1877
/*      Description:    This function writes a string to the specified file.                                                                                                                            */
1878
/*                                                                                                                                                                                                                                                                              */
1879
/*      Returnvalue:    The function returns a no negative value or EOF on error.                                                                                                                       */
1880
/****************************************************************************************************************************************/
89 killagreg 1881
s16 fputs_(s8 * const string, File_t * const file)
24 StephanB 1882
{
41 ingob 1883
        u8 i=0;
1884
        s16 c = 0;
88 killagreg 1885
 
211 killagreg 1886
        if((!Partition.IsValid) || (file == NULL) || (string == NULL)) return(EOF);
1887
        if(file->Mode == 'r') return(EOF);
41 ingob 1888
        while((string[i] != 0)&& (c != EOF))
24 StephanB 1889
        {
41 ingob 1890
                c = fputc_(string[i], file);
1891
                i++;
24 StephanB 1892
        }
41 ingob 1893
        return(c);
24 StephanB 1894
}
1895
 
41 ingob 1896
/****************************************************************************************************************************************/
1897
/*      Function:               fgets_(s8 *, s16 , File_t *);                                                                                                                                                                           */
1898
/*                                                                                                                                                                                                                                                                              */
1899
/*      Description:    This function reads a string from the file to the specifies string.                                                                                             */
1900
/*                                                                                                                                                                                                                                                                              */
1901
/*      Returnvalue:    A pointer to the string read from the file or 0 on error.                                                                                                                       */
1902
/****************************************************************************************************************************************/
89 killagreg 1903
s8 * fgets_(s8 * const string, s16 const length, File_t * const file)
24 StephanB 1904
{
89 killagreg 1905
        s8 *pbuff;
1906
        s16 c = 0, bytecount;
88 killagreg 1907
 
89 killagreg 1908
        if((!Partition.IsValid) || (file == NULL) || (string == NULL) || (length < 1)) return (0);
1909
        bytecount = length;
1910
        pbuff = string;                                                         // set write pointer to start of string
1911
        while(bytecount > 1)                                            // read the length-1 characters from the file to the string.
24 StephanB 1912
        {
41 ingob 1913
                c = fgetc_(file);                                               // read a character from the opened file.
1914
                switch(c)
1 ingob 1915
                {
89 killagreg 1916
                        case 0x0A:                                                      // new line
1917
                                *pbuff = 0;                                             // set string terminator
1918
                                return(string);                                 // return normal
88 killagreg 1919
 
41 ingob 1920
                        case EOF:
89 killagreg 1921
                                *pbuff = 0;                                             // set string terminator
1922
                                return(0);
1923
 
1924
                        default:
1925
                                *pbuff++ = (s8)c;                               // copy byte to string
1926
                                bytecount--;
88 killagreg 1927
                                break;
1 ingob 1928
                }
24 StephanB 1929
        }
89 killagreg 1930
        *pbuff = 0;     // set string terminator
41 ingob 1931
        return(string);
24 StephanB 1932
}
1933
 
41 ingob 1934
/****************************************************************************************************************************************/
1935
/*      Function:               fexist_(const u8*);                                                                                                                                                                                                     */
1936
/*                                                                                                                                                                                                                                                                              */
1937
/*      Description:    This function checks if a file already exist.                                                                                                                                           */
1938
/*                                                                                                                                                                                                                                                                              */
1939
/*      Returnvalue:    1 if the file exist else 0.                                                                                                                                                                                     */
1940
/****************************************************************************************************************************************/
89 killagreg 1941
u8 fexist_(s8 * const filename)
24 StephanB 1942
{
41 ingob 1943
        u8 exist = 0;
1944
        File_t *file = 0;
1945
        file = LockFilePointer();
1946
        exist = FileExist(filename, ATTR_NONE, ATTR_SUBDIRECTORY|ATTR_VOLUMELABEL, file);
1947
        UnlockFilePointer(file);
1948
        return(exist);
1 ingob 1949
}
24 StephanB 1950
 
41 ingob 1951
/****************************************************************************************************************************************/
1952
/*      Function:               feof_(File_t *File);                                                                                                                                                                                            */
1953
/*                                                                                                                                                                                                                                                                              */
1954
/*      Description:    This function checks wether the end of the file has been reached.                                                                                                                                               */
1955
/*                                                                                                                                                                                                                                                                              */
1956
/*      Returnvalue:    0 if the end of the file was not reached otherwise 1.                                                                                                                                                                           */
1957
/****************************************************************************************************************************************/
1958
u8 feof_(File_t *file)
88 killagreg 1959
{
41 ingob 1960
        if(((file->Position)+1) < (file->Size))
24 StephanB 1961
        {
1962
                return(0);
1963
        }
88 killagreg 1964
        else
24 StephanB 1965
        {
88 killagreg 1966
                return(1);
24 StephanB 1967
        }
1968
}
41 ingob 1969
 
210 killagreg 1970
/****************************************************************************************************************************************************/
1971
/* Function:    s8* FAT16_GetVolumeLabel(void)                                                                                                                                                                                                                  */
1972
/*                                                                                                                                                                                                                                                                                                      */
1973
/* Description: This function returns the volume label                                                                                                                                                                                          */
1974
/*                                                                                                                                                                                                                                                                                                      */
1975
/* Returnvalue: This function returns the pointer to the volume label or NULL if not found.                                                                                                                     */
1976
/****************************************************************************************************************************************************/
1977
s8* FAT16_GetVolumeLabel(void)
1978
{
1979
        s8              *pVolumeLabel = NULL;
1980
        u32             dir_sector, max_dir_sector, curr_sector;
1981
        u16     dir_entry = 0;
1982
        u8              i = 0;
41 ingob 1983
 
210 killagreg 1984
        DirEntry_t * dir;
1985
        File_t *file = NULL;
1986
 
1987
        // if Partition is not valud return NULL
1988
        if(!Partition.IsValid) return(pVolumeLabel);
1989
        // if Volume label was read before return it
1990
        if(Partition.VolumeLabel[0]!= '\0') return (Partition.VolumeLabel);
1991
        // try to catch a file pointer
1992
        file = LockFilePointer();
1993
        if(file == NULL) return(pVolumeLabel);
1994
        // search dir entries direct within the root directory area
1995
        file->DirectorySector = 0;
1996
        max_dir_sector = (Partition.MaxRootEntries * DIRENTRY_SIZE)/BYTES_PER_SECTOR;
1997
        file->FirstSectorOfFirstCluster = Partition.FirstRootDirSector;
1998
 
1999
        // update current file data area position to start of first cluster
2000
        file->FirstSectorOfCurrCluster  = file->FirstSectorOfFirstCluster;
2001
        file->SectorOfCurrCluster               = 0;
2002
        file->ByteOfCurrSector                  = 0;
2003
 
2004
        dir_sector = 0; // reset sector counter within a new cluster
2005
        do // loop over all sectors of the root directory
2006
        {
2007
                curr_sector = file->FirstSectorOfCurrCluster + dir_sector;      // calculate sector number
2008
                file->SectorInCache = curr_sector;                                                      // upate the sector number of file cache.
2009
                if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read the sector
2010
                {
2011
                        Fat16_Deinit();
2012
                        return(pVolumeLabel);
2013
                }
2014
                dir = (DirEntry_t *)file->Cache;                                                        // set pointer to directory
2015
                // search all directory entries within that sector
2016
                for(dir_entry = 0; dir_entry < DIRENTRIES_PER_SECTOR; dir_entry++)
2017
                {   // check for existing dir entry
2018
                        switch((u8)dir[dir_entry].Name[0])
2019
                        {
2020
                                case SLOT_EMPTY:
2021
                                case SLOT_DELETED:
2022
                                        // ignore empty or deleted dir entries
2023
                                        break;
2024
                                default:
2025
                                        // check attributes for volume label
2026
                                        if ((dir[dir_entry].Attribute & ATTR_VOLUMELABEL) != ATTR_VOLUMELABEL) break; // attribute must match
2027
                                        // (first 11 characters include 8 chars of basename and 3 chars extension.)
2028
                                        for(i = 0; i<11;i++) Partition.VolumeLabel[i] = dir[dir_entry].Name[i];
2029
                                        Partition.VolumeLabel[11] = '\0'; // terminate string
2030
                                        file->Attribute = dir[dir_entry].Attribute; // store attribute of found dir entry
2031
                                        file->FirstSectorOfFirstCluster = Fat16ClusterToSector(dir[dir_entry].StartCluster); // set sector of first data cluster
2032
                                        file->FirstSectorOfCurrCluster = file->FirstSectorOfFirstCluster;
219 killagreg 2033
                                        file->SectorOfCurrCluster = 0;
2034
                                        file->ByteOfCurrSector = 0;
210 killagreg 2035
                                        file->DirectorySector = curr_sector; // current sector
2036
                                        file->DirectoryIndex  = dir_entry; // current direntry in current sector
2037
                                        file->Size = dir[dir_entry].Size;
2038
                                        dir_entry = DIRENTRIES_PER_SECTOR;      // stop for-loop
2039
                                        pVolumeLabel =  Partition.VolumeLabel;
2040
                        } // end of first byte of name check
2041
                }
2042
                dir_sector++; // search next sector
2043
        // stop if we reached the end of the cluster or the end of the root dir
2044
        }while((dir_sector < max_dir_sector) && (!pVolumeLabel));
2045
 
2046
        UnlockFilePointer(file);
2047
        return(pVolumeLabel);
2048
}