Subversion Repositories NaviCtrl

Rev

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