ATmega8GPSLoggerBasismodul  20131018
fat16.c
Go to the documentation of this file.
1 #include <stdio.h>
2 #include <avr/io.h>
3 #include "mmc.h"
4 #include "fat16.h"
5 
6 
7 //________________________________________________________________________________________________________________________________________
8 // Module name: fat16.c
9 // Compiler used: avr-gcc 3.4.5
10 // Last Modifikation: 24.07.2007
11 // Version: 1.23
12 // Authors: Stephan Busker
13 // Description: Source files for FAT16 implementation with read and write-access using AVR-Mikrocontrollers
14 // Copyright (C) 2007 Stephan Busker
15 //........................................................................................................................................
16 // Functions: extern unsigned char InitFat16(void);
17 // unsigned char fopen_(unsigned char *fname,char mode, File *file);
18 // void fclose_(File *file);
19 // unsigned long fread_(void *buffer, unsigned long size, unsigned long count, File *file);
20 // unsigned long fwrite_(void *buffer, unsigned long size, unsigned long count, File *file);
21 // int fseek_(File *file, long offset, int origin);
22 // char fgetchar_(File *file);
23 // unsigned char fputchar_(File *file,char c);
24 // unsigned char fputs_(File *file,char *string);
25 // char * fgets(char *, int, File);
26 // unsigned char fexist_(unsigned char*, unsigned char *, File *file);
27 //........................................................................................................................................
28 // ext. functions: extern unsigned char SDC_GetSector (unsigned long,unsigned char *);
29 // extern unsigned char SDC_PutSector (unsigned long,unsigned char *);
30 //........................................................................................................................................
31 //
32 // URL: www.Mikro-Control.de
33 // mailto: stephan.busker@mikro-control.de
34 //________________________________________________________________________________________________________________________________________
35 
36 
37 
38 
39 //________________________________________________________________________________________________________________________________________
40 //
41 // Global variables needed for read- or write-acces to the FAT16- filesystem.
42 //
43 //________________________________________________________________________________________________________________________________________
44 
45 unsigned char SectorsPerCluster = 0; // how many sectors does a cluster contain?
46 unsigned char FatCopies = 0; // Numbers of copies of the FAT
47 unsigned int PossibleRootEntries = 0; // Possible number of entries in the root directory.
48 unsigned int SectorsPerFat = 0; // how many sectors does a fat16 contain?
49 unsigned long ReservedSectors = 0; // Sectors reserved by the filesystem.
50 unsigned long FirstPartitionSector = 0; // Distance in sectors between the first partition and the master bootrecord.
51 unsigned long FileAllocationTable = 0; // pointer to the first FAT
52 unsigned long RootDirectory = 0; // Pointer to the rootdirectory of the first partition.
53 unsigned long FirstDataCluster = 0; // Pointer to the first cluster containing data (cluster0).
54 
55 unsigned char FileBuffer[512]; // Buffer for read and write operation from or to the mmc.
56 struct DirEntry *DirectoryEntry; // Pointer to an entry of the directory.
57 struct FatEntry *Fat; // Pointer to an entry of the fat (next clusterposition).
58 
59 
60 
61 
62 //________________________________________________________________________________________________________________________________________
63 // Funtion: InitFat16(void);
64 //
65 // Description: This function reads the Masterbootrecord and finds the position of the Volumebootrecord, the FAT and the Rootdirectory
66 // and stores the information in global variables.
67 //
68 // Returnvalue: The function returns "0" if the filesystem could not be initialized because no partition was found on the disc.
69 //________________________________________________________________________________________________________________________________________
70 
71 unsigned char InitFat16(void)
72 {
73  SDC_GetSector((unsigned long)MBR_SECTOR,&FileBuffer[0]); // Read the master bootrecord from mmc.
74  FirstPartitionSector= *((unsigned long*)&FileBuffer[0x1C6]); // Position of the first datacluster.
75  SDC_GetSector((unsigned long)FirstPartitionSector,&FileBuffer[0]); // Read the volume bootrecord from mmc.
76  SectorsPerCluster = FileBuffer[0x0D]; // Number of sectors per cluster. Depends on the memorysize of the sd-card.
77  FatCopies = FileBuffer[0x10]; // Number of fatcopies.
78  PossibleRootEntries = *((unsigned int*) &FileBuffer[0x11]); // How many Entries are possible in the rootdirectory (FAT16 allows max. 512 entries).
79  SectorsPerFat = *((unsigned int*) &FileBuffer[0x16]);
80  ReservedSectors = *((unsigned int*)&FileBuffer[0x0E]); // calculate the sectorpositon of the FAT, the Rootdirectory and the first Datacluster.
81  FileAllocationTable = (unsigned long)((unsigned long)FirstPartitionSector + (unsigned long)ReservedSectors);
82  RootDirectory = (unsigned long)((unsigned long)FileAllocationTable + (unsigned long)((unsigned long)SectorsPerFat*(unsigned long)FatCopies));
83  FirstDataCluster = (unsigned long)((unsigned long)RootDirectory + ((unsigned long)(PossibleRootEntries>>4)));
84  return(0);
85 }
86 
87 //________________________________________________________________________________________________________________________________________
88 // Funtion: unsigned char fopen_(unsigned char*, unsigned char *, File *file);
89 //
90 // Description: This function looks for the specified file in the rootdirectory of the drive. If the file is found the number of the
91 // corrosponding datacluster is returned to main. Only modes 'r' (reading) and 'a' append are implemented yet.
92 //
93 // Return: 0 = faild to open speicified file
94 // 1 = file opened
95 //________________________________________________________________________________________________________________________________________
96 
97 unsigned char fopen_(unsigned char *fname, char mode, File *file)
98 {
99  unsigned long cluster_temp = 0;
100  unsigned char name[11] = " ";
101  unsigned int temp = 0;
102 
103  if(file == 0) return(0); // no valid pointer
104 
105  file->start_cluster = 0; // Sectorpointer to the first sector of the first datacluster of the file.
106  file->cluster_pointer = 0; // Pointer to the cluster which is edited at the moment.
107  file->sector_index = 0; // The sector which is edited at the moment (cluster_pointer + sector_index).
108  file->byte_index = 0; // The bytelocation within the current sector (cluster_pointer + sector_index + byte_index).
109  file->mode = mode; // mode of fileoperation (read,write)
110  file->filesize = 0; // the size of the opend file in bytes.
111  file->fileposition = 0; // pointer to a character within the file 0 < fileposition < filesize
112  file->sector_in_buffer = 0; // the last sector read, wich is still in the sectorbuffer.
113  file->directory_sector = 0; // the sectorposition where the directoryentry has been made.
114  file->directory_index = 0; // the index to the directoryentry within the specified sector.
115  file->attribute = 0; // the attribute of the file opened.
116 
117  if(ScanSubDirectories(&fname[0], file)) // Is the specified filepath available?
118  {
119  SeperateFileName(&fname[0], &name[0]); // seperate the filename and attribute from the filepath and bring them in the correct format.
120  file->attribute = _FILE;
121  if(SeekDirectoryEntry(&name[0], file)) // if file was found
122  {
123  if(mode == 'a') // open existing file for writing (append data at the end of the file)
124  {
125  fseek_(file, 0, SEEK_END); // fseek points to the end of the file
126  }
127  return(1);
128  }
129  else
130  {
131  if((mode == 'a') || (mode == 'w')) // specified file doesn't exist so create new file for writing data.
132  {
133  cluster_temp = (unsigned long)FindNextFreeCluster(file); // the next free cluster on the disk.
134  if(cluster_temp) // if a free cluster is available:
135  {
136  temp = (unsigned int)cluster_temp; // remember the index of the free datacluster found for the directory entry.
137  cluster_temp -=2; // Clusterposition is ((position in FAT)-2). first two entries in FAT are reserved.
138  cluster_temp *= SectorsPerCluster; // Calculate relative sectorindex of first datacluster.
139  file->start_cluster = (FirstDataCluster + cluster_temp); // Calculate absolute sectorposition of first datacluster.
140  file->cluster_pointer = file->start_cluster; // start reading the file with the first sector of the first datacluster.
141  if(CreateDirectoryEntry(&name[0],temp,file,_FILE)) // Could an entry for the new file in the rootdirectory be created?
142  {
143  return(1);
144  }
145  }
146  }
147  }
148  }
149  return(0);
150 }
151 
152 //________________________________________________________________________________________________________________________________________
153 // Funtion: fflush_(File *file);
154 //
155 // Description: This function writes the data already in the buffer but not yet written to the file.
156 //
157 //________________________________________________________________________________________________________________________________________
158 
159 int fflush_(File *file)
160 {
161  unsigned int time=0;
162  unsigned int date=0;
163 
164 #ifdef __USE_TIME_DATE_ATTRIBUTE // has the date and time attribute of the file to be set?
165 
166  time = (((rtctime.hour)<<11) | ((rtctime.minute)<<5) | rtctime.second);
167  date = ((((rtctime.year)-1980) <<9) | ((rtctime.month) <<5) | rtctime.day);
168 
169 #endif
170 
171 
172  if(file && file->mode =='a')
173  {
174  if(file->byte_index > 0) // has data been added to the file?
175  {
176  SDC_PutSector((unsigned long)(file->cluster_pointer + file->sector_index),&FileBuffer[0]); // save the data still in the buffer
177  }
178  SDC_GetSector((unsigned long)file->directory_sector,&FileBuffer[0]); // read the directoryentry for this file.
179  DirectoryEntry = (struct DirEntry *)&FileBuffer[0];
180  DirectoryEntry[file->directory_index].size = (unsigned long) file->filesize;
181  DirectoryEntry[file->directory_index].time = (unsigned int) time;
182  DirectoryEntry[file->directory_index].date = (unsigned int) date;
183  SDC_PutSector((unsigned long)file->directory_sector,&FileBuffer[0]);
184  }
185  return(0);
186 }
187 
188 //________________________________________________________________________________________________________________________________________
189 // Funtion: fclose_(File *file);
190 //
191 // Description: This function closes the open file by writing the remaining data from the buffer to the device and entering the filesize
192 // in the directory entry.
193 //________________________________________________________________________________________________________________________________________
194 
195 void fclose_(File *file)
196 {
197  fflush_(file);
198 
199  file->start_cluster = 0; // Sectorpointer to the first sector of the first datacluster of the file.
200  file->cluster_pointer = 0; // Pointer to the cluster which is edited at the moment.
201  file->sector_index = 0; // The sector which is edited at the moment (cluster_pointer + sector_index).
202  file->byte_index = 0; // The bytelocation within the current sector (cluster_pointer + sector_index + byte_index).
203  file->mode = 0; // mode of fileoperation (read,write)
204  file->filesize = 0; // the size of the opend file in bytes.
205  file->fileposition = 0; // pointer to a character within the file 0 < fileposition < filesize
206  file->sector_in_buffer = 0; // the last sector read, wich is still in the sectorbuffer.
207  file->directory_sector = 0; // the sectorposition where the directoryentry has been made.
208  file->directory_index = 0; // the index to the directoryentry within the specified sector.
209  file->attribute = 0; // the attribute of the file opened.
210 }
211 
212 //________________________________________________________________________________________________________________________________________
213 // Funtion: long fread_(void *buffer, long size, long count, File *file);
214 //
215 // Description: This function reads count objects of the specified size from the actual position of the file to the specified buffer.
216 //
217 // Returnvalue: The function returns the number of objects (not bytes) read from the file.
218 //
219 //________________________________________________________________________________________________________________________________________
220 
221 unsigned long fread_(void *buffer, unsigned long size, unsigned long count, File *file)
222 {
223  unsigned long object_cnt = 0; // count the number of objects read from the file.
224  unsigned long object_size = 0; // count the number of bytes read from the actual object.
225  unsigned char *buff_pnt = 0; // a pointer to the actual bufferposition.
226  unsigned char success = 1; // no error occured during read operation to the file.
227 
228  buff_pnt = (unsigned char *) buffer; // cast the void pointer to an unsigned char *
229 
230  while((object_cnt < count) && success)
231  {
232  object_size = size;
233  while((size > 0) && success)
234  {
235  *buff_pnt = (unsigned char) fgetchar_(file); // read a byte from the buffer to the opened file.
236  buff_pnt++;
237  size--;
238  }
239  if(success) object_cnt++;
240  }
241 
242  return(object_cnt); // return the number of objects succesfully read from the file
243 }
244 
245 //________________________________________________________________________________________________________________________________________
246 // Funtion: long fwrite_(void *buffer, long size, long count, File *file);
247 //
248 // Description: This function writes count objects of the specified size from the buffer to the actual positon within the file.
249 //
250 // Returnvalue: The function returns the number of objects (not bytes) written to the file.
251 //
252 //________________________________________________________________________________________________________________________________________
253 
254 unsigned long fwrite_(void *buffer, unsigned long size, unsigned long count, File *file)
255 {
256  unsigned long object_cnt = 0; // count the number of objects written to the file.
257  unsigned long object_size = 0; // count the number of bytes written from the actual object.
258  unsigned char *buff_pnt = 0; // a pointer to the actual bufferposition.
259  unsigned char success = 1; // no error occured during write operation to the file.
260 
261  buff_pnt = (unsigned char *) buffer; // cast the void pointer to an unsigned char *
262 
263  while((object_cnt < count) && success)
264  {
265  object_size = size;
266  while((size > 0) && success)
267  {
268  success = fputchar_(file, *buff_pnt); // write a byte from the buffer to the opened file.
269  buff_pnt++;
270  size--;
271  }
272  if(success) object_cnt++;
273  }
274 
275  return(object_cnt); // return the number of objects succesfully written to the file
276 } // (!!!!! objects and not bytes !!!!)
277 
278 //________________________________________________________________________________________________________________________________________
279 // Funtion: int fseek_(File *, long, int)
280 //
281 // Description: This function sets the pointer of the stream relative to the position
282 // specified by origin (SEEK_SET, SEEK_CUR, SEEK_END).
283 //
284 //________________________________________________________________________________________________________________________________________
285 
286 int fseek_(File *file, long offset, int origin)
287 {
288  long fposition = 0;
289  int retvalue = 1;
290  unsigned long temp = 0;
291 
292 //......................................................
293  if(origin == SEEK_SET) // Fileposition relative to the beginning of the file.
294  {
295  fposition = 0;
296  }
297 //......................................................
298  else if(origin == SEEK_END) // Fileposition relative to the end of the file.
299  {
300  fposition = (long) file->filesize;
301  }
302 //......................................................
303  else if(origin == SEEK_CUR) // Fileposition relative to the current position of the file.
304  {
305  fposition = file->fileposition;
306  }
307 
308  fposition += offset;
309 
310  if((fposition >= 0) && (fposition <= (long)file->filesize)) // is the pointer still within the file?
311  {
312  retvalue = 0;
313  file->sector_index = 0;
314  file->byte_index = 0;
315  file->fileposition = 0;
316  file->cluster_pointer = file->start_cluster;
317 
318  while(file->fileposition < fposition)
319  {
320  file->fileposition++;
321  if(file->byte_index < 511)
322  {
323  file->byte_index++;
324  }
325  else
326  {
327  file->byte_index=0; // reading at the beginning of new sector.
328  file->sector_index++; // continue reading in next sector
329  if(file->sector_index >= SectorsPerCluster) // When end of cluster is reached, the next datacluster has to be searched in the FAT.
330  {
331  if(file->fileposition < fposition)
332  {
333  file->sector_index = 0; // start reading new cluster at first sector of the cluster.
334  GetNextCluster(file); // Sets the clusterpointer of the file to the next datacluster.
335  }
336  }
337  }
338  }
339  if(file->byte_index)
340  {
341  temp = (unsigned long)((unsigned long)file->cluster_pointer + (unsigned long)file->sector_index);
342  SDC_GetSector((unsigned long)temp,&FileBuffer[0]); // FileBuffer will be written at once at the end of the cluster and has to be updated.
343  }
344  }
345  return(retvalue);
346 }
347 
348 //________________________________________________________________________________________________________________________________________
349 // Funtion: fgetchar_(File *file);
350 //
351 // Description: This function reads and returns one character from the specified file. Is the end of the actual sector reached the
352 // next sector of the cluster is read. Is the last sector of the cluster read the next cluster will be searched in FAT.
353 // Returnvalue: The function returns the character read from the specified memorylocation as unsigned char casted to int or EOF.
354 //________________________________________________________________________________________________________________________________________
355 
356 int fgetchar_(File *file)
357 {
358  int c = EOF;
359  unsigned long temp1;
360 
361  if(file->filesize > 0) // wen the end of the file is not reached, get the next character.
362  {
363  temp1 = (unsigned long)file->cluster_pointer; // calculate the adress of the next character to be read.
364  temp1 += (unsigned long)file->sector_index;
365 
366  if(file->sector_in_buffer != temp1) // Has the content of the buffer been modified and has to be updated?
367  {
368  SDC_GetSector((unsigned long)temp1,FileBuffer); // Read the calculated cluster.
369  file->sector_in_buffer = (unsigned long)temp1;
370  }
371  c = (int) FileBuffer[file->byte_index];
372  file->filesize--; // decrement the number of characters available.
373 
374  if(file->byte_index < 511) // continue reading from this sector until the end of the sector is reached.
375  {
376  file->byte_index++;
377  }
378  else // has the end of an sector been reached->
379  {
380  file->byte_index=0; // continue reading at the beginning -
381  file->sector_index++; // of new sector.
382  if(file->sector_index >= SectorsPerCluster) // When the end of an cluster is reached, the next datacluster has to be searched in the FAT.
383  {
384  file->sector_index = 0; // start reading new cluster at first sector of the cluster.
385  GetNextCluster(file); // Sets the clusterpointer of the file to the next datacluster.
386  }
387  }
388  }
389  return(c);
390 }
391 
392 //________________________________________________________________________________________________________________________________________
393 // Funtion: fputchar_(File *file);
394 //
395 // Description: This function writes a byte to the specified file and takes care of writing the necessary FAT- Entries.
396 //
397 // Returnvalue: The function returns a value of 0 if the data could not be written.
398 //________________________________________________________________________________________________________________________________________
399 
400 unsigned char fputchar_(File *file,char c)
401 {
402  unsigned long ul_temp = 0;
403  unsigned char retvalue = 1;
404 
405  if(file->sector_index >= SectorsPerCluster) // if end of the cluster is reached, find next free cluster
406  {
407  file->sector_index = 0;
408  if(!AppendCluster(file)) retvalue = 0; // append a new and free cluster at the end of the file.
409  }
410 
411  FileBuffer[file->byte_index] = c; // write databyte into the buffer. The byte will be written to the device at once
412  if(file->filesize == file->fileposition) file->filesize++; // a character has been written to the file so the size is inkremented but only when the character has been added at the end of the file.
413  file->fileposition++; // the actual positon within the file.
414  // if the buffer contains the complete sectordata.
415  if(file->byte_index < 511) // if the end of this sector is not reached yet
416  {
417  file->byte_index++; // the next byte will be written to the next byteposition in this sector.
418  }
419  else // otherwise the data in the sectorbuffer will be written to the device and the next sector will be selected.
420  {
421  ul_temp = (unsigned long)file->cluster_pointer;
422  ul_temp += (unsigned long)file->sector_index;
423 
424  SDC_PutSector((unsigned long)ul_temp,&FileBuffer[0]);
425  file->byte_index=0; // and the next byte will be written at the beginning of this new sector.
426  file->sector_index++;
427  if(file->sector_index >= SectorsPerCluster) // if end of the cluster is reached, find next free cluster
428  {
429  file->sector_index = 0;
430  if(!AppendCluster(file)) retvalue = 0; // append a new and free cluster at the end of the file.
431  }
432  }
433  return(retvalue);
434 }
435 
436 //________________________________________________________________________________________________________________________________________
437 // Funtion: fputs_(File *file);
438 //
439 // Description: This function writes a string to the specified file.
440 //
441 //________________________________________________________________________________________________________________________________________
442 
443 unsigned char fputs_(File *file,char *string)
444 {
445  unsigned char i=0;
446 
447  while(string[i] != 0)
448  {
449  fputchar_(file,string[i]);
450  i++;
451  }
452  return(0);
453 }
454 
455 //________________________________________________________________________________________________________________________________________
456 // Funtion: fgets_(File *file);
457 //
458 // Description: This function reads a string from the file to the specifies string.
459 //
460 // Returnvalue: A pointer to the string written from the file.
461 //________________________________________________________________________________________________________________________________________
462 
463 char * fgets_(char *string, int count, File *file)
464 {
465  int buff_pnt = 0;
466  int buff_tmp = 0;
467  unsigned char state = 0; // Variable used for a statemachine to recognize the end of a line.
468 
469  while(count > 1) // read the count-1 characters from the file to the string.
470  {
471  buff_tmp = fgetchar_(file); // read a character from the opened file.
472  switch(state)
473  {
474  case 0:
475  if(buff_tmp == 0x0D) state++;
476  break;
477 
478  case 1:
479  if(buff_tmp == 0x0A)
480  {
481  count = 1;
482  }
483  state = 0;
484  break;
485  }
486  if(buff_tmp == EOF) {buff_tmp = 0; count = 1;} // is the end of the file reached, terminate the string with zero.
487  string[buff_pnt] = (char) buff_tmp;
488  count--;
489  buff_pnt++;
490  }
491  string[buff_pnt] = 0;
492  return(string);
493 }
494 
495 //________________________________________________________________________________________________________________________________________
496 // Funtion: unsigned char fexist_(unsigned char*, unsigned char *, File *file);
497 //
498 // Description: This function searches the specified file and returns 0 if the file was not found.
499 //
500 //
501 // Return: 0 = file does not exist
502 // 1 = file exists
503 //________________________________________________________________________________________________________________________________________
504 
505 unsigned char fexist_(unsigned char *fname, File *file)
506 {
507  if(fopen_(fname,'r', file))
508  {
509  fclose_(file);
510  return(1);
511  }
512  else
513  {
514  return(0);
515  }
516 }
517 
518 //________________________________________________________________________________________________________________________________________
519 // Funtion: GetNextCluster(File *file);
520 //
521 // Description: This function finds the next datacluster of the file specified with File *file.
522 //
523 // Returnvalue: The function returns "0" if the last cluster has already been reached.
524 //________________________________________________________________________________________________________________________________________
525 
526 unsigned int GetNextCluster(File *file)
527 {
528  unsigned long fat_pointer = 0;
529  unsigned long fat_sector_offset = 0;
530  unsigned long ul_tmp = 0;
531  unsigned char retvalue = 0; // no new cluster found yet.
532 
533 
534  if((file->cluster_pointer >= RootDirectory) && (file->cluster_pointer < (RootDirectory + 31)))
535  { // Is the next cluster searched within the rootdirectory and available?
536  file->cluster_pointer++; // the rootdirectory is a linear adress space of 32 clusters.
537  retvalue = 1; // and the next cluster has been found.
538  }
539  else if(file->cluster_pointer > (RootDirectory + 31)) // The specified cluster is within the FAT.
540  {
541  fat_sector_offset = ((file->cluster_pointer) - (FirstDataCluster)); // Calculate index of actual cluster within the FAT.
542  fat_sector_offset /= SectorsPerCluster; // calculate the index of the actual sector within the FAT.
543  fat_sector_offset += 2; // In Fat16 clusterpositions have an offset of two.
544  fat_pointer = (fat_sector_offset%0x100); // Calculate the sector within the cluster.
545  fat_sector_offset = (fat_sector_offset>>8); // and the position within the sector.
546 
547  SDC_GetSector((unsigned long)(FileAllocationTable + fat_sector_offset),&FileBuffer[0]);
548  file->sector_in_buffer = (FileAllocationTable + fat_sector_offset); // Mark that new sector has been read.
549 
550  ul_tmp = (unsigned long)FileBuffer[((fat_pointer << 1)+1)]; // Read next sector information from calculated clusterposition.
551  ul_tmp = (ul_tmp << 8);
552  ul_tmp |= (unsigned long)FileBuffer[(fat_pointer << 1)];
553  ul_tmp -=2; // next datacluster is clusterposition in fat - 2.
554  ul_tmp *= SectorsPerCluster; // calculate sectorposition of new cluster
555  ul_tmp += FirstDataCluster; // in relation to first datacluster of the disk.
556 
557  if(ul_tmp < 0xfff7) // has a new cluster been read or was the end of the fat reached?
558  {
559  file->cluster_pointer = (unsigned long) ul_tmp; // continue reading the file at the beginning of new datacluster.
560  retvalue = 1; // a new cluster was found.
561  }
562  }
563  return(retvalue);
564 }
565 
566 //________________________________________________________________________________________________________________________________________
567 // Funtion: unsigned int FindNextFreeCluster(void)
568 //
569 // Description: This function looks in the FAT to find the next free datacluster
570 //
571 // Returnvalue: The function returns the adress of the next free cluster found within the fAT.
572 //________________________________________________________________________________________________________________________________________
573 
574 unsigned int FindNextFreeCluster(File *file)
575 {
576  unsigned long fat_pointer = 0; // Pointer to the first sector of the FAT.
577  unsigned long ul_tmp = 0; // temporary variable used to calculate a sectornumber.
578  unsigned int fat_sector_offset = 0; // index to a sector within the FAT.
579  unsigned int fat_entry = 0; // index to an fatentry within the actual sector (256 fatentries are possible within one sector).
580  unsigned int free_cluster = 0; // a pointer to the first sector of the next free cluster.
581 
582  fat_pointer = (unsigned long) FileAllocationTable; // start searching for empty cluster at the beginning of the fat.
583  // if the end of the fat is not reached yet and no free cluster has been found
584  while((fat_sector_offset < SectorsPerFat) && (!free_cluster))
585  {
586  ul_tmp = (unsigned long) ((unsigned long)fat_pointer + (unsigned long)fat_sector_offset);
587  SDC_GetSector((unsigned long)ul_tmp,&FileBuffer[0]); // read next sector of FAT.
588  file->sector_in_buffer = ul_tmp; // remember the number of the sector in FileBuffer.
589  Fat = (struct FatEntry *)&FileBuffer[0];
590  for(fat_entry=0;fat_entry<256;fat_entry++) // look for an free cluster at all entries in this sector of the fat.
591  {
592  if(Fat[fat_entry].next_cluster == 0x0000) // empty cluster found!!
593  {
594  Fat[fat_entry].next_cluster = 0xffff; // mark this fat-entry as used and save it to the device.
595  SDC_PutSector((unsigned long)file->sector_in_buffer,&FileBuffer[0]);
596  free_cluster = fat_entry; // the relative position of the free cluster found in this sector of the FAT.
597  free_cluster += (fat_sector_offset << 8); // calculate the absolute position of the free cluster in the FAT;
598  fat_entry = 256; // terminate the search for a free cluster in this sector.
599  }
600  }
601  fat_sector_offset++;
602  }
603 return(free_cluster);
604 }
605 
606 //________________________________________________________________________________________________________________________________________
607 // Funtion: unsigned int AppendCluster(File *file);
608 //
609 // Description: This function finds the next free datacluster on the disk and appends it to the specified file.
610 //
611 // Returnvalue: This funktion returns 1 if a cluster was appended to the specified file.
612 //________________________________________________________________________________________________________________________________________
613 
614 unsigned char AppendCluster(File *file)
615 {
616  unsigned int free_cluster = 0;
617  unsigned long fat_pointer = 0;
618  unsigned char retvalue = 0;
619 
620  free_cluster = FindNextFreeCluster(file); // the next free cluster found on the disk.
621  if(free_cluster) retvalue = 1; // A free cluster was found and can be added to the end of the file.
622  fat_pointer = FileAllocationTable; // Set Pointer to the beginnig of the FAT.
623  fat_pointer += (unsigned long)((unsigned long)GetFatClusterOffset(file) >> 8); // find the sector in the FAT with 256 entries per sector.
624 
625  SDC_GetSector(fat_pointer,&FileBuffer[0]);
626  Fat = (struct FatEntry *)&FileBuffer[0];
627  Fat[GetFatSectorIndex(file)].next_cluster = free_cluster; // append the free cluster to the end of the file in the FAT.
628  SDC_PutSector((unsigned long)fat_pointer,&FileBuffer[0]); // save the modified sector to the FAT.
629 
630  fat_pointer = (unsigned long)free_cluster;
631  fat_pointer -= 2;
632  fat_pointer *= SectorsPerCluster;
633  fat_pointer += FirstDataCluster;
634 
635  file->cluster_pointer = fat_pointer; // continue wrtiting to the file in the new and free datacluster.
636  return(retvalue); // return 1 when a new cluster was appended to the file
637 }
638 
639 //________________________________________________________________________________________________________________________________________
640 // Funtion: unsigned int GetFatClusterIndex(File *file);
641 //
642 // Description: This function returns the clusterindex of the cluster specified by file->cluster_pointer of the specified file.
643 //
644 //________________________________________________________________________________________________________________________________________
645 
646 unsigned int GetFatClusterOffset(File *file)
647 {
648  unsigned long fat_sector_offset = 0;
649 
650  fat_sector_offset = ((file->cluster_pointer) - (FirstDataCluster)); // Calculate index of actual cluster in FAT.
651  fat_sector_offset /= SectorsPerCluster;
652  fat_sector_offset += 2; // In Fat16 clusterpositions have an offset of two.
653 
654  return((unsigned int)fat_sector_offset);
655 }
656 
657 //________________________________________________________________________________________________________________________________________
658 // Funtion: unsigned int GetFatSectorIndex(File *file);
659 //
660 // Description: This function returns the sectorindex of the cluster specified by file->cluster_pointer of the specified file.
661 //
662 //________________________________________________________________________________________________________________________________________
663 
664 unsigned int GetFatSectorIndex(File *file)
665 {
666  unsigned int fat_pointer = 0;
667 
668  fat_pointer = GetFatClusterOffset(file);
669  fat_pointer = fat_pointer % 0x100; // Calculate the clusterposition in the fat
670 
671  return(fat_pointer);
672 }
673 
674 //________________________________________________________________________________________________________________________________________
675 // Funtion: unsigned int CreateDirectoryEntry(unsigned char *, unsigned int, unsigned char attrib)
676 //
677 // Description: This function looks for the next free position in the directory and creates an entry. The type of an directoryentry is
678 // specified by the attribute.
679 // bit0: unused
680 // bit1: archive
681 // bit2: read_only
682 // bit3: system
683 // bit4: directory
684 // bit5: volume
685 //________________________________________________________________________________________________________________________________________
686 
687 unsigned char CreateDirectoryEntry(unsigned char *fname, unsigned int cluster, File *file,unsigned char attrib)
688 {
689  unsigned int rootentry = 0; // index to an entry in the rootdirectory.
690  unsigned int cnt_enries_searched = 0; // count the number of rootentries which have been searched already.
691  unsigned char i = 0;
692  unsigned int sector_offset = 0; // index to the sector of the Rootentry which is searched momentarily
693  unsigned char retvalue = 0;
694 
695  // directory starts at sector specified by dir_sector. This can be the rootdirectory or any other directory.
696  do
697  { // search the next 16 rootentries in this sector of the roordirectory.
698  rootentry=0;
699  SDC_GetSector((unsigned long)(RootDirectory + sector_offset),&FileBuffer[0]); // Read the Rootdirectory.
700  DirectoryEntry = (struct DirEntry *)&FileBuffer[0];
701  while((rootentry<16) && (!retvalue))
702  {
703  if((DirectoryEntry[rootentry].attribute == 0) || (DirectoryEntry[rootentry].attribute == 0xE5)) // empty directory entry found
704  {
705  for(i=0;i<11;i++) DirectoryEntry[rootentry].name[i] = fname[i]; // Kopie the filename and the file extension to the directoryentry.
706  DirectoryEntry[rootentry].attribute = attrib; // Set the fileattribute to archive to reserve the directoryentry.
707  DirectoryEntry[rootentry].startcluster = cluster; // copy the location of the first datacluster to the directoryentry.
708  DirectoryEntry[rootentry].size = 0; // the new createted file has no content yet.
709  file->directory_sector = (unsigned long) (RootDirectory + sector_offset);
710  file->directory_index = (unsigned char) rootentry;
711  retvalue = 1;
712  SDC_PutSector((unsigned long)(RootDirectory + sector_offset),&FileBuffer[0]);
713  }
714  rootentry++;
715  cnt_enries_searched++;
716  }
717  if(!retvalue) // file not found in this sector so take next sector.
718  {
719  rootentry = 0;
720  sector_offset++;
721  }
722  }
723  while((cnt_enries_searched< PossibleRootEntries) && (!retvalue));
724 
725  return(retvalue); // return 1 if file has been created otherwise return 0.
726 }
727 
728 //________________________________________________________________________________________________________________________________________
729 // Funtion: unsigned int SeekDirectoryEntry(unsigned char*, File *, unsigned char)
730 //
731 // Description: this function searches all possible rootentries until the file or directory is found or the end of the rootdirectory is reached
732 //
733 // Returnvalue: This function returns 1 if the directoryentry specified was found.
734 //________________________________________________________________________________________________________________________________________
735 
736 unsigned char SeekDirectoryEntry(unsigned char *fname, File *file)
737 {
738  unsigned int rootentry=0;
739  unsigned int end_of_directory_not_reached = 0; // the directory has been read completely without a result.
740  unsigned char i=0;
741  unsigned char retvalue = 0;
742  unsigned long cluster_temp = 0;
743  unsigned int cnt = 0;
744  // directory starts at sector specified by dir_sector. This can be the rootdirectory or any other directory.
745  do
746  { // search the next 16 rootentries in this sector of the roordirectory.
747  rootentry=0;
748  SDC_GetSector((unsigned long) file->cluster_pointer,&FileBuffer[0]); // Read the Rootdirectory.
749  DirectoryEntry = (struct DirEntry *)&FileBuffer[0];
750  cnt++;
751  while((!retvalue)&&(rootentry<16))
752  {
753  i=0;
754  while((i<10)&&(DirectoryEntry[rootentry].name[i] == fname[i]))
755  {
756  i++;
757  }
758  if((i==10) && (DirectoryEntry[rootentry].attribute == file->attribute)) // entry found!! -> reading startcluster of entry from offset 26.
759  {
760  cluster_temp = (unsigned long)DirectoryEntry[rootentry].startcluster;
761  cluster_temp -=2; // Clusterposition is ((position in FAT)-2). first two entries in FAT are reserved.
762  cluster_temp *= (unsigned long)SectorsPerCluster; // Calculate positon of first cluster.
763  file->start_cluster = (FirstDataCluster + cluster_temp);
764  file->directory_sector = (unsigned long) file->cluster_pointer;
765  file->cluster_pointer = file->start_cluster; // start reading the file with the first cluster.
766  file->filesize = (unsigned long) DirectoryEntry[rootentry].size;
767  file->directory_index = (unsigned char) rootentry;
768  retvalue = 1;
769  }
770  rootentry++;
771  }
772  if(!retvalue) // file not found in this sector so take next sector.
773  {
774  end_of_directory_not_reached = GetNextCluster(file);
775  }
776  }
777  while((end_of_directory_not_reached) && (!retvalue));
778  return(retvalue);
779 }
780 
781 //________________________________________________________________________________________________________________________________________
782 // Funtion: void ScanSubDirectories(unsigned char*, File *file);
783 //
784 // Description: This function scans the filename for subdirectories and changes the directory until the last directory is reached.
785 // here the specified file is searched.
786 //
787 // Returnvalue:
788 //________________________________________________________________________________________________________________________________________
789 
790 unsigned char ScanSubDirectories(unsigned char *fname, File *file)
791 {
792  unsigned char readpointer = 0; // pointer to read a character within the filepath.
793  unsigned char writepointer = 0; // pointer to write a character into the string dirname.
794  unsigned char dircnt = 0; // the number of subdirectories found in filepath.
795  unsigned char dirname[11]; // temporary variable containing the name of a directory within the filepath.
796  unsigned char retvalue = 1; // no error opening a subdirectory occured yet.
797  unsigned char cnt = 0; // maximun number of characters in a path is 256;
798 
799 
800  while((fname[readpointer]!=0) && (cnt < 255)) // search the string until the end is reached.
801  {
802  cnt++;
803  if((fname[readpointer] == '/') && readpointer) // subdirectory found. ignore first "/" as directory.
804  {
805  dircnt++; // count the number of subdirectories found within the filepath.
806  }
807  readpointer++;
808  }
809 
810  for(writepointer=0;writepointer<10;writepointer++) dirname[writepointer] = ' ';
811  writepointer = 0;
812  readpointer = 0; // start scanning the string at the beginning.
813 
814  file->cluster_pointer = RootDirectory; // always start searching in the rootdirectory.
815  file->attribute = _DIRECTORY; // the attribute of the item to be searched in the specified directory.
816 
817  while(dircnt && retvalue) // scan all subdirectories found before.
818  {
819  if(fname[readpointer] != '/') // is the end of the subdirectory entry not reached yet?
820  {
821  if((fname[readpointer]>96) && (fname[readpointer]<123))
822  { // all characters must be upper case.
823  dirname[writepointer]=(fname[readpointer] - 32);
824  }
825  else
826  {
827  dirname[writepointer]=fname[readpointer];
828  }
829  writepointer++;
830  }
831  else
832  {
833  dircnt--;
834  if(!(SeekDirectoryEntry(dirname, file))) // was the seperated subdirectory not found?
835  {
836  retvalue = 0; // leave the function with return(0) otherwise continue with the next subdirectory until all directories have been searched.
837  }
838  for(writepointer=0;writepointer<10;writepointer++) dirname[writepointer] = ' ';
839  writepointer = 0;
840  }
841  readpointer++;
842  }
843  file->attribute = _FILE; // All subdirectories have been searched. the next thing to find is the specified file.
844  return(retvalue);
845 }
846 
847 //________________________________________________________________________________________________________________________________________
848 // Funtion: void SeperateFileName(unsigned char*);
849 //
850 // Description: This function seperates the filename and the fileattribute and brings them into the needed format ('test.txt' -> 'TEST TXT');
851 //
852 //________________________________________________________________________________________________________________________________________
853 
854 void SeperateFileName(unsigned char *fname, unsigned char *name)
855 {
856  unsigned char readpointer = 0;
857  unsigned char writepointer = 0;
858  unsigned char dircnt = 0; // the number of subdirectories found in filepath.
859  unsigned char fileindex = 0; // the position in the filenamestring where the last "/" is found.
860 
861  while(fname[readpointer]!=0) // search the string until the end is reached.
862  {
863  if((fname[readpointer] == '/') && readpointer) // subdirectory found. ignore first "/" as directory.
864  {
865  dircnt++; // subdirectory entry found.
866  fileindex = (readpointer + 1); // store the index of the last slash found as the beginning of the filename.
867  }
868  readpointer++;
869  }
870  readpointer = fileindex; // start seperating the filename from the directory at the stored position.
871  dircnt = 0;
872 
873  while((writepointer<=10) && (fname[readpointer]!=0)) // the rootdirectoryentry is 8bytes for filename and 3bytes for fileattribute.
874  { // the filename in the rootdirectory is in the format "TEST TXT" without the dot.
875  if(fname[readpointer]=='.') // seperating filename and attribute.
876  {
877  readpointer++;
878  writepointer=8;
879  }
880  else
881  {
882  if((fname[readpointer]>96) && (fname[readpointer]<123))
883  {
884  name[writepointer]=(fname[readpointer] - 32); // all characters must be upper case.
885  }
886  else
887  {
888  name[writepointer]=fname[readpointer];
889  }
890  readpointer++;
891  writepointer++;
892  }
893  }
894 }
unsigned long filesize
Definition: fat16.h:17
unsigned long fwrite_(void *buffer, unsigned long size, unsigned long count, File *file)
Definition: fat16.c:254
unsigned long FileAllocationTable
Definition: fat16.c:51
#define MBR_SECTOR
Definition: fat16.h:97
unsigned int SectorsPerFat
Definition: fat16.c:48
unsigned long size
Definition: fat16.h:40
unsigned long FirstPartitionSector
Definition: fat16.c:50
#define SDC_GetSector
Definition: mmc.h:70
unsigned long directory_sector
Definition: fat16.h:20
unsigned char name[8]
Definition: fat16.h:33
unsigned int startcluster
Definition: fat16.h:39
unsigned char mode
Definition: fat16.h:16
unsigned int GetNextCluster(File *file)
Definition: fat16.c:526
unsigned char attribute
Definition: fat16.h:35
unsigned char fexist_(unsigned char *fname, File *file)
Definition: fat16.c:505
unsigned int time
Definition: fat16.h:37
Definition: fat16.h:49
Definition: fat16.h:10
unsigned long fread_(void *buffer, unsigned long size, unsigned long count, File *file)
Definition: fat16.c:221
unsigned char ScanSubDirectories(unsigned char *fname, File *file)
Definition: fat16.c:790
int fseek_(File *file, long offset, int origin)
Definition: fat16.c:286
unsigned char fputchar_(File *file, char c)
Definition: fat16.c:400
unsigned long fileposition
Definition: fat16.h:18
unsigned char FileBuffer[512]
Definition: fat16.c:55
unsigned int FindNextFreeCluster(File *file)
Definition: fat16.c:574
struct DirEntry * DirectoryEntry
Definition: fat16.c:56
unsigned int GetFatSectorIndex(File *file)
Definition: fat16.c:664
unsigned char SeekDirectoryEntry(unsigned char *fname, File *file)
Definition: fat16.c:736
int fflush_(File *file)
Definition: fat16.c:159
void fclose_(File *file)
Definition: fat16.c:195
Definition: fat16.h:31
unsigned long start_cluster
Definition: fat16.h:12
unsigned int GetFatClusterOffset(File *file)
Definition: fat16.c:646
unsigned char InitFat16(void)
Definition: fat16.c:71
unsigned char FatCopies
Definition: fat16.c:46
struct FatEntry * Fat
Definition: fat16.c:57
#define SDC_PutSector
Definition: mmc.h:68
unsigned long sector_in_buffer
Definition: fat16.h:19
unsigned int date
Definition: fat16.h:38
char * fgets_(char *string, int count, File *file)
Definition: fat16.c:463
unsigned int next_cluster
Definition: fat16.h:51
unsigned char fputs_(File *file, char *string)
Definition: fat16.c:443
unsigned long ReservedSectors
Definition: fat16.c:49
unsigned char AppendCluster(File *file)
Definition: fat16.c:614
unsigned char CreateDirectoryEntry(unsigned char *fname, unsigned int cluster, File *file, unsigned char attrib)
Definition: fat16.c:687
unsigned char sector_index
Definition: fat16.h:14
unsigned int PossibleRootEntries
Definition: fat16.c:47
#define _DIRECTORY
Definition: fat16.h:102
unsigned long RootDirectory
Definition: fat16.c:52
int fgetchar_(File *file)
Definition: fat16.c:356
unsigned char SectorsPerCluster
Definition: fat16.c:45
unsigned long cluster_pointer
Definition: fat16.h:13
unsigned char attribute
Definition: fat16.h:22
unsigned char directory_index
Definition: fat16.h:21
#define _FILE
Definition: fat16.h:103
unsigned int byte_index
Definition: fat16.h:15
unsigned char fopen_(unsigned char *fname, char mode, File *file)
Definition: fat16.c:97
unsigned long FirstDataCluster
Definition: fat16.c:53
void SeperateFileName(unsigned char *fname, unsigned char *name)
Definition: fat16.c:854