Subversion Repositories NaviCtrl

Rev

Rev 379 | Rev 383 | 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
// + www.MikroKopter.com
6
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
360 holgerb 7
// + Software Nutzungsbedingungen (english version: see below)
8
// + der Fa. HiSystems GmbH, Flachsmeerstrasse 2, 26802 Moormerland - nachfolgend Lizenzgeber genannt -
9
// + Der Lizenzgeber räumt dem Kunden ein nicht-ausschließliches, zeitlich und räumlich* unbeschränktes Recht ein, die im den
10
// + Mikrocontroller verwendete Firmware für die Hardware Flight-Ctrl, Navi-Ctrl, BL-Ctrl, MK3Mag & PC-Programm MikroKopter-Tool 
11
// + - nachfolgend Software genannt - nur für private Zwecke zu nutzen.
12
// + Der Einsatz dieser Software ist nur auf oder mit Produkten des Lizenzgebers zulässig.
1 ingob 13
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
360 holgerb 14
// + Die vom Lizenzgeber gelieferte Software ist urheberrechtlich geschützt. Alle Rechte an der Software sowie an sonstigen im
15
// + Rahmen der Vertragsanbahnung und Vertragsdurchführung überlassenen Unterlagen stehen im Verhältnis der Vertragspartner ausschließlich dem Lizenzgeber zu.
16
// + Die in der Software enthaltenen Copyright-Vermerke, Markenzeichen, andere Rechtsvorbehalte, Seriennummern sowie
17
// + sonstige der Programmidentifikation dienenden Merkmale dürfen vom Kunden nicht verändert oder unkenntlich gemacht werden.
18
// + Der Kunde trifft angemessene Vorkehrungen für den sicheren Einsatz der Software. Er wird die Software gründlich auf deren
19
// + Verwendbarkeit zu dem von ihm beabsichtigten Zweck testen, bevor er diese operativ einsetzt.
20
// + Die Haftung des Lizenzgebers wird - soweit gesetzlich zulässig - begrenzt in Höhe des typischen und vorhersehbaren
21
// + Schadens. Die gesetzliche Haftung bei Personenschäden und nach dem Produkthaftungsgesetz bleibt unberührt. Dem Lizenzgeber steht jedoch der Einwand 
22
// + des Mitverschuldens offen.
23
// + Der Kunde trifft angemessene Vorkehrungen für den Fall, dass die Software ganz oder teilweise nicht ordnungsgemäß arbeitet.
24
// + Er wird die Software gründlich auf deren Verwendbarkeit zu dem von ihm beabsichtigten Zweck testen, bevor er diese operativ einsetzt.
25
// + Der Kunde wird er seine Daten vor Einsatz der Software nach dem Stand der Technik sichern.
26
// + Der Kunde ist darüber unterrichtet, dass der Lizenzgeber seine Daten im zur Vertragsdurchführung erforderlichen Umfang
27
// + und auf Grundlage der Datenschutzvorschriften erhebt, speichert, verarbeitet und, sofern notwendig, an Dritte übermittelt.
28
// + *) Die räumliche Nutzung bezieht sich nur auf den Einsatzort, nicht auf die Reichweite der programmierten Software.
29
// + #### ENDE DER NUTZUNGSBEDINGUNGEN ####'
30
// +  Hinweis: Informationen über erweiterte Nutzungsrechte (wie z.B. Nutzung für nicht-private Zwecke) sind auf Anfrage per Email an info(@)hisystems.de verfügbar.
1 ingob 31
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
360 holgerb 32
// + Software LICENSING TERMS
1 ingob 33
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
360 holgerb 34
// + of HiSystems GmbH, Flachsmeerstrasse 2, 26802 Moormerland, Germany - the Licensor -
35
// + The Licensor grants the customer a non-exclusive license to use the microcontroller firmware of the Flight-Ctrl, Navi-Ctrl, BL-Ctrl, and MK3Mag hardware 
36
// + (the Software) exclusively for private purposes. The License is unrestricted with respect to time and territory*.
37
// + The Software may only be used with the Licensor's products.
38
// + The Software provided by the Licensor is protected by copyright. With respect to the relationship between the parties to this
39
// + agreement, all rights pertaining to the Software and other documents provided during the preparation and execution of this
40
// + agreement shall be the property of the Licensor.
41
// + The information contained in the Software copyright notices, trademarks, other legal reservations, serial numbers and other
42
// + features that can be used to identify the program may not be altered or defaced by the customer.
43
// + The customer shall be responsible for taking reasonable precautions
44
// + for the safe use of the Software. The customer shall test the Software thoroughly regarding its suitability for the
45
// + intended purpose before implementing it for actual operation. The Licensor's liability shall be limited to the extent of typical and
46
// + foreseeable damage to the extent permitted by law, notwithstanding statutory liability for bodily injury and product
47
// + liability. However, the Licensor shall be entitled to the defense of contributory negligence.
48
// + The customer will take adequate precautions in the case, that the software is not working properly. The customer will test
49
// + the software for his purpose before any operational usage. The customer will backup his data before using the software.
50
// + The customer understands that the Licensor collects, stores and processes, and, where required, forwards, customer data
51
// + to third parties to the extent necessary for executing the agreement, subject to applicable data protection and privacy regulations.
52
// + *) The territory aspect only refers to the place where the Software is used, not its programmed range.
53
// + #### END OF LICENSING TERMS ####
54
// + Note: For information on license extensions (e.g. commercial use), please contact us at info(@)hisystems.de.
1 ingob 55
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
41 ingob 56
#include <stdio.h>
379 holgerb 57
#include <string.h>
41 ingob 58
#include "91x_lib.h"
119 killagreg 59
#include "timer1.h"
41 ingob 60
#include "fat16.h"
61
#include "sdc.h"
62
#include "uart1.h"
379 holgerb 63
#include "main.h"
64
 
1 ingob 65
//________________________________________________________________________________________________________________________________________
88 killagreg 66
// Module name:                 fat16.c
1 ingob 67
// Compiler used:               avr-gcc 3.4.5
211 killagreg 68
// Last Modifikation:   20.03.2010
69
// Version:                             2.10
88 killagreg 70
// Authors:                             Stephan Busker & Gregor Stobrawa
41 ingob 71
// Description:                 Source files for FAT16 implementation with read and write-access
72
//                                              Copyright (C) 2008 Stephan Busker & Gregor Stobrawa
1 ingob 73
//........................................................................................................................................
41 ingob 74
// Functions:                   extern s16              Fat16_Init(void);
88 killagreg 75
//                                              extern s16              Fat16_Deinit(void);
211 killagreg 76
//                                              extern s8*              FAT16_GetVolumeLabel(void);
41 ingob 77
//                                              extern File_t * fopen_(const u8 *filename, const s8 mode);
78
//                                              extern s16              fclose_(File_t *File);
211 killagreg 79
//                                              extern u8               fexist_(s8 * const filename);
41 ingob 80
//                                              extern s16              fflush_(File_t *File);
81
//                                              extern s16      fseek_(File_t *File, s32 offset, s16 origin);
82
//                                              extern s16              fgetc_(File_t *File);
83
//                                              extern s16              fputc_(u8 c, File_t *File);
88 killagreg 84
//                                              extern u32              fread_(void *buffer, u32 size, u32 count, File_t *File);
41 ingob 85
//                                              extern u32              fwrite_(void *buffer, u32 size, u32 count, File_t *File);
86
//                                              extern s16              fputs_(const u8 *string, File_t *File);
87
//                                              extern u8 *     fgets_(u8 *string, s16 length, File_t *File);
211 killagreg 88
//                                              extern u8               feof_(File_t * const file);
1 ingob 89
//........................................................................................................................................
41 ingob 90
// ext. functions:              extern SD_Result_t SDC_Init(void;)
91
//                                              extern SD_Result_t SDC_Deinit(void);
88 killagreg 92
//                      extern SD_Result_t SDC_GetSector (u32,u8 *);
41 ingob 93
//                                              extern SD_Result_t SDC_PutSector (u32,u8 *);
1 ingob 94
//........................................................................................................................................
95
//
96
// URL:                                 www.Mikro-Control.de
97
// mailto:                              stephan.busker@mikro-control.de
98
//________________________________________________________________________________________________________________________________________
99
 
41 ingob 100
/*
101
FAT16 Drive Layout:
102
Description                                             Offset
103
Volume Boot Sector                                      Start of Partition
104
Fat Tables                                                      Start + # of Reserved Sectors
105
Root Directory Entry                            Start + # of Reserved + (# of Sectors Per FAT * 2)
106
Data Area (Starts with Cluster #2)      Start + # of Reserved + (# of Sectors Per FAT * 2) + ((Maximum Root Directory Entries * 32) / Bytes per Sector)
107
*/
1 ingob 108
 
109
 
379 holgerb 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
 
379 holgerb 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
379 holgerb 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
 
379 holgerb 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
 
379 holgerb 326
 
327
 
41 ingob 328
/****************************************************************************************************************************************/
211 killagreg 329
/*      Function:               FileDate(DateTime_t *);                                                                                                                                                                                         */
41 ingob 330
/*                                                                                                                                                                                                                                                                              */
211 killagreg 331
/*      Description:    This function calculates the DOS date from a pointer to a time structure.                                                                                       */
41 ingob 332
/*                                                                                                                                                                                                                                                                              */
211 killagreg 333
/*      Returnvalue:    Returns the DOS date.                                                                                                                                                                                           */
41 ingob 334
/****************************************************************************************************************************************/
211 killagreg 335
u16 FileDate(DateTime_t * pTimeStruct)
336
{
337
        u16 date = 0;
338
        if(pTimeStruct == NULL)   return date;
339
        if(!(pTimeStruct->Valid)) return date;
41 ingob 340
 
211 killagreg 341
        date |= (0x007F & (u16)(pTimeStruct->Year - 1980))<<9; // set year
342
        date |= (0x000F & (u16)(pTimeStruct->Month))<<5; // set month
343
        date |= (0x001F & (u16)(pTimeStruct->Day));
344
        return date;
345
}
346
 
347
/****************************************************************************************************************************************/
348
/*      Function:               FileTime(DateTime_t *);                                                                                                                                                                                         */
349
/*                                                                                                                                                                                                                                                                              */
350
/*      Description:    This function calculates the DOS time from a pointer to a time structure.                                                                                       */
351
/*                                                                                                                                                                                                                                                                              */
352
/*      Returnvalue:    Returns the DOS time.                                                                                                                                                                                           */
353
/****************************************************************************************************************************************/
354
 
355
u16 FileTime(DateTime_t * pTimeStruct)
1 ingob 356
{
211 killagreg 357
        u16 time = 0;
358
        if(pTimeStruct == NULL)   return time;
359
        if(!(pTimeStruct->Valid)) return time;
24 StephanB 360
 
211 killagreg 361
        time |= (0x001F & (u16)(pTimeStruct->Hour))<<11;
362
        time |= (0x003F & (u16)(pTimeStruct->Min))<<5;
363
        time |= (0x001F & (u16)(pTimeStruct->Sec/2));
364
        return time;
1 ingob 365
}
366
 
41 ingob 367
/****************************************************************************************************************************************/
368
/*      Function:               LockFilePointer();                                                                                                                                                                                                      */
369
/*                                                                                                                                                                                                                                                                              */
370
/*      Description:    This function trys to lock a free file pointer.                                                                                                                                         */
371
/*                                                                                                                                                                                                                                                                              */
372
/*      Returnvalue:    Returns the Filepointer on success or 0.                                                                                                                                                        */
373
/****************************************************************************************************************************************/
374
File_t * LockFilePointer(void)
1 ingob 375
{
41 ingob 376
        u8 i;
377
        File_t * File = 0;
378
        for(i = 0; i < FILE_MAX_OPEN; i++)
1 ingob 379
        {
88 killagreg 380
                if(FilePointer[i].State == FSTATE_UNUSED)               // found an unused one
1 ingob 381
                {
88 killagreg 382
                        File = &FilePointer[i];                                         // set pointer to that entry
41 ingob 383
                        FilePointer[i].State = FSTATE_USED;                     // mark it as used
384
                        break;
1 ingob 385
                }
41 ingob 386
        }
387
        return(File);
1 ingob 388
}
389
 
41 ingob 390
/****************************************************************************************************************************************/
391
/*      Function:               UnlockFilePointer(file_t *);                                                                                                                                                                            */
392
/*                                                                                                                                                                                                                                                                              */
393
/*      Description:    This function trys to unlock a file pointer.                                                                                                                                            */
394
/*                                                                                                                                                                                                                                                                              */
395
/*      Returnvalue:    Returns 1 if file pointer was freed else 0.                                                                                                                                                     */
396
/****************************************************************************************************************************************/
397
u8 UnlockFilePointer(File_t * file)
1 ingob 398
{
41 ingob 399
        u8 cnt;
400
        if(file == NULL) return(0);
401
        for(cnt = 0; cnt < FILE_MAX_OPEN; cnt++)
1 ingob 402
        {
41 ingob 403
                if(&FilePointer[cnt] == file)                                           // filepointer to be freed found?
1 ingob 404
                {
88 killagreg 405
                        file->State = FSTATE_UNUSED;
211 killagreg 406
                        file->FirstSectorOfFirstCluster = SECTOR_UNDEFINED;                     // Sectorpointer to the first sector of the first datacluster of the file.
407
                        file->FirstSectorOfCurrCluster  = SECTOR_UNDEFINED;                     // Pointer to the cluster which is edited at the moment.
41 ingob 408
                        file->SectorOfCurrCluster               = 0;                    // The sector which is edited at the moment (cluster_pointer + sector_index).
409
                        file->ByteOfCurrSector                  = 0;                    // The bytelocation within the current sector (cluster_pointer + sector_index + byte_index).
410
                        file->Mode                                              = 0;                    // mode of fileoperation (read,write)
411
                        file->Size                                              = 0;                    // the size of the opend file in bytes.
412
                        file->Position                                  = 0;                    // pointer to a character within the file 0 < fileposition < filesize
211 killagreg 413
                        file->SectorInCache                     = SECTOR_UNDEFINED;                     // the last sector read, wich is still in the sectorbuffer.
414
                        file->DirectorySector                   = SECTOR_UNDEFINED;                     // the sectorposition where the directoryentry has been made.
41 ingob 415
                        file->DirectoryIndex                    = 0;                    // the index to the directoryentry within the specified sector.
416
                        file->Attribute                                 = 0;                    // the attribute of the file opened.
88 killagreg 417
                        file = NULL;
41 ingob 418
                        return(1);
1 ingob 419
                }
41 ingob 420
        }
421
        return(0);
422
}
1 ingob 423
 
41 ingob 424
/****************************************************************************************************************************************/
425
/*      Function:               SeperateDirName(s8*, s8*);                                                                                                                                                                              */
426
/*                                                                                                                                                                                                                                                                              */
427
/*      Description:    This function seperates the first dirname from filepath and brings them                                                                                         */
428
/*                                      into the needed format ('test.txt' -> 'TEST    TXT')                                                                                                                            */
210 killagreg 429
/*                                      The subpath is the pointer to the remaining substring of the filepath                                                                                           */
41 ingob 430
/*                                                                                                                                                                                                                                                                              */
431
/*      Returnvalue:    Return NULL on error or pointer to subpath                                                                                                                                                                                                      */
432
/****************************************************************************************************************************************/
433
s8* SeperateDirName(const s8 *filepath, s8 *dirname)
434
{
435
        s8* subpath = NULL;
436
        u8 readpointer  = 0;
437
        u8 writepointer = 0;
1 ingob 438
 
88 killagreg 439
        // search subpath from beginning of filepath
41 ingob 440
        subpath = NULL;
441
        readpointer     = 0;
442
        if(filepath[0] == '/') readpointer = 1; // ignore first '/'
368 holgerb 443
        while(subpath == NULL)  // search the filepath until a subpath was found.
1 ingob 444
        {
88 killagreg 445
                if(((filepath[readpointer] == 0) || (filepath[readpointer] == '/')))    // if '/' found or end of filepath reached
446
                {
41 ingob 447
                        subpath = (s8*)&filepath[readpointer];                          // store the position of the first "/" found after the beginning of the filenpath
448
                }
449
                readpointer++;
450
        }
1 ingob 451
 
41 ingob 452
        // clear dirname with spaces
453
        dirname[11] = 0; // terminate dirname
454
        for(writepointer = 0; writepointer < 11; writepointer++) dirname[writepointer] = ' ';
379 holgerb 455
 
456
        // handle the special dirnames "." and ".." seperately
457
        readpointer = 0;
458
        if(filepath[0] == '/') readpointer++;
459
        // if we are trying to enter directories "." or ".." 
460
        if(filepath[readpointer] == '.')
461
        {
462
                // directory '.'
463
                if(filepath[readpointer+1] == 0)
464
                {
465
                        dirname[0] = '.';
466
                        return((s8*)&filepath[readpointer]);
467
                }
468
                // directory '..'               
469
                if((filepath[readpointer+1] == '.') &&  (filepath[readpointer+2] == 0))
470
                {
471
                        dirname[0] = '.';
472
                        dirname[1] = '.';
473
                        return((s8*)&filepath[readpointer]);
474
                }
475
        }
476
 
41 ingob 477
        writepointer = 0;
478
        // start seperating the dirname from the filepath.
479
        readpointer = 0;
480
        if(filepath[0] == '/') readpointer = 1; // ignore first '/'
368 holgerb 481
        while( &filepath[readpointer] < subpath)
1 ingob 482
        {
41 ingob 483
                if(writepointer >= 11) return(NULL);            // dirname to long
484
                if(filepath[readpointer] == '.')                        // seperating dirname and extension.
1 ingob 485
                {
41 ingob 486
                        if(writepointer <= 8)
1 ingob 487
                        {
41 ingob 488
                                readpointer++;                                          // next character in filename
489
                                writepointer = 8;                                       // jump to start of extension
1 ingob 490
                        }
88 killagreg 491
                        else return(NULL);                                              // dirbasename to long
41 ingob 492
                }
493
                else
494
                {
495
                        if((0x60 < filepath[readpointer]) && (filepath[readpointer] < 0x7B))
496
                        {
497
                                dirname[writepointer] = (filepath[readpointer] - 0x20);                                 // all characters must be upper case.
498
                        }
1 ingob 499
                        else
500
                        {
41 ingob 501
                                dirname[writepointer] = filepath[readpointer];
88 killagreg 502
                        }
41 ingob 503
                        readpointer++;
504
                        writepointer++;
1 ingob 505
                }
41 ingob 506
        }
88 killagreg 507
        return(subpath);
1 ingob 508
}
509
 
510
 
41 ingob 511
/**************************************************************************************************************************************+*/
512
/*      Function:       Fat16ClusterToSector( u16 cluster);                                                                                                                                                                             */
513
/*                                                                                                                                                                                                                                                                              */
514
/*      Description:    This function converts a cluster number given by the fat to the corresponding                                                                           */
515
/*                                      sector that points to the start of the data area that is represented by the cluster number.                                                     */
516
/*                                                                                                                                                                                                                                                                              */
517
/*      Returnvalue: The sector number with the data area of the given cluster                                                                                                                          */
518
/****************************************************************************************************************************************/
519
u32     Fat16ClusterToSector(u16 cluster)
520
{
211 killagreg 521
        if(!Partition.IsValid) return SECTOR_UNDEFINED;
218 killagreg 522
        if ((cluster < 2) || (cluster == CLUSTER_UNDEFINED))
211 killagreg 523
        {
524
                return SECTOR_UNDEFINED;
525
        }
526
        else
527
        {
528
                return ( (cluster - 2) * Partition.SectorsPerCluster) + Partition.FirstDataSector; // the first data sector     is represented by the 2nd cluster
529
        }
41 ingob 530
}
531
 
532
/****************************************************************************************************************************************/
533
/*      Function:       SectorToFat16Cluster( u32 sector);                                                                                                                                                                              */
534
/*                                                                                                                                                                                                                                                                              */
535
/*      Description:    This function converts a given sector number given to the corresponding                                                                                         */
536
/*                                      cluster number in the fat that represents this data area.                                                                                                                       */
537
/*                                                                                                                                                                                                                                                                              */
538
/*      Returnvalue: The cluster number representing the data area of the sector.                                                                                                                       */
539
/****************************************************************************************************************************************/
540
u16     SectorToFat16Cluster(u32 sector)
541
{
211 killagreg 542
        if(!Partition.IsValid) return CLUSTER_UNDEFINED;
543
        if((sector == SECTOR_UNDEFINED) || (sector < Partition.FirstDataSector)) return CLUSTER_UNDEFINED;
544
        else return ((u16)((sector - Partition.FirstDataSector) / Partition.SectorsPerCluster) + 2);
41 ingob 545
}
546
 
547
 
548
/****************************************************************************************************************************************/
210 killagreg 549
/*      Function:       Fat16_IsValid(void);                                                                                                                                                                                                    */
90 killagreg 550
/*                                                                                                                                                                                                                                                                              */
210 killagreg 551
/*      Description:    This function return the Fat 16 filesystem state                                                                                                                                        */
90 killagreg 552
/*                                                                                                                                                                                                                                                                              */
553
/*      Returnvalue: The function returns "1" on success                                                                                                                                                                        */
554
/****************************************************************************************************************************************/
555
u8 Fat16_IsValid(void)
556
{
557
        return(Partition.IsValid);
558
}
559
 
560
/****************************************************************************************************************************************/
41 ingob 561
/*      Function:       Fat16_Deinit(void);                                                                                                                                                                                                             */
562
/*                                                                                                                                                                                                                                                                              */
563
/*      Description:    This function uninitializes the fat 16 api                                                                                                                                                      */
564
/*                                                                                                                                                                                                                                                                              */
565
/*      Returnvalue: The function returns "0" on success                                                                                                                                                                        */
566
/****************************************************************************************************************************************/
567
u8 Fat16_Deinit(void)
568
{
569
        s16 returnvalue = 0;
570
        u8 cnt;
146 killagreg 571
 
572
        UART1_PutString("\r\n FAT16 deinit...");
41 ingob 573
        // declare the filepointers as unused.
574
        for(cnt = 0; cnt < FILE_MAX_OPEN; cnt++)
324 killagreg 575
        {      
576
                UnlockFilePointer(&FilePointer[cnt]);
1 ingob 577
        }
324 killagreg 578
        returnvalue = SDC_Deinit();                     // uninitialize interface to sd-card
41 ingob 579
        Partition.IsValid = 0;  // mark data in partition structure as invalid
210 killagreg 580
        Partition.VolumeLabel[0]='\0';
146 killagreg 581
        UART1_PutString("ok");
379 holgerb 582
SD_WatchDog = 0;
41 ingob 583
        return(returnvalue);
1 ingob 584
}
585
 
41 ingob 586
/****************************************************************************************************************************************/
587
/*      Function:               Fat16_Init(void);                                                                                                                                                                                                       */
588
/*                                                                                                                                                                                                                                                                          */
589
/*      Description:    This function reads the Masterbootrecord and finds the position of the Volumebootrecord, the FAT and the Rootdir    */
590
/*                                      and stores the information in global variables.                                                                                                                                     */
591
/*                                                                                                                                                                                                                                                                          */
592
/*      Returnvalue:    The function returns "0" if the filesystem is initialized.                                                                                                                      */
593
/****************************************************************************************************************************************/
594
u8 Fat16_Init(void)
88 killagreg 595
{
41 ingob 596
    u8  cnt     = 0;
597
        u32     partitionfirstsector;
88 killagreg 598
        VBR_Entry_t *VBR;
41 ingob 599
        MBR_Entry_t *MBR;
600
        File_t *file;
601
        u8 result = 0;
1 ingob 602
 
110 killagreg 603
        UART1_PutString("\r\n FAT16 init...");
41 ingob 604
        Partition.IsValid = 0;
605
        // declare the filepointers as unused.
606
        for(cnt = 0; cnt < FILE_MAX_OPEN; cnt++)
1 ingob 607
        {
211 killagreg 608
                UnlockFilePointer(&FilePointer[cnt]);
1 ingob 609
        }
41 ingob 610
        // set current file pinter to first position in list
88 killagreg 611
        file = &FilePointer[0];
612
 
211 killagreg 613
        // try to initialize the sd-card.
88 killagreg 614
        if(SD_SUCCESS != SDC_Init())
615
        {
110 killagreg 616
                UART1_PutString("SD-Card could not be initialized.");
41 ingob 617
                result = 1;
88 killagreg 618
                goto end;
41 ingob 619
        }
1 ingob 620
 
41 ingob 621
        // SD-Card is initialized successfully
622
        if(SD_SUCCESS != SDC_GetSector((u32)MBR_SECTOR,file->Cache))    // Read the MasterBootRecord
1 ingob 623
        {
110 killagreg 624
                UART1_PutString("Error reading the MBR.");
41 ingob 625
                result = 2;
88 killagreg 626
                goto end;
1 ingob 627
        }
41 ingob 628
        MBR = (MBR_Entry_t *)file->Cache;                                               // Enter the MBR using the structure MBR_Entry_t.
88 killagreg 629
        if((MBR->PartitionEntry1.Type == PART_TYPE_FAT16_ST_32_MB) ||
41 ingob 630
           (MBR->PartitionEntry1.Type == PART_TYPE_FAT16_LT_32_MB) ||
631
           (MBR->PartitionEntry1.Type == PART_TYPE_FAT16LBA))
1 ingob 632
        {
41 ingob 633
                // get sector offset 1st partition
634
                partitionfirstsector = MBR->PartitionEntry1.NoSectorsBeforePartition;
635
                // Start of Partition is the Volume Boot Sector
636
                if(SD_SUCCESS != SDC_GetSector(partitionfirstsector,file->Cache)) // Read the volume boot record
1 ingob 637
                {
110 killagreg 638
                        UART1_PutString("Error reading the VBR.");
41 ingob 639
                        result = 3;
88 killagreg 640
                        goto end;
641
                }
1 ingob 642
        }
41 ingob 643
        else  // maybe the medium has no partition assuming sector 0 is the vbr
644
        {
645
                partitionfirstsector = 0;
646
        }
88 killagreg 647
 
41 ingob 648
        VBR = (VBR_Entry_t *) file->Cache;                                              // Enter the VBR using the structure VBR_Entry_t.
649
        if(VBR->BytesPerSector != BYTES_PER_SECTOR)
650
        {
110 killagreg 651
                UART1_PutString("VBR: Sector size not supported.");
41 ingob 652
                result = 4;
88 killagreg 653
                goto end;
41 ingob 654
        }
655
        Partition.SectorsPerCluster             = VBR->SectorsPerCluster;                       // Number of sectors per cluster. Depends on the memorysize of the sd-card.
656
        Partition.FatCopies                     = VBR->NoFATCopies;                                     // Number of fatcopies.
657
        Partition.MaxRootEntries                = VBR->MaxRootEntries;                          // How many Entries are possible in the rootdirectory (FAT16 allows max. 512 entries).
210 killagreg 658
        Partition.SectorsPerFat                 = VBR->SectorsPerFAT;                           // The number of sectors per FAT                                // copy volume label
659
        Partition.VolumeLabel[0] = '\0';                                                                        // set string terminator
41 ingob 660
 
661
        /* Calculate the sectorpositon of the FAT, the Rootdirectory and the first Datacluster. */
88 killagreg 662
        // Calculate the position of the FileAllocationTable:
41 ingob 663
        // Start + # of Reserved Sectors
88 killagreg 664
        Partition.FirstFatSector        =   (u32)(partitionfirstsector + (u32)(VBR->ReservedSectors));
665
        // Calculate the position of the Rootdirectory:
666
        // Start + # of Reserved Sectors + (# of Sectors Per FAT * # of FAT Copies)
41 ingob 667
        Partition.FirstRootDirSector    =   Partition.FirstFatSector + (u32)((u32)Partition.SectorsPerFat*(u32)Partition.FatCopies);
668
        // Calculate the position of the first datacluster:
88 killagreg 669
        // Start + # of Reserved + (# of Sectors Per FAT * # of FAT Copies) + ((Maximum Root Directory Entries * 32) / Bytes per Sector)
41 ingob 670
        Partition.FirstDataSector       =   Partition.FirstRootDirSector + (u32)(Partition.MaxRootEntries>>4);  // assuming 512 Byte Per Sector
671
        // Calculate the last data sector
672
        if(VBR->NoSectors == 0)
673
        {
110 killagreg 674
                UART1_PutString("VBR: Bad number of sectors.");
41 ingob 675
                result = 5;
88 killagreg 676
                goto end;
41 ingob 677
        }
678
        Partition.LastDataSector = Partition.FirstDataSector + VBR->NoSectors - 1;
679
        // check for FAT16 in VBR of first partition
680
        if(!((VBR->FATName[0]=='F') && (VBR->FATName[1]=='A') && (VBR->FATName[2]=='T') && (VBR->FATName[3]=='1')&&(VBR->FATName[4]=='6')))
681
        {
110 killagreg 682
                UART1_PutString("VBR: Partition ist not FAT16 type.");
41 ingob 683
                result = 6;
684
                goto end;
685
        }
686
        Partition.IsValid = 1; // mark data in partition structure as valid
379 holgerb 687
        Partition.CurrentWorkingDirectory = Partition.FirstRootDirSector;
688
        strcpy(Partition.PathToCwd,"/");       
41 ingob 689
        result = 0;
690
        end:
691
        if(result != 0) Fat16_Deinit();
110 killagreg 692
        else UART1_PutString("ok");
88 killagreg 693
        return(result);
1 ingob 694
}
695
 
696
 
41 ingob 697
 
698
/****************************************************************************************************************************************/
699
/* Function:    ClearCurrCluster(File_t*);                                                                                                                                                                                      */
700
/*                                                                                                                                                                                                                                                                              */
701
/* Description: This function fills the current cluster with 0.                                                                                                                                                 */
702
/*                                                                                                                                                                                                                                                                              */
703
/* Returnvalue: The function returns 1 on success else 0.                                                                                                                                                               */
704
/****************************************************************************************************************************************/
705
u8 ClearCurrCluster(File_t * file)
1 ingob 706
{
41 ingob 707
        u8 retvalue = 1;
708
        u32 i;
88 killagreg 709
 
41 ingob 710
        if((!Partition.IsValid) || (file == NULL)) return(0);
711
 
712
        for(i = 0; i < BYTES_PER_SECTOR; i++) file->Cache[i] = 0; // clear file cache
211 killagreg 713
        if(file->FirstSectorOfCurrCluster == SECTOR_UNDEFINED) return (0); // nothing to do 
41 ingob 714
        for(i = 0; i < Partition.SectorsPerCluster; i++)
1 ingob 715
        {
41 ingob 716
                file->SectorInCache = file->FirstSectorOfCurrCluster + i;
717
                if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))
718
                {
88 killagreg 719
                        Fat16_Deinit();
379 holgerb 720
                        return(0);
41 ingob 721
                }
1 ingob 722
        }
88 killagreg 723
        return(retvalue);
1 ingob 724
}
725
 
41 ingob 726
/*****************************************************************************************************************************************/
727
/* Function:    GetNextCluster(File_t* );                                                                                                                                                                                        */
728
/*                                                                                                                                                                                                                                                                               */
729
/* Description: This function finds the next datacluster of the file specified with File *File.                                                                                  */
730
/*                                                                                                                                                                                                                                                                               */
731
/* Returnvalue: The function returns the next cluster or 0 if the last cluster has already reached.                                                                                                      */
732
/*****************************************************************************************************************************************/
733
u16 GetNextCluster(File_t * file)
1 ingob 734
{
211 killagreg 735
        u16 cluster = CLUSTER_UNDEFINED;
41 ingob 736
        u32 fat_byte_offset, sector, byte;
737
        Fat16Entry_t * fat;
88 killagreg 738
 
41 ingob 739
        if((!Partition.IsValid) || (file == NULL)) return(cluster);
211 killagreg 740
        if(file->FirstSectorOfCurrCluster == SECTOR_UNDEFINED) return(cluster);
41 ingob 741
        // if sector is within the data area
742
        if((Partition.FirstDataSector <= file->FirstSectorOfCurrCluster)&& (file->FirstSectorOfCurrCluster <= Partition.LastDataSector))
1 ingob 743
        {
41 ingob 744
                // determine current file cluster
745
                cluster = SectorToFat16Cluster(file->FirstSectorOfCurrCluster);
746
                // calculate byte offset in the fat for corresponding entry
747
                fat_byte_offset = ((u32)cluster)<<1; // two FAT bytes (16 bits) for every cluster
748
                // calculate the sector that contains the current cluster within the fat
749
                sector = Partition.FirstFatSector + ( fat_byte_offset / BYTES_PER_SECTOR);
750
                // calculate byte offset of the current cluster within that fat sector
751
                byte = fat_byte_offset % BYTES_PER_SECTOR;
752
                // read this sector to the file cache
753
                if(file->SectorInCache != sector)
1 ingob 754
                {
41 ingob 755
                        file->SectorInCache = sector;                                           // update sector stored in buffer
756
                        if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))       // read sector from sd-card
24 StephanB 757
                        {
41 ingob 758
                                Fat16_Deinit();
379 holgerb 759
                                return (CLUSTER_UNDEFINED);
88 killagreg 760
                        }
761
                }
41 ingob 762
                // read the next cluster from cache
763
                fat = (Fat16Entry_t *)(&(file->Cache[byte]));
764
                cluster = fat->NextCluster;
211 killagreg 765
                // if no next cluster exist
41 ingob 766
                if(FAT16_CLUSTER_LAST_MIN <= cluster)
767
                {
211 killagreg 768
                         cluster = CLUSTER_UNDEFINED; // next cluster is undefined
1 ingob 769
                }
24 StephanB 770
                else
771
                {
41 ingob 772
                        file->FirstSectorOfCurrCluster = Fat16ClusterToSector(cluster);
773
                        file->SectorOfCurrCluster = 0;
774
                        file->ByteOfCurrSector = 0;
24 StephanB 775
                }
88 killagreg 776
        }
41 ingob 777
        return(cluster);
1 ingob 778
}
779
 
780
 
379 holgerb 781
 
41 ingob 782
/****************************************************************************************************************************************/
783
/* Function:    FindNextFreeCluster(File_t *);                                                                                                                                                                          */
784
/*                                                                                                                                                                                                                                                                              */
785
/* Description: This function looks in the fat to find the next free cluster                                                                                                                    */
786
/*                                                                                                                                                                                                                                                                              */
787
/* Returnvalue: The function returns the cluster number of the next free cluster found within the fat.                                                                  */
788
/****************************************************************************************************************************************/
789
u16 FindNextFreeCluster(File_t *file)
1 ingob 790
{
41 ingob 791
        u32 fat_sector;                                 // current sector within the fat relative to the first sector of the fat.
792
        u32     curr_sector;                            // current sector
793
        u16     fat_entry;                                      // index to an fatentry within the actual sector (256 fatentries are possible within one sector).
211 killagreg 794
        u16     free_cluster    = CLUSTER_UNDEFINED;    // next free cluster number.
41 ingob 795
        Fat16Entry_t * fat;
88 killagreg 796
 
41 ingob 797
        if((!Partition.IsValid) || (file == NULL)) return(0);
24 StephanB 798
 
41 ingob 799
        // start searching for an empty cluster at the beginning of the fat.
88 killagreg 800
        fat_sector = 0;
801
        do
1 ingob 802
        {
41 ingob 803
                curr_sector = Partition.FirstFatSector + fat_sector;    // calculate sector to read
804
                file->SectorInCache = curr_sector;                                              // upate the sector number of file cache.
805
                if( SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))              // read sector of fat from sd-card.
806
                {
807
                        Fat16_Deinit();
379 holgerb 808
                        return(CLUSTER_UNDEFINED);
41 ingob 809
                }
810
 
811
                fat = (Fat16Entry_t *)file->Cache;                                              // set fat pointer to file cache
812
 
88 killagreg 813
                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 814
                {
815
                        if(fat[fat_entry].NextCluster == FAT16_CLUSTER_FREE)            // empty cluster found!!
88 killagreg 816
                        {
817
                                fat[fat_entry].NextCluster = FAT16_CLUSTER_LAST_MAX;    // mark this fat-entry as used
41 ingob 818
                                if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))               // and save the sector at the sd-card.
819
                                {
820
                                        Fat16_Deinit();
379 holgerb 821
                                        return(CLUSTER_UNDEFINED);
41 ingob 822
                                }
88 killagreg 823
                                free_cluster = (u16)(fat_sector * FAT16_ENTRIES_PER_SECTOR + (u32)fat_entry);
41 ingob 824
                                fat_entry = FAT16_ENTRIES_PER_SECTOR;                                   // terminate the search for a free cluster in this sector.
825
                        }
826
                }
827
                fat_sector++;                                                                                                   // continue the search in next fat sector
88 killagreg 828
        // repeat until the end of the fat is  reached and no free cluster has been found so far
368 holgerb 829
        }while((fat_sector < Partition.SectorsPerFat) && (!free_cluster));
41 ingob 830
        return(free_cluster);
1 ingob 831
}
832
 
833
 
41 ingob 834
/****************************************************************************************************************************************************/
835
/* Function:    s16 fseek_(File_t *, s32 *, u8)                                                                                                                                                                                                         */
836
/*                                                                                                                                                                                                                                                                                                      */
837
/* Description: This function sets the pointer of the stream relative to the position                                                                                                                           */
838
/*                              specified by origin (SEEK_SET, SEEK_CUR, SEEK_END)                                                                                                                                                                      */
380 holgerb 839
/* Returnvalue: Is 0 if seek was successful                                                                                                                                                                                                                     */
41 ingob 840
/****************************************************************************************************************************************************/
841
s16 fseek_(File_t *file, s32 offset, s16 origin)
1 ingob 842
{
41 ingob 843
        s32             fposition       = 0;
844
        s16     retvalue        = 1;
88 killagreg 845
 
380 holgerb 846
        // the byteindex within a sector 
847
        u32             byte_index       = 0;                  
848
        // the  sectorindex within a cluster                                                                    
849
        u32             sector_index  = 0;
850
        // the index of the cluster within the clusterchain inside the fat                                                                                                      
851
        u32     cluster_index = 0;                                                                                                     
852
 
853
        // check if the partition is valid      
211 killagreg 854
        if((!Partition.IsValid) || (file == NULL)) return(retvalue);
380 holgerb 855
//......................................................
856
        if(origin == SEEK_SET)                                                                                                          // Fileposition relative to the beginning of the file.
41 ingob 857
        {
380 holgerb 858
                fposition = 0;
859
        }      
860
//......................................................
861
        else if(origin == SEEK_END)                                                                                                     // Fileposition relative to the end of the file.
862
        {
863
                fposition  = (s32) file->Size;
864
        }      
865
//......................................................
866
        else if(origin == SEEK_CUR)                                                                                                     // Fileposition relative to the current position of the file.
867
        {
868
                fposition = (s32)file->Position;
869
        }      
41 ingob 870
 
380 holgerb 871
        // calculate the specified fileposition according to the selected mode
872
        fposition += offset;                                                                                                            // Die Absolute Dateiposition welche durch fseek angesprungen werden soll.
873
        // is the fileposition within the file?
874
        if((fposition >= 0) && (fposition <= (s32)file->Size))                                          // Ist die berechnete Dateiposition innerhalb der geöffneten Datei?
1 ingob 875
        {
380 holgerb 876
                // initialize the filepointer
41 ingob 877
                file->FirstSectorOfCurrCluster = file->FirstSectorOfFirstCluster;
878
                file->SectorOfCurrCluster       = 0;
879
                file->ByteOfCurrSector          = 0;
880
                file->Position                          = 0;
380 holgerb 881
                // has the specified file at least one valid sector attached?
211 killagreg 882
                if(file->FirstSectorOfCurrCluster == SECTOR_UNDEFINED) return(retvalue);
380 holgerb 883
                // calculate the absolute number of the sector wich contains the fileposition we are looking for
884
                sector_index = (u32) ((u32)fposition >> 9);
885
                // calculate the index of the cluster containing the specified sector
886
                cluster_index = (u32) sector_index / Partition.SectorsPerCluster;      
887
                // the absolute sectornumber becomes relative to the beginning of the specified cluster
888
                sector_index = (sector_index % Partition.SectorsPerCluster);           
889
                // calculate the index of the byteposition the fileposition points to
890
                byte_index = (u32) fposition % 512;
891
                // parse the fat till the calculated cluster has been reached
892
                while(cluster_index--) GetNextCluster(file);
893
                // set the filepointer to the specified sector and byteposition
894
                file->SectorOfCurrCluster = (u8) sector_index;
895
                file->ByteOfCurrSector = (u16) byte_index;
896
                // the fileposition now equals the filepointer
897
                file->Position = (u32)fposition;       
898
                // the specified fileposition has been reached
899
                retvalue = 0;                                                                                  
900
        }      
1 ingob 901
        return(retvalue);
902
}
903
 
904
 
41 ingob 905
/****************************************************************************************************************************************/
906
/* Function:    u16 DeleteClusterChain(File *file);                                                                                                                                                                             */
907
/*                                                                                                                                                                                                                                                                              */
908
/* Description: This function trances along a cluster chain in the fat and frees all clusters visited.                                                                  */
909
/*                                                                                                                                                                                                                                                                              */
910
/****************************************************************************************************************************************/
911
u8 DeleteClusterChain(u16 StartCluster)
1 ingob 912
{
88 killagreg 913
        u16 cluster;
41 ingob 914
        u32 fat_byte_offset, sector, byte;
915
        Fat16Entry_t * fat;
916
        u8 buffer[BYTES_PER_SECTOR];
917
        u32 sector_in_buffer = 0;
918
        u8 repeat = 0;
919
 
211 killagreg 920
        if(!Partition.IsValid) return(0);
921
        if(StartCluster == CLUSTER_UNDEFINED) return(0);
210 killagreg 922
        cluster = StartCluster; // init chain trace
211 killagreg 923
        // if start cluster is no real cluster
924
    if(FAT16_CLUSTER_LAST_MIN <= cluster) return 1;
41 ingob 925
 
926
        // calculate byte offset in the fat for corresponding entry
927
        fat_byte_offset = ((u32)cluster)<<1; // two FAT bytes (16 bits) for every cluster
928
        // calculate the sector that contains the current cluster within the fat
929
        sector = Partition.FirstFatSector + ( fat_byte_offset / BYTES_PER_SECTOR);
930
        // calculate byte offset of the current cluster within that fat sector
931
        byte = fat_byte_offset % BYTES_PER_SECTOR;
88 killagreg 932
        do
1 ingob 933
        {
41 ingob 934
                if(sector != sector_in_buffer)
1 ingob 935
                {
41 ingob 936
                        // read this sector to buffer
937
                        sector_in_buffer = sector;
938
                        if(SD_SUCCESS != SDC_GetSector(sector_in_buffer, buffer)) return 0;     // read sector from sd-card
88 killagreg 939
                }
41 ingob 940
                // read the next cluster from cache
941
                fat = (Fat16Entry_t *)(&(buffer[byte]));
942
                cluster = fat->NextCluster;
211 killagreg 943
                fat->NextCluster =      FAT16_CLUSTER_FREE; // mark current cluster as free
944
 
945
                if((FAT16_CLUSTER_USED_MIN <= cluster) && (cluster <= FAT16_CLUSTER_USED_MAX) )
946
                {
947
                        repeat = 1;
948
                        // calculate sector byte and byte offset in the fat for the next cluster
949
                        fat_byte_offset = ((u32)cluster)<<1; // two FAT bytes (16 bits) for every cluster
950
                        // calculate the sector that contains the current cluster within the fat
951
                        sector = Partition.FirstFatSector + ( fat_byte_offset / BYTES_PER_SECTOR);
952
                        // calculate byte offset of the current cluster within that fat sector
953
                        byte = fat_byte_offset % BYTES_PER_SECTOR;
954
                }
41 ingob 955
                else repeat = 0;
956
 
957
                // if new sector is not the sector in buffer or the last cluster in the chain was traced
958
                if((sector != sector_in_buffer) || !repeat)
959
                {       // write sector in buffer
210 killagreg 960
                        if(SD_SUCCESS != SDC_PutSector(sector_in_buffer,buffer))
146 killagreg 961
                        {
962
                                Fat16_Deinit();
211 killagreg 963
                                return(0);
146 killagreg 964
                        }
1 ingob 965
                }
41 ingob 966
        }
368 holgerb 967
        while(repeat);
41 ingob 968
 
969
        return 1;
1 ingob 970
}
971
 
972
 
41 ingob 973
/****************************************************************************************************************************************/
974
/* Function:    u16 AppendCluster(File *file);                                                                                                                                                                                  */
975
/*                                                                                                                                                                                                                                                                              */
976
/* Description: This function looks in the fat to find the next free cluster and appends it to the file.                                                                */
977
/*                                                                                                                                                                                                                                                                              */
211 killagreg 978
/* Returnvalue: The function returns the appened cluster number or CLUSTER_UNDEFINED of no cluster was appended.                                                */
41 ingob 979
/****************************************************************************************************************************************/
380 holgerb 980
 
41 ingob 981
u16 AppendCluster(File_t *file)
1 ingob 982
{
211 killagreg 983
        u16 last_cluster, new_cluster = CLUSTER_UNDEFINED;
41 ingob 984
        u32 fat_byte_offset, sector, byte;
985
        Fat16Entry_t * fat;
380 holgerb 986
//      s8 text[64];
88 killagreg 987
 
41 ingob 988
        if((!Partition.IsValid) || (file == NULL)) return(new_cluster);
1 ingob 989
 
41 ingob 990
        new_cluster = FindNextFreeCluster(file);        // the next free cluster found on the disk.
211 killagreg 991
        if(new_cluster != CLUSTER_UNDEFINED)
380 holgerb 992
        {       // A free cluster was found and can be added to the end of the file.            
993
                // is there at least one cluster appended to the file?
994
                if(file->FirstSectorOfLastCluster == CLUSTER_UNDEFINED)
995
                {
996
                        fseek_(file, 0, SEEK_END);                                                                                                      // jump to the end of the file
997
                        // remember the first sector of the last cluster
998
                        file->FirstSectorOfLastCluster = file->FirstSectorOfCurrCluster;
999
                        last_cluster = SectorToFat16Cluster(file->FirstSectorOfCurrCluster);            // determine current file cluster
1000
                }
1001
                else
1002
                {
1003
                        last_cluster = SectorToFat16Cluster(file->FirstSectorOfLastCluster);            // determine current file cluster
1004
                }
1005
 
211 killagreg 1006
                if(last_cluster != CLUSTER_UNDEFINED)
41 ingob 1007
                {
211 killagreg 1008
                        // update FAT entry of last cluster
1009
                        fat_byte_offset = ((u32)last_cluster)<<1;
1010
                        sector = Partition.FirstFatSector + ( fat_byte_offset / BYTES_PER_SECTOR);
1011
                        byte = fat_byte_offset % BYTES_PER_SECTOR;
1012
                        // read the sector containing the last cluster of the file
1013
                        if(file->SectorInCache != sector)
41 ingob 1014
                        {
211 killagreg 1015
                                file->SectorInCache = sector;   // update sector stored in buffer
1016
                                if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))       // read sector from sd-card
1017
                                {
1018
                                        Fat16_Deinit();
1019
                                        return(0);
1020
                                }
1021
                        }
1022
                        fat = (Fat16Entry_t *)(&(file->Cache[byte]));
1023
                        fat->NextCluster = new_cluster;                                                 // append the free cluster to the end of the file in the FAT.
1024
                        if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))               // save the modified sector to the FAT.
1025
                        {
41 ingob 1026
                                Fat16_Deinit();
211 killagreg 1027
                                return(0);
88 killagreg 1028
                        }
380 holgerb 1029
                        // now the new cluster appended to the fat is the last cluster
1030
                        file->FirstSectorOfLastCluster = Fat16ClusterToSector(new_cluster);
88 killagreg 1031
                }
211 killagreg 1032
                else // last cluster of the file is undefined
1033
                {   // then the new cluster must be the first one of the file
1034
                    // and its cluster number must be set in the direntry
1035
                        DirEntry_t * dir;
1036
                        file->SectorInCache = file->DirectorySector;                            // update the sector number of file cache.
1037
                        if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read in the sector.
1038
                        {
1039
                                Fat16_Deinit();
1040
                                return(CLUSTER_UNDEFINED);
1041
                        }
1042
                        dir = (DirEntry_t *)file->Cache;                                                        // set pointer to directory
1043
                        dir[file->DirectoryIndex].Res1 = 0;
1044
                        dir[file->DirectoryIndex].Res2[0] = 0;
1045
                        dir[file->DirectoryIndex].Res2[1] = 0;
1046
                        dir[file->DirectoryIndex].StartCluster = new_cluster;           // update startcluster 
1047
                    dir[file->DirectoryIndex].ModTime   = FileTime(&SystemTime);// set time
1048
                        dir[file->DirectoryIndex].ModDate       = FileDate(&SystemTime);// and date of modification
1049
                        dir[file->DirectoryIndex].LastAccessDate = dir[file->DirectoryIndex].ModDate;
1050
                        dir[file->DirectoryIndex].Size          = 0;
1051
                        // write sector containing the direntry
1052
                        if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))
1053
                        {
1054
                                Fat16_Deinit();
1055
                                return(CLUSTER_UNDEFINED);
1056
                        }
1057
                        // update file info     
1058
                        file->FirstSectorOfFirstCluster = Fat16ClusterToSector(new_cluster);
380 holgerb 1059
                        file->FirstSectorOfLastCluster = file->FirstSectorOfFirstCluster;
211 killagreg 1060
                        file->Size = 0;
1061
                        file->Position = 0;
41 ingob 1062
                }
211 killagreg 1063
                // update file pointes
41 ingob 1064
                file->FirstSectorOfCurrCluster = Fat16ClusterToSector(new_cluster);
1065
                file->SectorOfCurrCluster = 0;
1066
                file->ByteOfCurrSector = 0;
1067
        }
1068
        return(new_cluster);
1 ingob 1069
}
1070
 
380 holgerb 1071
 
41 ingob 1072
/****************************************************************************************************************************************************/
1073
/* Function:    DirectoryEntryExist(s8 *, u8, u8, File_t *)                                                                                                                                                                                     */
1074
/*                                                                                                                                                                                                                                                                                                      */
1075
/* Description: This function searches all possible dir entries until the file or directory is found or the end of the directory is reached                     */
1076
/*                                                                                                                                                                                                                                                                                                      */
1077
/* Returnvalue: This function returns 1 if the directory entry specified was found.                                                                                                                                     */
1078
/****************************************************************************************************************************************************/
1079
u8 DirectoryEntryExist(s8 *dirname, u8 attribfilter, u8 attribmask, File_t *file)
1080
{
1081
        u32             dir_sector, max_dir_sector, curr_sector;
1082
        u16     dir_entry = 0;
24 StephanB 1083
 
41 ingob 1084
        u16     end_of_directory_not_reached = 0;
1085
        u8              i = 0;
1086
        u8      direntry_exist = 0;
1087
        DirEntry_t * dir;
24 StephanB 1088
 
41 ingob 1089
        // if incomming pointers are useless return immediatly
88 killagreg 1090
        if((!Partition.IsValid) || (file == NULL) || (dirname == NULL)) return(direntry_exist);
41 ingob 1091
 
88 killagreg 1092
        // dir entries can be searched only in filesclusters that have
1093
        // a corresponding dir entry with adir-flag set in its attribute
41 ingob 1094
        // or direct within the root directory area
211 killagreg 1095
        file->FirstSectorOfFirstCluster = SECTOR_UNDEFINED;
41 ingob 1096
        // no current directory exist therefore assume searching in the root
211 killagreg 1097
        if(file->DirectorySector == SECTOR_UNDEFINED)
24 StephanB 1098
        {
41 ingob 1099
                max_dir_sector = (Partition.MaxRootEntries * DIRENTRY_SIZE)/BYTES_PER_SECTOR;
1100
                file->FirstSectorOfFirstCluster = Partition.FirstRootDirSector;
1101
        }
1102
        // within the root directory area we can read sectors sequentially until the end of this area
1103
        else if((Partition.FirstRootDirSector <= file->DirectorySector) && (file->DirectorySector < Partition.FirstDataSector))
1104
        {
1105
                max_dir_sector = (Partition.MaxRootEntries * DIRENTRY_SIZE)/BYTES_PER_SECTOR;
1106
        }
88 killagreg 1107
        // within the data clusters we can read sectors sequentially only within the cluster
41 ingob 1108
        else if((Partition.FirstDataSector <= file->DirectorySector) && (file->DirectorySector <= Partition.LastDataSector))
1109
        {
1110
                max_dir_sector = Partition.SectorsPerCluster;                           // limit max secters before next cluster
1111
        }
1112
        else return (direntry_exist); // bad sector range for directory sector of the file
1113
        // if search area is not defined yet
211 killagreg 1114
        if(file->FirstSectorOfFirstCluster == SECTOR_UNDEFINED)
41 ingob 1115
        {
1116
                // check if the directory entry of current file is existent and has the dir-flag set
1117
                file->SectorInCache = file->DirectorySector;                            // update the sector number of file cache.
1118
                if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read in the sector.
24 StephanB 1119
                {
41 ingob 1120
                        Fat16_Deinit();
379 holgerb 1121
                        return(0);
24 StephanB 1122
                }
41 ingob 1123
                dir = (DirEntry_t *)file->Cache;                                                        // set pointer to directory
211 killagreg 1124
                switch((u8)dir[file->DirectoryIndex].Name[0])                           // check if current directory exist
24 StephanB 1125
                {
41 ingob 1126
                        case SLOT_EMPTY:
1127
                        case SLOT_DELETED:
1128
                                // the directrory pointer of this file points to a deleted or not existen directory
1129
                                // therefore no file or subdirectory can be created
1130
                                return (direntry_exist);
1131
                                break;
88 killagreg 1132
                        default:        // and is a real directory
41 ingob 1133
                                if((dir[file->DirectoryIndex].Attribute & ATTR_SUBDIRECTORY) != ATTR_SUBDIRECTORY)
1134
                                {       // current file is not a directory therefore no file or subdirectory can be created here
1135
                                        return (direntry_exist);
1136
                                }
1137
                                break;
24 StephanB 1138
                }
41 ingob 1139
                file->FirstSectorOfFirstCluster = Fat16ClusterToSector(dir[file->DirectoryIndex].StartCluster);
24 StephanB 1140
        }
1141
 
41 ingob 1142
        // update current file data area position to start of first cluster
88 killagreg 1143
        file->FirstSectorOfCurrCluster  = file->FirstSectorOfFirstCluster;
1144
        file->SectorOfCurrCluster               = 0;
41 ingob 1145
        file->ByteOfCurrSector                  = 0;
24 StephanB 1146
 
41 ingob 1147
        do // loop over all data clusters of the current directory entry
88 killagreg 1148
        {
379 holgerb 1149
                dir_sector = 0;
41 ingob 1150
                do // loop over all sectors of a cluster or all sectors of the root directory
88 killagreg 1151
                {
41 ingob 1152
                        curr_sector = file->FirstSectorOfCurrCluster + dir_sector;      // calculate sector number
1153
                        file->SectorInCache = curr_sector;                                                      // upate the sector number of file cache.
1154
                        if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read the sector
1155
                        {
1156
                                Fat16_Deinit();
379 holgerb 1157
                                return(0);
41 ingob 1158
                        }
1159
                        dir = (DirEntry_t *)file->Cache;                                                        // set pointer to directory
1160
                        // search all directory entries within that sector
1161
                        for(dir_entry = 0; dir_entry < DIRENTRIES_PER_SECTOR; dir_entry++)
1162
                        {   // check for existing dir entry
1163
                                switch((u8)dir[dir_entry].Name[0])
1164
                                {
1165
                                        case SLOT_EMPTY:
1166
                                        case SLOT_DELETED:
1167
                                                // ignore empty or deleted dir entries
1168
                                                break;
1169
                                        default:
1170
                                                // if existing check attributes before names are compared will safe performance
1171
                                                if ((dir[dir_entry].Attribute & attribmask) != attribfilter) break; // attribute must match
1172
                                                // then compare the name to the giveb dirname (first 11 characters include 8 chars of basename and 3 chars extension.)
1173
                                                i = 0;
1174
                                                while((i < 11) && (dir[dir_entry].Name[i] == dirname[i])) i++;
1175
                                                if (i < 10) break; // names does not match
1176
                                                // if dirname and attribute have matched
1177
                                                file->Attribute = dir[dir_entry].Attribute; // store attribute of found dir entry
88 killagreg 1178
                                                file->FirstSectorOfFirstCluster = Fat16ClusterToSector(dir[dir_entry].StartCluster); // set sector of first data cluster
41 ingob 1179
                                                file->FirstSectorOfCurrCluster = file->FirstSectorOfFirstCluster;
1180
                                                file->SectorOfCurrCluster = 0;
1181
                                                file->ByteOfCurrSector = 0;
1182
                                                file->DirectorySector = curr_sector; // current sector
1183
                                                file->DirectoryIndex  = dir_entry; // current direntry in current sector
88 killagreg 1184
                                                file->Size = dir[dir_entry].Size;
1185
                                                direntry_exist = 1; // mark as found
1186
                                                dir_entry = DIRENTRIES_PER_SECTOR;      // stop for-loop
41 ingob 1187
                                } // end of first byte of name check
1188
                        }
1189
                        dir_sector++; // search next sector
1190
                // stop if we reached the end of the cluster or the end of the root dir
368 holgerb 1191
                }while((dir_sector < max_dir_sector) && (!direntry_exist));
1 ingob 1192
 
41 ingob 1193
                // if we are seaching in the data area and the file not found in this cluster so take next cluster.
88 killagreg 1194
                if(!direntry_exist && ( Partition.FirstDataSector <= file->FirstSectorOfCurrCluster))
41 ingob 1195
                {
1196
                        end_of_directory_not_reached = GetNextCluster(file);  // updates File->FirstSectorOfCurrCluster
1197
                }
368 holgerb 1198
        }while((end_of_directory_not_reached) && (!direntry_exist)); // repeat until a next cluster exist an no
41 ingob 1199
        return(direntry_exist);
1 ingob 1200
}
1201
 
1202
 
41 ingob 1203
/****************************************************************************************************************************************/
1204
/*      Function:               CreateDirectoryEntry(s8 *, u16, File_t *)                                                                                                                                                       */
1205
/*                                                                                                                                                                                                                                                                              */
1206
/*      Description:    This function looks for the next free position in the directory and creates an entry.                                                           */
1207
/*                                      The type of an directory entry is specified by the file attribute.                                                                                                      */
1208
/*                                                                                                                                                                                                                                                                              */
1209
/*      Returnvalue:    Return 0 on error                                                                                                                                                                                                       */
1210
/****************************************************************************************************************************************/
1211
u8 CreateDirectoryEntry(s8 *dirname, u8 attrib, File_t *file)
1 ingob 1212
{
41 ingob 1213
        u32 dir_sector, max_dir_sector, curr_sector;
1214
        u16 dir_entry   = 0;
1215
        u16 subdircluster, dircluster = 0;
1216
        u16 end_of_directory_not_reached = 0;
1217
        u8      i                       = 0;
88 killagreg 1218
        u8      retvalue        = 0;
41 ingob 1219
        DirEntry_t *dir;
1220
 
1221
        if((!Partition.IsValid) || (file == NULL) || (dirname == NULL)) return (retvalue);
1222
        // It is not checked here that the dir entry that should be created is already existent!
88 killagreg 1223
 
1224
        // Dir entries can be created only in file-clusters that have
41 ingob 1225
        // the dir-flag set in its attribute or within the root directory
88 killagreg 1226
 
211 killagreg 1227
        file->FirstSectorOfFirstCluster = SECTOR_UNDEFINED;
41 ingob 1228
        // no current directory exist therefore assume creating in the root
211 killagreg 1229
        if(file->DirectorySector == SECTOR_UNDEFINED)
24 StephanB 1230
        {
41 ingob 1231
                max_dir_sector = (Partition.MaxRootEntries * DIRENTRY_SIZE)/BYTES_PER_SECTOR;
1232
                dircluster = 0;
1233
                file->FirstSectorOfFirstCluster = Partition.FirstRootDirSector;
1234
        }
1235
        // within the root directory area we can read sectors sequentially until the end of this area
1236
        else if((Partition.FirstRootDirSector <= file->DirectorySector) && (file->DirectorySector < Partition.FirstDataSector))
1237
        {
1238
                max_dir_sector = (Partition.MaxRootEntries * DIRENTRY_SIZE)/BYTES_PER_SECTOR;
1239
        }
88 killagreg 1240
        // within the data clusters we can read sectors sequentially only within the cluster
41 ingob 1241
        else if((Partition.FirstDataSector <= file->DirectorySector) && (file->DirectorySector <= Partition.LastDataSector))
1242
        {
1243
                max_dir_sector = Partition.SectorsPerCluster;
1244
        }
88 killagreg 1245
        else return (retvalue); // bad sector range for directory sector of the file
41 ingob 1246
        // if search area is not defined yet
211 killagreg 1247
        if(file->FirstSectorOfFirstCluster == SECTOR_UNDEFINED)
41 ingob 1248
        {
1249
            // check if the directory entry of current file is existent and has the dir-flag set
1250
                file->SectorInCache = file->DirectorySector;                            // update the sector number of file cache.
88 killagreg 1251
                if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read in the sector.
41 ingob 1252
                {
1253
                        Fat16_Deinit();
379 holgerb 1254
                        return(0);
88 killagreg 1255
                }
41 ingob 1256
                dir = (DirEntry_t *)file->Cache;                                                        // set pointer to directory
218 killagreg 1257
                switch((u8)dir[file->DirectoryIndex].Name[0])                           // check if current directory exist
41 ingob 1258
                {
1259
                        case SLOT_EMPTY:
1260
                        case SLOT_DELETED:
1261
                                return (retvalue);
1262
                                break;
88 killagreg 1263
                        default:        // and is a real directory
41 ingob 1264
                                if((dir[file->DirectoryIndex].Attribute & ATTR_SUBDIRECTORY) != ATTR_SUBDIRECTORY)
1265
                                {       // current file is not a directory therefore no file or subdirectory can be created here
1266
                                        return (retvalue);
1267
                                }
1268
                                break;
1269
                }
1270
                dircluster = dir[file->DirectoryIndex].StartCluster;
88 killagreg 1271
                file->FirstSectorOfFirstCluster = Fat16ClusterToSector(dircluster);
41 ingob 1272
        }
88 killagreg 1273
 
218 killagreg 1274
        // if the new direntry is a subdirectory
1275
        if((attrib & ATTR_SUBDIRECTORY) == ATTR_SUBDIRECTORY)
1276
        {       // get a free clutser for its content
1277
                subdircluster = FindNextFreeCluster(file);      // get the next free cluster on the disk and mark it as used.
1278
        }
1279
        else // a normal file
1280
        {       // has no data cluster after creation
1281
                subdircluster = CLUSTER_UNDEFINED;
1282
        }
1283
 
211 killagreg 1284
        file->FirstSectorOfCurrCluster  = file->FirstSectorOfFirstCluster;
1285
        file->SectorOfCurrCluster               = 0;
1286
        do // loop over all clusters of current directory
41 ingob 1287
        {
211 killagreg 1288
                dir_sector = 0; // reset sector counter within a new cluster
1289
                do // loop over all sectors of a cluster or all sectors of the root directory
88 killagreg 1290
                {
211 killagreg 1291
                        curr_sector = file->FirstSectorOfCurrCluster + dir_sector;      // calculate sector number
1292
                        file->SectorInCache = curr_sector;                                                      // upate the sector number of file cache.
1293
                        if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read in the sector.
1 ingob 1294
                        {
211 killagreg 1295
                                Fat16_Deinit();
379 holgerb 1296
                                return(0);
211 killagreg 1297
                        }
1298
 
1299
                        dir = (DirEntry_t *)file->Cache;                                                        // set pointer to directory
1300
                        // search all directory entries of a sector
1301
                        for(dir_entry = 0; dir_entry < DIRENTRIES_PER_SECTOR; dir_entry++)
1302
                        {       // check if current direntry is available
1303
                                if(((u8)dir[dir_entry].Name[0] == SLOT_EMPTY) || ((u8)dir[dir_entry].Name[0] == SLOT_DELETED))
1304
                                {       // a free direntry was found
1305
                                        for(i = 0; i < 11; i++) dir[dir_entry].Name[i] = dirname[i];            // Set dir name
1306
                                        dir[dir_entry].Attribute    = attrib;
1307
                                        dir[dir_entry].Res1 = 0;
1308
                                        dir[dir_entry].CreationTime10ms = (u8)(SystemTime.mSec/10);
1309
                                        dir[dir_entry].CreationTime     = FileTime(&SystemTime);
1310
                                        dir[dir_entry].CreationDate     = FileDate(&SystemTime);
1311
                                        dir[dir_entry].LastAccessDate = dir[dir_entry].CreationDate;
1312
                                        dir[dir_entry].Res2[0] = 0;
1313
                                        dir[dir_entry].Res2[1] = 0;
1314
                                        dir[dir_entry].ModTime = dir[dir_entry].CreationTime;
1315
                                        dir[dir_entry].ModDate = dir[dir_entry].CreationDate;
1316
                                        // Set the attribute of the new directoryentry.
1317
                                        dir[dir_entry].StartCluster = subdircluster;                                            // copy the location of the first datacluster to the directoryentry.
1318
                                        dir[dir_entry].Size             = 0;                                                                    // the new createted file has no content yet.
1319
                                        if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))       // write back to card
1320
                                        {
1321
                                                Fat16_Deinit();
379 holgerb 1322
                                                return(0);
211 killagreg 1323
                                        }
218 killagreg 1324
                                        file->FirstSectorOfFirstCluster = Fat16ClusterToSector(subdircluster);  // Calculate absolute sectorposition of first datacluster.
211 killagreg 1325
                                        file->FirstSectorOfCurrCluster  = file->FirstSectorOfFirstCluster;      // Start reading the file with the first sector of the first datacluster.
1326
                                        file->SectorOfCurrCluster               = 0;                                                            // reset sector of cureen cluster
1327
                                        file->ByteOfCurrSector                  = 0;                                                            // reset the byte location within the current sector
1328
                                        file->Attribute                                 = attrib;                                               // set file attribute to dir attribute
1329
                                        file->Size                                              = 0;                                                        // new file has no size
1330
                                        file->DirectorySector                   = curr_sector;
1331
                                        file->DirectoryIndex                    = dir_entry;
1332
                                        // prepare subdirectory data cluster
1333
                                        if((attrib & ATTR_SUBDIRECTORY) == ATTR_SUBDIRECTORY)                           // if a new directory was created then initilize the data area
1334
                                        {
1335
                                                ClearCurrCluster(file); // fill cluster with zeros
1336
                                                file->SectorInCache = file->FirstSectorOfFirstCluster;
1337
                                                if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read in the sector.
41 ingob 1338
                                                {
211 killagreg 1339
                                                        Fat16_Deinit();
379 holgerb 1340
                                                        return(0);
41 ingob 1341
                                                }
211 killagreg 1342
                                                dir = (DirEntry_t *)file->Cache;
1343
                                                // create direntry "." to current dir
1344
                                                dir[0].Name[0] = 0x2E;
1345
                                                for(i = 1; i < 11; i++) dir[0].Name[i] = ' ';
1346
                                                dir[0].Attribute = ATTR_SUBDIRECTORY;
1347
                                                dir[0].StartCluster = subdircluster;
1348
                                                dir[0].Size = 0;
1349
                                                // create direntry ".." to the upper dir
1350
                                                dir[1].Name[0] = 0x2E;
1351
                                                dir[1].Name[1] = 0x2E;
1352
                                                for(i = 2; i < 11; i++) dir[1].Name[i] = ' ';
1353
                                                dir[1].Attribute = ATTR_SUBDIRECTORY;
1354
                                                dir[1].StartCluster = dircluster;
1355
                                                dir[1].Size = 0;
1356
                                                if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))// read in the sector.
88 killagreg 1357
                                                {
211 killagreg 1358
                                                        Fat16_Deinit();
379 holgerb 1359
                                                        return(0);
211 killagreg 1360
                                                }
1361
                                        }
1362
                                        retvalue = 1;
1363
                                        dir_entry = DIRENTRIES_PER_SECTOR;      // stop for-loop
88 killagreg 1364
                                }
211 killagreg 1365
                        }
1366
                        dir_sector++; // search next sector
1367
                // stop if we reached the end of the cluster or the end of the root dir
368 holgerb 1368
                }while((dir_sector < max_dir_sector) && (!retvalue));
88 killagreg 1369
 
211 killagreg 1370
                // if we are seaching in the data area and the file not found in this cluster so take next cluster.
1371
                if(!retvalue && ( Partition.FirstDataSector <= file->FirstSectorOfCurrCluster))
1372
                {
1373
                        end_of_directory_not_reached = GetNextCluster(file);  // updates File->FirstSectorOfCurrCluster
1374
                }
368 holgerb 1375
        }while((end_of_directory_not_reached) && (!retvalue));
211 killagreg 1376
        // Perhaps we are at the end of the last cluster of a directory file and have no free direntry found.
1377
        // Then we would need to add a cluster to that file and create the new direntry there.
1378
        // This code is not implemented yet, because its occurs only if more that 32*32=1024 direntries are
1379
        // within a subdirectory of root.
1380
 
41 ingob 1381
        return(retvalue);       // return 1 if file has been created otherwise return 0.
1 ingob 1382
}
1383
 
41 ingob 1384
/********************************************************************************************************************************************/
1385
/*      Function:               FileExist(const s8* filename, u8 attribfilter, u8 attribmask, File_t *file);                                                                                    */
1386
/*                                                                                                                                                                                                                                                                                      */
1387
/*      Description:    This function looks for the specified file including its subdirectories beginning                                                                               */
1388
/*                                      in the rootdirectory of the drive. If the file is found the Filepointer properties are                                                                  */
1389
/*                                      updated.                                                                                                                                                                                                                                */
1390
/*                                                                                                                                                                                                                                                                                      */
1391
/*      Returnvalue:    1 if file is found else 0.                                                                                                                                                                                              */
1392
/********************************************************************************************************************************************/
1393
u8 FileExist(const s8* filename, const u8 attribfilter, const u8 attribmask, File_t *file)
1 ingob 1394
{
41 ingob 1395
        s8* path = 0;
1396
        s8* subpath = 0;
1397
        u8 af, am, file_exist = 0;
1398
        s8 dirname[12]; // 8+3 + temination character
1 ingob 1399
 
41 ingob 1400
        // if incomming pointers are useless return immediatly
1401
        if ((filename == NULL) || (file == NULL) || (!Partition.IsValid)) return 0;
1 ingob 1402
 
41 ingob 1403
        // trace along the filepath
1404
        path = (s8*)filename;                                                           // start a the beginning of the filename string
1405
        file->DirectorySector = 0;                                                              // start at RootDirectory with file search
88 killagreg 1406
        file->DirectoryIndex = 0;
379 holgerb 1407
        /* if a path begins with a '/' at index 0 the search starts at the rootdirectory otherwise we will start relative to the cwd */
1408
        if(path[0] != '/')
1409
        {
1410
                /* is the current working directory the rootdirectory? */
1411
                if(Partition.CurrentWorkingDirectory == Partition.FirstRootDirSector) file->DirectorySector = 0;
1412
                /* otherwise we are working in an subdirectory */
1413
                else file->DirectorySector = Partition.CurrentWorkingDirectory;
1414
        }
41 ingob 1415
        // as long as the file was not found and the remaining path is not empty
368 holgerb 1416
        while((*path != 0) && !file_exist)
41 ingob 1417
        {       // separate dirname and subpath from filepath string
1418
                subpath = SeperateDirName(path, dirname);
1419
                if(subpath != NULL)
88 killagreg 1420
                {
1421
                        if(*subpath == 0)
41 ingob 1422
                        {       // empty subpath indicates last element of dir chain
1423
                                af = attribfilter;
1424
                                am = attribmask;
1425
                        }
1426
                        else  // it must be a subdirectory and no volume label
1 ingob 1427
                        {
41 ingob 1428
                                af = ATTR_SUBDIRECTORY;
1429
                                am = ATTR_SUBDIRECTORY|ATTR_VOLUMELABEL;
1430
                        }
1431
                        if(!DirectoryEntryExist(dirname, af, am, file))
1432
                        {
1433
                                return (file_exist); // subdirectory does not exist
1434
                        }
88 killagreg 1435
                        else
1436
                        {
41 ingob 1437
                                if (*subpath == 0)
24 StephanB 1438
                                {
41 ingob 1439
                                        file_exist = 1; // last element of path chain was found with the given attribute filter
24 StephanB 1440
                                }
1 ingob 1441
                        }
1442
                }
41 ingob 1443
                else // error seperating the subpath
1 ingob 1444
                {
41 ingob 1445
                        return file_exist; // bad subdir format
1 ingob 1446
                }
41 ingob 1447
                path = subpath;
1448
                subpath = 0;
1 ingob 1449
        }
41 ingob 1450
        return (file_exist);
1 ingob 1451
}
1452
 
24 StephanB 1453
 
41 ingob 1454
/********************************************************************************************************************************************/
1455
/*      Function:               FileCreate(const s8* filename, u8 attrib, File_t *file);                                                                                                                                */
1456
/*                                                                                                                                                                                                                                                                                      */
1457
/*      Description:    This function looks for the specified file including its subdirectories beginning                                                                               */
1458
/*                                      in the rootdirectory of the partition. If the file is found the Filepointer properties are                                                              */
88 killagreg 1459
/*                                      updated. If file or its subdirectories are not found they will be created                                                                                               */
41 ingob 1460
/*                                                                                                                                                                                                                                                                                      */
1461
/*      Returnvalue:    1 if file was created else 0.                                                                                                                                                                                   */
1462
/********************************************************************************************************************************************/
1463
u8 FileCreate(const s8* filename, const u8 attrib, File_t *file)
1464
{
1465
        s8 *path = 0;
1466
        s8 *subpath = 0;
1467
        u8 af, am, file_created = 0;
1468
        s8 dirname[12];
24 StephanB 1469
 
41 ingob 1470
        // if incomming pointers are useless return immediatly
1471
        if ((filename == NULL) || (file == NULL) || (!Partition.IsValid)) return 0;
1 ingob 1472
 
41 ingob 1473
        // trace along the filepath
1474
        path = (s8*)filename;                                                                   // start a the beginning of the filename string
1475
        file->DirectorySector = 0;                                                              // start at RootDirectory with file search
1476
        file->DirectoryIndex = 0;
1477
        // as long as the file was not created and the remaining file path is not empty
368 holgerb 1478
        while((*path != 0) && !file_created)
41 ingob 1479
        {   // separate dirname and subpath from filepath string
1480
                subpath = SeperateDirName(path, dirname);
1481
                if(subpath != NULL)
24 StephanB 1482
                {
88 killagreg 1483
                        if(*subpath == 0)
41 ingob 1484
                        {       // empty subpath indicates last element of dir chain
1485
                                af = ATTR_NONE;
1486
                                am = ATTR_SUBDIRECTORY|ATTR_VOLUMELABEL;  // any file that is no subdir or volume label
24 StephanB 1487
                        }
41 ingob 1488
                        else  // it must be a subdirectory and no volume label
24 StephanB 1489
                        {
41 ingob 1490
                                af = ATTR_SUBDIRECTORY;
1491
                                am = ATTR_SUBDIRECTORY|ATTR_VOLUMELABEL;
24 StephanB 1492
                        }
41 ingob 1493
                        if(!DirectoryEntryExist(dirname, af, am, file)) // if subdir or file is not existent
1494
                        {  // try to create subdir or file
1495
                                if(*subpath == 0) af = attrib; // if last element in dir chain take the given attribute
1496
                                if(!CreateDirectoryEntry(dirname, af, file))
1497
                                {       // could not be created
88 killagreg 1498
                                        return(file_created);
1499
                                }
41 ingob 1500
                                else if (*subpath == 0) file_created = 1; // last element of path chain was created
24 StephanB 1501
                        }
1502
                }
41 ingob 1503
                else // error seperating the subpath
24 StephanB 1504
                {
41 ingob 1505
                        return file_created; // bad subdir format
24 StephanB 1506
                }
41 ingob 1507
                path = subpath;
1508
                subpath = 0;
1509
        }
1510
        return (file_created);
24 StephanB 1511
}
1 ingob 1512
 
24 StephanB 1513
 
41 ingob 1514
/********************************************************************************************************************************************/
1515
/*      Function:               File_t * fopen_(s8* filename, s8 mode);                                                                                                                                                                 */
1516
/*                                                                                                                                                                                                                                                                                      */
1517
/*      Description:    This function looks for the specified file in the rootdirectory of the drive. If the file is found the number of the    */
1518
/*                                      corrosponding filepointer is returned. Only modes 'r' (reading) and 'a' append are implemented yet.                                             */
1519
/*                                                                                                                                                                                                                                                                                      */
1520
/*      Returnvalue:    The filepointer to the file or 0 if faild.                                                                                                                                                              */
1521
/********************************************************************************************************************************************/
89 killagreg 1522
File_t * fopen_(s8 * const filename, const s8 mode)
88 killagreg 1523
{
41 ingob 1524
        File_t *file    = 0;
379 holgerb 1525
        s8 *cptr;
88 killagreg 1526
 
41 ingob 1527
        if((!Partition.IsValid) || (filename == 0)) return(file);
1528
 
1529
        // Look for an unused filepointer in the file pointer list?
1530
        file = LockFilePointer();
1531
        // if no unused file pointer was found return 0
1532
        if(file == NULL) return(file);
1533
 
1534
        // now we have found a free filepointer and claimed it
1535
        // so let initiate its property values
211 killagreg 1536
        file->FirstSectorOfFirstCluster = SECTOR_UNDEFINED;             // Sectorpointer to the first sector of the first datacluster of the file.
1537
        file->FirstSectorOfCurrCluster  = SECTOR_UNDEFINED;             // Pointer to the cluster which is edited at the moment.
41 ingob 1538
        file->SectorOfCurrCluster               = 0;            // The sector which is edited at the moment (cluster_pointer + sector_index).
1539
        file->ByteOfCurrSector                  = 0;            // The bytelocation within the current sector (cluster_pointer + sector_index + byte_index).
1540
        file->Mode                                              = mode;         // mode of fileoperation (read,write)
1541
        file->Size                                              = 0;            // the size of the opened file in bytes.
1542
        file->Position                                  = 0;            // pointer to a byte within the file 0 < fileposition < filesize
211 killagreg 1543
        file->SectorInCache                             = SECTOR_UNDEFINED;             // the last sector read, wich is still in the sectorbuffer.
1544
        file->DirectorySector                   = SECTOR_UNDEFINED;             // the sectorposition where the directoryentry has been made.
41 ingob 1545
        file->DirectoryIndex                    = 0;            // the index to the directoryentry within the specified sector.
1546
        file->Attribute                                 = 0;            // the attribute of the file opened.
1547
 
379 holgerb 1548
        // bring the path into the correct syntax 
1549
        cptr = filename;
1550
        // search the whole string 
1551
        while(*cptr != 0)
1552
        {
1553
                // replace all '\' by '/'
1554
                if(*cptr == '\\') *cptr = '/';
1555
                cptr++;
1556
        }
41 ingob 1557
        // check if a real file (no directory) to the given filename exist
88 killagreg 1558
        if(FileExist(filename, ATTR_NONE, ATTR_SUBDIRECTORY|ATTR_VOLUMELABEL, file))
41 ingob 1559
        {  // file exist
1560
                switch(mode)  // check mode
1 ingob 1561
                {
41 ingob 1562
                        case 'a':       // if mode is: append to file
1563
                                if((file->Attribute & ATTR_READONLY) == ATTR_READONLY)
1564
                                {       // file is marked as readonly --> do not open this file
1565
                                        fclose_(file);
1566
                                        file = NULL;
1567
                                }
1568
                                else
1569
                                {       // file is not marked as read only --> goto end of file
1570
                                        fseek_(file, 0, SEEK_END);              // point to the end of the file
1571
                                }
1572
                                break;
1573
                        case 'w':       // if mode is: write to file
1574
                                if((file->Attribute & ATTR_READONLY) == ATTR_READONLY)
1575
                                {       // file is marked as readonly --> do not open this file
1576
                                        fclose_(file);
1577
                                        file = NULL;
1578
                                }
1579
                                else
211 killagreg 1580
                                {       // file is not marked as read only
1581
                                        DirEntry_t * dir;
41 ingob 1582
                                        // free all clusters of that file
1583
                                        DeleteClusterChain(SectorToFat16Cluster(file->FirstSectorOfFirstCluster));
211 killagreg 1584
                                        // update directory entry of that file
1585
                                        file->SectorInCache = file->DirectorySector;                            // update the sector number of file cache.
1586
                                        if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read in the sector.
1587
                                        {
1588
                                                Fat16_Deinit();
1589
                                                return(NULL);
1590
                                        }
1591
                                        dir = (DirEntry_t *)file->Cache;                                                                // set pointer to directory
1592
                                    dir[file->DirectoryIndex].ModTime   = FileTime(&SystemTime);        // set modification time
1593
                                        dir[file->DirectoryIndex].ModDate       = FileDate(&SystemTime);        // set modification date
1594
                                        dir[file->DirectoryIndex].LastAccessDate = dir[file->DirectoryIndex].ModDate;
1595
                                        dir[file->DirectoryIndex].StartCluster = CLUSTER_UNDEFINED;             // update startcluster 
1596
                                        dir[file->DirectoryIndex].Size          = 0;
1597
                                        // write sector containing the direntry
1598
                                        if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))
1599
                                        {
1600
                                                Fat16_Deinit();
1601
                                                return(NULL);
1602
                                        }
1603
                                        file->FirstSectorOfFirstCluster = SECTOR_UNDEFINED;
41 ingob 1604
                                        file->FirstSectorOfCurrCluster = file->FirstSectorOfFirstCluster;
1605
                                        file->SectorOfCurrCluster = 0;
1606
                                        file->ByteOfCurrSector = 0;
1607
                                        file->Size = 0;
1608
                                        file->Position = 0;
1609
                                        fseek_(file, 0, SEEK_SET);
1610
                                }
1611
                                break;
1612
                        case 'r':       // if mode is: read from file
88 killagreg 1613
                                // goto end of file
41 ingob 1614
                                fseek_(file, 0, SEEK_SET);
1615
                                break;
1616
                        default: // other modes are not supported
1617
                                fclose_(file);
1618
                                file = NULL;
24 StephanB 1619
                        break;
1 ingob 1620
                }
88 killagreg 1621
                return(file);
1 ingob 1622
        }
41 ingob 1623
        else // file does not exist
1624
        {
1625
                switch(mode)  // check mode
1626
                {
1627
                        case 'a':
1628
                        case 'w': // if mode is write or append
1629
                                // try to create the file
1630
                                if(!FileCreate(filename, ATTR_ARCHIVE, file))
1631
                                { // if it could not be created
1632
                                        fclose_(file);
1633
                                        file = NULL;
379 holgerb 1634
                                }
41 ingob 1635
                                break;
1636
                        case 'r': // else opened for 'r'
218 killagreg 1637
                        default:  // if unsupported mode
41 ingob 1638
                                fclose_(file);
1639
                                file = NULL;
88 killagreg 1640
                                break;
41 ingob 1641
                }
88 killagreg 1642
                return(file);
41 ingob 1643
        }
1644
        // we should never come to this point
1645
        fclose_(file);
1646
        file = NULL;
24 StephanB 1647
        return(file);
1648
}
1649
 
41 ingob 1650
/****************************************************************************************************************************************************/
1651
/* Function:    fflush_(File *);                                                                                                                                                                                                                                        */
1652
/*                                                                                                                                                                                                                                                                                                      */
1653
/* Description: This function writes the data already in the buffer but not yet written to the file.                                                                                            */
1654
/*                                                                                                                                                                                                                                                                                                      */
1655
/* Returnvalue: 0 on success EOF on error                                                                                                                                                                                                                       */
1656
/****************************************************************************************************************************************************/
1657
s16     fflush_(File_t *file)
24 StephanB 1658
{
88 killagreg 1659
        DirEntry_t *dir;
1660
 
41 ingob 1661
        if((file == NULL) || (!Partition.IsValid)) return (EOF);
88 killagreg 1662
 
41 ingob 1663
        switch(file->Mode)
24 StephanB 1664
        {
41 ingob 1665
                case 'a':
1666
                case 'w':
88 killagreg 1667
                        if(file->ByteOfCurrSector > 0)                                                                          // has data been added to the file?
41 ingob 1668
                        {
88 killagreg 1669
                                if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))// save the data still in the buffer
41 ingob 1670
                                {
88 killagreg 1671
                                        Fat16_Deinit();
1672
                                        return(EOF);
1673
                                }
41 ingob 1674
                        }
1675
                        file->SectorInCache     = file->DirectorySector;
1676
                        if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))                                       // read the directory entry for this file.
1677
                        {
1678
                                Fat16_Deinit();
88 killagreg 1679
                                return(EOF);
41 ingob 1680
                        }
88 killagreg 1681
 
41 ingob 1682
                        dir = (DirEntry_t *)file->Cache;
324 killagreg 1683
                        // update file size and modification time & date
211 killagreg 1684
                        dir[file->DirectoryIndex].ModTime = FileTime(&SystemTime);
1685
                        dir[file->DirectoryIndex].ModDate = FileDate(&SystemTime);
1686
                        dir[file->DirectoryIndex].LastAccessDate = dir[file->DirectoryIndex].ModDate;
41 ingob 1687
                        dir[file->DirectoryIndex].Size = file->Size;                                            // update file size
1688
                        if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))       // write back to sd-card
1689
                        {
1690
                                Fat16_Deinit();
1691
                                return(EOF);
1692
                        }
1693
                        break;
1694
                case 'r':
1695
                default:
211 killagreg 1696
                        // do nothing!
41 ingob 1697
                        return(EOF);
1698
                        break;
1699
 
24 StephanB 1700
        }
41 ingob 1701
        return(0);
24 StephanB 1702
}
1 ingob 1703
 
41 ingob 1704
/****************************************************************************************************************************************/
1705
/*      Function:               fclose_(File *file);                                                                                                                                                                                            */
1706
/*                                                                                                                                                                                                                                                                              */
1707
/*      Description:    This function closes the open file by writing the remaining data                                                                                                        */
1708
/*                                      from the buffer to the device and entering the filesize in the directory entry.                                                                         */
1709
/*                                                                                                                                                                                                                                                                              */
1710
/*      Returnvalue:    0 on success EOF on error                                                                                                                                                                                       */
1711
/****************************************************************************************************************************************/
1712
s16 fclose_(File_t *file)
24 StephanB 1713
{
41 ingob 1714
        s16 returnvalue = EOF;
24 StephanB 1715
 
41 ingob 1716
        if(file == NULL) return(returnvalue);
1717
        returnvalue = fflush_(file);
1718
        UnlockFilePointer(file);
1719
        return(returnvalue);
24 StephanB 1720
}
1721
 
41 ingob 1722
/********************************************************************************************************************************************/
1723
/*      Function:               fgetc_(File *file);                                                                                                                                                                                                             */
1724
/*                                                                                                                                                                                                                                                                                      */
1725
/*      Description:    This function reads and returns one character from the specified file. Is the end of the actual sector reached the              */
1726
/*                                      next sector of the cluster is read. If the last sector of the cluster read the next cluster will be searched in FAT.    */
1727
/*                                                                                                                                                                                                                                                                                      */
1728
/*      Returnvalue:    The function returns the character read from the specified memorylocation as u8 casted to s16 or EOF.                                   */
1729
/********************************************************************************************************************************************/
1730
s16 fgetc_(File_t *file)
88 killagreg 1731
{
41 ingob 1732
        s16 c = EOF;
1733
        u32 curr_sector;
88 killagreg 1734
 
41 ingob 1735
        if( (!Partition.IsValid) || (file == NULL)) return(c);
1736
        // if the end of the file is not reached, get the next character.
379 holgerb 1737
        if((0 < file->Size) && ((file->Position) < file->Size) )
1 ingob 1738
        {
41 ingob 1739
                curr_sector  = file->FirstSectorOfCurrCluster;          // calculate the sector of the next character to be read.
88 killagreg 1740
                curr_sector += file->SectorOfCurrCluster;
1741
 
41 ingob 1742
                if(file->SectorInCache != curr_sector)
1 ingob 1743
                {
41 ingob 1744
                        file->SectorInCache = curr_sector;
1745
                        if(SD_SUCCESS != SDC_GetSector(file->SectorInCache,file->Cache))
1746
                        {
1747
                                Fat16_Deinit();
379 holgerb 1748
                                return(EOF);
88 killagreg 1749
                        }
1750
                }
41 ingob 1751
                c = (s16) file->Cache[file->ByteOfCurrSector];
1752
                file->Position++;                                                                       // increment file position
88 killagreg 1753
                file->ByteOfCurrSector++;                                                       // goto next byte in sector
41 ingob 1754
                if(file->ByteOfCurrSector >= BYTES_PER_SECTOR)          // if end of sector
24 StephanB 1755
                {
41 ingob 1756
                        file->ByteOfCurrSector = 0;                                             //  reset byte location
1757
                        file->SectorOfCurrCluster++;                                    //      next sector
1758
                        if(file->SectorOfCurrCluster >= Partition.SectorsPerCluster)    // if end of cluster is reached, the next datacluster has to be searched in the FAT.
24 StephanB 1759
                        {
88 killagreg 1760
 
41 ingob 1761
                                if(GetNextCluster(file))                                                                                // Sets the clusterpointer of the file to the next datacluster.
24 StephanB 1762
                                {
41 ingob 1763
                                        file->SectorOfCurrCluster = 0;                                                          // start reading new cluster at first sector of the cluster.
1764
                                }
1765
                                else // the last cluster was allready reached
1766
                                {
1767
                                        file->SectorOfCurrCluster--;                                                    // jump back to the last sector in the last cluster
1768
                                        file->ByteOfCurrSector = BYTES_PER_SECTOR;                              // set ByteOfCurrSector one byte over sector end
1769
                                }
1 ingob 1770
                        }
24 StephanB 1771
                }
1772
        }
41 ingob 1773
        return(c);
24 StephanB 1774
}
1775
 
41 ingob 1776
/********************************************************************************************************************************************/
1777
/*      Function:               fputc_( const s8 c, File *file);                                                                                                                                                                                */
1778
/*                                                                                                                                                                                                                                                                                      */
1779
/*      Description:    This function writes a byte to the specified file and takes care of writing the necessary FAT- Entries.                                 */
1780
/*                                      next sector of the cluster is read. If the last sector of the cluster read the next cluster will be searched in FAT.    */
1781
/*                                                                                                                                                                                                                                                                                      */
1782
/*      Returnvalue:    The function returns the character written to the stream or EOF on error.                                                                                               */
1783
/********************************************************************************************************************************************/
1784
s16 fputc_(const s8 c, File_t *file)
88 killagreg 1785
{
41 ingob 1786
        u32 curr_sector  = 0;
88 killagreg 1787
 
41 ingob 1788
        if((!Partition.IsValid) || (file == NULL)) return(EOF);
211 killagreg 1789
        switch(file->Mode)
41 ingob 1790
        {
211 killagreg 1791
                case 'w':
1792
                case 'a':
1793
                        // If file position equals to file size, then the end of file has been reached.
1794
                        // In this case it has to be checked that the ByteOfCurrSector is BYTES_PER_SECTOR
1795
                        // and a new cluster should be appended.
1796
                        // If the first sector of first cluster is unvalid, then the file claims no data clusters 
1797
                        // and size should be zero, therefore append a new Cluster too.
1798
                        if(((file->Position >= file->Size) && (file->ByteOfCurrSector >= BYTES_PER_SECTOR)) || (file->FirstSectorOfFirstCluster == SECTOR_UNDEFINED))
1799
                        {
1800
                                if(CLUSTER_UNDEFINED == AppendCluster(file)) return(EOF);
1801
                        }
1802
 
1803
                        curr_sector  = file->FirstSectorOfCurrCluster;
1804
                        curr_sector += file->SectorOfCurrCluster;
1805
                        if(file->SectorInCache != curr_sector)
1806
                        {
1807
                                file->SectorInCache = curr_sector;
1808
                                if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))
24 StephanB 1809
                                {
211 killagreg 1810
                                        Fat16_Deinit();
1811
                                        return(EOF);
24 StephanB 1812
                                }
1 ingob 1813
                        }
379 holgerb 1814
 
1815
                        file->Cache[file->ByteOfCurrSector] = (u8)c;            // write databyte into the buffer. The byte will be written to the device at once
211 killagreg 1816
                        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.
1817
                        file->Position++;                                                                       // the actual positon within the file.
1818
                        file->ByteOfCurrSector++;                                                       // goto next byte in sector
1819
                        if(file->ByteOfCurrSector >= BYTES_PER_SECTOR)          // if the end of this sector is reached yet
1820
                        {       // save the sector to the sd-card
1821
                                if(SD_SUCCESS != SDC_PutSector(file->SectorInCache, file->Cache))
1822
                                {
1823
                                        Fat16_Deinit();
1824
                                        return(EOF);
1825
                                }
1826
                                file->ByteOfCurrSector = 0;                                             //  reset byte location
1827
                                file->SectorOfCurrCluster++;                                    //      next sector
1828
                                if(file->SectorOfCurrCluster >= Partition.SectorsPerCluster)// if end of cluster is reached, the next datacluster has to be searched in the FAT.
1829
                                {
1830
                                        if(!GetNextCluster(file))                                                               // Sets the clusterpointer of the file to the next datacluster.
1831
                                        { // if current cluster was the last cluster of the file
1832
                                                if(!AppendCluster(file))                                                // append a new and free cluster at the end of the file.
1833
                                                {
1834
                                                        file->SectorOfCurrCluster--;                            // jump back to last sector of last cluster
1835
                                                        file->ByteOfCurrSector = BYTES_PER_SECTOR;      // set byte location to 1 byte over sector len
1836
                                                        return(EOF);
1837
                                                }
1838
                                        }
1839
                                        else // next cluster
1840
                                        {
1841
                                                file->SectorOfCurrCluster = 0;                                                  // start reading new cluster at first sector of the cluster.
1842
                                        }
1843
                                }
88 killagreg 1844
                        }
211 killagreg 1845
                        break;
1846
                case 'r':
1847
                default:
1848
                        return(EOF);
1849
                        break;
1850
        } // EOF switch(file->Mode)
41 ingob 1851
        return(0);
24 StephanB 1852
}
1853
 
1854
 
41 ingob 1855
/****************************************************************************************************************************************/
1856
/*      Function:               fread_(void *buffer, s32 size, s32 count, File *File);                                                                                                                          */
1857
/*                                                                                                                                                                                                                                                                              */
1858
/*      Description:    This function reads count objects of the specified size                                                                                                                         */
1859
/*                                      from the actual position of the file to the specified buffer.                                                                                                           */
1860
/*                                                                                                                                                                                                                                                                              */
1861
/*      Returnvalue:    The function returns the number of objects (not bytes) read from the file.                                                                                      */
1862
/****************************************************************************************************************************************/
1863
u32 fread_(void *buffer, u32 size, u32 count, File_t *file)
1864
{
1865
        u32 object_cnt  = 0;                                                                                    // count the number of objects read from the file.
1866
        u32 object_size = 0;                                                                                    // count the number of bytes read from the actual object.
1867
        u8 *pbuff       = 0;                                                                                    // a pointer to the actual bufferposition.
1868
        u8 success      = 1;                                                                                    // no error occured during read operation to the file.
88 killagreg 1869
        s16 c;
24 StephanB 1870
 
41 ingob 1871
        if((!Partition.IsValid) || (file == NULL) || (buffer == NULL)) return(0);
24 StephanB 1872
 
41 ingob 1873
        pbuff = (u8 *) buffer;                                                                                  // cast the void pointer to an u8 *
88 killagreg 1874
 
368 holgerb 1875
        while((object_cnt < count) && success)
24 StephanB 1876
        {
41 ingob 1877
                object_size = size;
368 holgerb 1878
                while((size > 0) && success)
41 ingob 1879
                {
1880
                        c = fgetc_(file);
1881
                        if(c != EOF)
1882
                        {
1883
                                *pbuff = (u8)c;                                                                         // read a byte from the buffer to the opened file.
1884
                                pbuff++;
1885
                                size--;
1886
                        }
1887
                        else // error or end of file reached
1888
                        {
88 killagreg 1889
                                success = 0;
41 ingob 1890
                        }
1891
                }
1892
                if(success) object_cnt++;
88 killagreg 1893
        }
41 ingob 1894
        return(object_cnt);                                                                                             // return the number of objects succesfully read from the file
1 ingob 1895
}
1896
 
24 StephanB 1897
 
41 ingob 1898
/****************************************************************************************************************************************/
1899
/*      Function:               fwrite_(void *buffer, s32 size, s32 count, File *file);                                                                                                                         */
1900
/*                                                                                                                                                                                                                                                                              */
1901
/*      Description:    This function writes count objects of the specified size                                                                                                                        */
1902
/*                                      from the buffer pointer to the actual position in the file.                                                                                                                     */
1903
/*                                                                                                                                                                                                                                                                              */
1904
/*      Returnvalue:    The function returns the number of objects (not bytes) read from the file.                                                                                      */
1905
/****************************************************************************************************************************************/
1906
u32 fwrite_(void *buffer, u32 size, u32 count, File_t *file)
1 ingob 1907
{
41 ingob 1908
        u32 object_cnt  = 0;                                                                                                            // count the number of objects written to the file.
1909
        u32 object_size = 0;                                                                                                            // count the number of bytes written from the actual object.
1910
        u8 *pbuff           = 0;                                                                                                                // a pointer to the actual bufferposition.
1911
        u8 success      = 1;                                                                                                            // no error occured during write operation to the file.
88 killagreg 1912
        s16 c;
24 StephanB 1913
 
41 ingob 1914
        if((!Partition.IsValid) || (file == NULL) || (buffer == NULL)) return(0);
211 killagreg 1915
        if(file->Mode == 'r') return (0); // opened read only
41 ingob 1916
        pbuff = (u8 *) buffer;                                                                                                          // cast the void pointer to an u8 *
88 killagreg 1917
 
368 holgerb 1918
        while((object_cnt < count) && success)
1 ingob 1919
        {
41 ingob 1920
                object_size = size;
368 holgerb 1921
                while((size > 0) && success)
1 ingob 1922
                {
41 ingob 1923
                        c = fputc_(*pbuff, file);                                                                               // write a byte from the buffer to the opened file.
1924
                        if(c != EOF)
24 StephanB 1925
                        {
41 ingob 1926
                                pbuff++;
1927
                                size--;
24 StephanB 1928
                        }
41 ingob 1929
                        else
24 StephanB 1930
                        {
41 ingob 1931
                                success = 0;
24 StephanB 1932
                        }
1 ingob 1933
                }
41 ingob 1934
                if(success) object_cnt++;
88 killagreg 1935
        }
1936
 
41 ingob 1937
        return(object_cnt);                                                                                                                             // return the number of objects succesfully written to the file
88 killagreg 1938
}
1 ingob 1939
 
24 StephanB 1940
 
41 ingob 1941
/****************************************************************************************************************************************/
1942
/*      Function:               fputs_(const s8 *string, File_t *File);                                                                                                                                                         */
1943
/*                                                                                                                                                                                                                                                                              */
1944
/*      Description:    This function writes a string to the specified file.                                                                                                                            */
1945
/*                                                                                                                                                                                                                                                                              */
1946
/*      Returnvalue:    The function returns a no negative value or EOF on error.                                                                                                                       */
1947
/****************************************************************************************************************************************/
89 killagreg 1948
s16 fputs_(s8 * const string, File_t * const file)
24 StephanB 1949
{
41 ingob 1950
        u8 i=0;
1951
        s16 c = 0;
88 killagreg 1952
 
211 killagreg 1953
        if((!Partition.IsValid) || (file == NULL) || (string == NULL)) return(EOF);
1954
        if(file->Mode == 'r') return(EOF);
368 holgerb 1955
        while((string[i] != 0)&& (c != EOF))
24 StephanB 1956
        {
41 ingob 1957
                c = fputc_(string[i], file);
1958
                i++;
24 StephanB 1959
        }
41 ingob 1960
        return(c);
24 StephanB 1961
}
1962
 
41 ingob 1963
/****************************************************************************************************************************************/
1964
/*      Function:               fgets_(s8 *, s16 , File_t *);                                                                                                                                                                           */
1965
/*                                                                                                                                                                                                                                                                              */
1966
/*      Description:    This function reads a string from the file to the specifies string.                                                                                             */
1967
/*                                                                                                                                                                                                                                                                              */
1968
/*      Returnvalue:    A pointer to the string read from the file or 0 on error.                                                                                                                       */
1969
/****************************************************************************************************************************************/
89 killagreg 1970
s8 * fgets_(s8 * const string, s16 const length, File_t * const file)
24 StephanB 1971
{
89 killagreg 1972
        s8 *pbuff;
1973
        s16 c = 0, bytecount;
88 killagreg 1974
 
89 killagreg 1975
        if((!Partition.IsValid) || (file == NULL) || (string == NULL) || (length < 1)) return (0);
1976
        bytecount = length;
1977
        pbuff = string;                                                         // set write pointer to start of string
368 holgerb 1978
        while(bytecount > 1)                                            // read the length-1 characters from the file to the string.
24 StephanB 1979
        {
41 ingob 1980
                c = fgetc_(file);                                               // read a character from the opened file.
1981
                switch(c)
1 ingob 1982
                {
89 killagreg 1983
                        case 0x0A:                                                      // new line
1984
                                *pbuff = 0;                                             // set string terminator
1985
                                return(string);                                 // return normal
88 killagreg 1986
 
41 ingob 1987
                        case EOF:
89 killagreg 1988
                                *pbuff = 0;                                             // set string terminator
1989
                                return(0);
1990
 
1991
                        default:
1992
                                *pbuff++ = (s8)c;                               // copy byte to string
1993
                                bytecount--;
88 killagreg 1994
                                break;
1 ingob 1995
                }
24 StephanB 1996
        }
89 killagreg 1997
        *pbuff = 0;     // set string terminator
41 ingob 1998
        return(string);
24 StephanB 1999
}
2000
 
41 ingob 2001
/****************************************************************************************************************************************/
2002
/*      Function:               fexist_(const u8*);                                                                                                                                                                                                     */
2003
/*                                                                                                                                                                                                                                                                              */
2004
/*      Description:    This function checks if a file already exist.                                                                                                                                           */
2005
/*                                                                                                                                                                                                                                                                              */
2006
/*      Returnvalue:    1 if the file exist else 0.                                                                                                                                                                                     */
2007
/****************************************************************************************************************************************/
89 killagreg 2008
u8 fexist_(s8 * const filename)
24 StephanB 2009
{
41 ingob 2010
        u8 exist = 0;
2011
        File_t *file = 0;
2012
        file = LockFilePointer();
2013
        exist = FileExist(filename, ATTR_NONE, ATTR_SUBDIRECTORY|ATTR_VOLUMELABEL, file);
2014
        UnlockFilePointer(file);
2015
        return(exist);
1 ingob 2016
}
24 StephanB 2017
 
41 ingob 2018
/****************************************************************************************************************************************/
2019
/*      Function:               feof_(File_t *File);                                                                                                                                                                                            */
2020
/*                                                                                                                                                                                                                                                                              */
2021
/*      Description:    This function checks wether the end of the file has been reached.                                                                                                                                               */
2022
/*                                                                                                                                                                                                                                                                              */
2023
/*      Returnvalue:    0 if the end of the file was not reached otherwise 1.                                                                                                                                                                           */
2024
/****************************************************************************************************************************************/
2025
u8 feof_(File_t *file)
88 killagreg 2026
{
41 ingob 2027
        if(((file->Position)+1) < (file->Size))
24 StephanB 2028
        {
2029
                return(0);
2030
        }
88 killagreg 2031
        else
24 StephanB 2032
        {
88 killagreg 2033
                return(1);
24 StephanB 2034
        }
2035
}
41 ingob 2036
 
210 killagreg 2037
/****************************************************************************************************************************************************/
2038
/* Function:    s8* FAT16_GetVolumeLabel(void)                                                                                                                                                                                                                  */
2039
/*                                                                                                                                                                                                                                                                                                      */
2040
/* Description: This function returns the volume label                                                                                                                                                                                          */
2041
/*                                                                                                                                                                                                                                                                                                      */
2042
/* Returnvalue: This function returns the pointer to the volume label or NULL if not found.                                                                                                                     */
2043
/****************************************************************************************************************************************************/
2044
s8* FAT16_GetVolumeLabel(void)
2045
{
2046
        s8              *pVolumeLabel = NULL;
2047
        u32             dir_sector, max_dir_sector, curr_sector;
2048
        u16     dir_entry = 0;
2049
        u8              i = 0;
41 ingob 2050
 
210 killagreg 2051
        DirEntry_t * dir;
2052
        File_t *file = NULL;
2053
 
2054
        // if Partition is not valud return NULL
2055
        if(!Partition.IsValid) return(pVolumeLabel);
2056
        // if Volume label was read before return it
2057
        if(Partition.VolumeLabel[0]!= '\0') return (Partition.VolumeLabel);
2058
        // try to catch a file pointer
2059
        file = LockFilePointer();
2060
        if(file == NULL) return(pVolumeLabel);
2061
        // search dir entries direct within the root directory area
2062
        file->DirectorySector = 0;
2063
        max_dir_sector = (Partition.MaxRootEntries * DIRENTRY_SIZE)/BYTES_PER_SECTOR;
2064
        file->FirstSectorOfFirstCluster = Partition.FirstRootDirSector;
2065
 
2066
        // update current file data area position to start of first cluster
2067
        file->FirstSectorOfCurrCluster  = file->FirstSectorOfFirstCluster;
2068
        file->SectorOfCurrCluster               = 0;
2069
        file->ByteOfCurrSector                  = 0;
2070
 
2071
        dir_sector = 0; // reset sector counter within a new cluster
2072
        do // loop over all sectors of the root directory
2073
        {
2074
                curr_sector = file->FirstSectorOfCurrCluster + dir_sector;      // calculate sector number
2075
                file->SectorInCache = curr_sector;                                                      // upate the sector number of file cache.
2076
                if(SD_SUCCESS != SDC_GetSector(file->SectorInCache, file->Cache))// read the sector
2077
                {
2078
                        Fat16_Deinit();
379 holgerb 2079
                        return(NULL);
210 killagreg 2080
                }
2081
                dir = (DirEntry_t *)file->Cache;                                                        // set pointer to directory
2082
                // search all directory entries within that sector
2083
                for(dir_entry = 0; dir_entry < DIRENTRIES_PER_SECTOR; dir_entry++)
2084
                {   // check for existing dir entry
2085
                        switch((u8)dir[dir_entry].Name[0])
2086
                        {
2087
                                case SLOT_EMPTY:
2088
                                case SLOT_DELETED:
2089
                                        // ignore empty or deleted dir entries
2090
                                        break;
2091
                                default:
2092
                                        // check attributes for volume label
2093
                                        if ((dir[dir_entry].Attribute & ATTR_VOLUMELABEL) != ATTR_VOLUMELABEL) break; // attribute must match
2094
                                        // (first 11 characters include 8 chars of basename and 3 chars extension.)
2095
                                        for(i = 0; i<11;i++) Partition.VolumeLabel[i] = dir[dir_entry].Name[i];
2096
                                        Partition.VolumeLabel[11] = '\0'; // terminate string
2097
                                        file->Attribute = dir[dir_entry].Attribute; // store attribute of found dir entry
2098
                                        file->FirstSectorOfFirstCluster = Fat16ClusterToSector(dir[dir_entry].StartCluster); // set sector of first data cluster
2099
                                        file->FirstSectorOfCurrCluster = file->FirstSectorOfFirstCluster;
219 killagreg 2100
                                        file->SectorOfCurrCluster = 0;
2101
                                        file->ByteOfCurrSector = 0;
210 killagreg 2102
                                        file->DirectorySector = curr_sector; // current sector
2103
                                        file->DirectoryIndex  = dir_entry; // current direntry in current sector
2104
                                        file->Size = dir[dir_entry].Size;
2105
                                        dir_entry = DIRENTRIES_PER_SECTOR;      // stop for-loop
2106
                                        pVolumeLabel =  Partition.VolumeLabel;
2107
                        } // end of first byte of name check
2108
                }
2109
                dir_sector++; // search next sector
2110
        // stop if we reached the end of the cluster or the end of the root dir
368 holgerb 2111
        }while((dir_sector < max_dir_sector) && (!pVolumeLabel));
210 killagreg 2112
 
2113
        UnlockFilePointer(file);
2114
        return(pVolumeLabel);
2115
}
379 holgerb 2116
 
2117
 
2118
 
2119
#define ATTR_NONE               0x00    // normal file
2120
#define ATTR_READONLY           0x01    // file is readonly
2121
#define ATTR_HIDDEN                     0x02    // file is hidden
2122
#define ATTR_SYSTEM                     0x04    // file is a system file
2123
#define ATTR_VOLUMELABEL        0x08    // entry is a volume label
2124
#define ATTR_LONG_FILENAME      0x0F    // this is a long filename entry
2125
#define ATTR_SUBDIRECTORY       0x10    // entry is a directory name
2126
#define ATTR_ARCHIVE            0x20    // file is new or modified
2127
 
2128
 
2129
/********************************************************************************************************************************************/
2130
/*      Function:               u8 FindItem(Find_t);                                                                                                                                                                                                                    */
2131
/*                                                                                                                                                                                                                                                                                      */
2132
/*      Description:    This function looks for the item specified by global structure FindElement in the actual directory                                      */
2133
/*                                                                                                                                                                                                                                                              */
2134
/*                                                                                                                                                                                                                                                                                      */
2135
/*      Returnvalue:    TRUE if an matching element was found                                                                                                                                                                           */
2136
/********************************************************************************************************************************************/
2137
 
2138
u8 FindItem(Find_t *findelement)
2139
{
2140
        u16             index = 0;
2141
        u16             max_dir_sector = 0;
2142
        u16     end_of_directory_not_reached = 1;                                                                               // the directory has been read completely without a result.
2143
        u8              i = 0;
2144
        u8              readpointer = 0;
2145
        u8              writepointer = 0;
2146
        u8              retvalue = 0;
2147
        DirEntry_t      *DirectoryEntry;
2148
        File_t  file;
2149
 
2150
        file.FirstSectorOfCurrCluster   = findelement->fp.FirstSectorOfCurrCluster;
2151
        file.SectorOfCurrCluster        = findelement->fp.SectorOfCurrCluster;
2152
        index                                                   = findelement->fp.DirectoryIndex;
2153
 
2154
        // within the root directory area we can read sectors sequentially until the end of this area
2155
        if((Partition.FirstRootDirSector <= file.FirstSectorOfCurrCluster) && (file.FirstSectorOfCurrCluster < Partition.FirstDataSector))
2156
        {
2157
                max_dir_sector = (Partition.MaxRootEntries * DIRENTRY_SIZE)/BYTES_PER_SECTOR;
2158
        }
2159
        // within the data clusters we can read sectors sequentially only within the cluster
2160
        else if((Partition.FirstDataSector <= file.FirstSectorOfCurrCluster) && (file.FirstSectorOfCurrCluster <= Partition.LastDataSector))
2161
        {
2162
                max_dir_sector = Partition.SectorsPerCluster;                           // limit max secters before next cluster
2163
        }
2164
 
2165
        do
2166
        {                                                                                                                                                               // search the next 16 rootentries in this sector of the roordirectory.          
2167
                if(SD_SUCCESS != SDC_GetSector(((u32) file.FirstSectorOfCurrCluster + (u32)file.SectorOfCurrCluster), file.Cache));                                             // Read the Rootdirectory.
2168
                {
2169
                        Fat16_Deinit();
2170
                        return(0);
2171
                }
2172
 
2173
                DirectoryEntry = (DirEntry_t *)file.Cache;
2174
 
2175
                while((!retvalue)&&(index<16))
2176
                {
2177
                        i=0;                   
2178
                        if((u8) DirectoryEntry[index].Name[0] != 0xe5)                                                          // ignore deleted items.
2179
                        {
2180
                                while((i<=10)&&((DirectoryEntry[index].Name[i] == findelement->searchstring[i]) || (findelement->searchstring[i]=='*') || findelement->searchstring[i]=='?'))
2181
                                {
2182
                                        i++;
2183
                                }
2184
                        }
2185
                        if((DirectoryEntry[index].Attribute <= 0x30) && (DirectoryEntry[index].Attribute & findelement->attribmask) && (i==11))
2186
                        {
2187
                for(readpointer=0;readpointer<=10;readpointer++)
2188
                                {
2189
                                        if((DirectoryEntry[index].Name[readpointer] != ' ') && (readpointer!=8))
2190
                                        {
2191
                                                findelement->name[writepointer] = DirectoryEntry[index].Name[readpointer];      // copy the name of the item found to the find_structure.
2192
                                                writepointer++;
2193
                                        }
2194
                                        else  
2195
                                        {
2196
                                                if(DirectoryEntry[index].Attribute == ATTR_ARCHIVE)                                            
2197
                                                {
2198
                                        if(readpointer < 8) readpointer=8;
2199
                                        if(DirectoryEntry[index].Name[readpointer] != ' ')
2200
                                        {
2201
                                        findelement->name[writepointer] = '.';                                                  // then seperate the name and the extension by a '.' at index 8.                                                
2202
                                        writepointer++;
2203
                                        findelement->name[writepointer] = DirectoryEntry[index].Name[readpointer];      // copy the name of the item found to the find_structure.
2204
                                        writepointer++;
2205
                                        }
2206
                                            else break;
2207
                                                }
2208
                            else break;
2209
                        }
2210
                        /* terminate the namestring with 0 for debugpurposes*/
2211
                        findelement->name[12] = 0;
2212
                                }
2213
                                findelement->fp.FirstSectorOfFirstCluster = (u32) DirectoryEntry[index].StartCluster;                                                  
2214
                                findelement->fp.DirectoryIndex   = index;              
2215
                                findelement->fp.FirstSectorOfCurrCluster   = file.FirstSectorOfCurrCluster;
2216
                                findelement->fp.DirectorySector  = (file.FirstSectorOfCurrCluster + file.SectorOfCurrCluster);
2217
                                findelement->fp.SectorOfCurrCluster      = file.SectorOfCurrCluster;
2218
                findelement->fp.Size            = DirectoryEntry[index].Size;
2219
                                findelement->fp.Attribute               = DirectoryEntry[index].Attribute;
2220
                retvalue = 1;
2221
                        }                      
2222
                        /* search the next sector */
2223
                        index++;
2224
                }
2225
                /* this sector has been searched but we havn't found what we are looking for. Therefore we have to find the next sector */
2226
                if(!retvalue)                                                                                                                           // file not found in this sector so take next sector.
2227
                {
2228
                        /* in the next sector we start looking for the specified entry beginning at index 0 */
2229
                        index = 0;
2230
                        /* there are still sectors to be read within the cluster or within the linear addresspace of the rootdirectory */
2231
                        if(file.SectorOfCurrCluster < max_dir_sector-1)  file.SectorOfCurrCluster++; else end_of_directory_not_reached = 0;
2232
                        /* if we are looking for an directoryentry outside the rootdirectory and have reached the end of the cluster we have to get the next one */
2233
                        if(Partition.FirstDataSector <= file.FirstSectorOfCurrCluster)
2234
                        {
2235
                                end_of_directory_not_reached = GetNextCluster(&file);
2236
                        }
2237
                }
2238
        }
2239
        while((end_of_directory_not_reached) && (!retvalue) );
2240
 
2241
        return(retvalue);      
2242
}
2243
 
2244
 
2245
 
2246
 
2247
/********************************************************************************************************************************************/
2248
/*      Function:               findnext_(Find_t *);                                                                                                                                                                                                                    */
2249
/*                                                                                                                                                                                                                                                                                      */
2250
/*      Description:    This function looks for the next item in the specified directory with a matching filename and fileattributes specified  */
2251
/*                  by function findfirst()                                                                                                                                                                                                     */
2252
/*                                                                                                                                                                                                                                                                                      */
2253
/*      Returnvalue:                                                                                                                                                                                                                                                    */
2254
/********************************************************************************************************************************************/
2255
u8 findnext_(Find_t * findelement)
2256
{
2257
        u8 itemfound = 0;
2258
        u8 index = 0;
2259
 
2260
        findelement->fp.DirectoryIndex++;
2261
 
2262
        /* before we start searching an element we clear the complete namestring within the structure FindElement */
2263
        for(index=0;index<11;index++) findelement->name[index] = 0;
2264
 
2265
        if(FindItem(findelement))
2266
        {
2267
                itemfound = 1;         
2268
        }
2269
 
2270
        return(itemfound);
2271
}
2272
 
2273
 
2274
 
2275
/********************************************************************************************************************************************/
2276
/*      Function:               findfirst_(s8* filename, u8 attribmask, Find_t *);                                                                                                                                              */
2277
/*                                                                                                                                                                                                                                                                                      */
2278
/*      Description:    This function looks for the first item in the specified directory with a matching filename and fileattributes                   */
2279
/*                                      The filename of the element found is transformed from 8.3 to a string                                                                                                   */
2280
/*                                                                                                                                                                                                                                                                                      */
2281
/*                                                                                                                                                                                                                                                                                      */
2282
/*      Returnvalue:    (1) if Element was found. (0) if no valid element was found                                                                                                                     */
2283
/********************************************************************************************************************************************/
2284
u8 findfirst_(const s8* name, u8 attribmask, Find_t *findelement)
2285
{
2286
        u8 itemfound = 0;
2287
        u8 index = 0;  
2288
 
2289
        /* initialize the FindElement structure */
2290
        findelement->fp.FirstSectorOfFirstCluster = 0;  // First sector of the first cluster of the file.
2291
        findelement->fp.FirstSectorOfCurrCluster = Partition.CurrentWorkingDirectory;                                   // First sector of the cluster which is edited at the moment.
2292
        findelement->fp.SectorOfCurrCluster = 0;                                                        // The sector within the current cluster.
2293
        findelement->fp.ByteOfCurrSector = 0;                                                   // The byte location within the current sector.
2294
        findelement->fp.Size = 0;                                                                               // The size of the opend file in bytes.
2295
        findelement->fp.Position = 0;                                                                   // Pointer to a character within the file 0 < fileposition < filesize
2296
        findelement->fp.DirectorySector = 0;                                                            // the sectorposition where the directoryentry has been made.
2297
        findelement->fp.DirectoryIndex = 0;                                                             // The index to the directoryentry within the specified sector.
2298
        findelement->attribfilter = 0;
2299
        findelement->attribmask = attribmask;
2300
        findelement->searchstring[0]=0;
2301
 
2302
        /* seperate the name of the element to be found from the filepath and bring it to the 8.3*/
2303
        SeperateDirName(name, findelement->searchstring);
2304
        /* after the name of the element is in 8.3 we process the wildcards (*). After an * all following character are wildcards to */
2305
        for(index=0;index<8;index++)
2306
        {
2307
                /* if we find an wildcard within the name of the searchstring all remaining character after the wildcard shall be wildcards also */
2308
                if(findelement->searchstring[index] == '*')
2309
                {
2310
                        /*  */
2311
                        while(++index <8) findelement->searchstring[index] = '*';
2312
                }
2313
        }
2314
        for(index=8;index<11;index++)
2315
        {                                                                                                                                                                                                                                        
2316
                /* if we find an wildcard within the name of the searchstring all remaining character after the wildcard shall be wildcards also */
2317
                if(findelement->searchstring[index] == '*')
2318
                {
2319
                        /*  */
2320
                        while(++index <11) findelement->searchstring[index] = '*';
2321
                }
2322
        }
2323
 
2324
        /* the value of ...DirectoryIndex will be incremented in findnext_() thererfore it has to be decremented in findfirst_() */
2325
        findelement->fp.DirectoryIndex--;
2326
        /* now lets search for the item within the direcory */
2327
        itemfound = findnext_(findelement);
2328
 
2329
        return(itemfound);
2330
}
2331
 
2332
 
2333
/********************************************************************************************************************************************/
2334
/*      Function:               u8 GetDirCount(s8* filepath);                                                                                                                                                                                   */
2335
/*                                                                                                                                                                                                                                                                                      */
2336
/*      Description:    This function counts the number of subdirectories the dirpath contains                                                                                                  */
2337
/*                                                                                                                                                                                                                                                              */
2338
/*                                                                                                                                                                                                                                                                                      */
2339
/*      Returnvalue:    then number of subdirectories within the specified path                                                                                                                                 */
2340
/********************************************************************************************************************************************/
2341
u8 GetDirCount(u8 *dirpath)
2342
{
2343
   u8 i=0;
2344
   u8 cnt=0;
2345
 
2346
   while(dirpath[i] != 0 )
2347
   {
2348
      if(dirpath[i]=='/')
2349
      {  
2350
         if(dirpath[i+1]!=0) cnt++;                                            // ignore last'/'
2351
      }
2352
      i++;  
2353
   }
2354
   i=0;  
2355
   return(cnt);
2356
}
2357
 
2358
 
2359
/********************************************************************************************************************************************/
2360
/* Funtion:     char *GetSubDirectory (char *dirpath, char *directory)                                                                                                                                          */
2361
/*                                                                                                                                                                                                                                                                                      */
2362
/* Description: this function returns a pointer to the beginning of the next subdirectory or NULL                                                                                       */
2363
/*                                                                                                                                                                                                                                                                                      */
2364
/*                                                                                                                                                                                                                                                                                      */
2365
/* returnvalue:   number of subdirectories in the filepath                                                                                                                                                                      */
2366
/********************************************************************************************************************************************/
2367
u8 * GetSubDirectory(u8 *dirpath, u8 *directory)
2368
{
2369
   u8 *cptr = dirpath;
2370
   u8 *dptr = directory;
2371
   u8 *retvalue = NULL;
2372
 
2373
   /* if the first character of the path is an '/' we go to the next character */
2374
   if(*cptr == '/') cptr++;
2375
   /* search end of path or subdirectory*/
2376
   while((*cptr != 0) && (*cptr != '/'))
2377
   {
2378
      *dptr = *cptr;
2379
       dptr++;
2380
       cptr++;
2381
   }  
2382
   if(*cptr!=0) retvalue = ++cptr;
2383
   *dptr = 0;
2384
 
2385
   return(retvalue);
2386
}
2387
 
2388
/********************************************************************************************************************************************/
2389
/*      Function:               s8 *GetPath(void);                                                                                                                                                                                                              */
2390
/*                                                                                                                                                                                                                                                                                      */
2391
/*      Description:    This function function returns a pointer to the absolute path of the active partition                                                                   */
2392
/*                                                                                                                                                                                                                                      */
2393
/*                                                                                                                                                                                                                                                                                      */
2394
/*      Returnvalue:                                                                                                                                                                                                                                                    */
2395
/********************************************************************************************************************************************/
2396
 
2397
s8 *GetPath(void)
2398
{
2399
        return(Partition.PathToCwd);
2400
}
2401
 
2402
/********************************************************************************************************************************************/
2403
/*      Function:               void SetPathToRoot(void);                                                                                                                                                                                                       */
2404
/*                                                                                                                                                                                                                                                                                      */
2405
/*      Description:    This function sets the path to the rootdirectory                                                                                                                                                */
2406
/*                                                                                                                                                                                                                                      */
2407
/*                                                                                                                                                                                                                                                                                      */
2408
/*      Returnvalue:                                                                                                                                                                                                                                                    */
2409
/********************************************************************************************************************************************/
2410
 
2411
void SetPathToRoot(void)
2412
{
2413
        /* lets point to the rootdirectory */
2414
        strcpy(Partition.PathToCwd, "/");      
2415
}
2416
 
2417
/********************************************************************************************************************************************/
2418
/*      Function:               void AppendDirToPath(s8* directory);                                                                                                                                                                                    */
2419
/*                                                                                                                                                                                                                                                                                      */
2420
/*      Description:    This function function appends the name of an directory to the Path to the CWD                                                                                  */
2421
/*                                                                                                                                                                                                                                      */
2422
/*                                                                                                                                                                                                                                                                                      */
2423
/*      Returnvalue:                                                                                                                                                                                                                                                    */
2424
/********************************************************************************************************************************************/
2425
 
2426
void AppendDirToPath(s8* directory)
2427
{
2428
        /* append the name of the directory to the path */
2429
        strcat(Partition.PathToCwd, directory);
2430
        /* append a '/' after the directoryname */
2431
        strcat(Partition.PathToCwd, "/");
2432
}
2433
 
2434
/********************************************************************************************************************************************/
2435
/*      Function:               RemoveLastDirFromPath(void);                                                                                                                                                                                    */
2436
/*                                                                                                                                                                                                                                                                                      */
2437
/*      Description:    This function removes the last directory from the path to the cwd                                                                                                               */
2438
/*                                                                                                                                                                                                                                      */
2439
/*                                                                                                                                                                                                                                                                                      */
2440
/*      Returnvalue:                                                                                                                                                                                                                                                    */
2441
/********************************************************************************************************************************************/
2442
 
2443
void RemoveLastDirFromPath(void)
2444
{
2445
        /* a pointer to the beginning of the absolute path to the cwd */
2446
        s8 * cptr = Partition.PathToCwd;
2447
        /* lets find the end of the path to the cwd */
2448
        while(*cptr != 0 ) cptr++;
2449
        /* if the path is terminated with an '/' */
2450
        if((*(cptr-1)) == '/') *(cptr-1)=0;    
2451
        /* now lets find the beginning of the last directorientry */
2452
        while((*cptr != '/' ) && cptr > Partition.PathToCwd) cptr--;
2453
        /* is there one subdirectory left within the path? */
2454
        if(cptr > Partition.PathToCwd)
2455
        {
2456
                /* we delete the direntry by terminating the path with 0 */
2457
                *cptr = 0;
2458
        }
2459
        /* there is no subdirectory left within the path. Therefore we create the root instead. */
2460
        else
2461
        {
2462
                *cptr = '/';
2463
                *(cptr+1) = 0;
2464
        }
2465
}
2466
 
2467
/********************************************************************************************************************************************/
2468
/*      Function:               chdir_(s8* filepath);                                                                                                                                                                                                   */
2469
/*                                                                                                                                                                                                                                                                                      */
2470
/*      Description:    This function changed the current working directory to the directory specified by the filepath                                                  */
2471
/*                  by function findfirst()                                                                                                                                                                                                     */
2472
/*                                                                                                                                                                                                                                                                                      */
2473
/*      Returnvalue:                                                                                                                                                                                                                                                    */
2474
/********************************************************************************************************************************************/
2475
/*                                                                         
2476
#define ATTR_NONE               0x00    // normal file
2477
#define ATTR_READONLY           0x01    // file is readonly
2478
#define ATTR_HIDDEN                     0x02    // file is hidden
2479
#define ATTR_SYSTEM                     0x04    // file is a system file
2480
#define ATTR_VOLUMELABEL        0x08    // entry is a volume label
2481
#define ATTR_LONG_FILENAME      0x0F    // this is a long filename entry
2482
#define ATTR_SUBDIRECTORY       0x10    // entry is a directory name
2483
#define ATTR_ARCHIVE            0x20    // file is new or modified
2484
*/
2485
 
2486
u8 chdir_(s8 *path)
2487
{
2488
        u8              retvalue = 0;                                   // the value returned by this function
2489
        u32     ultemp = 0;                                             // temp. variable
2490
        u8     *directory = path;                               // pointer to a directoryname within the path
2491
        u8      dircount = 0;                                   // the number of subdirectoryentries within the path
2492
        u8      cache[64];                                              // a buffer containing the name of the subdirectory we are actually looking for
2493
        Find_t  fe;                                                             // The findelement needed for function findfirst to find the subdirectoryentry
2494
        s8              tp[256];                                                // temporarily we remember the actual path until the operation has finished successfully
2495
        u32     cwdt = 0;
2496
        s8     *cptr;
2497
 
2498
        /* bring the path into the correct syntax */
2499
        cptr = path;
2500
        /* search the whole string */
2501
        while(*cptr != 0 )
2502
        {
2503
                if(*cptr == '\\') *cptr = '/';
2504
                cptr++;
2505
        }
2506
        /* lets remember the actual path */
2507
        strcpy(tp, Partition.PathToCwd);
2508
        cwdt = Partition.CurrentWorkingDirectory;
2509
        /* how many subdirectories are there within the path? */
2510
        dircount = GetDirCount(path);  
2511
        /* if the path is absolute we begin at the rootdirectory */
2512
        if(path[0] == '/')
2513
        {
2514
                strcpy(Partition.PathToCwd, "/");
2515
                Partition.CurrentWorkingDirectory = Partition.FirstRootDirSector;
2516
                /* if there is no other pathinformation we only switch to the rootdirectory. So theres nothing left todo.*/
2517
                if(!dircount) return(1);
2518
        }
2519
        /* now we parse through all the subdirectories within the path */
2520
        do
2521
        {  
2522
                /* until all the subdirectories within the path have been processed */
2523
        if(dircount) dircount--;
2524
                /* this is the name of the next subdirectory we are looking for */             
2525
            directory = GetSubDirectory(directory, cache);  
2526
                /* search for the next subdirectory within the path */
2527
                if(findfirst_(cache, ATTR_SUBDIRECTORY, &fe))
2528
                {
2529
                        /* we try to change into the directory "..". Now we have to delete the last direntry from the path */
2530
                        if(strcmp(cache,"..") == 0) RemoveLastDirFromPath();
2531
                        /* we try to change into the actual directory so there's nothing todo */
2532
                        else if(cache[0] == '.') return(1);
2533
                        /* otherwise we append the name of the directory we are changing in to the path */
2534
                        else AppendDirToPath(cache);
2535
                        /* The startcluster within an directoryentry specifies the position within the fat where the file or directory starts */
2536
                        ultemp = (u32) fe.fp.FirstSectorOfFirstCluster;
2537
                        /* the first 2 entries are reserved for '.' and '..' */
2538
                        ultemp -= 2;
2539
                        /* 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*/
2540
                        ultemp *= Partition.SectorsPerCluster;
2541
                        /* at least we make the sectoraddress absolute by adding the relative address to the beginning of the datasection of the active partition */
2542
                        ultemp += Partition.FirstDataSector;
2543
                        /* the cwd now points to the specified directory */
2544
                        Partition.CurrentWorkingDirectory = ultemp;
2545
                        /* we found the folder specified by the foldername */
2546
                        retvalue = 1;
2547
                }
2548
        }
2549
        /* do this until all subdirectories have been found or a subdirectory is missing */
2550
        while(dircount && retvalue );
2551
 
2552
        /* if we could not change to the specified directory we restore the actual path */
2553
        if(!retvalue)
2554
        {
2555
                Partition.CurrentWorkingDirectory = cwdt;                                                  
2556
                strcpy(Partition.PathToCwd, tp);
2557
        }
2558
        return(retvalue);      
2559
}