Subversion Repositories NaviCtrl

Rev

Rev 324 | Rev 353 | Go to most recent revision | 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>
349 ingob 58
#include <string.h>
41 ingob 59
#include "91x_lib.h"
119 killagreg 60
#include "timer1.h"
41 ingob 61
#include "fat16.h"
62
#include "sdc.h"
63
#include "uart1.h"
1 ingob 64
 
349 ingob 65
void Test(void);
1 ingob 66
//________________________________________________________________________________________________________________________________________
88 killagreg 67
// Module name:                 fat16.c
1 ingob 68
// Compiler used:               avr-gcc 3.4.5
211 killagreg 69
// Last Modifikation:   20.03.2010
70
// Version:                             2.10
88 killagreg 71
// Authors:                             Stephan Busker & Gregor Stobrawa
41 ingob 72
// Description:                 Source files for FAT16 implementation with read and write-access
73
//                                              Copyright (C) 2008 Stephan Busker & Gregor Stobrawa
1 ingob 74
//........................................................................................................................................
41 ingob 75
// Functions:                   extern s16              Fat16_Init(void);
88 killagreg 76
//                                              extern s16              Fat16_Deinit(void);
211 killagreg 77
//                                              extern s8*              FAT16_GetVolumeLabel(void);
41 ingob 78
//                                              extern File_t * fopen_(const u8 *filename, const s8 mode);
79
//                                              extern s16              fclose_(File_t *File);
211 killagreg 80
//                                              extern u8               fexist_(s8 * const filename);
41 ingob 81
//                                              extern s16              fflush_(File_t *File);
82
//                                              extern s16      fseek_(File_t *File, s32 offset, s16 origin);
83
//                                              extern s16              fgetc_(File_t *File);
84
//                                              extern s16              fputc_(u8 c, File_t *File);
88 killagreg 85
//                                              extern u32              fread_(void *buffer, u32 size, u32 count, File_t *File);
41 ingob 86
//                                              extern u32              fwrite_(void *buffer, u32 size, u32 count, File_t *File);
87
//                                              extern s16              fputs_(const u8 *string, File_t *File);
88
//                                              extern u8 *     fgets_(u8 *string, s16 length, File_t *File);
211 killagreg 89
//                                              extern u8               feof_(File_t * const file);
1 ingob 90
//........................................................................................................................................
41 ingob 91
// ext. functions:              extern SD_Result_t SDC_Init(void;)
92
//                                              extern SD_Result_t SDC_Deinit(void);
88 killagreg 93
//                      extern SD_Result_t SDC_GetSector (u32,u8 *);
41 ingob 94
//                                              extern SD_Result_t SDC_PutSector (u32,u8 *);
1 ingob 95
//........................................................................................................................................
96
//
97
// URL:                                 www.Mikro-Control.de
98
// mailto:                              stephan.busker@mikro-control.de
99
//________________________________________________________________________________________________________________________________________
100
 
41 ingob 101
/*
102
FAT16 Drive Layout:
103
Description                                             Offset
104
Volume Boot Sector                                      Start of Partition
105
Fat Tables                                                      Start + # of Reserved Sectors
106
Root Directory Entry                            Start + # of Reserved + (# of Sectors Per FAT * 2)
107
Data Area (Starts with Cluster #2)      Start + # of Reserved + (# of Sectors Per FAT * 2) + ((Maximum Root Directory Entries * 32) / Bytes per Sector)
108
*/
1 ingob 109
 
110
 
41 ingob 111
/*
112
________________________________________________________________________________________________________________________________________
88 killagreg 113
 
114
        Structure of an partition entry
41 ingob 115
________________________________________________________________________________________________________________________________________
1 ingob 116
 
41 ingob 117
        Partition Entry is 16 bytes long
118
*/
119
typedef struct
120
{
121
        u8      PartitionState;                         // Current State of Partition (00h=Inactive, 80h=Active)
122
        u8      BeginningHead;                          // Beginning of Partition - Head
123
        u16     BeginningCylSec;                        // Beginning of Partition - Cylinder/Sector (See Below)
124
        u8      Type;                                           // Type of Partition (See List Below)
125
        u8      EndHead;                                        // End of Partition - Head
126
        u16     EndCylSec;                                      // End of Partition - Cylinder/Sector
127
        u32     NoSectorsBeforePartition;       // Number of Sectors between the MBR and the First Sector in the Partition
128
        u32     NoSectorsPartition      ;               // Number of Sectors in the Partition
88 killagreg 129
} __attribute__((packed)) PartitionEntry_t;
1 ingob 130
 
349 ingob 131
 
132
 
41 ingob 133
/*
134
Coding of Cylinder/Sector words
1 ingob 135
 
41 ingob 136
Cylinder is 10 bits:  [7:0] at [15:8] and [9:8] at [7:6]
88 killagreg 137
Sector is 5 bits:  [5:0] at [5:0]
41 ingob 138
*/
1 ingob 139
 
41 ingob 140
// Partition Types:
141
#define PART_TYPE_UNKNOWN                       0x00
142
#define PART_TYPE_FAT12                         0x01
143
#define PART_TYPE_XENIX                         0x02
144
#define PART_TYPE_FAT16_ST_32_MB        0x04
145
#define PART_TYPE_EXTDOS                        0x05
146
#define PART_TYPE_FAT16_LT_32_MB        0x06
147
#define PART_TYPE_NTFS                          0x07
148
#define PART_TYPE_FAT32                         0x0B
149
#define PART_TYPE_FAT32LBA                      0x0C
150
#define PART_TYPE_FAT16LBA                      0x0E
151
#define PART_TYPE_EXTDOSLBA                     0x0F
152
#define PART_TYPE_EISA                          0x12
153
#define PART_TYPE_ONTRACK                       0x33
154
#define PART_TYPE_NOVELL                        0x40
155
#define PART_TYPE_DYNAMIC                       0x42
156
#define PART_TYPE_PCIX                          0x4B
157
#define PART_TYPE_LINUX_SWAP            0x82
158
#define PART_TYPE_LINUX_NATIVE          0x83
159
#define PART_TYPE_LINUX_LVM                     0x8E
160
#define PART_TYPE_PHOENIXSAVE           0xA0
161
#define PART_TYPE_FREEBSD                       0xA5
162
#define PART_TYPE_OPENBSD                       0xA6
163
#define PART_TYPE_NETNBSD                       0xA9
164
#define PART_TYPE_CPM                           0xDB
165
#define PART_TYPE_DBFS                          0xE0
166
#define PART_TYPE_BBT                           0xFF
1 ingob 167
 
168
 
41 ingob 169
/*
170
________________________________________________________________________________________________________________________________________
88 killagreg 171
 
172
        Structure of the MasterBootRecord
41 ingob 173
________________________________________________________________________________________________________________________________________
1 ingob 174
 
41 ingob 175
        Master Boot Record is 512 bytes long
176
        The Master Boot Record is the same for pretty much all Operating Systems.
177
        It is located on the first Sector of the Hard Drive, at Cylinder 0, Head 0, Sector 1
178
*/
179
typedef struct
180
{
88 killagreg 181
        u8                              ExecutableCode[446];    // 446 bytes for machine start code
182
        PartitionEntry_t        PartitionEntry1;                // 16 bytes for partition entry 1
183
        PartitionEntry_t        PartitionEntry2;                // 16 bytes for partition entry 2
184
        PartitionEntry_t        PartitionEntry3;                // 16 bytes for partition entry 3
185
        PartitionEntry_t        PartitionEntry4;                // 16 bytes for partition entry 4
186
        u16                                     ExecutableMarker;               // BIOS-Signature (0x55 0xAA)
187
} __attribute__((packed)) MBR_Entry_t;
1 ingob 188
 
189
 
41 ingob 190
/*
191
________________________________________________________________________________________________________________________________________
88 killagreg 192
 
193
        Structure of the VolumeBootRecord
41 ingob 194
________________________________________________________________________________________________________________________________________
24 StephanB 195
 
41 ingob 196
        The Volume Boot Record is 512 bytes long
197
        This information is located in the first sector of every partition.
198
*/
199
typedef struct
200
{
201
        u8  JumpCode[3];                        // Jump Code + NOP
88 killagreg 202
        s8  OEMName[8];                         // OEM Name
41 ingob 203
        u16 BytesPerSector;                     // Bytes Per Sector
204
        u8  SectorsPerCluster;          // Sectors Per Cluster
205
        u16 ReservedSectors;            // Reserved Sectors
206
        u8  NoFATCopies;                        // Number of Copies of FAT
88 killagreg 207
        u16 MaxRootEntries;                     // Maximum Root Directory Entries
41 ingob 208
        u16 NoSectorsInPartSml32MB;     // Number of Sectors in Partition Smaller than 32 MB
209
        u8  MediaDescriptor;            // Media Descriptor (0xF8 for Hard Disks)
210
        u16 SectorsPerFAT;                      // Sectors Per FAT
211
        u16 SectorsPerTrack;            // Sectors Per Track
212
        u16 NoHeads;                            // Number of Heads
213
        u32 NoHiddenSectors;            // Number of Hidden Sectors     in Partition
214
        u32 NoSectors;                          // Number of Sectors in Partition
215
        u16     DriveNo;                                // Logical Drive Number of Partition
216
        u8  ExtendedSig;                        // Extended Signature (0x29)
217
        u32 SerialNo;                           // Serial Number of the Partition
218
        s8  VolumeName[11];                     // Volume Name of the Partititon
219
        s8  FATName[8];                         // FAT Name (FAT16)
88 killagreg 220
        u8  ExecutableCode[446];        // 446 bytes for machine start code
221
        u16 ExecutableMarker;           // Executable Marker (0x55 0xAA)
222
} __attribute__((packed)) VBR_Entry_t;
1 ingob 223
 
224
 
225
 
41 ingob 226
/*
227
________________________________________________________________________________________________________________________________________
228
 
88 killagreg 229
        Structure of an directory entry
41 ingob 230
________________________________________________________________________________________________________________________________________
231
 
232
        Directory entry is 32 bytes.
233
*/
234
typedef struct
1 ingob 235
{
41 ingob 236
        s8      Name[8];                                        // 8 bytes name, padded with spaces.
237
        u8      Extension[3];                           // 3 bytes extension, padded with spaces.
238
        u8      Attribute;                                      // attribute of the directory entry (unused,archive,read-only,system,directory,volume)
211 killagreg 239
        u8  Res1;                                               // should be zero
240
        u8  CreationTime10ms;                   // subsecond resolution of creation time
241
        u16 CreationTime;                               // Time of creation h:m:s
242
        u16 CreationDate;                               // Date of creation Y.M.D
243
        u16 LastAccessDate;             // The date where the file was last accessed
244
        u8      Res2[2];                                    // should be zero
245
        u16 ModTime;                                    // date of last write access
246
        u16 ModDate;                                    // date of last write access to the file or directory.
41 ingob 247
        u16 StartCluster;                               // first cluster of the file or directory.
248
        u32 Size;                                               // size of the file or directory in bytes.
249
}  __attribute__((packed)) DirEntry_t;
1 ingob 250
 
41 ingob 251
#define SLOT_EMPTY              0x00    // slot has never been used
252
#define SLOT_E5                 0x05    // the real value is 0xe5
253
#define SLOT_DELETED            0xE5    // file in this slot deleted
1 ingob 254
 
41 ingob 255
#define ATTR_NONE               0x00    // normal file
256
#define ATTR_READONLY           0x01    // file is readonly
257
#define ATTR_HIDDEN                     0x02    // file is hidden
258
#define ATTR_SYSTEM                     0x04    // file is a system file
259
#define ATTR_VOLUMELABEL        0x08    // entry is a volume label
260
#define ATTR_LONG_FILENAME      0x0F    // this is a long filename entry
261
#define ATTR_SUBDIRECTORY       0x10    // entry is a directory name
262
#define ATTR_ARCHIVE            0x20    // file is new or modified
24 StephanB 263
 
264
 
41 ingob 265
/*
266
________________________________________________________________________________________________________________________________________
88 killagreg 267
 
268
        Structure of an entry within the fileallocationtable.
41 ingob 269
________________________________________________________________________________________________________________________________________
270
*/
271
typedef struct
272
{
273
        u16  NextCluster;                               // the next cluster of the file.
274
} __attribute__((packed)) Fat16Entry_t;
1 ingob 275
 
41 ingob 276
// secial fat entries
277
#define FAT16_CLUSTER_FREE                      0x0000
278
#define FAT16_CLUSTER_RESERVED          0x0001
279
#define FAT16_CLUSTER_USED_MIN          0x0002
280
#define FAT16_CLUSTER_USED_MAX          0xFFEF
281
#define FAT16_CLUSTER_ROOTDIR_MIN       0xFFF0
282
#define FAT16_CLUSTER_ROOTDIR_MAX       0xFFF6
283
#define FAT16_CLUSTER_BAD                       0xFFF7
284
#define FAT16_CLUSTER_LAST_MIN          0xFFF8
285
#define FAT16_CLUSTER_LAST_MAX          0xFFFF
286
 
88 killagreg 287
/*****************************************************************************************************************************************/
41 ingob 288
/*                                                                                                                                                                                                                                                                               */
289
/*      Global variables needed for read- or write-acces to the FAT16- filesystem.                                                                                                                       */
290
/*                                                                                                                                                                                                                                                                               */
291
/*****************************************************************************************************************************************/
292
 
293
#define MBR_SECTOR                                      0x00    // the masterboot record is located in sector 0.
294
#define DIRENTRY_SIZE                           32              //bytes
295
#define DIRENTRIES_PER_SECTOR           BYTES_PER_SECTOR/DIRENTRY_SIZE
296
#define FAT16_BYTES                                     2
297
#define FAT16_ENTRIES_PER_SECTOR        BYTES_PER_SECTOR/FAT16_BYTES
298
 
211 killagreg 299
#define SECTOR_UNDEFINED        0x00000000L
300
#define CLUSTER_UNDEFINED       0x0000
301
 
88 killagreg 302
#define FSTATE_UNUSED   0
41 ingob 303
#define FSTATE_USED             1
304
 
305
typedef struct
1 ingob 306
{
41 ingob 307
        u8      IsValid;                                // 0 means invalid, else valid
308
        u8      SectorsPerCluster;              // how many sectors does a cluster contain?
309
        u8      FatCopies;                              // Numbers of copies of the FAT
310
        u16     MaxRootEntries;                 // Possible number of entries in the root directory.
311
        u16     SectorsPerFat;                  // how many sectors does a fat16 contain?
312
        u32 FirstFatSector;                     // sector of the start of the fat
313
        u32 FirstRootDirSector;         // sector of the rootdirectory
314
        u32 FirstDataSector;            // sector of the first cluster containing data (cluster2).
315
        u32 LastDataSector;                     // the last data sector of the partition
349 ingob 316
        u8  VolumeLabel[12];        // the volume label
317
        u32     CurrentWorkingDirectory;// A pointer to the directory we are actual using 
318
        s8      PathToCwd[256];                 // a string containing the complete path to the current working directory                               
319
}   __attribute__((packed)) Partition_t;
1 ingob 320
 
349 ingob 321
Partition_t     Partition;              // Structure holds partition information
1 ingob 322
 
41 ingob 323
File_t FilePointer[FILE_MAX_OPEN];      // Allocate Memmoryspace for each filepointer used.
1 ingob 324
 
41 ingob 325
 
326
/****************************************************************************************************************************************/
211 killagreg 327
/*      Function:               FileDate(DateTime_t *);                                                                                                                                                                                         */
41 ingob 328
/*                                                                                                                                                                                                                                                                              */
211 killagreg 329
/*      Description:    This function calculates the DOS date from a pointer to a time structure.                                                                                       */
41 ingob 330
/*                                                                                                                                                                                                                                                                              */
211 killagreg 331
/*      Returnvalue:    Returns the DOS date.                                                                                                                                                                                           */
41 ingob 332
/****************************************************************************************************************************************/
211 killagreg 333
u16 FileDate(DateTime_t * pTimeStruct)
334
{
335
        u16 date = 0;
336
        if(pTimeStruct == NULL)   return date;
337
        if(!(pTimeStruct->Valid)) return date;
41 ingob 338
 
211 killagreg 339
        date |= (0x007F & (u16)(pTimeStruct->Year - 1980))<<9; // set year
340
        date |= (0x000F & (u16)(pTimeStruct->Month))<<5; // set month
341
        date |= (0x001F & (u16)(pTimeStruct->Day));
342
        return date;
343
}
344
 
345
/****************************************************************************************************************************************/
346
/*      Function:               FileTime(DateTime_t *);                                                                                                                                                                                         */
347
/*                                                                                                                                                                                                                                                                              */
348
/*      Description:    This function calculates the DOS time from a pointer to a time structure.                                                                                       */
349
/*                                                                                                                                                                                                                                                                              */
350
/*      Returnvalue:    Returns the DOS time.                                                                                                                                                                                           */
351
/****************************************************************************************************************************************/
352
 
353
u16 FileTime(DateTime_t * pTimeStruct)
1 ingob 354
{
211 killagreg 355
        u16 time = 0;
356
        if(pTimeStruct == NULL)   return time;
357
        if(!(pTimeStruct->Valid)) return time;
24 StephanB 358
 
211 killagreg 359
        time |= (0x001F & (u16)(pTimeStruct->Hour))<<11;
360
        time |= (0x003F & (u16)(pTimeStruct->Min))<<5;
361
        time |= (0x001F & (u16)(pTimeStruct->Sec/2));
362
        return time;
1 ingob 363
}
364
 
41 ingob 365
/****************************************************************************************************************************************/
366
/*      Function:               LockFilePointer();                                                                                                                                                                                                      */
367
/*                                                                                                                                                                                                                                                                              */
368
/*      Description:    This function trys to lock a free file pointer.                                                                                                                                         */
369
/*                                                                                                                                                                                                                                                                              */
370
/*      Returnvalue:    Returns the Filepointer on success or 0.                                                                                                                                                        */
371
/****************************************************************************************************************************************/
372
File_t * LockFilePointer(void)
1 ingob 373
{
41 ingob 374
        u8 i;
375
        File_t * File = 0;
376
        for(i = 0; i < FILE_MAX_OPEN; i++)
1 ingob 377
        {
88 killagreg 378
                if(FilePointer[i].State == FSTATE_UNUSED)               // found an unused one
1 ingob 379
                {
88 killagreg 380
                        File = &FilePointer[i];                                         // set pointer to that entry
41 ingob 381
                        FilePointer[i].State = FSTATE_USED;                     // mark it as used
382
                        break;
1 ingob 383
                }
41 ingob 384
        }
385
        return(File);
1 ingob 386
}
387
 
41 ingob 388
/****************************************************************************************************************************************/
389
/*      Function:               UnlockFilePointer(file_t *);                                                                                                                                                                            */
390
/*                                                                                                                                                                                                                                                                              */
391
/*      Description:    This function trys to unlock a file pointer.                                                                                                                                            */
392
/*                                                                                                                                                                                                                                                                              */
393
/*      Returnvalue:    Returns 1 if file pointer was freed else 0.                                                                                                                                                     */
394
/****************************************************************************************************************************************/
395
u8 UnlockFilePointer(File_t * file)
1 ingob 396
{
41 ingob 397
        u8 cnt;
398
        if(file == NULL) return(0);
399
        for(cnt = 0; cnt < FILE_MAX_OPEN; cnt++)
1 ingob 400
        {
41 ingob 401
                if(&FilePointer[cnt] == file)                                           // filepointer to be freed found?
1 ingob 402
                {
88 killagreg 403
                        file->State = FSTATE_UNUSED;
211 killagreg 404
                        file->FirstSectorOfFirstCluster = SECTOR_UNDEFINED;                     // Sectorpointer to the first sector of the first datacluster of the file.
405
                        file->FirstSectorOfCurrCluster  = SECTOR_UNDEFINED;                     // Pointer to the cluster which is edited at the moment.
41 ingob 406
                        file->SectorOfCurrCluster               = 0;                    // The sector which is edited at the moment (cluster_pointer + sector_index).
407
                        file->ByteOfCurrSector                  = 0;                    // The bytelocation within the current sector (cluster_pointer + sector_index + byte_index).
408
                        file->Mode                                              = 0;                    // mode of fileoperation (read,write)
409
                        file->Size                                              = 0;                    // the size of the opend file in bytes.
410
                        file->Position                                  = 0;                    // pointer to a character within the file 0 < fileposition < filesize
211 killagreg 411
                        file->SectorInCache                     = SECTOR_UNDEFINED;                     // the last sector read, wich is still in the sectorbuffer.
412
                        file->DirectorySector                   = SECTOR_UNDEFINED;                     // the sectorposition where the directoryentry has been made.
41 ingob 413
                        file->DirectoryIndex                    = 0;                    // the index to the directoryentry within the specified sector.
414
                        file->Attribute                                 = 0;                    // the attribute of the file opened.
88 killagreg 415
                        file = NULL;
41 ingob 416
                        return(1);
1 ingob 417
                }
41 ingob 418
        }
419
        return(0);
420
}
1 ingob 421
 
41 ingob 422
/****************************************************************************************************************************************/
423
/*      Function:               SeperateDirName(s8*, s8*);                                                                                                                                                                              */
424
/*                                                                                                                                                                                                                                                                              */
425
/*      Description:    This function seperates the first dirname from filepath and brings them                                                                                         */
426
/*                                      into the needed format ('test.txt' -> 'TEST    TXT')                                                                                                                            */
210 killagreg 427
/*                                      The subpath is the pointer to the remaining substring of the filepath                                                                                           */
41 ingob 428
/*                                                                                                                                                                                                                                                                              */
429
/*      Returnvalue:    Return NULL on error or pointer to subpath                                                                                                                                                                                                      */
430
/****************************************************************************************************************************************/
431
s8* SeperateDirName(const s8 *filepath, s8 *dirname)
432
{
433
        s8* subpath = NULL;
434
        u8 readpointer  = 0;
435
        u8 writepointer = 0;
1 ingob 436
 
88 killagreg 437
        // search subpath from beginning of filepath
41 ingob 438
        subpath = NULL;
439
        readpointer     = 0;
440
        if(filepath[0] == '/') readpointer = 1; // ignore first '/'
88 killagreg 441
        while(subpath == NULL)  // search the filepath until a subpath was found.
1 ingob 442
        {
88 killagreg 443
                if(((filepath[readpointer] == 0) || (filepath[readpointer] == '/')))    // if '/' found or end of filepath reached
444
                {
41 ingob 445
                        subpath = (s8*)&filepath[readpointer];                          // store the position of the first "/" found after the beginning of the filenpath
446
                }
447
                readpointer++;
448
        }
1 ingob 449
 
41 ingob 450
        // clear dirname with spaces
451
        dirname[11] = 0; // terminate dirname
452
        for(writepointer = 0; writepointer < 11; writepointer++) dirname[writepointer] = ' ';
453
        writepointer = 0;
454
        // start seperating the dirname from the filepath.
455
        readpointer = 0;
456
        if(filepath[0] == '/') readpointer = 1; // ignore first '/'
457
        while( &filepath[readpointer] < subpath)
1 ingob 458
        {
41 ingob 459
                if(writepointer >= 11) return(NULL);            // dirname to long
460
                if(filepath[readpointer] == '.')                        // seperating dirname and extension.
1 ingob 461
                {
41 ingob 462
                        if(writepointer <= 8)
1 ingob 463
                        {
41 ingob 464
                                readpointer++;                                          // next character in filename
465
                                writepointer = 8;                                       // jump to start of extension
1 ingob 466
                        }
88 killagreg 467
                        else return(NULL);                                              // dirbasename to long
41 ingob 468
                }
469
                else
470
                {
471
                        if((0x60 < filepath[readpointer]) && (filepath[readpointer] < 0x7B))
472
                        {
473
                                dirname[writepointer] = (filepath[readpointer] - 0x20);                                 // all characters must be upper case.
474
                        }
1 ingob 475
                        else
476
                        {
41 ingob 477
                                dirname[writepointer] = filepath[readpointer];
88 killagreg 478
                        }
41 ingob 479
                        readpointer++;
480
                        writepointer++;
1 ingob 481
                }
41 ingob 482
        }
88 killagreg 483
        return(subpath);
1 ingob 484
}
485
 
486
 
41 ingob 487
/**************************************************************************************************************************************+*/
488
/*      Function:       Fat16ClusterToSector( u16 cluster);                                                                                                                                                                             */
489
/*                                                                                                                                                                                                                                                                              */
490
/*      Description:    This function converts a cluster number given by the fat to the corresponding                                                                           */
491
/*                                      sector that points to the start of the data area that is represented by the cluster number.                                                     */
492
/*                                                                                                                                                                                                                                                                              */
493
/*      Returnvalue: The sector number with the data area of the given cluster                                                                                                                          */
494
/****************************************************************************************************************************************/
495
u32     Fat16ClusterToSector(u16 cluster)
496
{
211 killagreg 497
        if(!Partition.IsValid) return SECTOR_UNDEFINED;
218 killagreg 498
        if ((cluster < 2) || (cluster == CLUSTER_UNDEFINED))
211 killagreg 499
        {
500
                return SECTOR_UNDEFINED;
501
        }
502
        else
503
        {
504
                return ( (cluster - 2) * Partition.SectorsPerCluster) + Partition.FirstDataSector; // the first data sector     is represented by the 2nd cluster
505
        }
41 ingob 506
}
507
 
508
/****************************************************************************************************************************************/
509
/*      Function:       SectorToFat16Cluster( u32 sector);                                                                                                                                                                              */
510
/*                                                                                                                                                                                                                                                                              */
511
/*      Description:    This function converts a given sector number given to the corresponding                                                                                         */
512
/*                                      cluster number in the fat that represents this data area.                                                                                                                       */
513
/*                                                                                                                                                                                                                                                                              */
514
/*      Returnvalue: The cluster number representing the data area of the sector.                                                                                                                       */
515
/****************************************************************************************************************************************/
516
u16     SectorToFat16Cluster(u32 sector)
517
{
211 killagreg 518
        if(!Partition.IsValid) return CLUSTER_UNDEFINED;
519
        if((sector == SECTOR_UNDEFINED) || (sector < Partition.FirstDataSector)) return CLUSTER_UNDEFINED;
520
        else return ((u16)((sector - Partition.FirstDataSector) / Partition.SectorsPerCluster) + 2);
41 ingob 521
}
522
 
523
 
524
/****************************************************************************************************************************************/
210 killagreg 525
/*      Function:       Fat16_IsValid(void);                                                                                                                                                                                                    */
90 killagreg 526
/*                                                                                                                                                                                                                                                                              */
210 killagreg 527
/*      Description:    This function return the Fat 16 filesystem state                                                                                                                                        */
90 killagreg 528
/*                                                                                                                                                                                                                                                                              */
529
/*      Returnvalue: The function returns "1" on success                                                                                                                                                                        */
530
/****************************************************************************************************************************************/
531
u8 Fat16_IsValid(void)
532
{
533
        return(Partition.IsValid);
534
}
535
 
536
/****************************************************************************************************************************************/
41 ingob 537
/*      Function:       Fat16_Deinit(void);                                                                                                                                                                                                             */
538
/*                                                                                                                                                                                                                                                                              */
539
/*      Description:    This function uninitializes the fat 16 api                                                                                                                                                      */
540
/*                                                                                                                                                                                                                                                                              */
541
/*      Returnvalue: The function returns "0" on success                                                                                                                                                                        */
542
/****************************************************************************************************************************************/
543
u8 Fat16_Deinit(void)
544
{
545
        s16 returnvalue = 0;
546
        u8 cnt;
146 killagreg 547
 
548
        UART1_PutString("\r\n FAT16 deinit...");
41 ingob 549
        // declare the filepointers as unused.
550
        for(cnt = 0; cnt < FILE_MAX_OPEN; cnt++)
324 killagreg 551
        {      
552
                UnlockFilePointer(&FilePointer[cnt]);
1 ingob 553
        }
324 killagreg 554
        returnvalue = SDC_Deinit();                     // uninitialize interface to sd-card
41 ingob 555
        Partition.IsValid = 0;  // mark data in partition structure as invalid
210 killagreg 556
        Partition.VolumeLabel[0]='\0';
146 killagreg 557
        UART1_PutString("ok");
41 ingob 558
        return(returnvalue);
1 ingob 559
}
560
 
41 ingob 561
/****************************************************************************************************************************************/
562
/*      Function:               Fat16_Init(void);                                                                                                                                                                                                       */
563
/*                                                                                                                                                                                                                                                                          */
564
/*      Description:    This function reads the Masterbootrecord and finds the position of the Volumebootrecord, the FAT and the Rootdir    */
565
/*                                      and stores the information in global variables.                                                                                                                                     */
566
/*                                                                                                                                                                                                                                                                          */
567
/*      Returnvalue:    The function returns "0" if the filesystem is initialized.                                                                                                                      */
568
/****************************************************************************************************************************************/
569
u8 Fat16_Init(void)
88 killagreg 570
{
41 ingob 571
    u8  cnt     = 0;
572
        u32     partitionfirstsector;
88 killagreg 573
        VBR_Entry_t *VBR;
41 ingob 574
        MBR_Entry_t *MBR;
575
        File_t *file;
576
        u8 result = 0;
1 ingob 577
 
110 killagreg 578
        UART1_PutString("\r\n FAT16 init...");
41 ingob 579
        Partition.IsValid = 0;
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
349 ingob 662
        Partition.CurrentWorkingDirectory = Partition.FirstRootDirSector;
663
        strcpy(Partition.PathToCwd,"/");
41 ingob 664
        result = 0;
349 ingob 665
 
666
//      Test();
41 ingob 667
        end:
668
        if(result != 0) Fat16_Deinit();
110 killagreg 669
        else UART1_PutString("ok");
88 killagreg 670
        return(result);
1 ingob 671
}
672
 
673
 
41 ingob 674
 
675
/****************************************************************************************************************************************/
676
/* Function:    ClearCurrCluster(File_t*);                                                                                                                                                                                      */
677
/*                                                                                                                                                                                                                                                                              */
678
/* Description: This function fills the current cluster with 0.                                                                                                                                                 */
679
/*                                                                                                                                                                                                                                                                              */
680
/* Returnvalue: The function returns 1 on success else 0.                                                                                                                                                               */
681
/****************************************************************************************************************************************/
682
u8 ClearCurrCluster(File_t * file)
1 ingob 683
{
41 ingob 684
        u8 retvalue = 1;
685
        u32 i;
88 killagreg 686
 
41 ingob 687
        if((!Partition.IsValid) || (file == NULL)) return(0);
688
 
689
        for(i = 0; i < BYTES_PER_SECTOR; i++) file->Cache[i] = 0; // clear file cache
211 killagreg 690
        if(file->FirstSectorOfCurrCluster == SECTOR_UNDEFINED) return (0); // nothing to do 
41 ingob 691
        for(i = 0; i < Partition.SectorsPerCluster; i++)
1 ingob 692
        {
41 ingob 693
                file->SectorInCache = file->FirstSectorOfCurrCluster + i;
694
                if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))
695
                {
88 killagreg 696
                        Fat16_Deinit();
41 ingob 697
                        retvalue = 0;
282 killagreg 698
                        return(retvalue);
41 ingob 699
                }
1 ingob 700
        }
88 killagreg 701
        return(retvalue);
1 ingob 702
}
703
 
41 ingob 704
/*****************************************************************************************************************************************/
705
/* Function:    GetNextCluster(File_t* );                                                                                                                                                                                        */
706
/*                                                                                                                                                                                                                                                                               */
707
/* Description: This function finds the next datacluster of the file specified with File *File.                                                                                  */
708
/*                                                                                                                                                                                                                                                                               */
709
/* Returnvalue: The function returns the next cluster or 0 if the last cluster has already reached.                                                                                                      */
710
/*****************************************************************************************************************************************/
711
u16 GetNextCluster(File_t * file)
1 ingob 712
{
211 killagreg 713
        u16 cluster = CLUSTER_UNDEFINED;
41 ingob 714
        u32 fat_byte_offset, sector, byte;
715
        Fat16Entry_t * fat;
88 killagreg 716
 
41 ingob 717
        if((!Partition.IsValid) || (file == NULL)) return(cluster);
211 killagreg 718
        if(file->FirstSectorOfCurrCluster == SECTOR_UNDEFINED) return(cluster);
41 ingob 719
        // if sector is within the data area
720
        if((Partition.FirstDataSector <= file->FirstSectorOfCurrCluster)&& (file->FirstSectorOfCurrCluster <= Partition.LastDataSector))
1 ingob 721
        {
41 ingob 722
                // determine current file cluster
723
                cluster = SectorToFat16Cluster(file->FirstSectorOfCurrCluster);
724
                // calculate byte offset in the fat for corresponding entry
725
                fat_byte_offset = ((u32)cluster)<<1; // two FAT bytes (16 bits) for every cluster
726
                // calculate the sector that contains the current cluster within the fat
727
                sector = Partition.FirstFatSector + ( fat_byte_offset / BYTES_PER_SECTOR);
728
                // calculate byte offset of the current cluster within that fat sector
729
                byte = fat_byte_offset % BYTES_PER_SECTOR;
730
                // read this sector to the file cache
731
                if(file->SectorInCache != sector)
1 ingob 732
                {
41 ingob 733
                        file->SectorInCache = sector;                                           // update sector stored in buffer
734
                        if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))       // read sector from sd-card
24 StephanB 735
                        {
41 ingob 736
                                Fat16_Deinit();
737
                                return (cluster);
88 killagreg 738
                        }
739
                }
41 ingob 740
                // read the next cluster from cache
741
                fat = (Fat16Entry_t *)(&(file->Cache[byte]));
742
                cluster = fat->NextCluster;
211 killagreg 743
                // if no next cluster exist
41 ingob 744
                if(FAT16_CLUSTER_LAST_MIN <= cluster)
745
                {
211 killagreg 746
                         cluster = CLUSTER_UNDEFINED; // next cluster is undefined
1 ingob 747
                }
24 StephanB 748
                else
749
                {
41 ingob 750
                        file->FirstSectorOfCurrCluster = Fat16ClusterToSector(cluster);
751
                        file->SectorOfCurrCluster = 0;
752
                        file->ByteOfCurrSector = 0;
24 StephanB 753
                }
88 killagreg 754
        }
41 ingob 755
        return(cluster);
1 ingob 756
}
757
 
758
 
41 ingob 759
/****************************************************************************************************************************************/
760
/* Function:    FindNextFreeCluster(File_t *);                                                                                                                                                                          */
761
/*                                                                                                                                                                                                                                                                              */
762
/* Description: This function looks in the fat to find the next free cluster                                                                                                                    */
763
/*                                                                                                                                                                                                                                                                              */
764
/* Returnvalue: The function returns the cluster number of the next free cluster found within the fat.                                                                  */
765
/****************************************************************************************************************************************/
766
u16 FindNextFreeCluster(File_t *file)
1 ingob 767
{
41 ingob 768
        u32 fat_sector;                                 // current sector within the fat relative to the first sector of the fat.
769
        u32     curr_sector;                            // current sector
770
        u16     fat_entry;                                      // index to an fatentry within the actual sector (256 fatentries are possible within one sector).
211 killagreg 771
        u16     free_cluster    = CLUSTER_UNDEFINED;    // next free cluster number.
41 ingob 772
        Fat16Entry_t * fat;
88 killagreg 773
 
41 ingob 774
        if((!Partition.IsValid) || (file == NULL)) return(0);
24 StephanB 775
 
41 ingob 776
        // start searching for an empty cluster at the beginning of the fat.
88 killagreg 777
        fat_sector = 0;
778
        do
1 ingob 779
        {
41 ingob 780
                curr_sector = Partition.FirstFatSector + fat_sector;    // calculate sector to read
781
                file->SectorInCache = curr_sector;                                              // upate the sector number of file cache.
782
                if( SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))              // read sector of fat from sd-card.
783
                {
784
                        Fat16_Deinit();
785
                        return(free_cluster);
786
                }
787
 
788
                fat = (Fat16Entry_t *)file->Cache;                                              // set fat pointer to file cache
789
 
88 killagreg 790
                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 791
                {
792
                        if(fat[fat_entry].NextCluster == FAT16_CLUSTER_FREE)            // empty cluster found!!
88 killagreg 793
                        {
794
                                fat[fat_entry].NextCluster = FAT16_CLUSTER_LAST_MAX;    // mark this fat-entry as used
41 ingob 795
                                if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))               // and save the sector at the sd-card.
796
                                {
797
                                        Fat16_Deinit();
798
                                        return(free_cluster);
799
                                }
88 killagreg 800
                                free_cluster = (u16)(fat_sector * FAT16_ENTRIES_PER_SECTOR + (u32)fat_entry);
41 ingob 801
                                fat_entry = FAT16_ENTRIES_PER_SECTOR;                                   // terminate the search for a free cluster in this sector.
802
                        }
803
                }
804
                fat_sector++;                                                                                                   // continue the search in next fat sector
88 killagreg 805
        // repeat until the end of the fat is  reached and no free cluster has been found so far
41 ingob 806
        }while((fat_sector < Partition.SectorsPerFat) && (!free_cluster));
807
        return(free_cluster);
1 ingob 808
}
809
 
810
 
41 ingob 811
/****************************************************************************************************************************************************/
812
/* Function:    s16 fseek_(File_t *, s32 *, u8)                                                                                                                                                                                                         */
813
/*                                                                                                                                                                                                                                                                                                      */
814
/* Description: This function sets the pointer of the stream relative to the position                                                                                                                           */
815
/*                              specified by origin (SEEK_SET, SEEK_CUR, SEEK_END)                                                                                                                                                                      */
211 killagreg 816
/* Returnvalue: Is 0 if seek was successful                                                                                                                                                                                                                                                                     */
41 ingob 817
/****************************************************************************************************************************************************/
818
s16 fseek_(File_t *file, s32 offset, s16 origin)
1 ingob 819
{
41 ingob 820
        s32             fposition       = 0;
821
        s16     retvalue        = 1;
88 killagreg 822
 
211 killagreg 823
        if((!Partition.IsValid) || (file == NULL)) return(retvalue);
41 ingob 824
        switch(origin)
825
        {
826
                case SEEK_SET:                          // Fileposition relative to the beginning of the file.
88 killagreg 827
                        fposition = 0;
41 ingob 828
                        break;
829
                case SEEK_END:                          // Fileposition relative to the end of the file.
830
                        fposition = (s32)file->Size;
831
                        break;
832
                case SEEK_CUR:                          // Fileposition relative to the current position of the file.
833
                default:
834
                        fposition = file->Position;
835
                        break;
1 ingob 836
        }
41 ingob 837
 
838
        fposition += offset;
839
 
840
        if((fposition >= 0) && (fposition <= (s32)file->Size))          // is the pointer still within the file?
1 ingob 841
        {
41 ingob 842
                // reset file position to start of the file
843
                file->FirstSectorOfCurrCluster = file->FirstSectorOfFirstCluster;
844
                file->SectorOfCurrCluster       = 0;
845
                file->ByteOfCurrSector          = 0;
846
                file->Position                          = 0;
211 killagreg 847
                if(file->FirstSectorOfCurrCluster == SECTOR_UNDEFINED) return(retvalue);
41 ingob 848
                while(file->Position < fposition)       // repeat until the current position is less than target
1 ingob 849
                {
41 ingob 850
                        file->Position++;                               // increment file position
88 killagreg 851
                        file->ByteOfCurrSector++;               // next byte in current sector
852
                        if(file->ByteOfCurrSector >= BYTES_PER_SECTOR)
41 ingob 853
                        {
854
                                file->ByteOfCurrSector = 0;                                                                             // reading at the beginning of new sector.
855
                                file->SectorOfCurrCluster++;                                                                    // continue reading in next sector
856
                                if(file->SectorOfCurrCluster >= Partition.SectorsPerCluster)    // if end of cluster is reached, the next datacluster has to be searched in the FAT.
857
                                {
858
                                        if(GetNextCluster(file))                                                                        // Sets the clusterpointer of the file to the next datacluster.
859
                                        {
88 killagreg 860
                                                file->SectorOfCurrCluster = 0;
41 ingob 861
                                        }
862
                                        else // the last cluster was allready reached
863
                                        {
211 killagreg 864
                                                file->SectorOfCurrCluster--;                                                    // jump back to the last sector in the last cluster
41 ingob 865
                                                file->ByteOfCurrSector = BYTES_PER_SECTOR;                              // set ByteOfCurrSector one byte over sector end
866
                                        }
867
                                }
88 killagreg 868
                        }
869
                }
1 ingob 870
        }
88 killagreg 871
        if(file->Position == fposition) retvalue = 0;
1 ingob 872
        return(retvalue);
873
}
874
 
875
 
41 ingob 876
/****************************************************************************************************************************************/
877
/* Function:    u16 DeleteClusterChain(File *file);                                                                                                                                                                             */
878
/*                                                                                                                                                                                                                                                                              */
879
/* Description: This function trances along a cluster chain in the fat and frees all clusters visited.                                                                  */
880
/*                                                                                                                                                                                                                                                                              */
881
/****************************************************************************************************************************************/
882
u8 DeleteClusterChain(u16 StartCluster)
1 ingob 883
{
88 killagreg 884
        u16 cluster;
41 ingob 885
        u32 fat_byte_offset, sector, byte;
886
        Fat16Entry_t * fat;
887
        u8 buffer[BYTES_PER_SECTOR];
888
        u32 sector_in_buffer = 0;
889
        u8 repeat = 0;
890
 
211 killagreg 891
        if(!Partition.IsValid) return(0);
892
        if(StartCluster == CLUSTER_UNDEFINED) return(0);
210 killagreg 893
        cluster = StartCluster; // init chain trace
211 killagreg 894
        // if start cluster is no real cluster
895
    if(FAT16_CLUSTER_LAST_MIN <= cluster) return 1;
41 ingob 896
 
897
        // calculate byte offset in the fat for corresponding entry
898
        fat_byte_offset = ((u32)cluster)<<1; // two FAT bytes (16 bits) for every cluster
899
        // calculate the sector that contains the current cluster within the fat
900
        sector = Partition.FirstFatSector + ( fat_byte_offset / BYTES_PER_SECTOR);
901
        // calculate byte offset of the current cluster within that fat sector
902
        byte = fat_byte_offset % BYTES_PER_SECTOR;
88 killagreg 903
        do
1 ingob 904
        {
41 ingob 905
                if(sector != sector_in_buffer)
1 ingob 906
                {
41 ingob 907
                        // read this sector to buffer
908
                        sector_in_buffer = sector;
909
                        if(SD_SUCCESS != SDC_GetSector(sector_in_buffer, buffer)) return 0;     // read sector from sd-card
88 killagreg 910
                }
41 ingob 911
                // read the next cluster from cache
912
                fat = (Fat16Entry_t *)(&(buffer[byte]));
913
                cluster = fat->NextCluster;
211 killagreg 914
                fat->NextCluster =      FAT16_CLUSTER_FREE; // mark current cluster as free
915
 
916
                if((FAT16_CLUSTER_USED_MIN <= cluster) && (cluster <= FAT16_CLUSTER_USED_MAX) )
917
                {
918
                        repeat = 1;
919
                        // calculate sector byte and byte offset in the fat for the next cluster
920
                        fat_byte_offset = ((u32)cluster)<<1; // two FAT bytes (16 bits) for every cluster
921
                        // calculate the sector that contains the current cluster within the fat
922
                        sector = Partition.FirstFatSector + ( fat_byte_offset / BYTES_PER_SECTOR);
923
                        // calculate byte offset of the current cluster within that fat sector
924
                        byte = fat_byte_offset % BYTES_PER_SECTOR;
925
                }
41 ingob 926
                else repeat = 0;
927
 
928
                // if new sector is not the sector in buffer or the last cluster in the chain was traced
929
                if((sector != sector_in_buffer) || !repeat)
930
                {       // write sector in buffer
210 killagreg 931
                        if(SD_SUCCESS != SDC_PutSector(sector_in_buffer,buffer))
146 killagreg 932
                        {
933
                                Fat16_Deinit();
211 killagreg 934
                                return(0);
146 killagreg 935
                        }
1 ingob 936
                }
41 ingob 937
        }
938
        while(repeat);
939
 
940
        return 1;
1 ingob 941
}
942
 
943
 
41 ingob 944
/****************************************************************************************************************************************/
945
/* Function:    u16 AppendCluster(File *file);                                                                                                                                                                                  */
946
/*                                                                                                                                                                                                                                                                              */
947
/* Description: This function looks in the fat to find the next free cluster and appends it to the file.                                                                */
948
/*                                                                                                                                                                                                                                                                              */
211 killagreg 949
/* Returnvalue: The function returns the appened cluster number or CLUSTER_UNDEFINED of no cluster was appended.                                                */
41 ingob 950
/****************************************************************************************************************************************/
951
u16 AppendCluster(File_t *file)
1 ingob 952
{
211 killagreg 953
        u16 last_cluster, new_cluster = CLUSTER_UNDEFINED;
41 ingob 954
        u32 fat_byte_offset, sector, byte;
955
        Fat16Entry_t * fat;
88 killagreg 956
 
41 ingob 957
        if((!Partition.IsValid) || (file == NULL)) return(new_cluster);
1 ingob 958
 
41 ingob 959
        new_cluster = FindNextFreeCluster(file);        // the next free cluster found on the disk.
211 killagreg 960
        if(new_cluster != CLUSTER_UNDEFINED)
88 killagreg 961
        {       // A free cluster was found and can be added to the end of the file.
41 ingob 962
                fseek_(file, 0, SEEK_END);                                                                                                      // jump to the end of the file
88 killagreg 963
                last_cluster = SectorToFat16Cluster(file->FirstSectorOfCurrCluster);            // determine current file cluster
211 killagreg 964
                if(last_cluster != CLUSTER_UNDEFINED)
41 ingob 965
                {
211 killagreg 966
                        // update FAT entry of last cluster
967
                        fat_byte_offset = ((u32)last_cluster)<<1;
968
                        sector = Partition.FirstFatSector + ( fat_byte_offset / BYTES_PER_SECTOR);
969
                        byte = fat_byte_offset % BYTES_PER_SECTOR;
970
                        // read the sector containing the last cluster of the file
971
                        if(file->SectorInCache != sector)
41 ingob 972
                        {
211 killagreg 973
                                file->SectorInCache = sector;   // update sector stored in buffer
974
                                if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))       // read sector from sd-card
975
                                {
976
                                        Fat16_Deinit();
977
                                        return(0);
978
                                }
979
                        }
980
                        fat = (Fat16Entry_t *)(&(file->Cache[byte]));
981
                        fat->NextCluster = new_cluster;                                                 // append the free cluster to the end of the file in the FAT.
982
                        if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))               // save the modified sector to the FAT.
983
                        {
41 ingob 984
                                Fat16_Deinit();
211 killagreg 985
                                return(0);
88 killagreg 986
                        }
987
                }
211 killagreg 988
                else // last cluster of the file is undefined
989
                {   // then the new cluster must be the first one of the file
990
                    // and its cluster number must be set in the direntry
991
                        DirEntry_t * dir;
992
                        file->SectorInCache = file->DirectorySector;                            // update the sector number of file cache.
993
                        if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read in the sector.
994
                        {
995
                                Fat16_Deinit();
996
                                return(CLUSTER_UNDEFINED);
997
                        }
998
                        dir = (DirEntry_t *)file->Cache;                                                        // set pointer to directory
999
                        dir[file->DirectoryIndex].Res1 = 0;
1000
                        dir[file->DirectoryIndex].Res2[0] = 0;
1001
                        dir[file->DirectoryIndex].Res2[1] = 0;
1002
                        dir[file->DirectoryIndex].StartCluster = new_cluster;           // update startcluster 
1003
                    dir[file->DirectoryIndex].ModTime   = FileTime(&SystemTime);// set time
1004
                        dir[file->DirectoryIndex].ModDate       = FileDate(&SystemTime);// and date of modification
1005
                        dir[file->DirectoryIndex].LastAccessDate = dir[file->DirectoryIndex].ModDate;
1006
                        dir[file->DirectoryIndex].Size          = 0;
1007
                        // write sector containing the direntry
1008
                        if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))
1009
                        {
1010
                                Fat16_Deinit();
1011
                                return(CLUSTER_UNDEFINED);
1012
                        }
1013
                        // update file info     
1014
                        file->FirstSectorOfFirstCluster = Fat16ClusterToSector(new_cluster);
1015
                        file->Size = 0;
1016
                        file->Position = 0;
41 ingob 1017
                }
211 killagreg 1018
                // update file pointes
41 ingob 1019
                file->FirstSectorOfCurrCluster = Fat16ClusterToSector(new_cluster);
1020
                file->SectorOfCurrCluster = 0;
1021
                file->ByteOfCurrSector = 0;
1022
        }
1023
        return(new_cluster);
1 ingob 1024
}
1025
 
41 ingob 1026
/****************************************************************************************************************************************************/
1027
/* Function:    DirectoryEntryExist(s8 *, u8, u8, File_t *)                                                                                                                                                                                     */
1028
/*                                                                                                                                                                                                                                                                                                      */
1029
/* Description: This function searches all possible dir entries until the file or directory is found or the end of the directory is reached                     */
1030
/*                                                                                                                                                                                                                                                                                                      */
1031
/* Returnvalue: This function returns 1 if the directory entry specified was found.                                                                                                                                     */
1032
/****************************************************************************************************************************************************/
1033
u8 DirectoryEntryExist(s8 *dirname, u8 attribfilter, u8 attribmask, File_t *file)
1034
{
1035
        u32             dir_sector, max_dir_sector, curr_sector;
1036
        u16     dir_entry = 0;
24 StephanB 1037
 
41 ingob 1038
        u16     end_of_directory_not_reached = 0;
1039
        u8              i = 0;
1040
        u8      direntry_exist = 0;
1041
        DirEntry_t * dir;
24 StephanB 1042
 
41 ingob 1043
        // if incomming pointers are useless return immediatly
88 killagreg 1044
        if((!Partition.IsValid) || (file == NULL) || (dirname == NULL)) return(direntry_exist);
41 ingob 1045
 
88 killagreg 1046
        // dir entries can be searched only in filesclusters that have
1047
        // a corresponding dir entry with adir-flag set in its attribute
41 ingob 1048
        // or direct within the root directory area
211 killagreg 1049
        file->FirstSectorOfFirstCluster = SECTOR_UNDEFINED;
41 ingob 1050
        // no current directory exist therefore assume searching in the root
211 killagreg 1051
        if(file->DirectorySector == SECTOR_UNDEFINED)
24 StephanB 1052
        {
41 ingob 1053
                max_dir_sector = (Partition.MaxRootEntries * DIRENTRY_SIZE)/BYTES_PER_SECTOR;
1054
                file->FirstSectorOfFirstCluster = Partition.FirstRootDirSector;
1055
        }
1056
        // within the root directory area we can read sectors sequentially until the end of this area
1057
        else if((Partition.FirstRootDirSector <= file->DirectorySector) && (file->DirectorySector < Partition.FirstDataSector))
1058
        {
1059
                max_dir_sector = (Partition.MaxRootEntries * DIRENTRY_SIZE)/BYTES_PER_SECTOR;
1060
        }
88 killagreg 1061
        // within the data clusters we can read sectors sequentially only within the cluster
41 ingob 1062
        else if((Partition.FirstDataSector <= file->DirectorySector) && (file->DirectorySector <= Partition.LastDataSector))
1063
        {
1064
                max_dir_sector = Partition.SectorsPerCluster;                           // limit max secters before next cluster
1065
        }
1066
        else return (direntry_exist); // bad sector range for directory sector of the file
1067
        // if search area is not defined yet
211 killagreg 1068
        if(file->FirstSectorOfFirstCluster == SECTOR_UNDEFINED)
41 ingob 1069
        {
1070
                // check if the directory entry of current file is existent and has the dir-flag set
1071
                file->SectorInCache = file->DirectorySector;                            // update the sector number of file cache.
1072
                if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read in the sector.
24 StephanB 1073
                {
41 ingob 1074
                        Fat16_Deinit();
1075
                        return(direntry_exist);
24 StephanB 1076
                }
41 ingob 1077
                dir = (DirEntry_t *)file->Cache;                                                        // set pointer to directory
211 killagreg 1078
                switch((u8)dir[file->DirectoryIndex].Name[0])                           // check if current directory exist
24 StephanB 1079
                {
41 ingob 1080
                        case SLOT_EMPTY:
1081
                        case SLOT_DELETED:
1082
                                // the directrory pointer of this file points to a deleted or not existen directory
1083
                                // therefore no file or subdirectory can be created
1084
                                return (direntry_exist);
1085
                                break;
88 killagreg 1086
                        default:        // and is a real directory
41 ingob 1087
                                if((dir[file->DirectoryIndex].Attribute & ATTR_SUBDIRECTORY) != ATTR_SUBDIRECTORY)
1088
                                {       // current file is not a directory therefore no file or subdirectory can be created here
1089
                                        return (direntry_exist);
1090
                                }
1091
                                break;
24 StephanB 1092
                }
41 ingob 1093
                file->FirstSectorOfFirstCluster = Fat16ClusterToSector(dir[file->DirectoryIndex].StartCluster);
24 StephanB 1094
        }
1095
 
41 ingob 1096
        // update current file data area position to start of first cluster
88 killagreg 1097
        file->FirstSectorOfCurrCluster  = file->FirstSectorOfFirstCluster;
1098
        file->SectorOfCurrCluster               = 0;
41 ingob 1099
        file->ByteOfCurrSector                  = 0;
24 StephanB 1100
 
41 ingob 1101
        do // loop over all data clusters of the current directory entry
88 killagreg 1102
        {
349 ingob 1103
                dir_sector = 0;
41 ingob 1104
                do // loop over all sectors of a cluster or all sectors of the root directory
88 killagreg 1105
                {
41 ingob 1106
                        curr_sector = file->FirstSectorOfCurrCluster + dir_sector;      // calculate sector number
1107
                        file->SectorInCache = curr_sector;                                                      // upate the sector number of file cache.
1108
                        if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read the sector
1109
                        {
1110
                                Fat16_Deinit();
88 killagreg 1111
                                return(direntry_exist);
41 ingob 1112
                        }
1113
                        dir = (DirEntry_t *)file->Cache;                                                        // set pointer to directory
1114
                        // search all directory entries within that sector
1115
                        for(dir_entry = 0; dir_entry < DIRENTRIES_PER_SECTOR; dir_entry++)
1116
                        {   // check for existing dir entry
1117
                                switch((u8)dir[dir_entry].Name[0])
1118
                                {
1119
                                        case SLOT_EMPTY:
1120
                                        case SLOT_DELETED:
1121
                                                // ignore empty or deleted dir entries
1122
                                                break;
1123
                                        default:
1124
                                                // if existing check attributes before names are compared will safe performance
1125
                                                if ((dir[dir_entry].Attribute & attribmask) != attribfilter) break; // attribute must match
1126
                                                // then compare the name to the giveb dirname (first 11 characters include 8 chars of basename and 3 chars extension.)
1127
                                                i = 0;
1128
                                                while((i < 11) && (dir[dir_entry].Name[i] == dirname[i])) i++;
1129
                                                if (i < 10) break; // names does not match
1130
                                                // if dirname and attribute have matched
1131
                                                file->Attribute = dir[dir_entry].Attribute; // store attribute of found dir entry
88 killagreg 1132
                                                file->FirstSectorOfFirstCluster = Fat16ClusterToSector(dir[dir_entry].StartCluster); // set sector of first data cluster
41 ingob 1133
                                                file->FirstSectorOfCurrCluster = file->FirstSectorOfFirstCluster;
1134
                                                file->SectorOfCurrCluster = 0;
1135
                                                file->ByteOfCurrSector = 0;
1136
                                                file->DirectorySector = curr_sector; // current sector
1137
                                                file->DirectoryIndex  = dir_entry; // current direntry in current sector
88 killagreg 1138
                                                file->Size = dir[dir_entry].Size;
1139
                                                direntry_exist = 1; // mark as found
1140
                                                dir_entry = DIRENTRIES_PER_SECTOR;      // stop for-loop
41 ingob 1141
                                } // end of first byte of name check
1142
                        }
1143
                        dir_sector++; // search next sector
1144
                // stop if we reached the end of the cluster or the end of the root dir
1145
                }while((dir_sector < max_dir_sector) && (!direntry_exist));
1 ingob 1146
 
41 ingob 1147
                // if we are seaching in the data area and the file not found in this cluster so take next cluster.
88 killagreg 1148
                if(!direntry_exist && ( Partition.FirstDataSector <= file->FirstSectorOfCurrCluster))
41 ingob 1149
                {
1150
                        end_of_directory_not_reached = GetNextCluster(file);  // updates File->FirstSectorOfCurrCluster
1151
                }
1152
        }while((end_of_directory_not_reached) && (!direntry_exist)); // repeat until a next cluster exist an no
1153
        return(direntry_exist);
1 ingob 1154
}
1155
 
1156
 
41 ingob 1157
/****************************************************************************************************************************************/
1158
/*      Function:               CreateDirectoryEntry(s8 *, u16, File_t *)                                                                                                                                                       */
1159
/*                                                                                                                                                                                                                                                                              */
1160
/*      Description:    This function looks for the next free position in the directory and creates an entry.                                                           */
1161
/*                                      The type of an directory entry is specified by the file attribute.                                                                                                      */
1162
/*                                                                                                                                                                                                                                                                              */
1163
/*      Returnvalue:    Return 0 on error                                                                                                                                                                                                       */
1164
/****************************************************************************************************************************************/
1165
u8 CreateDirectoryEntry(s8 *dirname, u8 attrib, File_t *file)
1 ingob 1166
{
41 ingob 1167
        u32 dir_sector, max_dir_sector, curr_sector;
1168
        u16 dir_entry   = 0;
1169
        u16 subdircluster, dircluster = 0;
1170
        u16 end_of_directory_not_reached = 0;
1171
        u8      i                       = 0;
88 killagreg 1172
        u8      retvalue        = 0;
41 ingob 1173
        DirEntry_t *dir;
1174
 
1175
        if((!Partition.IsValid) || (file == NULL) || (dirname == NULL)) return (retvalue);
1176
        // It is not checked here that the dir entry that should be created is already existent!
88 killagreg 1177
 
1178
        // Dir entries can be created only in file-clusters that have
41 ingob 1179
        // the dir-flag set in its attribute or within the root directory
88 killagreg 1180
 
211 killagreg 1181
        file->FirstSectorOfFirstCluster = SECTOR_UNDEFINED;
41 ingob 1182
        // no current directory exist therefore assume creating in the root
211 killagreg 1183
        if(file->DirectorySector == SECTOR_UNDEFINED)
24 StephanB 1184
        {
41 ingob 1185
                max_dir_sector = (Partition.MaxRootEntries * DIRENTRY_SIZE)/BYTES_PER_SECTOR;
1186
                dircluster = 0;
1187
                file->FirstSectorOfFirstCluster = Partition.FirstRootDirSector;
1188
        }
1189
        // within the root directory area we can read sectors sequentially until the end of this area
1190
        else if((Partition.FirstRootDirSector <= file->DirectorySector) && (file->DirectorySector < Partition.FirstDataSector))
1191
        {
1192
                max_dir_sector = (Partition.MaxRootEntries * DIRENTRY_SIZE)/BYTES_PER_SECTOR;
1193
        }
88 killagreg 1194
        // within the data clusters we can read sectors sequentially only within the cluster
41 ingob 1195
        else if((Partition.FirstDataSector <= file->DirectorySector) && (file->DirectorySector <= Partition.LastDataSector))
1196
        {
1197
                max_dir_sector = Partition.SectorsPerCluster;
1198
        }
88 killagreg 1199
        else return (retvalue); // bad sector range for directory sector of the file
41 ingob 1200
        // if search area is not defined yet
211 killagreg 1201
        if(file->FirstSectorOfFirstCluster == SECTOR_UNDEFINED)
41 ingob 1202
        {
1203
            // check if the directory entry of current file is existent and has the dir-flag set
1204
                file->SectorInCache = file->DirectorySector;                            // update the sector number of file cache.
88 killagreg 1205
                if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read in the sector.
41 ingob 1206
                {
1207
                        Fat16_Deinit();
1208
                        return(retvalue);
88 killagreg 1209
                }
41 ingob 1210
                dir = (DirEntry_t *)file->Cache;                                                        // set pointer to directory
218 killagreg 1211
                switch((u8)dir[file->DirectoryIndex].Name[0])                           // check if current directory exist
41 ingob 1212
                {
1213
                        case SLOT_EMPTY:
1214
                        case SLOT_DELETED:
1215
                                return (retvalue);
1216
                                break;
88 killagreg 1217
                        default:        // and is a real directory
41 ingob 1218
                                if((dir[file->DirectoryIndex].Attribute & ATTR_SUBDIRECTORY) != ATTR_SUBDIRECTORY)
1219
                                {       // current file is not a directory therefore no file or subdirectory can be created here
1220
                                        return (retvalue);
1221
                                }
1222
                                break;
1223
                }
1224
                dircluster = dir[file->DirectoryIndex].StartCluster;
88 killagreg 1225
                file->FirstSectorOfFirstCluster = Fat16ClusterToSector(dircluster);
41 ingob 1226
        }
88 killagreg 1227
 
218 killagreg 1228
        // if the new direntry is a subdirectory
1229
        if((attrib & ATTR_SUBDIRECTORY) == ATTR_SUBDIRECTORY)
1230
        {       // get a free clutser for its content
1231
                subdircluster = FindNextFreeCluster(file);      // get the next free cluster on the disk and mark it as used.
1232
        }
1233
        else // a normal file
1234
        {       // has no data cluster after creation
1235
                subdircluster = CLUSTER_UNDEFINED;
1236
        }
1237
 
211 killagreg 1238
        file->FirstSectorOfCurrCluster  = file->FirstSectorOfFirstCluster;
1239
        file->SectorOfCurrCluster               = 0;
1240
        do // loop over all clusters of current directory
41 ingob 1241
        {
211 killagreg 1242
                dir_sector = 0; // reset sector counter within a new cluster
1243
                do // loop over all sectors of a cluster or all sectors of the root directory
88 killagreg 1244
                {
211 killagreg 1245
                        curr_sector = file->FirstSectorOfCurrCluster + dir_sector;      // calculate sector number
1246
                        file->SectorInCache = curr_sector;                                                      // upate the sector number of file cache.
1247
                        if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read in the sector.
1 ingob 1248
                        {
211 killagreg 1249
                                Fat16_Deinit();
1250
                                return(retvalue);
1251
                        }
1252
 
1253
                        dir = (DirEntry_t *)file->Cache;                                                        // set pointer to directory
1254
                        // search all directory entries of a sector
1255
                        for(dir_entry = 0; dir_entry < DIRENTRIES_PER_SECTOR; dir_entry++)
1256
                        {       // check if current direntry is available
1257
                                if(((u8)dir[dir_entry].Name[0] == SLOT_EMPTY) || ((u8)dir[dir_entry].Name[0] == SLOT_DELETED))
1258
                                {       // a free direntry was found
1259
                                        for(i = 0; i < 11; i++) dir[dir_entry].Name[i] = dirname[i];            // Set dir name
1260
                                        dir[dir_entry].Attribute    = attrib;
1261
                                        dir[dir_entry].Res1 = 0;
1262
                                        dir[dir_entry].CreationTime10ms = (u8)(SystemTime.mSec/10);
1263
                                        dir[dir_entry].CreationTime     = FileTime(&SystemTime);
1264
                                        dir[dir_entry].CreationDate     = FileDate(&SystemTime);
1265
                                        dir[dir_entry].LastAccessDate = dir[dir_entry].CreationDate;
1266
                                        dir[dir_entry].Res2[0] = 0;
1267
                                        dir[dir_entry].Res2[1] = 0;
1268
                                        dir[dir_entry].ModTime = dir[dir_entry].CreationTime;
1269
                                        dir[dir_entry].ModDate = dir[dir_entry].CreationDate;
1270
                                        // Set the attribute of the new directoryentry.
1271
                                        dir[dir_entry].StartCluster = subdircluster;                                            // copy the location of the first datacluster to the directoryentry.
1272
                                        dir[dir_entry].Size             = 0;                                                                    // the new createted file has no content yet.
1273
                                        if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))       // write back to card
1274
                                        {
1275
                                                Fat16_Deinit();
1276
                                                return(retvalue);
1277
                                        }
218 killagreg 1278
                                        file->FirstSectorOfFirstCluster = Fat16ClusterToSector(subdircluster);  // Calculate absolute sectorposition of first datacluster.
211 killagreg 1279
                                        file->FirstSectorOfCurrCluster  = file->FirstSectorOfFirstCluster;      // Start reading the file with the first sector of the first datacluster.
1280
                                        file->SectorOfCurrCluster               = 0;                                                            // reset sector of cureen cluster
1281
                                        file->ByteOfCurrSector                  = 0;                                                            // reset the byte location within the current sector
1282
                                        file->Attribute                                 = attrib;                                               // set file attribute to dir attribute
1283
                                        file->Size                                              = 0;                                                        // new file has no size
1284
                                        file->DirectorySector                   = curr_sector;
1285
                                        file->DirectoryIndex                    = dir_entry;
1286
                                        // prepare subdirectory data cluster
1287
                                        if((attrib & ATTR_SUBDIRECTORY) == ATTR_SUBDIRECTORY)                           // if a new directory was created then initilize the data area
1288
                                        {
1289
                                                ClearCurrCluster(file); // fill cluster with zeros
1290
                                                file->SectorInCache = file->FirstSectorOfFirstCluster;
1291
                                                if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read in the sector.
41 ingob 1292
                                                {
211 killagreg 1293
                                                        Fat16_Deinit();
41 ingob 1294
                                                        return(retvalue);
1295
                                                }
211 killagreg 1296
                                                dir = (DirEntry_t *)file->Cache;
1297
                                                // create direntry "." to current dir
1298
                                                dir[0].Name[0] = 0x2E;
1299
                                                for(i = 1; i < 11; i++) dir[0].Name[i] = ' ';
1300
                                                dir[0].Attribute = ATTR_SUBDIRECTORY;
1301
                                                dir[0].StartCluster = subdircluster;
1302
                                                dir[0].Size = 0;
1303
                                                // create direntry ".." to the upper dir
1304
                                                dir[1].Name[0] = 0x2E;
1305
                                                dir[1].Name[1] = 0x2E;
1306
                                                for(i = 2; i < 11; i++) dir[1].Name[i] = ' ';
1307
                                                dir[1].Attribute = ATTR_SUBDIRECTORY;
1308
                                                dir[1].StartCluster = dircluster;
1309
                                                dir[1].Size = 0;
1310
                                                if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))// read in the sector.
88 killagreg 1311
                                                {
211 killagreg 1312
                                                        Fat16_Deinit();
1313
                                                        return(retvalue);
1314
                                                }
1315
                                        }
1316
                                        retvalue = 1;
1317
                                        dir_entry = DIRENTRIES_PER_SECTOR;      // stop for-loop
88 killagreg 1318
                                }
211 killagreg 1319
                        }
1320
                        dir_sector++; // search next sector
1321
                // stop if we reached the end of the cluster or the end of the root dir
1322
                }while((dir_sector < max_dir_sector) && (!retvalue));
88 killagreg 1323
 
211 killagreg 1324
                // if we are seaching in the data area and the file not found in this cluster so take next cluster.
1325
                if(!retvalue && ( Partition.FirstDataSector <= file->FirstSectorOfCurrCluster))
1326
                {
1327
                        end_of_directory_not_reached = GetNextCluster(file);  // updates File->FirstSectorOfCurrCluster
1328
                }
1329
        }while((end_of_directory_not_reached) && (!retvalue));
1330
        // Perhaps we are at the end of the last cluster of a directory file and have no free direntry found.
1331
        // Then we would need to add a cluster to that file and create the new direntry there.
1332
        // This code is not implemented yet, because its occurs only if more that 32*32=1024 direntries are
1333
        // within a subdirectory of root.
1334
 
41 ingob 1335
        return(retvalue);       // return 1 if file has been created otherwise return 0.
1 ingob 1336
}
1337
 
41 ingob 1338
/********************************************************************************************************************************************/
1339
/*      Function:               FileExist(const s8* filename, u8 attribfilter, u8 attribmask, File_t *file);                                                                                    */
1340
/*                                                                                                                                                                                                                                                                                      */
1341
/*      Description:    This function looks for the specified file including its subdirectories beginning                                                                               */
1342
/*                                      in the rootdirectory of the drive. If the file is found the Filepointer properties are                                                                  */
1343
/*                                      updated.                                                                                                                                                                                                                                */
1344
/*                                                                                                                                                                                                                                                                                      */
1345
/*      Returnvalue:    1 if file is found else 0.                                                                                                                                                                                              */
1346
/********************************************************************************************************************************************/
1347
u8 FileExist(const s8* filename, const u8 attribfilter, const u8 attribmask, File_t *file)
1 ingob 1348
{
41 ingob 1349
        s8* path = 0;
1350
        s8* subpath = 0;
1351
        u8 af, am, file_exist = 0;
1352
        s8 dirname[12]; // 8+3 + temination character
1 ingob 1353
 
41 ingob 1354
        // if incomming pointers are useless return immediatly
1355
        if ((filename == NULL) || (file == NULL) || (!Partition.IsValid)) return 0;
1 ingob 1356
 
41 ingob 1357
        // trace along the filepath
1358
        path = (s8*)filename;                                                           // start a the beginning of the filename string
1359
        file->DirectorySector = 0;                                                              // start at RootDirectory with file search
88 killagreg 1360
        file->DirectoryIndex = 0;
349 ingob 1361
        /* if a path begins with a '/' at index 0 the search starts at the rootdirectory otherwise we will start relative to the cwd */
1362
        if(path[0] != '/')
1363
        {
1364
                /* is the current working directory the rootdirectory? */
1365
                if(Partition.CurrentWorkingDirectory == Partition.FirstRootDirSector) file->DirectorySector = 0;
1366
                /* otherwise we are working in an subdirectory */
1367
                else file->DirectorySector = Partition.CurrentWorkingDirectory;
1368
        }
41 ingob 1369
        // as long as the file was not found and the remaining path is not empty
1370
        while((*path != 0) && !file_exist)
1371
        {       // separate dirname and subpath from filepath string
1372
                subpath = SeperateDirName(path, dirname);
1373
                if(subpath != NULL)
88 killagreg 1374
                {
1375
                        if(*subpath == 0)
41 ingob 1376
                        {       // empty subpath indicates last element of dir chain
1377
                                af = attribfilter;
1378
                                am = attribmask;
1379
                        }
1380
                        else  // it must be a subdirectory and no volume label
1 ingob 1381
                        {
41 ingob 1382
                                af = ATTR_SUBDIRECTORY;
1383
                                am = ATTR_SUBDIRECTORY|ATTR_VOLUMELABEL;
1384
                        }
1385
                        if(!DirectoryEntryExist(dirname, af, am, file))
1386
                        {
1387
                                return (file_exist); // subdirectory does not exist
1388
                        }
88 killagreg 1389
                        else
1390
                        {
41 ingob 1391
                                if (*subpath == 0)
24 StephanB 1392
                                {
41 ingob 1393
                                        file_exist = 1; // last element of path chain was found with the given attribute filter
24 StephanB 1394
                                }
1 ingob 1395
                        }
1396
                }
41 ingob 1397
                else // error seperating the subpath
1 ingob 1398
                {
41 ingob 1399
                        return file_exist; // bad subdir format
1 ingob 1400
                }
41 ingob 1401
                path = subpath;
1402
                subpath = 0;
1 ingob 1403
        }
41 ingob 1404
        return (file_exist);
1 ingob 1405
}
1406
 
24 StephanB 1407
 
41 ingob 1408
/********************************************************************************************************************************************/
1409
/*      Function:               FileCreate(const s8* filename, u8 attrib, File_t *file);                                                                                                                                */
1410
/*                                                                                                                                                                                                                                                                                      */
1411
/*      Description:    This function looks for the specified file including its subdirectories beginning                                                                               */
1412
/*                                      in the rootdirectory of the partition. If the file is found the Filepointer properties are                                                              */
88 killagreg 1413
/*                                      updated. If file or its subdirectories are not found they will be created                                                                                               */
41 ingob 1414
/*                                                                                                                                                                                                                                                                                      */
1415
/*      Returnvalue:    1 if file was created else 0.                                                                                                                                                                                   */
1416
/********************************************************************************************************************************************/
1417
u8 FileCreate(const s8* filename, const u8 attrib, File_t *file)
1418
{
1419
        s8 *path = 0;
1420
        s8 *subpath = 0;
1421
        u8 af, am, file_created = 0;
1422
        s8 dirname[12];
24 StephanB 1423
 
41 ingob 1424
        // if incomming pointers are useless return immediatly
1425
        if ((filename == NULL) || (file == NULL) || (!Partition.IsValid)) return 0;
1 ingob 1426
 
41 ingob 1427
        // trace along the filepath
1428
        path = (s8*)filename;                                                                   // start a the beginning of the filename string
1429
        file->DirectorySector = 0;                                                              // start at RootDirectory with file search
1430
        file->DirectoryIndex = 0;
1431
        // as long as the file was not created and the remaining file path is not empty
1432
        while((*path != 0) && !file_created)
1433
        {   // separate dirname and subpath from filepath string
1434
                subpath = SeperateDirName(path, dirname);
1435
                if(subpath != NULL)
24 StephanB 1436
                {
88 killagreg 1437
                        if(*subpath == 0)
41 ingob 1438
                        {       // empty subpath indicates last element of dir chain
1439
                                af = ATTR_NONE;
1440
                                am = ATTR_SUBDIRECTORY|ATTR_VOLUMELABEL;  // any file that is no subdir or volume label
24 StephanB 1441
                        }
41 ingob 1442
                        else  // it must be a subdirectory and no volume label
24 StephanB 1443
                        {
41 ingob 1444
                                af = ATTR_SUBDIRECTORY;
1445
                                am = ATTR_SUBDIRECTORY|ATTR_VOLUMELABEL;
24 StephanB 1446
                        }
41 ingob 1447
                        if(!DirectoryEntryExist(dirname, af, am, file)) // if subdir or file is not existent
1448
                        {  // try to create subdir or file
1449
                                if(*subpath == 0) af = attrib; // if last element in dir chain take the given attribute
1450
                                if(!CreateDirectoryEntry(dirname, af, file))
1451
                                {       // could not be created
88 killagreg 1452
                                        return(file_created);
1453
                                }
41 ingob 1454
                                else if (*subpath == 0) file_created = 1; // last element of path chain was created
24 StephanB 1455
                        }
1456
                }
41 ingob 1457
                else // error seperating the subpath
24 StephanB 1458
                {
41 ingob 1459
                        return file_created; // bad subdir format
24 StephanB 1460
                }
41 ingob 1461
                path = subpath;
1462
                subpath = 0;
1463
        }
1464
        return (file_created);
24 StephanB 1465
}
1 ingob 1466
 
24 StephanB 1467
 
41 ingob 1468
/********************************************************************************************************************************************/
1469
/*      Function:               File_t * fopen_(s8* filename, s8 mode);                                                                                                                                                                 */
1470
/*                                                                                                                                                                                                                                                                                      */
1471
/*      Description:    This function looks for the specified file in the rootdirectory of the drive. If the file is found the number of the    */
1472
/*                                      corrosponding filepointer is returned. Only modes 'r' (reading) and 'a' append are implemented yet.                                             */
1473
/*                                                                                                                                                                                                                                                                                      */
1474
/*      Returnvalue:    The filepointer to the file or 0 if faild.                                                                                                                                                              */
1475
/********************************************************************************************************************************************/
89 killagreg 1476
File_t * fopen_(s8 * const filename, const s8 mode)
88 killagreg 1477
{
41 ingob 1478
        File_t *file    = 0;
88 killagreg 1479
 
41 ingob 1480
        if((!Partition.IsValid) || (filename == 0)) return(file);
1481
 
1482
        // Look for an unused filepointer in the file pointer list?
1483
        file = LockFilePointer();
1484
        // if no unused file pointer was found return 0
1485
        if(file == NULL) return(file);
1486
 
1487
        // now we have found a free filepointer and claimed it
1488
        // so let initiate its property values
211 killagreg 1489
        file->FirstSectorOfFirstCluster = SECTOR_UNDEFINED;             // Sectorpointer to the first sector of the first datacluster of the file.
1490
        file->FirstSectorOfCurrCluster  = SECTOR_UNDEFINED;             // Pointer to the cluster which is edited at the moment.
41 ingob 1491
        file->SectorOfCurrCluster               = 0;            // The sector which is edited at the moment (cluster_pointer + sector_index).
1492
        file->ByteOfCurrSector                  = 0;            // The bytelocation within the current sector (cluster_pointer + sector_index + byte_index).
1493
        file->Mode                                              = mode;         // mode of fileoperation (read,write)
1494
        file->Size                                              = 0;            // the size of the opened file in bytes.
1495
        file->Position                                  = 0;            // pointer to a byte within the file 0 < fileposition < filesize
211 killagreg 1496
        file->SectorInCache                             = SECTOR_UNDEFINED;             // the last sector read, wich is still in the sectorbuffer.
1497
        file->DirectorySector                   = SECTOR_UNDEFINED;             // the sectorposition where the directoryentry has been made.
41 ingob 1498
        file->DirectoryIndex                    = 0;            // the index to the directoryentry within the specified sector.
1499
        file->Attribute                                 = 0;            // the attribute of the file opened.
1500
 
1501
        // check if a real file (no directory) to the given filename exist
88 killagreg 1502
        if(FileExist(filename, ATTR_NONE, ATTR_SUBDIRECTORY|ATTR_VOLUMELABEL, file))
41 ingob 1503
        {  // file exist
1504
                switch(mode)  // check mode
1 ingob 1505
                {
41 ingob 1506
                        case 'a':       // if mode is: append 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
1513
                                {       // file is not marked as read only --> goto end of file
1514
                                        fseek_(file, 0, SEEK_END);              // point to the end of the file
1515
                                }
1516
                                break;
1517
                        case 'w':       // if mode is: write to file
1518
                                if((file->Attribute & ATTR_READONLY) == ATTR_READONLY)
1519
                                {       // file is marked as readonly --> do not open this file
1520
                                        fclose_(file);
1521
                                        file = NULL;
1522
                                }
1523
                                else
211 killagreg 1524
                                {       // file is not marked as read only
1525
                                        DirEntry_t * dir;
41 ingob 1526
                                        // free all clusters of that file
1527
                                        DeleteClusterChain(SectorToFat16Cluster(file->FirstSectorOfFirstCluster));
211 killagreg 1528
                                        // update directory entry of that file
1529
                                        file->SectorInCache = file->DirectorySector;                            // update the sector number of file cache.
1530
                                        if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read in the sector.
1531
                                        {
1532
                                                Fat16_Deinit();
1533
                                                return(NULL);
1534
                                        }
1535
                                        dir = (DirEntry_t *)file->Cache;                                                                // set pointer to directory
1536
                                    dir[file->DirectoryIndex].ModTime   = FileTime(&SystemTime);        // set modification time
1537
                                        dir[file->DirectoryIndex].ModDate       = FileDate(&SystemTime);        // set modification date
1538
                                        dir[file->DirectoryIndex].LastAccessDate = dir[file->DirectoryIndex].ModDate;
1539
                                        dir[file->DirectoryIndex].StartCluster = CLUSTER_UNDEFINED;             // update startcluster 
1540
                                        dir[file->DirectoryIndex].Size          = 0;
1541
                                        // write sector containing the direntry
1542
                                        if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))
1543
                                        {
1544
                                                Fat16_Deinit();
1545
                                                return(NULL);
1546
                                        }
1547
                                        file->FirstSectorOfFirstCluster = SECTOR_UNDEFINED;
41 ingob 1548
                                        file->FirstSectorOfCurrCluster = file->FirstSectorOfFirstCluster;
1549
                                        file->SectorOfCurrCluster = 0;
1550
                                        file->ByteOfCurrSector = 0;
1551
                                        file->Size = 0;
1552
                                        file->Position = 0;
1553
                                        fseek_(file, 0, SEEK_SET);
1554
                                }
1555
                                break;
1556
                        case 'r':       // if mode is: read from file
88 killagreg 1557
                                // goto end of file
41 ingob 1558
                                fseek_(file, 0, SEEK_SET);
1559
                                break;
1560
                        default: // other modes are not supported
1561
                                fclose_(file);
1562
                                file = NULL;
24 StephanB 1563
                        break;
1 ingob 1564
                }
88 killagreg 1565
                return(file);
1 ingob 1566
        }
41 ingob 1567
        else // file does not exist
1568
        {
1569
                switch(mode)  // check mode
1570
                {
1571
                        case 'a':
1572
                        case 'w': // if mode is write or append
1573
                                // try to create the file
1574
                                if(!FileCreate(filename, ATTR_ARCHIVE, file))
1575
                                { // if it could not be created
1576
                                        fclose_(file);
1577
                                        file = NULL;
349 ingob 1578
                                }
41 ingob 1579
                                break;
1580
                        case 'r': // else opened for 'r'
218 killagreg 1581
                        default:  // if unsupported mode
41 ingob 1582
                                fclose_(file);
1583
                                file = NULL;
88 killagreg 1584
                                break;
41 ingob 1585
                }
88 killagreg 1586
                return(file);
41 ingob 1587
        }
1588
        // we should never come to this point
1589
        fclose_(file);
1590
        file = NULL;
24 StephanB 1591
        return(file);
1592
}
1593
 
41 ingob 1594
/****************************************************************************************************************************************************/
1595
/* Function:    fflush_(File *);                                                                                                                                                                                                                                        */
1596
/*                                                                                                                                                                                                                                                                                                      */
1597
/* Description: This function writes the data already in the buffer but not yet written to the file.                                                                                            */
1598
/*                                                                                                                                                                                                                                                                                                      */
1599
/* Returnvalue: 0 on success EOF on error                                                                                                                                                                                                                       */
1600
/****************************************************************************************************************************************************/
1601
s16     fflush_(File_t *file)
24 StephanB 1602
{
88 killagreg 1603
        DirEntry_t *dir;
1604
 
41 ingob 1605
        if((file == NULL) || (!Partition.IsValid)) return (EOF);
88 killagreg 1606
 
41 ingob 1607
        switch(file->Mode)
24 StephanB 1608
        {
41 ingob 1609
                case 'a':
1610
                case 'w':
88 killagreg 1611
                        if(file->ByteOfCurrSector > 0)                                                                          // has data been added to the file?
41 ingob 1612
                        {
88 killagreg 1613
                                if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))// save the data still in the buffer
41 ingob 1614
                                {
88 killagreg 1615
                                        Fat16_Deinit();
1616
                                        return(EOF);
1617
                                }
41 ingob 1618
                        }
1619
                        file->SectorInCache     = file->DirectorySector;
1620
                        if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))                                       // read the directory entry for this file.
1621
                        {
1622
                                Fat16_Deinit();
88 killagreg 1623
                                return(EOF);
41 ingob 1624
                        }
88 killagreg 1625
 
41 ingob 1626
                        dir = (DirEntry_t *)file->Cache;
324 killagreg 1627
                        // update file size and modification time & date
211 killagreg 1628
                        dir[file->DirectoryIndex].ModTime = FileTime(&SystemTime);
1629
                        dir[file->DirectoryIndex].ModDate = FileDate(&SystemTime);
1630
                        dir[file->DirectoryIndex].LastAccessDate = dir[file->DirectoryIndex].ModDate;
41 ingob 1631
                        dir[file->DirectoryIndex].Size = file->Size;                                            // update file size
1632
                        if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))       // write back to sd-card
1633
                        {
1634
                                Fat16_Deinit();
1635
                                return(EOF);
1636
                        }
1637
                        break;
1638
                case 'r':
1639
                default:
211 killagreg 1640
                        // do nothing!
41 ingob 1641
                        return(EOF);
1642
                        break;
1643
 
24 StephanB 1644
        }
41 ingob 1645
        return(0);
24 StephanB 1646
}
1 ingob 1647
 
41 ingob 1648
/****************************************************************************************************************************************/
1649
/*      Function:               fclose_(File *file);                                                                                                                                                                                            */
1650
/*                                                                                                                                                                                                                                                                              */
1651
/*      Description:    This function closes the open file by writing the remaining data                                                                                                        */
1652
/*                                      from the buffer to the device and entering the filesize in the directory entry.                                                                         */
1653
/*                                                                                                                                                                                                                                                                              */
1654
/*      Returnvalue:    0 on success EOF on error                                                                                                                                                                                       */
1655
/****************************************************************************************************************************************/
1656
s16 fclose_(File_t *file)
24 StephanB 1657
{
41 ingob 1658
        s16 returnvalue = EOF;
24 StephanB 1659
 
41 ingob 1660
        if(file == NULL) return(returnvalue);
1661
        returnvalue = fflush_(file);
1662
        UnlockFilePointer(file);
1663
        return(returnvalue);
24 StephanB 1664
}
1665
 
41 ingob 1666
/********************************************************************************************************************************************/
1667
/*      Function:               fgetc_(File *file);                                                                                                                                                                                                             */
1668
/*                                                                                                                                                                                                                                                                                      */
1669
/*      Description:    This function reads and returns one character from the specified file. Is the end of the actual sector reached the              */
1670
/*                                      next sector of the cluster is read. If the last sector of the cluster read the next cluster will be searched in FAT.    */
1671
/*                                                                                                                                                                                                                                                                                      */
1672
/*      Returnvalue:    The function returns the character read from the specified memorylocation as u8 casted to s16 or EOF.                                   */
1673
/********************************************************************************************************************************************/
1674
s16 fgetc_(File_t *file)
88 killagreg 1675
{
41 ingob 1676
        s16 c = EOF;
1677
        u32 curr_sector;
88 killagreg 1678
 
41 ingob 1679
        if( (!Partition.IsValid) || (file == NULL)) return(c);
1680
        // if the end of the file is not reached, get the next character.
349 ingob 1681
        if((0 < file->Size) && ((file->Position) < file->Size) )
1 ingob 1682
        {
41 ingob 1683
                curr_sector  = file->FirstSectorOfCurrCluster;          // calculate the sector of the next character to be read.
88 killagreg 1684
                curr_sector += file->SectorOfCurrCluster;
1685
 
41 ingob 1686
                if(file->SectorInCache != curr_sector)
1 ingob 1687
                {
41 ingob 1688
                        file->SectorInCache = curr_sector;
1689
                        if(SD_SUCCESS != SDC_GetSector(file->SectorInCache,file->Cache))
1690
                        {
1691
                                Fat16_Deinit();
1692
                                return(c);
88 killagreg 1693
                        }
1694
                }
41 ingob 1695
                c = (s16) file->Cache[file->ByteOfCurrSector];
1696
                file->Position++;                                                                       // increment file position
88 killagreg 1697
                file->ByteOfCurrSector++;                                                       // goto next byte in sector
41 ingob 1698
                if(file->ByteOfCurrSector >= BYTES_PER_SECTOR)          // if end of sector
24 StephanB 1699
                {
41 ingob 1700
                        file->ByteOfCurrSector = 0;                                             //  reset byte location
1701
                        file->SectorOfCurrCluster++;                                    //      next sector
1702
                        if(file->SectorOfCurrCluster >= Partition.SectorsPerCluster)    // if end of cluster is reached, the next datacluster has to be searched in the FAT.
24 StephanB 1703
                        {
88 killagreg 1704
 
41 ingob 1705
                                if(GetNextCluster(file))                                                                                // Sets the clusterpointer of the file to the next datacluster.
24 StephanB 1706
                                {
41 ingob 1707
                                        file->SectorOfCurrCluster = 0;                                                          // start reading new cluster at first sector of the cluster.
1708
                                }
1709
                                else // the last cluster was allready reached
1710
                                {
1711
                                        file->SectorOfCurrCluster--;                                                    // jump back to the last sector in the last cluster
1712
                                        file->ByteOfCurrSector = BYTES_PER_SECTOR;                              // set ByteOfCurrSector one byte over sector end
1713
                                }
1 ingob 1714
                        }
24 StephanB 1715
                }
1716
        }
41 ingob 1717
        return(c);
24 StephanB 1718
}
1719
 
41 ingob 1720
/********************************************************************************************************************************************/
1721
/*      Function:               fputc_( const s8 c, File *file);                                                                                                                                                                                */
1722
/*                                                                                                                                                                                                                                                                                      */
1723
/*      Description:    This function writes a byte to the specified file and takes care of writing the necessary FAT- Entries.                                 */
1724
/*                                      next sector of the cluster is read. If the last sector of the cluster read the next cluster will be searched in FAT.    */
1725
/*                                                                                                                                                                                                                                                                                      */
1726
/*      Returnvalue:    The function returns the character written to the stream or EOF on error.                                                                                               */
1727
/********************************************************************************************************************************************/
1728
s16 fputc_(const s8 c, File_t *file)
88 killagreg 1729
{
41 ingob 1730
        u32 curr_sector  = 0;
88 killagreg 1731
 
41 ingob 1732
        if((!Partition.IsValid) || (file == NULL)) return(EOF);
211 killagreg 1733
        switch(file->Mode)
41 ingob 1734
        {
211 killagreg 1735
                case 'w':
1736
                case 'a':
1737
                        // If file position equals to file size, then the end of file has been reached.
1738
                        // In this case it has to be checked that the ByteOfCurrSector is BYTES_PER_SECTOR
1739
                        // and a new cluster should be appended.
1740
                        // If the first sector of first cluster is unvalid, then the file claims no data clusters 
1741
                        // and size should be zero, therefore append a new Cluster too.
1742
                        if(((file->Position >= file->Size) && (file->ByteOfCurrSector >= BYTES_PER_SECTOR)) || (file->FirstSectorOfFirstCluster == SECTOR_UNDEFINED))
1743
                        {
1744
                                if(CLUSTER_UNDEFINED == AppendCluster(file)) return(EOF);
1745
                        }
1746
 
1747
                        curr_sector  = file->FirstSectorOfCurrCluster;
1748
                        curr_sector += file->SectorOfCurrCluster;
1749
                        if(file->SectorInCache != curr_sector)
1750
                        {
1751
                                file->SectorInCache = curr_sector;
1752
                                if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))
24 StephanB 1753
                                {
211 killagreg 1754
                                        Fat16_Deinit();
1755
                                        return(EOF);
24 StephanB 1756
                                }
1 ingob 1757
                        }
211 killagreg 1758
 
1759
                        file->Cache[file->ByteOfCurrSector] = (u8)c;            // write databyte into the buffer. The byte will be written to the device at once
1760
                        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.
1761
                        file->Position++;                                                                       // the actual positon within the file.
1762
                        file->ByteOfCurrSector++;                                                       // goto next byte in sector
1763
                        if(file->ByteOfCurrSector >= BYTES_PER_SECTOR)          // if the end of this sector is reached yet
1764
                        {       // save the sector to the sd-card
1765
                                if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))
1766
                                {
1767
                                        Fat16_Deinit();
1768
                                        return(EOF);
1769
                                }
1770
                                file->ByteOfCurrSector = 0;                                             //  reset byte location
1771
                                file->SectorOfCurrCluster++;                                    //      next sector
1772
                                if(file->SectorOfCurrCluster >= Partition.SectorsPerCluster)// if end of cluster is reached, the next datacluster has to be searched in the FAT.
1773
                                {
1774
                                        if(!GetNextCluster(file))                                                               // Sets the clusterpointer of the file to the next datacluster.
1775
                                        { // if current cluster was the last cluster of the file
1776
                                                if(!AppendCluster(file))                                                // append a new and free cluster at the end of the file.
1777
                                                {
1778
                                                        file->SectorOfCurrCluster--;                            // jump back to last sector of last cluster
1779
                                                        file->ByteOfCurrSector = BYTES_PER_SECTOR;      // set byte location to 1 byte over sector len
1780
                                                        return(EOF);
1781
                                                }
1782
                                        }
1783
                                        else // next cluster
1784
                                        {
1785
                                                file->SectorOfCurrCluster = 0;                                                  // start reading new cluster at first sector of the cluster.
1786
                                        }
1787
                                }
88 killagreg 1788
                        }
211 killagreg 1789
                        break;
1790
                case 'r':
1791
                default:
1792
                        return(EOF);
1793
                        break;
1794
        } // EOF switch(file->Mode)
41 ingob 1795
        return(0);
24 StephanB 1796
}
1797
 
1798
 
41 ingob 1799
/****************************************************************************************************************************************/
1800
/*      Function:               fread_(void *buffer, s32 size, s32 count, File *File);                                                                                                                          */
1801
/*                                                                                                                                                                                                                                                                              */
1802
/*      Description:    This function reads count objects of the specified size                                                                                                                         */
1803
/*                                      from the actual position of the file to the specified buffer.                                                                                                           */
1804
/*                                                                                                                                                                                                                                                                              */
1805
/*      Returnvalue:    The function returns the number of objects (not bytes) read from the file.                                                                                      */
1806
/****************************************************************************************************************************************/
1807
u32 fread_(void *buffer, u32 size, u32 count, File_t *file)
1808
{
1809
        u32 object_cnt  = 0;                                                                                    // count the number of objects read from the file.
1810
        u32 object_size = 0;                                                                                    // count the number of bytes read from the actual object.
1811
        u8 *pbuff       = 0;                                                                                    // a pointer to the actual bufferposition.
1812
        u8 success      = 1;                                                                                    // no error occured during read operation to the file.
88 killagreg 1813
        s16 c;
24 StephanB 1814
 
41 ingob 1815
        if((!Partition.IsValid) || (file == NULL) || (buffer == NULL)) return(0);
24 StephanB 1816
 
41 ingob 1817
        pbuff = (u8 *) buffer;                                                                                  // cast the void pointer to an u8 *
88 killagreg 1818
 
41 ingob 1819
        while((object_cnt < count) && success)
24 StephanB 1820
        {
41 ingob 1821
                object_size = size;
1822
                while((size > 0) && success)
1823
                {
1824
                        c = fgetc_(file);
1825
                        if(c != EOF)
1826
                        {
1827
                                *pbuff = (u8)c;                                                                         // read a byte from the buffer to the opened file.
1828
                                pbuff++;
1829
                                size--;
1830
                        }
1831
                        else // error or end of file reached
1832
                        {
88 killagreg 1833
                                success = 0;
41 ingob 1834
                        }
1835
                }
1836
                if(success) object_cnt++;
88 killagreg 1837
        }
41 ingob 1838
        return(object_cnt);                                                                                             // return the number of objects succesfully read from the file
1 ingob 1839
}
1840
 
24 StephanB 1841
 
41 ingob 1842
/****************************************************************************************************************************************/
1843
/*      Function:               fwrite_(void *buffer, s32 size, s32 count, File *file);                                                                                                                         */
1844
/*                                                                                                                                                                                                                                                                              */
1845
/*      Description:    This function writes count objects of the specified size                                                                                                                        */
1846
/*                                      from the buffer pointer to the actual position in the file.                                                                                                                     */
1847
/*                                                                                                                                                                                                                                                                              */
1848
/*      Returnvalue:    The function returns the number of objects (not bytes) read from the file.                                                                                      */
1849
/****************************************************************************************************************************************/
1850
u32 fwrite_(void *buffer, u32 size, u32 count, File_t *file)
1 ingob 1851
{
41 ingob 1852
        u32 object_cnt  = 0;                                                                                                            // count the number of objects written to the file.
1853
        u32 object_size = 0;                                                                                                            // count the number of bytes written from the actual object.
1854
        u8 *pbuff           = 0;                                                                                                                // a pointer to the actual bufferposition.
1855
        u8 success      = 1;                                                                                                            // no error occured during write operation to the file.
88 killagreg 1856
        s16 c;
24 StephanB 1857
 
41 ingob 1858
        if((!Partition.IsValid) || (file == NULL) || (buffer == NULL)) return(0);
211 killagreg 1859
        if(file->Mode == 'r') return (0); // opened read only
41 ingob 1860
        pbuff = (u8 *) buffer;                                                                                                          // cast the void pointer to an u8 *
88 killagreg 1861
 
41 ingob 1862
        while((object_cnt < count) && success)
1 ingob 1863
        {
41 ingob 1864
                object_size = size;
1865
                while((size > 0) && success)
1 ingob 1866
                {
41 ingob 1867
                        c = fputc_(*pbuff, file);                                                                               // write a byte from the buffer to the opened file.
1868
                        if(c != EOF)
24 StephanB 1869
                        {
41 ingob 1870
                                pbuff++;
1871
                                size--;
24 StephanB 1872
                        }
41 ingob 1873
                        else
24 StephanB 1874
                        {
41 ingob 1875
                                success = 0;
24 StephanB 1876
                        }
1 ingob 1877
                }
41 ingob 1878
                if(success) object_cnt++;
88 killagreg 1879
        }
1880
 
41 ingob 1881
        return(object_cnt);                                                                                                                             // return the number of objects succesfully written to the file
88 killagreg 1882
}
1 ingob 1883
 
24 StephanB 1884
 
41 ingob 1885
/****************************************************************************************************************************************/
1886
/*      Function:               fputs_(const s8 *string, File_t *File);                                                                                                                                                         */
1887
/*                                                                                                                                                                                                                                                                              */
1888
/*      Description:    This function writes a string to the specified file.                                                                                                                            */
1889
/*                                                                                                                                                                                                                                                                              */
1890
/*      Returnvalue:    The function returns a no negative value or EOF on error.                                                                                                                       */
1891
/****************************************************************************************************************************************/
89 killagreg 1892
s16 fputs_(s8 * const string, File_t * const file)
24 StephanB 1893
{
41 ingob 1894
        u8 i=0;
1895
        s16 c = 0;
88 killagreg 1896
 
211 killagreg 1897
        if((!Partition.IsValid) || (file == NULL) || (string == NULL)) return(EOF);
1898
        if(file->Mode == 'r') return(EOF);
41 ingob 1899
        while((string[i] != 0)&& (c != EOF))
24 StephanB 1900
        {
41 ingob 1901
                c = fputc_(string[i], file);
1902
                i++;
24 StephanB 1903
        }
41 ingob 1904
        return(c);
24 StephanB 1905
}
1906
 
41 ingob 1907
/****************************************************************************************************************************************/
1908
/*      Function:               fgets_(s8 *, s16 , File_t *);                                                                                                                                                                           */
1909
/*                                                                                                                                                                                                                                                                              */
1910
/*      Description:    This function reads a string from the file to the specifies string.                                                                                             */
1911
/*                                                                                                                                                                                                                                                                              */
1912
/*      Returnvalue:    A pointer to the string read from the file or 0 on error.                                                                                                                       */
1913
/****************************************************************************************************************************************/
89 killagreg 1914
s8 * fgets_(s8 * const string, s16 const length, File_t * const file)
24 StephanB 1915
{
89 killagreg 1916
        s8 *pbuff;
1917
        s16 c = 0, bytecount;
88 killagreg 1918
 
89 killagreg 1919
        if((!Partition.IsValid) || (file == NULL) || (string == NULL) || (length < 1)) return (0);
1920
        bytecount = length;
1921
        pbuff = string;                                                         // set write pointer to start of string
1922
        while(bytecount > 1)                                            // read the length-1 characters from the file to the string.
24 StephanB 1923
        {
41 ingob 1924
                c = fgetc_(file);                                               // read a character from the opened file.
1925
                switch(c)
1 ingob 1926
                {
89 killagreg 1927
                        case 0x0A:                                                      // new line
1928
                                *pbuff = 0;                                             // set string terminator
1929
                                return(string);                                 // return normal
88 killagreg 1930
 
41 ingob 1931
                        case EOF:
89 killagreg 1932
                                *pbuff = 0;                                             // set string terminator
1933
                                return(0);
1934
 
1935
                        default:
1936
                                *pbuff++ = (s8)c;                               // copy byte to string
1937
                                bytecount--;
88 killagreg 1938
                                break;
1 ingob 1939
                }
24 StephanB 1940
        }
89 killagreg 1941
        *pbuff = 0;     // set string terminator
41 ingob 1942
        return(string);
24 StephanB 1943
}
1944
 
41 ingob 1945
/****************************************************************************************************************************************/
1946
/*      Function:               fexist_(const u8*);                                                                                                                                                                                                     */
1947
/*                                                                                                                                                                                                                                                                              */
1948
/*      Description:    This function checks if a file already exist.                                                                                                                                           */
1949
/*                                                                                                                                                                                                                                                                              */
1950
/*      Returnvalue:    1 if the file exist else 0.                                                                                                                                                                                     */
1951
/****************************************************************************************************************************************/
89 killagreg 1952
u8 fexist_(s8 * const filename)
24 StephanB 1953
{
41 ingob 1954
        u8 exist = 0;
1955
        File_t *file = 0;
1956
        file = LockFilePointer();
1957
        exist = FileExist(filename, ATTR_NONE, ATTR_SUBDIRECTORY|ATTR_VOLUMELABEL, file);
1958
        UnlockFilePointer(file);
1959
        return(exist);
1 ingob 1960
}
24 StephanB 1961
 
41 ingob 1962
/****************************************************************************************************************************************/
1963
/*      Function:               feof_(File_t *File);                                                                                                                                                                                            */
1964
/*                                                                                                                                                                                                                                                                              */
1965
/*      Description:    This function checks wether the end of the file has been reached.                                                                                                                                               */
1966
/*                                                                                                                                                                                                                                                                              */
1967
/*      Returnvalue:    0 if the end of the file was not reached otherwise 1.                                                                                                                                                                           */
1968
/****************************************************************************************************************************************/
1969
u8 feof_(File_t *file)
88 killagreg 1970
{
41 ingob 1971
        if(((file->Position)+1) < (file->Size))
24 StephanB 1972
        {
1973
                return(0);
1974
        }
88 killagreg 1975
        else
24 StephanB 1976
        {
88 killagreg 1977
                return(1);
24 StephanB 1978
        }
1979
}
41 ingob 1980
 
210 killagreg 1981
/****************************************************************************************************************************************************/
1982
/* Function:    s8* FAT16_GetVolumeLabel(void)                                                                                                                                                                                                                  */
1983
/*                                                                                                                                                                                                                                                                                                      */
1984
/* Description: This function returns the volume label                                                                                                                                                                                          */
1985
/*                                                                                                                                                                                                                                                                                                      */
1986
/* Returnvalue: This function returns the pointer to the volume label or NULL if not found.                                                                                                                     */
1987
/****************************************************************************************************************************************************/
1988
s8* FAT16_GetVolumeLabel(void)
1989
{
1990
        s8              *pVolumeLabel = NULL;
1991
        u32             dir_sector, max_dir_sector, curr_sector;
1992
        u16     dir_entry = 0;
1993
        u8              i = 0;
41 ingob 1994
 
210 killagreg 1995
        DirEntry_t * dir;
1996
        File_t *file = NULL;
1997
 
1998
        // if Partition is not valud return NULL
1999
        if(!Partition.IsValid) return(pVolumeLabel);
2000
        // if Volume label was read before return it
2001
        if(Partition.VolumeLabel[0]!= '\0') return (Partition.VolumeLabel);
2002
        // try to catch a file pointer
2003
        file = LockFilePointer();
2004
        if(file == NULL) return(pVolumeLabel);
2005
        // search dir entries direct within the root directory area
2006
        file->DirectorySector = 0;
2007
        max_dir_sector = (Partition.MaxRootEntries * DIRENTRY_SIZE)/BYTES_PER_SECTOR;
2008
        file->FirstSectorOfFirstCluster = Partition.FirstRootDirSector;
2009
 
2010
        // update current file data area position to start of first cluster
2011
        file->FirstSectorOfCurrCluster  = file->FirstSectorOfFirstCluster;
2012
        file->SectorOfCurrCluster               = 0;
2013
        file->ByteOfCurrSector                  = 0;
2014
 
2015
        dir_sector = 0; // reset sector counter within a new cluster
2016
        do // loop over all sectors of the root directory
2017
        {
2018
                curr_sector = file->FirstSectorOfCurrCluster + dir_sector;      // calculate sector number
2019
                file->SectorInCache = curr_sector;                                                      // upate the sector number of file cache.
2020
                if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read the sector
2021
                {
2022
                        Fat16_Deinit();
2023
                        return(pVolumeLabel);
2024
                }
2025
                dir = (DirEntry_t *)file->Cache;                                                        // set pointer to directory
2026
                // search all directory entries within that sector
2027
                for(dir_entry = 0; dir_entry < DIRENTRIES_PER_SECTOR; dir_entry++)
2028
                {   // check for existing dir entry
2029
                        switch((u8)dir[dir_entry].Name[0])
2030
                        {
2031
                                case SLOT_EMPTY:
2032
                                case SLOT_DELETED:
2033
                                        // ignore empty or deleted dir entries
2034
                                        break;
2035
                                default:
2036
                                        // check attributes for volume label
2037
                                        if ((dir[dir_entry].Attribute & ATTR_VOLUMELABEL) != ATTR_VOLUMELABEL) break; // attribute must match
2038
                                        // (first 11 characters include 8 chars of basename and 3 chars extension.)
2039
                                        for(i = 0; i<11;i++) Partition.VolumeLabel[i] = dir[dir_entry].Name[i];
2040
                                        Partition.VolumeLabel[11] = '\0'; // terminate string
2041
                                        file->Attribute = dir[dir_entry].Attribute; // store attribute of found dir entry
2042
                                        file->FirstSectorOfFirstCluster = Fat16ClusterToSector(dir[dir_entry].StartCluster); // set sector of first data cluster
2043
                                        file->FirstSectorOfCurrCluster = file->FirstSectorOfFirstCluster;
219 killagreg 2044
                                        file->SectorOfCurrCluster = 0;
2045
                                        file->ByteOfCurrSector = 0;
210 killagreg 2046
                                        file->DirectorySector = curr_sector; // current sector
2047
                                        file->DirectoryIndex  = dir_entry; // current direntry in current sector
2048
                                        file->Size = dir[dir_entry].Size;
2049
                                        dir_entry = DIRENTRIES_PER_SECTOR;      // stop for-loop
2050
                                        pVolumeLabel =  Partition.VolumeLabel;
2051
                        } // end of first byte of name check
2052
                }
2053
                dir_sector++; // search next sector
2054
        // stop if we reached the end of the cluster or the end of the root dir
2055
        }while((dir_sector < max_dir_sector) && (!pVolumeLabel));
2056
 
2057
        UnlockFilePointer(file);
2058
        return(pVolumeLabel);
2059
}
349 ingob 2060
 
2061
 
2062
 
2063
#define ATTR_NONE               0x00    // normal file
2064
#define ATTR_READONLY           0x01    // file is readonly
2065
#define ATTR_HIDDEN                     0x02    // file is hidden
2066
#define ATTR_SYSTEM                     0x04    // file is a system file
2067
#define ATTR_VOLUMELABEL        0x08    // entry is a volume label
2068
#define ATTR_LONG_FILENAME      0x0F    // this is a long filename entry
2069
#define ATTR_SUBDIRECTORY       0x10    // entry is a directory name
2070
#define ATTR_ARCHIVE            0x20    // file is new or modified
2071
 
2072
 
2073
/********************************************************************************************************************************************/
2074
/*      Function:               u8 FindItem(Find_t);                                                                                                                                                                                                                    */
2075
/*                                                                                                                                                                                                                                                                                      */
2076
/*      Description:    This function looks for the item specified by global structure FindElement in the actual directory                                      */
2077
/*                                                                                                                                                                                                                                                              */
2078
/*                                                                                                                                                                                                                                                                                      */
2079
/*      Returnvalue:    TRUE if an matching element was found                                                                                                                                                                           */
2080
/********************************************************************************************************************************************/
2081
 
2082
u8 FindItem(Find_t *findelement)
2083
{
2084
        u16     index = 0;
2085
        u16   end_of_directory_not_reached = 1;                                                                         // the directory has been read completely without a result.
2086
        u8      i = 0;
2087
        u8              readpointer = 0;
2088
        u8              writepointer = 0;
2089
        u8              retvalue = 0;
2090
        DirEntry_t      *DirectoryEntry;
2091
        File_t  file;
2092
 
2093
        file.FirstSectorOfCurrCluster   = findelement->fp.FirstSectorOfCurrCluster;
2094
        file.SectorOfCurrCluster        = findelement->fp.SectorOfCurrCluster;
2095
        index                                                   = findelement->fp.DirectoryIndex;
2096
 
2097
 
2098
        do
2099
        {                                                                                                                                                               // search the next 16 rootentries in this sector of the roordirectory.          
2100
                SDC_GetSector(((u32) file.FirstSectorOfCurrCluster + (u32)file.SectorOfCurrCluster), file.Cache);                                               // Read the Rootdirectory.
2101
                DirectoryEntry = (DirEntry_t *)file.Cache;
2102
 
2103
                while((!retvalue)&&(index<16))
2104
                {
2105
                        i=0;                   
2106
                        if((u8) DirectoryEntry[index].Name[0] != 0xe5)                                                          // ignore deleted items.
2107
                        {
2108
                                while((i<=10)&&((DirectoryEntry[index].Name[i] == findelement->searchstring[i]) || (findelement->searchstring[i]=='*') || findelement->searchstring[i]=='?'))
2109
                                {
2110
                                        i++;
2111
                                }
2112
                        }
2113
                        if((DirectoryEntry[index].Attribute <= 0x30) && (DirectoryEntry[index].Attribute & findelement->attribmask) && (i==11))
2114
                        {
2115
                for(readpointer=0;readpointer<=10;readpointer++)
2116
                                {
2117
                                        if((DirectoryEntry[index].Name[readpointer] != ' ') && (readpointer!=8))
2118
                                        {
2119
                                                findelement->name[writepointer] = DirectoryEntry[index].Name[readpointer];      // copy the name of the item found to the find_structure.
2120
                                                writepointer++;
2121
                                        }
2122
                                        else  
2123
                                        {
2124
                                                if(DirectoryEntry[index].Attribute == ATTR_ARCHIVE)
2125
                                                {
2126
                                        if(readpointer < 8) readpointer=8;
2127
                                        if(DirectoryEntry[index].Name[readpointer] != ' ')
2128
                                        {
2129
                                        findelement->name[writepointer] = '.';                                                  // then seperate the name and the extension by a '.' at index 8.                                                
2130
                                        writepointer++;
2131
                                        findelement->name[writepointer] = DirectoryEntry[index].Name[readpointer];      // copy the name of the item found to the find_structure.
2132
                                        writepointer++;
2133
                                        }
2134
                                            else break;
2135
                                                }
2136
                            else break;
2137
                        }
2138
                        /* terminate the namestring with 0 for debugpurposes*/
2139
                        findelement->name[12] = 0;
2140
                                }
2141
                                findelement->fp.FirstSectorOfFirstCluster = (u32) DirectoryEntry[index].StartCluster;                                                  
2142
                                findelement->fp.DirectoryIndex   = index;              
2143
                                findelement->fp.FirstSectorOfCurrCluster   = file.FirstSectorOfCurrCluster;
2144
                                findelement->fp.DirectorySector  = (file.FirstSectorOfCurrCluster + file.SectorOfCurrCluster);
2145
                                findelement->fp.SectorOfCurrCluster      = file.SectorOfCurrCluster;
2146
                findelement->fp.Size            = DirectoryEntry[index].Size;
2147
                                findelement->fp.Attribute               = DirectoryEntry[index].Attribute;
2148
                retvalue = 1;
2149
                        }                      
2150
                        index++;
2151
                }
2152
                if(!retvalue)                                                                                                                           // file not found in this sector so take next sector.
2153
                {
2154
                file.SectorOfCurrCluster++;                            
2155
                        if(file.SectorOfCurrCluster >= Partition.SectorsPerCluster)
2156
                {  
2157
                                file.SectorOfCurrCluster=0;
2158
                                end_of_directory_not_reached = GetNextCluster(&file);
2159
                        }
2160
                }
2161
                index = 0;
2162
        }
2163
        while((end_of_directory_not_reached) && (!retvalue));
2164
 
2165
        return(retvalue);      
2166
}
2167
 
2168
 
2169
/********************************************************************************************************************************************/
2170
/*      Function:               findnext_(Find_t *);                                                                                                                                                                                                                    */
2171
/*                                                                                                                                                                                                                                                                                      */
2172
/*      Description:    This function looks for the next item in the specified directory with a matching filename and fileattributes specified  */
2173
/*                  by function findfirst()                                                                                                                                                                                                     */
2174
/*                                                                                                                                                                                                                                                                                      */
2175
/*      Returnvalue:                                                                                                                                                                                                                                                    */
2176
/********************************************************************************************************************************************/
2177
u8 findnext_(Find_t * findelement)
2178
{
2179
        u8 itemfound = 0;
2180
        u8 index = 0;
2181
 
2182
        findelement->fp.DirectoryIndex++;
2183
 
2184
        /* before we start searching an element we clear the complete namestring within the structure FindElement */
2185
        for(index=0;index<11;index++) findelement->name[index] = 0;
2186
 
2187
        if(FindItem(findelement))
2188
        {
2189
                itemfound = 1;         
2190
        }
2191
 
2192
        return(itemfound);
2193
}
2194
 
2195
 
2196
 
2197
/********************************************************************************************************************************************/
2198
/*      Function:               findfirst_(s8* filename, u8 attribfilter, u8 attribmask, Find_t *);                                                                                                                             */
2199
/*                                                                                                                                                                                                                                                                                      */
2200
/*      Description:    This function looks for the first item in the specified directory with a matching filename and fileattributes                   */
2201
/*                                      The filename of the element found is transformed from 8.3 to a string                                                                                                   */
2202
/*                                                                                                                                                                                                                                                                                      */
2203
/*                                                                                                                                                                                                                                                                                      */
2204
/*      Returnvalue:    (1) if Element was found. (0) if no valid element was found                                                                                                                     */
2205
/********************************************************************************************************************************************/
2206
u8 findfirst_(const s8* name, u8 attribmask, Find_t *findelement)
2207
{
2208
        u8 itemfound = 0;
2209
        u8 index = 0;  
2210
 
2211
        /* initialize the FindElement structure */
2212
        findelement->fp.FirstSectorOfFirstCluster = 0;  // First sector of the first cluster of the file.
2213
        findelement->fp.FirstSectorOfCurrCluster = Partition.CurrentWorkingDirectory;                                   // First sector of the cluster which is edited at the moment.
2214
        findelement->fp.SectorOfCurrCluster = 0;                                                        // The sector within the current cluster.
2215
        findelement->fp.ByteOfCurrSector = 0;                                                   // The byte location within the current sector.
2216
        findelement->fp.Size = 0;                                                                               // The size of the opend file in bytes.
2217
        findelement->fp.Position = 0;                                                                   // Pointer to a character within the file 0 < fileposition < filesize
2218
        findelement->fp.DirectorySector = 0;                                                            // the sectorposition where the directoryentry has been made.
2219
        findelement->fp.DirectoryIndex = 0;                                                             // The index to the directoryentry within the specified sector.
2220
        findelement->attribfilter = 0;
2221
        findelement->attribmask = attribmask;
2222
        findelement->searchstring[0]=0;
2223
 
2224
        /* seperate the name of the element to be found from the filepath and bring it to the 8.3*/
2225
        SeperateDirName(name, findelement->searchstring);
2226
        /* after the name of the element is in 8.3 we process the wildcards (*). After an * all following character are wildcards to */
2227
        for(index=0;index<8;index++)
2228
        {
2229
                /* if we find an wildcard within the name of the searchstring all remaining character after the wildcard shall be wildcards also */
2230
                if(findelement->searchstring[index] == '*')
2231
                {
2232
                        /*  */
2233
                        while(++index <8) findelement->searchstring[index] = '*';
2234
                }
2235
        }
2236
        for(index=8;index<11;index++)
2237
        {                                                                                                                                                                                                                                        
2238
                /* if we find an wildcard within the name of the searchstring all remaining character after the wildcard shall be wildcards also */
2239
                if(findelement->searchstring[index] == '*')
2240
                {
2241
                        /*  */
2242
                        while(++index <11) findelement->searchstring[index] = '*';
2243
                }
2244
        }
2245
 
2246
        /* the value of ...DirectoryIndex will be incremented in findnext_() thererfore it has to be decremented in findfirst_() */
2247
        findelement->fp.DirectoryIndex--;
2248
        /* now lets search for the item within the direcory */
2249
        itemfound = findnext_(findelement);
2250
 
2251
        return(itemfound);
2252
}
2253
 
2254
 
2255
/********************************************************************************************************************************************/
2256
/*      Function:               u8 GetDirCount(s8* filepath);                                                                                                                                                                                   */
2257
/*                                                                                                                                                                                                                                                                                      */
2258
/*      Description:    This function counts the number of subdirectories the dirpath contains                                                                                                  */
2259
/*                                                                                                                                                                                                                                                              */
2260
/*                                                                                                                                                                                                                                                                                      */
2261
/*      Returnvalue:    then number of subdirectories within the specified path                                                                                                                                 */
2262
/********************************************************************************************************************************************/
2263
u8 GetDirCount(u8 *dirpath)
2264
{
2265
   u8 i=0;
2266
   u8 cnt=0;
2267
 
2268
   while(dirpath[i] != 0)
2269
   {
2270
      if(dirpath[i]=='/')
2271
      {  
2272
         if(dirpath[i+1]!=0) cnt++;                                            // ignore last'/'
2273
      }
2274
      i++;  
2275
   }
2276
   i=0;  
2277
   return(cnt);
2278
}
2279
 
2280
 
2281
/********************************************************************************************************************************************/
2282
/* Funtion:     char *GetSubDirectory (char *dirpath, char *directory)                                                                                                                                          */
2283
/*                                                                                                                                                                                                                                                                                      */
2284
/* Description: this function returns a pointer to the beginning of the next subdirectory or NULL                                                                                       */
2285
/*                                                                                                                                                                                                                                                                                      */
2286
/*                                                                                                                                                                                                                                                                                      */
2287
/* returnvalue:   number of subdirectories in the filepath                                                                                                                                                                      */
2288
/********************************************************************************************************************************************/
2289
u8 * GetSubDirectory(u8 *dirpath, u8 *directory)
2290
{
2291
   u8 *cptr = dirpath;
2292
   u8 *dptr = directory;
2293
   u8 *retvalue = NULL;
2294
 
2295
   /* if the first character of the path is an '/' we go to the next character */
2296
   if(*cptr == '/') cptr++;
2297
   /* search end of path or subdirectory*/
2298
   while((*cptr != 0) && (*cptr != '/'))
2299
   {
2300
      *dptr = *cptr;
2301
       dptr++;
2302
       cptr++;
2303
   }  
2304
   if(*cptr!=0) retvalue = ++cptr;
2305
   *dptr = 0;
2306
 
2307
   return(retvalue);
2308
}
2309
 
2310
/********************************************************************************************************************************************/
2311
/*      Function:               s8 *GetPath(void);                                                                                                                                                                                                              */
2312
/*                                                                                                                                                                                                                                                                                      */
2313
/*      Description:    This function function returns a pointer to the absolute path of the active partition                                                                   */
2314
/*                                                                                                                                                                                                                                      */
2315
/*                                                                                                                                                                                                                                                                                      */
2316
/*      Returnvalue:                                                                                                                                                                                                                                                    */
2317
/********************************************************************************************************************************************/
2318
 
2319
s8 *GetPath(void)
2320
{
2321
        return(Partition.PathToCwd);
2322
}
2323
 
2324
/********************************************************************************************************************************************/
2325
/*      Function:               void SetPathToRoot(void);                                                                                                                                                                                                       */
2326
/*                                                                                                                                                                                                                                                                                      */
2327
/*      Description:    This function sets the path to the rootdirectory                                                                                                                                                */
2328
/*                                                                                                                                                                                                                                      */
2329
/*                                                                                                                                                                                                                                                                                      */
2330
/*      Returnvalue:                                                                                                                                                                                                                                                    */
2331
/********************************************************************************************************************************************/
2332
 
2333
void SetPathToRoot(void)
2334
{
2335
        /* lets point to the rootdirectory */
2336
        strcpy(Partition.PathToCwd, "/");      
2337
}
2338
 
2339
/********************************************************************************************************************************************/
2340
/*      Function:               void AppendDirToPath(s8* directory);                                                                                                                                                                                    */
2341
/*                                                                                                                                                                                                                                                                                      */
2342
/*      Description:    This function function appends the name of an directory to the Path to the CWD                                                                                  */
2343
/*                                                                                                                                                                                                                                      */
2344
/*                                                                                                                                                                                                                                                                                      */
2345
/*      Returnvalue:                                                                                                                                                                                                                                                    */
2346
/********************************************************************************************************************************************/
2347
 
2348
void AppendDirToPath(s8* directory)
2349
{
2350
        /* append the name of the directory to the path */
2351
        strcat(Partition.PathToCwd, directory);
2352
        /* append a '/' after the directoryname */
2353
        strcat(Partition.PathToCwd, "/");
2354
}
2355
 
2356
/********************************************************************************************************************************************/
2357
/*      Function:               RemoveLastDirFromPath(void);                                                                                                                                                                                    */
2358
/*                                                                                                                                                                                                                                                                                      */
2359
/*      Description:    This function removes the last directory from the path to the cwd                                                                                                               */
2360
/*                                                                                                                                                                                                                                      */
2361
/*                                                                                                                                                                                                                                                                                      */
2362
/*      Returnvalue:                                                                                                                                                                                                                                                    */
2363
/********************************************************************************************************************************************/
2364
 
2365
void RemoveLastDirFromPath(void)
2366
{
2367
        /* a pointer to the beginning of the absolute path to the cwd */
2368
        s8 * cptr = Partition.PathToCwd;
2369
        /* lets find the end of the path to the cwd */
2370
        while(*cptr++ != 0);
2371
        /* now lets find the beginning of the last directorientry */
2372
        while(*cptr-- != '/');
2373
        /* we delete the direntry by terminating the path with 0 */
2374
        *++cptr = 0;
2375
}
2376
 
2377
/********************************************************************************************************************************************/
2378
/*      Function:               chdir_(s8* filepath);                                                                                                                                                                                                   */
2379
/*                                                                                                                                                                                                                                                                                      */
2380
/*      Description:    This function changed the current working directory to the directory specified by the filepath                                                  */
2381
/*                  by function findfirst()                                                                                                                                                                                                     */
2382
/*                                                                                                                                                                                                                                                                                      */
2383
/*      Returnvalue:                                                                                                                                                                                                                                                    */
2384
/********************************************************************************************************************************************/
2385
/*
2386
#define ATTR_NONE               0x00    // normal file
2387
#define ATTR_READONLY           0x01    // file is readonly
2388
#define ATTR_HIDDEN                     0x02    // file is hidden
2389
#define ATTR_SYSTEM                     0x04    // file is a system file
2390
#define ATTR_VOLUMELABEL        0x08    // entry is a volume label
2391
#define ATTR_LONG_FILENAME      0x0F    // this is a long filename entry
2392
#define ATTR_SUBDIRECTORY       0x10    // entry is a directory name
2393
#define ATTR_ARCHIVE            0x20    // file is new or modified
2394
*/
2395
 
2396
u8 chdir_(s8 *path)
2397
{
2398
        u8              retvalue = 0;                                   // the value returned by this function
2399
        u32     ultemp = 0;                                             // temp. variable
2400
        u8     *directory = path;                               // pointer to a directoryname within the path
2401
        u8      dircount = 0;                                   // the number of subdirectoryentries within the path
2402
        u8      cache[64];                                              // a buffer containing the name of the subdirectory we are actually looking for
2403
        Find_t  fe;                                                             // The findelement needed for function findfirst to find the subdirectoryentry
2404
        s8              tp[256];                                                // temporarily we remember the actual path until the operation has finished successfully
2405
        u32     cwdt = 0;
2406
 
2407
        /* lets remember the actual path */
2408
        strcpy(tp, Partition.PathToCwd);
2409
        cwdt = Partition.CurrentWorkingDirectory;
2410
        /* if the path is absolute we begin at the rootdirectory */
2411
        strcpy(Partition.PathToCwd, "/");
2412
        /* how many subdirectories are there within the path? */
2413
        dircount = GetDirCount(path);  
2414
        /* now we parse through all the subdirectories within the path */
2415
        do
2416
        {  
2417
                /* until all the subdirectories within the path have been processed */
2418
        if(dircount) dircount--;
2419
                /* this is the name of the next subdirectory we are looking for */             
2420
            directory = GetSubDirectory(directory, cache);  
2421
                /* search for the next subdirectory within the path */
2422
                if(findfirst_(cache, ATTR_SUBDIRECTORY, &fe))
2423
                {
2424
                        /* we try to change into the directory "..". Now we have to delete the last direntry from the path */
2425
                        if(strcmp(cache,"..") == 0) RemoveLastDirFromPath();
2426
                        /* we try to change into the actual directory so there's nothing todo */
2427
                        else if(cache[0] == '.') return(1);
2428
                        /* otherwise we append the name of the directory we are changing in to the path */
2429
                        else AppendDirToPath(cache);
2430
                        /* The startcluster within an directoryentry specifies the position within the fat where the file or directory starts */
2431
                        ultemp = (u32) fe.fp.FirstSectorOfFirstCluster;
2432
                        /* the first 2 entries are reserved for '.' and '..' */
2433
                        ultemp -= 2;
2434
                        /* now we have to transform the position within the fat into the corrosponding sectoraddress relative to the beginning of the datasection of the active partition*/
2435
                        ultemp *= Partition.SectorsPerCluster;
2436
                        /* at least we make the sectoraddress absolute by adding the relative address to the beginning of the datasection of the active partition */
2437
                        ultemp += Partition.FirstDataSector;
2438
                        /* the cwd now points to the specified directory */
2439
                        Partition.CurrentWorkingDirectory = ultemp;
2440
                        /* we found the folder specified by the foldername */
2441
                        retvalue = 1;
2442
                }
2443
        }
2444
        /* do this until all subdirectories have been found or a subdirectory is missing */
2445
        while(dircount && retvalue);
2446
 
2447
        /* if we could not change to the specified directory we restore the actual path */
2448
        if(!retvalue)
2449
        {
2450
                Partition.CurrentWorkingDirectory = cwdt;
2451
                strcpy(Partition.PathToCwd, tp);
2452
        }
2453
        return(retvalue);      
2454
}
2455
 
2456
/********************************************************************************************************************************************/
2457
/*      Function:               void Test(void);                                                                                                                                                                                                                */
2458
/*                                                                                                                                                                                                                                                                                      */
2459
/*      Description:    Diese Funktion demonstriert die Möglichkeiten der Funktionen findfirst_() findnext_() und changedir_()                                  */
2460
/*                                                                                                                                                                                                                                                              */
2461
/*                                                                                                                                                                                                                                                                                      */
2462
/*      Returnvalue:                                                                                                                                                                                                                                                    */
2463
/********************************************************************************************************************************************/
2464
 
2465
void Test(void)
2466
{
2467
        File_t *fp = NULL;
2468
        Find_t fe;
2469
        u32 cwd = 0;
2470
 
2471
 
2472
        cwd = Partition.CurrentWorkingDirectory;
2473
sprintf(text,"\r\n Path: %s\r\n",Partition.PathToCwd); UART1_PutString(text);
2474
        /* Als Erstes suchen wir uns das erste Unterverzeichnis (ATTR_SUBDIRECTORY) auf der Speicherkarte */
2475
        if(findfirst_("*.*", ATTR_SUBDIRECTORY, &fe))
2476
        {
2477
                /* Danach wechseln wir in in dieses Unterverzeichnis auf der speicherkarte */
2478
                if(chdir_(fe.name))
2479
                {
2480
sprintf(text,"\r\n Path: %s\r\n",Partition.PathToCwd); UART1_PutString(text);
2481
                        /* Dann finden wir die erste Datei (ATTR_ARCIVE) in diesem Unterverzeichnis */
2482
                        if(findfirst_("*.*", ATTR_ARCHIVE, &fe))
2483
                        {
2484
                                /* Der Name der gefundenen Datei wird ausgegeben */
2485
                                UART1_PutString("\r\n");
2486
                                UART1_PutString(fe.name);              
2487
                                /* nun wir die erste gefundene Datei im Unterverzeichnis lesend geöffnet */
2488
                                fp = fopen_(fe.name, 'r');
2489
                                if(fp != NULL){
2490
                                        /* und die erste Zeile aus dem Inhalt ausgegeben */
2491
                                        fgets_(text,60,fp);
2492
                                        UART1_PutString("\r\n");
2493
                                        UART1_PutString(text);
2494
                                        fclose_(fp);
2495
                                }
2496
                                else {
2497
                                        UART1_PutString("\r\nfile not found");
2498
                                }
2499
 
2500
                                /* anschließend suchen wir alle weiteren Dateien im aktuellen Unterverzeichnis */              
2501
                                while(findnext_(&fe))
2502
                                {
2503
                                        /* und geben ebenfalls deren Namen */
2504
                                        UART1_PutString("\r\n");
2505
                                        UART1_PutString(fe.name);              
2506
                                        /* sowie nach dem Öffnen ihren Inhalt aus */
2507
                                        fp = fopen_(fe.name, 'r');
2508
                                        if(fp != NULL)
2509
                                        {
2510
                                                fgets_(text,60,fp);
2511
                                                UART1_PutString("\r\n");
2512
                                                UART1_PutString(text);
2513
                                                fclose_(fp);
2514
                                        }
2515
                                }
2516
                        }
2517
                }
2518
        }
2519
        Partition.CurrentWorkingDirectory = cwd;
2520
sprintf(text,"\r\n Path: %s\r\n",Partition.PathToCwd); UART1_PutString(text);
2521
        if(chdir_("/ordner1/ordner12/ordner13"))
2522
        {
2523
sprintf(text,"\r\n Path: %s\r\n",Partition.PathToCwd); UART1_PutString(text);
2524
                fp = fopen_("Datei13.txt", 'r');
2525
                if(fp != NULL){
2526
                        /* und die erste Zeile aus dem Inhalt ausgegeben */
2527
                        fgets_(text,60,fp);
2528
                        UART1_PutString("\r\n");
2529
                        UART1_PutString(text);
2530
                        fclose_(fp);
2531
                }
2532
                else {
2533
                        UART1_PutString("\r\nfile not found");
2534
                }                              
2535
        }
2536
        else
2537
                UART1_PutString("\r\ndirectory not found");
2538
        /* jetzt sind wir wieder im Rootverzeichnis */
2539
        Partition.CurrentWorkingDirectory = cwd;
2540
sprintf(text,"\r\n Path: %s\r\n",Partition.PathToCwd); UART1_PutString(text);
2541
}
2542