PageRenderTime 94ms CodeModel.GetById 372ms app.highlight 411ms RepoModel.GetById 82ms app.codeStats 1ms

/OpenSprinkler Controller/software/arduino-code/libraries/OpenSprinklerGen2/tinyFAT.cpp

https://github.com/sherckuith/opensprinkler
C++ | 952 lines | 829 code | 91 blank | 32 comment | 144 complexity | dbc9e4409990cca8658b9b148807eea0 MD5 | raw file
  1/*
  2	tinyFAT.cpp - Arduino library support FAT16 on SD cards
  3	Copyright (C)2010-2011 Henning Karlsen. All right reserved
  4
  5	You can find the latest version of the library at 
  6	http://www.henningkarlsen.com/electronics
  7
  8	This library has been made to easily use SD card with the Arduino.
  9
 10	If you make any modifications or improvements to the code, I would appreciate
 11	that you share the code with me so that I might include it in the next release.
 12	I can be contacted through http://www.henningkarlsen.com/electronics/contact.php
 13
 14	This library is free software; you can redistribute it and/or
 15	modify it under the terms of the GNU Lesser General Public
 16	License as published by the Free Software Foundation; either
 17	version 2.1 of the License, or (at your option) any later version.
 18
 19	This library is distributed in the hope that it will be useful,
 20	but WITHOUT ANY WARRANTY; without even the implied warranty of
 21	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 22	Lesser General Public License for more details.
 23
 24	You should have received a copy of the GNU Lesser General Public
 25	License along with this library; if not, write to the Free Software
 26	Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 27*/
 28#include "tinyFAT.h"

 29#include <mmc.h>

 30
 31/* Public */
 32
 33tinyFAT::tinyFAT()
 34{
 35	_inited=false;
 36}
 37
 38byte tinyFAT::initFAT(byte speed)
 39{
 40	mmc::initialize(speed);
 41// Read MBR
 42	if (RES_OK == mmc::readSector(buffer, 0))
 43	{
 44		if ((buffer[0x01FE]==0x55) && (buffer[0x01FF]==0xAA))
 45		{
 46			MBR.part1Type=buffer[450];
 47			MBR.part1Start = uint16_t(buffer[454])+(uint16_t(buffer[455])<<8)+(uint32_t(buffer[456])<<16)+(uint32_t(buffer[457])<<24);
 48			MBR.part1Size = uint16_t(buffer[458])+(uint16_t(buffer[459])<<8)+(uint32_t(buffer[460])<<16)+(uint32_t(buffer[461])<<24);
 49		}
 50		else
 51		{
 52			return ERROR_MBR_SIGNATURE;
 53		}
 54	}
 55	else
 56		return ERROR_MBR_READ_ERROR;
 57
 58	if ((MBR.part1Type!=0x04) && (MBR.part1Type!=0x06) && (MBR.part1Type!=0x86))
 59	{
 60		return ERROR_MBR_INVALID_FS;
 61	}
 62
 63// Read Boot Sector
 64	if (RES_OK == mmc::readSector(buffer, MBR.part1Start))
 65    {
 66		if ((buffer[0x01FE]==0x55) && (buffer[0x01FF]==0xAA))
 67		{
 68			BS.sectorsPerCluster = buffer[0x0D];
 69			BS.reservedSectors = uint16_t(buffer[0x0E])+(uint16_t(buffer[0x0F])<<8);
 70			BS.fatCopies = buffer[0x10];
 71			BS.rootDirectoryEntries = uint16_t(buffer[0x11])+(uint16_t(buffer[0x12])<<8);
 72			BS.totalFilesystemSectors = uint16_t(buffer[0x13])+(uint16_t(buffer[0x14])<<8);
 73			if (BS.totalFilesystemSectors==0)
 74				BS.totalFilesystemSectors = uint16_t(buffer[0x20])+(uint16_t(buffer[0x21])<<8)+(uint32_t(buffer[0x22])<<16)+(uint32_t(buffer[0x23])<<24);
 75			BS.sectorsPerFAT = uint16_t(buffer[0x16])+(uint16_t(buffer[0x17])<<8);
 76			BS.hiddenSectors = uint16_t(buffer[0x1C])+(uint16_t(buffer[0x1D])<<8)+(uint32_t(buffer[0x1E])<<16)+(uint32_t(buffer[0x1F])<<24);
 77			BS.partitionSerialNum = uint16_t(buffer[0x27])+(uint16_t(buffer[0x28])<<8)+(uint32_t(buffer[0x29])<<16)+(uint32_t(buffer[0x2A])<<24);
 78			firstDirSector = MBR.part1Start + BS.reservedSectors + (BS.fatCopies * BS.sectorsPerFAT);
 79			BS.fat1Start = MBR.part1Start + BS.reservedSectors;
 80			BS.fat2Start = BS.fat1Start + BS.sectorsPerFAT;
 81			BS.partitionSize = float((MBR.part1Size*512)/float(1048576));
 82		}
 83		else
 84			return ERROR_BOOTSEC_SIGNATURE;
 85	}
 86	else
 87		return ERROR_BOOTSEC_READ_ERROR;
 88
 89	_inited=true;
 90	return 0x00;
 91}
 92
 93byte tinyFAT::findFirstFile(_directory_entry *tempDE)
 94{
 95	unsigned long currSec = firstDirSector;
 96	word offset = 0;
 97
 98	DEcnt=0;
 99	mmc::readSector(buffer, currSec);
100
101	if (buffer[0]==0x00)
102		return ERROR_NO_MORE_FILES;
103	else
104	{
105		while ((buffer[offset + 0x0B] & 0x08) || (buffer[offset + 0x0B] & 0x10) || (buffer[offset]==0xE5))
106		{
107			offset+=32;
108			DEcnt++;
109			if (offset==512)
110			{
111			  currSec++;
112			  mmc::readSector(buffer, currSec);
113			  offset = 0;
114			} 
115			if (buffer[offset]==0x00)
116				return ERROR_NO_MORE_FILES;
117		}
118
119		for (int i=0; i<8; i++)
120		{
121			tempDE->filename[i] = buffer[i+offset];
122		}
123		for (int i=0; i<3; i++)
124		{
125			tempDE->fileext[i] = buffer[i+0x08+offset];
126		}
127		tempDE->filename[8] = 0;
128		tempDE->fileext[3] = 0;
129		tempDE->attributes = buffer[0x0B + offset];
130		tempDE->time = uint16_t(buffer[0x0E + offset]) + (uint16_t(buffer[0x0F + offset])<<8);
131		tempDE->date = uint16_t(buffer[0x10 + offset]) + (uint16_t(buffer[0x11 + offset])<<8);
132		tempDE->startCluster = uint16_t(buffer[0x1A + offset]) + (uint16_t(buffer[0x1B + offset])<<8);
133		tempDE->fileSize = uint16_t(buffer[offset + 0x1C]) | (uint16_t(buffer[offset + 0x1D])<<8) | (uint32_t(buffer[offset + 0x1E])<<16) | (uint32_t(buffer[offset + 0x1F])<<24);
134		DEcnt++;
135
136		return NO_ERROR;
137	}
138}
139
140byte tinyFAT::findNextFile(_directory_entry *tempDE)
141{
142	unsigned long currSec = firstDirSector;
143	word offset = DEcnt*32;
144
145	while (offset>=512)
146	{
147		currSec++;
148		offset-=512;
149	}
150
151	mmc::readSector(buffer, currSec);
152
153	if (buffer[offset]==0x00)
154		return ERROR_NO_MORE_FILES;
155	else
156	{
157		while ((buffer[offset + 0x0B] & 0x08) || (buffer[offset + 0x0B] & 0x10) || (buffer[offset]==0xE5))
158		{
159			offset+=32;
160			DEcnt++;
161			if (offset==512)
162			{
163			  currSec++;
164			  mmc::readSector(buffer, currSec);
165			  offset = 0;
166			} 
167			if (buffer[offset]==0x00)
168				return ERROR_NO_MORE_FILES;
169		}
170
171		for (int i=0; i<8; i++)
172		{
173			tempDE->filename[i] = buffer[i+offset];
174		}
175		for (int i=0; i<3; i++)
176		{
177			tempDE->fileext[i] = buffer[i+0x08+offset];
178		}
179		tempDE->filename[8] = 0;
180		tempDE->fileext[3] = 0;
181		tempDE->attributes = buffer[0x0B + offset];
182		tempDE->time = uint16_t(buffer[0x0E + offset]) + (uint16_t(buffer[0x0F + offset])<<8);
183		tempDE->date = uint16_t(buffer[0x10 + offset]) + (uint16_t(buffer[0x11 + offset])<<8);
184		tempDE->startCluster = uint16_t(buffer[0x1A + offset]) + (uint16_t(buffer[0x1B + offset])<<8);
185		tempDE->fileSize = uint16_t(buffer[offset + 0x1C]) | (uint16_t(buffer[offset + 0x1D])<<8) | (uint32_t(buffer[offset + 0x1E])<<16) | (uint32_t(buffer[offset + 0x1F])<<24);
186		DEcnt++;
187
188		return NO_ERROR;
189	}
190}
191
192byte tinyFAT::openFile(char *fn, byte mode)
193{
194	_directory_entry tmpDE;
195	char tmpFN[13];
196	byte res;
197	int i, j;
198
199	if (currFile.filename[0]!=0x00)
200		return ERROR_ANOTHER_FILE_OPEN;
201
202	for (i=0; i<strlen(fn); i++)
203		fn[i]=uCase(fn[i]);
204
205	res=findFirstFile(&tmpDE);
206	if (res==ERROR_NO_MORE_FILES)
207		return ERROR_FILE_NOT_FOUND;
208	else
209	{
210		i=0;
211		j=0;
212		while ((tmpDE.filename[i]!=0x20) and (i<8))
213		{
214			tmpFN[i]=tmpDE.filename[i];
215			i++;
216		}
217		tmpFN[i]='.';
218		i++;
219		while ((tmpDE.fileext[j]!=0x20) and (j<3))
220		{
221			tmpFN[i]=tmpDE.fileext[j];
222			i++;
223			j++;
224		}
225		tmpFN[i]=0x00;
226		if (!strcmp(tmpFN,fn))
227		{
228			for (i=0; i<13; i++)
229				currFile.filename[i]=tmpFN[i];
230			currFile.currentCluster=tmpDE.startCluster;
231			currFile.fileSize=tmpDE.fileSize;
232			currFile.currentPos=0;
233			currFile.fileMode=mode;
234			return NO_ERROR;
235		}
236		while (res==NO_ERROR)
237		{
238			res = file.findNextFile(&tmpDE);
239			if (res==NO_ERROR)
240			{
241				i=0;
242				j=0;
243				while ((tmpDE.filename[i]!=0x20) and (i<8))
244				{
245					tmpFN[i]=tmpDE.filename[i];
246					i++;
247				}
248				tmpFN[i]='.';
249				i++;
250				while ((tmpDE.fileext[j]!=0x20) and (j<3))
251				{
252					tmpFN[i]=tmpDE.fileext[j];
253					i++;
254					j++;
255				}
256				tmpFN[i]=0x00;
257				if (!strcmp(tmpFN,fn))
258				{
259					for (i=0; i<13; i++)
260						currFile.filename[i]=tmpFN[i];
261					currFile.currentCluster=tmpDE.startCluster;
262					currFile.fileSize=tmpDE.fileSize;
263					currFile.currentPos=0;
264					currFile.fileMode=mode;
265					return NO_ERROR;
266				}
267			}
268		}
269
270
271	}
272	return ERROR_FILE_NOT_FOUND;
273}
274
275uint16_t tinyFAT::readBinary()
276{
277	uint32_t sec;
278	uint8_t status_;
279
280	if (currFile.fileMode==FILEMODE_BINARY)
281	{
282		if ((currFile.currentPos==0) and (currFile.currentCluster==0))
283			return FILE_IS_EMPTY;
284		if (((currFile.currentPos % BS.sectorsPerCluster)==0) and (currFile.currentPos>0))
285			currFile.currentCluster=findNextCluster(currFile.currentCluster);
286		sec=BS.hiddenSectors + (uint32_t)BS.reservedSectors + ((uint32_t)BS.fatCopies*(uint32_t)BS.sectorsPerFAT)+(((uint32_t)BS.rootDirectoryEntries*32)/512)+((uint32_t)currFile.currentCluster-2)*(uint32_t)BS.sectorsPerCluster+((uint32_t)currFile.currentPos % (uint32_t)BS.sectorsPerCluster);
287		status_=mmc::readSector(buffer, sec);
288		if (status_)
289		{
290			return status_;
291		}
292		currFile.currentPos++;
293		if ((currFile.currentPos*512)>currFile.fileSize)
294		{
295				return (currFile.fileSize-((currFile.currentPos-1)*512));
296		}
297		else
298		{
299				return 512;
300		}
301	}
302	else
303		if (currFile.fileMode==0x00)
304			return ERROR_NO_FILE_OPEN;
305		else
306			return ERROR_WRONG_FILEMODE;
307}
308
309uint16_t tinyFAT::readLn(char *st, int bufSize)
310{
311	uint32_t sec;
312	int bufIndex=0;
313
314	for (int i=0; i<=bufSize; i++)
315		st[i]=0;
316
317	if (currFile.fileMode==FILEMODE_TEXT_READ)
318	{
319		if ((currFile.currentPos==0) and (currFile.currentCluster==0))
320			return FILE_IS_EMPTY;
321		sec=((uint32_t)BS.reservedSectors+((uint32_t)BS.fatCopies*(uint32_t)BS.sectorsPerFAT)+(((uint32_t)BS.rootDirectoryEntries*32)/512)+(((uint32_t)currFile.currentCluster-2)*(uint32_t)BS.sectorsPerCluster)+BS.hiddenSectors)+(((uint32_t)currFile.currentPos/512) % (uint32_t)BS.sectorsPerCluster);
322		mmc::readSector(buffer, sec);
323		while ((currFile.currentPos<currFile.fileSize) and (buffer[currFile.currentPos % 512]!=10) and (buffer[currFile.currentPos % 512]!=13) and (bufIndex<bufSize))
324		{
325			st[bufIndex]=buffer[currFile.currentPos % 512];
326			bufIndex++;
327			currFile.currentPos++;
328			if ((currFile.currentPos % 512) == 0)
329			{
330				sec++;
331				if (((currFile.currentPos/512) % BS.sectorsPerCluster)==0)
332				{
333					currFile.currentCluster=findNextCluster(currFile.currentCluster);
334					sec=((uint32_t)BS.reservedSectors+((uint32_t)BS.fatCopies*(uint32_t)BS.sectorsPerFAT)+(((uint32_t)BS.rootDirectoryEntries*32)/512)+(((uint32_t)currFile.currentCluster-2)*(uint32_t)BS.sectorsPerCluster)+BS.hiddenSectors);
335				}
336				mmc::readSector(buffer, sec);
337			}
338		}
339		if (currFile.currentPos>=currFile.fileSize)
340			return EOF;
341		else if ((buffer[(currFile.currentPos % 512)]==13) and (buffer[(currFile.currentPos % 512)+1]==10))
342		{
343			currFile.currentPos+=2;
344			return bufIndex;
345		}
346		else if ((buffer[(currFile.currentPos % 512)]==13) or (buffer[(currFile.currentPos % 512)]==10))
347		{
348			currFile.currentPos++;
349			return bufIndex;
350		}
351		else
352			return BUFFER_OVERFLOW;
353	}
354	else
355		if (currFile.fileMode==0x00)
356			return ERROR_NO_FILE_OPEN;
357		else
358			return ERROR_WRONG_FILEMODE;
359}
360
361uint16_t tinyFAT::writeLn(char *st)
362{
363	unsigned long currSec = firstDirSector;
364	uint16_t nextCluster = 0;
365	word offset = -32;
366	uint32_t sec;
367	char tmpFN[13];
368	int i, j;
369	int bufIndex=0;
370	boolean done=false;
371
372	if (currFile.fileMode==FILEMODE_TEXT_WRITE)
373	{
374		if (currFile.currentCluster==0)
375		{
376			currFile.currentCluster=findFreeCluster();
377
378			mmc::readSector(buffer, currSec);
379			while (!done)
380			{
381				offset+=32;
382				if (offset==512)
383				{
384				  currSec++;
385				  mmc::readSector(buffer, currSec);
386				  offset = 0;
387				} 
388
389				j=0;
390				for (int i=0; i<8; i++)
391				{
392					if (buffer[i+offset]!=0x20)
393					{
394						tmpFN[j]=buffer[i+offset];
395						j++;
396					}
397				}
398				tmpFN[j]='.';
399				j++;
400				for (int i=0; i<3; i++)
401				{
402					if (buffer[i+0x08+offset]!=0x20)
403					{
404						tmpFN[j]=buffer[i+0x08+offset];
405						j++;
406					}
407				}
408				tmpFN[j]=0x00;
409				
410				if (!strcmp(tmpFN, currFile.filename))
411				{
412					buffer[offset+0x1A]=currFile.currentCluster & 0xFF;
413					buffer[offset+0x1B]=currFile.currentCluster>>8;
414
415					mmc::writeSector(buffer, currSec);
416
417					mmc::readSector(buffer, BS.fat1Start+(currFile.currentCluster>>8));
418					buffer[(currFile.currentCluster & 0xFF)*2]=0xFF;
419					buffer[((currFile.currentCluster & 0xFF)*2)+1]=0xFF;
420					mmc::writeSector(buffer, BS.fat1Start+(currFile.currentCluster>>8));
421
422					mmc::readSector(buffer, BS.fat2Start+(currFile.currentCluster>>8));
423					buffer[(currFile.currentCluster & 0xFF)*2]=0xFF;
424					buffer[((currFile.currentCluster & 0xFF)*2)+1]=0xFF;
425					mmc::writeSector(buffer, BS.fat2Start+(currFile.currentCluster>>8));
426
427					done=true;
428				}
429			}
430
431		}
432
433		if ((((currFile.fileSize % 512)+strlen(st))<=510) and ((currFile.fileSize % (long(BS.sectorsPerCluster)*512)!=0) or (currFile.fileSize==0)))
434		{
435			currSec=(BS.reservedSectors+(BS.fatCopies*BS.sectorsPerFAT)+((BS.rootDirectoryEntries*32)/512)+((currFile.currentCluster-2)*BS.sectorsPerCluster)+BS.hiddenSectors)+((currFile.fileSize/512) % BS.sectorsPerCluster);
436			mmc::readSector(buffer, currSec);
437			for (int i=0; i<strlen(st); i++)
438				buffer[(currFile.fileSize%512)+i]=st[i];
439			buffer[(currFile.fileSize%512)+strlen(st)]=0x0D;
440			buffer[(currFile.fileSize%512)+strlen(st)+1]=0x0A;
441			mmc::writeSector(buffer, currSec);
442		}
443		else
444		{
445			currSec=(BS.reservedSectors+(BS.fatCopies*BS.sectorsPerFAT)+((BS.rootDirectoryEntries*32)/512)+((currFile.currentCluster-2)*BS.sectorsPerCluster)+BS.hiddenSectors)+((currFile.fileSize/512) % BS.sectorsPerCluster);
446
447			if ((currFile.fileSize%512)!=0)
448			{
449				mmc::readSector(buffer, currSec);
450				for (int i=0; i<(512-(currFile.fileSize%512)); i++)
451				{
452					buffer[(currFile.fileSize%512)+i]=st[i];
453					bufIndex++;
454				}
455				mmc::writeSector(buffer, currSec);
456				currSec++;
457			}
458			else
459				bufIndex=0;
460
461			if (((currSec-(BS.reservedSectors+(BS.fatCopies*BS.sectorsPerFAT)+((BS.rootDirectoryEntries*32)/512)+BS.hiddenSectors)) % BS.sectorsPerCluster)==0)
462			{
463				nextCluster=findFreeCluster();
464
465				mmc::readSector(buffer, BS.fat1Start+(currFile.currentCluster>>8));
466				buffer[(currFile.currentCluster & 0xFF)*2]=nextCluster & 0xFF;
467				buffer[((currFile.currentCluster & 0xFF)*2)+1]=nextCluster>>8;
468				if ((nextCluster>>8)==(currFile.currentCluster>>8))
469				{
470					buffer[(nextCluster & 0xFF)*2]=0xFF;
471					buffer[((nextCluster & 0xFF)*2)+1]=0xFF;
472					mmc::writeSector(buffer, BS.fat1Start+(currFile.currentCluster>>8));
473				}
474				else
475				{
476					mmc::writeSector(buffer, BS.fat1Start+(currFile.currentCluster>>8));
477					mmc::readSector(buffer, BS.fat1Start+(nextCluster>>8));
478					buffer[(nextCluster & 0xFF)*2]=0xFF;
479					buffer[((nextCluster & 0xFF)*2)+1]=0xFF;
480					mmc::writeSector(buffer, BS.fat1Start+(nextCluster>>8));
481				}
482
483				mmc::readSector(buffer, BS.fat2Start+(currFile.currentCluster>>8));
484				buffer[(currFile.currentCluster & 0xFF)*2]=nextCluster & 0xFF;
485				buffer[((currFile.currentCluster & 0xFF)*2)+1]=nextCluster>>8;
486				if ((nextCluster>>8)==(currFile.currentCluster>>8))
487				{
488					buffer[(nextCluster & 0xFF)*2]=0xFF;
489					buffer[((nextCluster & 0xFF)*2)+1]=0xFF;
490					mmc::writeSector(buffer, BS.fat2Start+(currFile.currentCluster>>8));
491				}
492				else
493				{
494					mmc::writeSector(buffer, BS.fat2Start+(currFile.currentCluster>>8));
495					mmc::readSector(buffer, BS.fat2Start+(nextCluster>>8));
496					buffer[(nextCluster & 0xFF)*2]=0xFF;
497					buffer[((nextCluster & 0xFF)*2)+1]=0xFF;
498					mmc::writeSector(buffer, BS.fat2Start+(nextCluster>>8));
499				}
500
501				currFile.currentCluster=nextCluster;
502
503				currSec=(BS.reservedSectors+(BS.fatCopies*BS.sectorsPerFAT)+((BS.rootDirectoryEntries*32)/512)+((currFile.currentCluster-2)*BS.sectorsPerCluster)+BS.hiddenSectors);
504			}
505			mmc::readSector(buffer, currSec);
506			for (int i=0; i<strlen(st)-bufIndex; i++)
507				buffer[i]=st[i+bufIndex];
508			buffer[strlen(st)-bufIndex]=0x0D;
509			buffer[strlen(st)-bufIndex+1]=0x0A;
510			mmc::writeSector(buffer, currSec);
511
512
513		}
514
515		currFile.fileSize+=(strlen(st)+2);
516
517		currSec=firstDirSector;
518		offset=-32;
519		done=false;
520		mmc::readSector(buffer, currSec);
521		while (!done)
522		{
523			offset+=32;
524			if (offset==512)
525			{
526			  currSec++;
527			  mmc::readSector(buffer, currSec);
528			  offset = 0;
529			} 
530
531			j=0;
532			for (int i=0; i<8; i++)
533			{
534				if (buffer[i+offset]!=0x20)
535				{
536					tmpFN[j]=buffer[i+offset];
537					j++;
538				}
539			}
540			tmpFN[j]='.';
541			j++;
542			for (int i=0; i<3; i++)
543			{
544				if (buffer[i+0x08+offset]!=0x20)
545				{
546					tmpFN[j]=buffer[i+0x08+offset];
547					j++;
548				}
549			}
550			tmpFN[j]=0x00;
551
552			if (!strcmp(tmpFN, currFile.filename))
553			{
554				buffer[offset+0x1C]=currFile.fileSize & 0xFF;
555				buffer[offset+0x1D]=(currFile.fileSize & 0xFF00)>>8;
556				buffer[offset+0x1E]=(currFile.fileSize & 0xFF0000)>>16;
557				buffer[offset+0x1F]=currFile.fileSize>>24;
558
559				mmc::writeSector(buffer, currSec);
560
561				done=true;
562			}
563		}
564
565		return NO_ERROR;
566	}
567	else
568		if (currFile.fileMode==0x00)
569			return ERROR_NO_FILE_OPEN;
570		else
571			return ERROR_WRONG_FILEMODE;
572}
573
574void tinyFAT::closeFile()
575{
576	currFile.filename[0]=0x00;
577	currFile.fileMode=0x00;
578}
579
580boolean tinyFAT::exists(char *fn)
581{
582	_directory_entry tmpDE;
583	char tmpFN[13];
584	byte res;
585	int i, j;
586
587	for (i=0; i<strlen(fn); i++)
588		fn[i]=uCase(fn[i]);
589
590	res=findFirstFile(&tmpDE);
591	if (res==ERROR_NO_MORE_FILES)
592		return false;
593	else
594	{
595		i=0;
596		j=0;
597		while ((tmpDE.filename[i]!=0x20) and (i<8))
598		{
599			tmpFN[i]=tmpDE.filename[i];
600			i++;
601		}
602		tmpFN[i]='.';
603		i++;
604		while ((tmpDE.fileext[j]!=0x20) and (j<3))
605		{
606			tmpFN[i]=tmpDE.fileext[j];
607			i++;
608			j++;
609		}
610		tmpFN[i]=0x00;
611		if (!strcmp(tmpFN,fn))
612			return true;
613		while (res==NO_ERROR)
614		{
615			res = file.findNextFile(&tmpDE);
616			if (res==NO_ERROR)
617			{
618				i=0;
619				j=0;
620				while ((tmpDE.filename[i]!=0x20) and (i<8))
621				{
622					tmpFN[i]=tmpDE.filename[i];
623					i++;
624				}
625				tmpFN[i]='.';
626				i++;
627				while ((tmpDE.fileext[j]!=0x20) and (j<3))
628				{
629					tmpFN[i]=tmpDE.fileext[j];
630					i++;
631					j++;
632				}
633				tmpFN[i]=0x00;
634				if (!strcmp(tmpFN,fn))
635					return true;
636			}
637		}
638	}
639	return false;
640}
641
642boolean tinyFAT::rename(char *fn1, char *fn2)
643{
644	unsigned long currSec = firstDirSector;
645	word offset = -32;
646	char tmpFN[13];
647	int i, j;
648	boolean done=false;
649
650	for (i=0; i<strlen(fn1); i++)
651		fn1[i]=uCase(fn1[i]);
652
653	for (i=0; i<strlen(fn2); i++)
654	{
655		fn2[i]=uCase(fn2[i]);
656		if (!validChar(fn2[i]))
657			return false;
658	}
659
660	if (exists(fn1))
661	{
662		mmc::readSector(buffer, currSec);
663		while (!done)
664		{
665			offset+=32;
666			if (offset==512)
667			{
668			  currSec++;
669			  mmc::readSector(buffer, currSec);
670			  offset = 0;
671			} 
672
673			j=0;
674			for (int i=0; i<8; i++)
675			{
676				if (buffer[i+offset]!=0x20)
677				{
678					tmpFN[j]=buffer[i+offset];
679					j++;
680				}
681			}
682			tmpFN[j]='.';
683			j++;
684			for (int i=0; i<3; i++)
685			{
686				if (buffer[i+0x08+offset]!=0x20)
687				{
688					tmpFN[j]=buffer[i+0x08+offset];
689					j++;
690				}
691			}
692			tmpFN[j]=0x00;
693			if (!strcmp(tmpFN, fn1))
694			{
695				for (int i=0; i<11; i++)
696				{
697					buffer[i+offset]=0x20;
698				}
699				j=0;
700				for (int i=0; i<strlen(fn2); i++)
701				{
702					if (fn2[i]=='.')
703						j=8;
704					else
705					{
706						buffer[j+offset]=fn2[i];
707						j++;
708					}
709				}
710				mmc::writeSector(buffer, currSec);
711				done=true;
712			}
713		}
714
715		return true;
716	}
717	else
718		return false;
719}
720
721boolean tinyFAT::delFile(char *fn)
722{
723	unsigned long currSec = firstDirSector;
724	uint16_t firstCluster, currCluster, nextCluster;
725	word offset = -32;
726	char tmpFN[13];
727	int j;
728	boolean done=false;
729
730	for (int i=0; i<strlen(fn); i++)
731		fn[i]=uCase(fn[i]);
732
733	if (exists(fn))
734	{
735		mmc::readSector(buffer, currSec);
736		while (!done)
737		{
738			offset+=32;
739			if (offset==512)
740			{
741			  currSec++;
742			  mmc::readSector(buffer, currSec);
743			  offset = 0;
744			} 
745
746			j=0;
747			for (int i=0; i<8; i++)
748			{
749				if (buffer[i+offset]!=0x20)
750				{
751					tmpFN[j]=buffer[i+offset];
752					j++;
753				}
754			}
755			tmpFN[j]='.';
756			j++;
757			for (int i=0; i<3; i++)
758			{
759				if (buffer[i+0x08+offset]!=0x20)
760				{
761					tmpFN[j]=buffer[i+0x08+offset];
762					j++;
763				}
764			}
765			tmpFN[j]=0x00;
766			if (!strcmp(tmpFN, fn))
767			{
768				buffer[offset]=0xE5;
769				firstCluster = uint16_t(buffer[0x1A + offset]) + (uint16_t(buffer[0x1B + offset])<<8);
770				mmc::writeSector(buffer, currSec);
771				
772				if (firstCluster!=0)
773				{
774					currSec=firstCluster/256;
775					mmc::readSector(buffer, BS.fat1Start+currSec);
776					currCluster=firstCluster;
777					nextCluster=0;
778					while (nextCluster!=0xFFFF)
779					{
780						nextCluster = buffer[(currCluster % 256)*2] + (buffer[((currCluster % 256)*2)+1]<<8);
781						buffer[(currCluster % 256)*2]=0;
782						buffer[((currCluster % 256)*2)+1]=0;
783						if (((currCluster/256) != (nextCluster/256)) and (nextCluster!=0xFFFF))
784						{
785							mmc::writeSector(buffer, BS.fat1Start+currSec);
786							currSec=nextCluster/256;
787							mmc::readSector(buffer, BS.fat1Start+currSec);
788
789						}
790						currCluster=nextCluster;
791					}
792					mmc::writeSector(buffer, BS.fat1Start+currSec);
793
794					currSec=firstCluster/256;
795					mmc::readSector(buffer, BS.fat2Start+currSec);
796					currCluster=firstCluster;
797					nextCluster=0;
798					while (nextCluster!=0xFFFF)
799					{
800						nextCluster = buffer[(currCluster % 256)*2] + (buffer[((currCluster % 256)*2)+1]<<8);
801						buffer[(currCluster % 256)*2]=0;
802						buffer[((currCluster % 256)*2)+1]=0;
803						if (((currCluster/256) != (nextCluster/256)) and (nextCluster!=0xFFFF))
804						{
805							mmc::writeSector(buffer, BS.fat2Start+currSec);
806							currSec=nextCluster/256;
807							mmc::readSector(buffer, BS.fat2Start+currSec);
808
809						}
810						currCluster=nextCluster;
811					}
812				mmc::writeSector(buffer, BS.fat2Start+currSec);
813				}
814
815				done=true;
816			}
817		}
818
819		return true;
820	}
821	else
822		return false;
823}
824
825boolean tinyFAT::create(char *fn)
826{
827	unsigned long currSec;
828	word offset = 0;
829	boolean done=false;
830	int j;
831
832	for (int i=0; i<strlen(fn); i++)
833	{
834		fn[i]=uCase(fn[i]);
835		if (!validChar(fn[i]))
836			return false;
837	}
838
839	if (!exists(fn))
840	{
841		currSec = firstDirSector;
842		mmc::readSector(buffer, currSec);
843		offset = -32;
844		while (!done)
845		{
846			offset+=32;
847			if (offset==512)
848			{
849			  currSec++;
850			  mmc::readSector(buffer, currSec);
851			  offset = 0;
852			} 
853
854			if ((buffer[offset]==0x00) or (buffer[offset]==0xE5))
855			{
856				for (int i=0; i<11; i++)
857				{
858					buffer[i+offset]=0x20;
859				}
860				j=0;
861				for (int i=0; i<strlen(fn); i++)
862				{
863					if (fn[i]=='.')
864						j=8;
865					else
866					{
867						buffer[j+offset]=fn[i];
868						j++;
869					}
870				}
871				
872				for (int i=0x0b; i<0x20; i++)
873					buffer[offset+i]=0;
874				buffer[offset+0x0b]=0x20;
875				buffer[offset+0x0f]=0x60;
876				buffer[offset+0x10]=0x21;
877				buffer[offset+0x11]=0x3E;
878				buffer[offset+0x12]=0x21;
879				buffer[offset+0x13]=0x3E;
880				buffer[offset+0x17]=0x60;
881				buffer[offset+0x18]=0x21;
882				buffer[offset+0x19]=0x3E;
883
884				mmc::writeSector(buffer, currSec);
885
886				done=true;
887			}
888		}
889		return true;
890	}
891	else
892		return false;
893}
894
895/* Private */
896
897uint16_t tinyFAT::findNextCluster(uint16_t cc)
898{
899	uint16_t nc;
900	mmc::readSector(buffer, BS.fat1Start+int(cc/256));
901	nc = buffer[(cc % 256)*2] + (buffer[((cc % 256)*2)+1]<<8);
902	return nc;
903}
904
905char tinyFAT::uCase(char c)
906{
907	if ((c>='a') && (c<='z'))
908		return (c-0x20);
909	else
910		return c;
911}
912
913boolean tinyFAT::validChar(char c)
914{
915	char valid[]= "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$&'()-@^_`{}~.";
916
917	for (int i=0; i<strlen(valid); i++)
918		if (c==valid[i])
919			return true;
920	return false;
921}
922
923uint16_t tinyFAT::findFreeCluster()
924{
925	unsigned long currSec=0;
926	word firstFreeCluster=0;
927	word offset=0;
928
929	while ((firstFreeCluster==0) and (currSec<=BS.sectorsPerFAT))
930	{
931		mmc::readSector(buffer, BS.fat1Start+currSec);
932		while ((firstFreeCluster==0) and (offset<=512))
933		{
934			if ((buffer[offset] + (buffer[offset+1]<<8))==0)
935				firstFreeCluster=(currSec<<8)+(offset/2);
936			else
937				offset+=2;
938		}
939		offset=0;
940		currSec++;
941	}
942}
943
944void tinyFAT::setSSpin(byte pin)
945{
946	if (_inited==false)
947		mmc::setSSpin(pin);
948}
949
950/* Declarations */
951
952tinyFAT file = tinyFAT();