Subversion Repositories NaviCtrl

Rev

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