Subversion Repositories NaviCtrl

Rev

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