#include #include #include "fat.h" #include "file.h" #include "hardware.h" struct Fat fat; // wichtige daten/variablen der fat struct File file; // wichtige dateibezogene daten/variablen #if (write==1) //*************************************************************************************************************** // schreibt sektor nummer:sec auf die karte (puffer:sector) !! // setzt bufferFlag=0 da puffer nicht dirty sein kann nach schreiben ! //*************************************************************************************************************** unsigned char fat_writeSector(unsigned long int sec){ fat.bufferDirty=0; // buffer kann nicht dirty sein weil wird geschrieben return(mmc_write_sector(sec,fat.sector)); // schreiben von sektor puffer } //*************************************************************************************************************** // markiert sector komplett mit 0x00 (nur den gepufferten) // wenn neuer direktory cluster verkettet wird, muss er mit 0x00 initialisiert werden (alle felder) //*************************************************************************************************************** void fat_markSector00(void){ fat.currentSectorNr=0; // geladener sektor wird hier geändert ! unsigned int i=512; do{ fat.sector[i]=0x00; //schreibt puffer sector voll mit 0x00==leer }while(--i); } #endif // *************************************************************************************************************** // umrechnung cluster auf 1.sektor des clusters (möglicherweise mehrere sektoren/cluster) ! // *************************************************************************************************************** unsigned long int fat_clustToSec(unsigned long int clust){ return (fat.dataDirSec+2+((clust-2) * fat.secPerClust)); // errechnet den 1. sektor der sektoren des clusters } // *************************************************************************************************************** // umrechnung sektor auf cluster (nicht die position im cluster selber!!) // *************************************************************************************************************** unsigned long int fat_secToClust(unsigned long int sec){ return ((sec-fat.dataDirSec-2+2*fat.secPerClust)/fat.secPerClust); // umkerhrfunktion von fat_clustToSec } //*************************************************************************************************************** // läd sektor:sec auf puffer:sector zum bearbeiten im ram ! // setzt currentSectorNr auf richtigen wert (also den sektor der gepuffert ist). es wird geprüft // ob der gepufferte sektor geändert wurde, wenn ja muss erst geschrieben werden, um diese daten nicht zu verlieren ! //*************************************************************************************************************** unsigned char fat_loadSector(unsigned long int sec){ if(sec!=fat.currentSectorNr){ // nachladen nötig #if (write==1) if(fat.bufferDirty==1) fat_writeSector(fat.currentSectorNr); // puffer diry, also vorher schreiben #endif mmc_read_sector(sec,fat.sector); // neuen sektor laden fat.currentSectorNr=sec; // aktualisiert sektor nummer (nummer des gepufferten sektors) return(0); } else return(0); // alles ok, daten sind schon da (sec==fat.currentSectorNr) return(1); // fehler } // datei lesen funktionen: // fat_loadSector -> fat_loadRowOfSector -> fat_loadFileDataFromCluster -> fat_loadFileDataFromDir -> fat_loadFileDataFromDir -> fat_cd "daten chain" //*************************************************************************************************************** // läd die reihe:row des gepufferten sektors auf das struct:file. dort stehen dann // alle wichgigen daten wie: 1.cluster,länge bei dateien, name des eintrags, reihen nummer (im sektor), attribut use... //*************************************************************************************************************** unsigned char fat_loadRowOfSector(unsigned int row){ unsigned char i; row=row<<5; // multipliziert mit 32 um immer auf zeilen anfang zu kommen (zeile 0=0,zeile 1=32,zeile 2=62 usw). void *firstCluster=&file.firstCluster; // void pointer auf file.firstCluster,zum schreiben von einzel bytes auf 4 byte variable. void *length=&file.length; // void pointer auf datei länge, zum schreiben von einzel bytes auf 4 byte variable. for(i=0;i<11;i++) file.name[i]=fat.sector[row+i]; // datei name, ersten 10 bytes vom 32 byte eintrag. file.attrib=fat.sector[row+11]; // datei attribut, byte 11. *(unsigned char*)firstCluster++=fat.sector[row+26]; // datei erster cluster , byte von klein nach hoch: 26,27,20,21 . *(unsigned char*)firstCluster++=fat.sector[row+27]; // hier nicht mit bytesOfSec pointer, weil man hin und her springen, *(unsigned char*)firstCluster++=fat.sector[row+20]; // müsste.. *(unsigned char*)firstCluster++=fat.sector[row+21]; *(unsigned char*)length++=fat.sector[row+28]; // datei länge, bytes 28,29,30,31. *(unsigned char*)length++=fat.sector[row+29]; *(unsigned char*)length++=fat.sector[row+30]; *(unsigned char*)length++=fat.sector[row+31]; return(0); } //*************************************************************************************************************** // geht reihen weise durch sektoren des clusters mit dem startsektor:sec, und sucht nach der datei mit dem // namen:name. es werden die einzelnen sektoren nachgeladen auf puffer:sector vor dem bearbeiten. // wird die datei in dem cluster gefunden ist return 0 , sonst return1. //*************************************************************************************************************** unsigned char fat_loadFileDataFromCluster(unsigned long int sec , char name[]){ unsigned char r; unsigned char s=0; do{ // sektoren des clusters prüfen r=0; // neuer sektor, dann reihen von 0 an. if(0==fat_loadSector(sec+s)){ // läd den sektor:sec auf den puffer:sector do{ // reihen des sektors prüfen fat_loadRowOfSector(r); // zeile 0-15 auf struct:file laden if(0==strncmp((char*)file.name,name,10)){ // zeile r ist gesuchte file.row=r; // zeile sichern. return(0); } r++; }while(r<16); // zählt zeilennummer (16(zeilen) * 32(spalten) == 512 bytes des sektors) } s++; }while(s fat_getFreeRowOfDir -> fat_makeRowDataEntry -> fat_makeFileEntry -> fat_writeSector -> eintrag gemacht !! // *************************************************************************************************************** // sucht leeren eintrag (zeile) im cluster mit dem startsektor:secStart. // wird dort kein freier eintrag gefunden ist return (1). // wird ein freier eintrag gefunden, ist die position der freien reihe auf file.row abzulesen und return (0). // der sektor mit der freien reihe ist auf dem puffer:sector gepuffert. // **************************************************************************************************************** unsigned char fat_getFreeRowOfCluster(unsigned long secStart){ unsigned char s=0; // sektoren des clusters. unsigned int i; do{ file.row=0; // neuer sektor(oder 1.sektor), reihen von vorne. if(0==fat_loadSector(secStart+s)){ // läd sektor auf puffer:buffer.dSector, setzt buffer.currentDatSector. for(i=0;i<512;i=i+32){ // zählt durch zeilen (0-15). if(fat.sector[i]==0x00||fat.sector[i]==0xE5)return(0); // prüft auf freihen eintrag (leer oder gelöscht == OK!). file.row++; // zählt reihe hoch (nächste reihe im sektor). } } s++; // sektoren des clusters ++ weil einen geprüft. }while(s neuer cluster nötig. fat_getClustersInRow(2,0); // sucht freie cluster in einer reihe dir=fat.startSectors; // muss neuen freien cluster suchen (benutzt puffer:sector). fat_setCluster(start,dir); // cluster-chain mit neuem verketten (benutzt puffer:sector). fat_setCluster(dir,0x0fffffff); // cluster-chain ende markieren (benutzt puffer:sector). fat_loadSector(fat_clustToSec(dir)); // läd neuen cluster (wenn bufferFlag==1 schreibt vorher alten cluster) !! fat_markSector00(); // löschen des sektors (nur im puffer) (benutzt puffer:sector). unsigned char i=1; do{ fat_writeSector(fat.currentSectorNr+i); // löschen des cluster (überschreibt mit 0x00), wichtig bei ffls, i++; }while(i>16; // 1. low von cluster *bytesOfSec++=(cluster&0xff000000)>>24; // high byte *bytesOfSec++=0x01; // nicht nötige felder beschreiben *bytesOfSec++=0x01; // nicht nötige felder beschreiben *bytesOfSec++=0x01; // nicht nötige felder beschreiben *bytesOfSec++=0x01; // nicht nötige felder beschreiben *bytesOfSec++=(cluster&0x000000ff); // low byte von cluster *bytesOfSec++=(cluster&0x0000ff00)>>8; // 2. low *bytesOfSec++ =*(unsigned char*)vLength++; // low von länge *bytesOfSec++ =*(unsigned char*)vLength++; // 1. hi *bytesOfSec++ =*(unsigned char*)vLength++; // 2. hi *bytesOfSec++ =*(unsigned char*)vLength; // hi return (0); // eintrag in puffer gemacht ! } //*************************************************************************************************************** // macht den datei eintrag im jetzigen verzeichniss (fat.dir). // file.row enthält die reihen nummer des leeren eintrags, der vorher gesucht wurde, auf puffer:sector ist der gewünschte // sektor gepuffert. für fat16 im root dir muss andere funktion genutzt werden, als fat_getFreeRowOfDir (durchsucht nur dirs). // fat.rootDir enthält bei fat32 den start cluster des directory, bei fat16 den 1. sektor des rootDir bereichs! //*************************************************************************************************************** unsigned char fat_makeFileEntry(char name[],unsigned char attrib,unsigned long int cluster,unsigned long int length){ unsigned int s; // zähler für root dir sektoren fat16 if(fat.dir==0&&fat.fatType==32)fat_getFreeRowOfDir(fat.rootDir); // IM ROOT DIR (fat32) else if(fat.dir==0 && fat.fatType==16){ // IM ROOT DIR (fat16) for(s=0;s<(unsigned int)(fat.dataDirSec+2-fat.rootDir);s++){ // zählt durch RootDir sektoren (errechnet anzahl rootDir sektoren). if(0==fat_getFreeRowOfCluster(fat.rootDir+s))break; // geht durch sektoren des root dir. } } else fat_getFreeRowOfDir(fat.dir); // NICHT ROOT DIR fat_makeRowDataEntry(file.row,name,attrib,cluster,length); // macht file eintrag im puffer fat_writeSector(fat.currentSectorNr); // schreibt file daten auf karte return(0); } #endif // fat funktionen: //*************************************************************************************************************** // sucht nötige folge Cluster aus der fat ! // erster daten cluster = 2, ende einer cluster chain 0xFFFF (fat16) oder 0xFFFFFFF, 0xFFFFFF8 (fat32), // stelle des clusters in der fat, hat als wert, den nächsten cluster. (1:1 gemapt)! //*************************************************************************************************************** unsigned long int fat_getNextCluster(unsigned long int oneCluster){ unsigned char *bytesOfSec; // FAT 16**************FAT 16 if(fat.fatType==16){ unsigned long int i=oneCluster>>8;; // (i=oneCluster/256)errechnet den sektor der fat in dem oneCluster ist (rundet immer ab) unsigned long int j=(oneCluster<<1)-(i<<9); // (j=(oneCluster-256*i)*2 == 2*oneCluster-512*i)errechnet das low byte von oneCluster if(0==fat_loadSector(i+fat.fatSec)){ // ob neu laden nötig, wird von fat_loadSector geprüft i=0; void *vi=&i; // zeiger auf i bytesOfSec=&fat.sector[j]; // zeiger auf puffer *(unsigned char*)vi++=*bytesOfSec++; // setzen low byte von i, aus puffer *(unsigned char*)vi++=*bytesOfSec++; // setzen von höherem byte in i, aus puffer return i; // gibt neuen cluster zurück (oder 0xffff) } } // FAT 32**************FAT 32 else{ unsigned long int i=oneCluster>>7; // (i=oneCluster/128)errechnet den sektor der fat in dem oneCluster ist (rundet immer ab) unsigned long int j=(oneCluster<<2)-(i<<9); // (j=(oneCluster-128*i)*4 == oneCluster*4-512*i)errechnet das low byte von oneCluster if(0==fat_loadSector(i+fat.fatSec)){ // ob neu laden nötig wird von fat_loadSector geprüft void *vi=&i; bytesOfSec=&fat.sector[j]; *(unsigned char*)vi++=*bytesOfSec++; *(unsigned char*)vi++=*bytesOfSec++; *(unsigned char*)vi++=*bytesOfSec++; *(unsigned char*)vi++=*bytesOfSec++; return i; } } return(0); // neuladen des fat sektors, in dem oneCluster ist nötig !! } //*************************************************************************************************************** // sucht freie sektoren oder verkettete in einer reihe ! // das flag emptyOrFirst sagt ob freie oder verkettete gesucht werden. offsetCluster ist einmal der cluster ab dem // freie gesucht werden oder der erste cluster der datei. beide male enthält fat.startSectors den ersten sektor der // reihe und fat.cntSectors die anzahl der sektoren in einer reihe! // [ fat.startSectors , fat.startSectors+fat.cntSectors ] = anzahl der sektoren !! //*************************************************************************************************************** unsigned char fat_getClustersInRow(unsigned long int offsetCluster,unsigned char emptyOrFirst){ unsigned char i; // variable für anzahl der zu suchenden sektoren if(0==emptyOrFirst){ /** SUCHEN von freien sektoren (max 255 am stück) **/ i=1; offsetCluster--; // ernidrigen, da dann inklusive diesem cluster gesucht wird do{ // suche des 1. freien offsetCluster++; // cluster nummer }while(fat_getNextCluster(offsetCluster)); // freier cluster gefunden, returnwert=0 -> abbruch fat.startSectors=fat_clustToSec(offsetCluster); // setzen des startsektors der freien sektoren (umrechnen von cluster zu sektoren) fat.endSectors=fat.startSectors; do{ // suche der nächsten freien if(0==fat_getNextCluster(offsetCluster+i) ) fat.endSectors+=fat.secPerClust; // zählen der zusammenhängenden sektoren else break; // cluster daneben ist nicht frei i++; }while(i<255); fat.endSectors+=fat.secPerClust; } else{ /** SUCHEN von verketteten sektoren der datei (max 255 am stück) **/ i=0; fat.startSectors=fat_clustToSec(offsetCluster); // setzen des 1. sektors der datei fat.endSectors=fat.startSectors; do{ if( (offsetCluster+1+i)==fat_getNextCluster(offsetCluster+i) ) fat.endSectors+=fat.secPerClust; // zählen der zusammenhängenden sektoren else { file.lastCluster=offsetCluster+i; // cluster daneben gehört nicht dazu, somit ist offset+i der letzte bekannte break; } i++; }while(i<255); fat.endSectors+=fat.secPerClust; } return 0; } #if (write==1) //*************************************************************************************************************** // bekommt cluster übergeben !!! // verkettet ab newOffsetCluster, cluster in einer reihe bis length (ist nötig zu berechnen ob schon ein neuer cluster angefangen wurde). // es ist wegen der fragmentierung der fat nötig, sich den letzten bekannten cluster zu merken, // damit man bei weiteren cluster in einer reihe die alten cluster noch dazu verketten kann (so sind lücken im verketten möglich). //*************************************************************************************************************** unsigned char fat_setClusterChain(unsigned long int newOffsetCluster,unsigned int length){ if(length==0){ // nur ein bis zu einem sektor geschrieben ? fat_setCluster(newOffsetCluster,0xfffffff); return 1; } unsigned int i=0; unsigned int tmp_length=length/fat.secPerClust; // anzahl der cluster zum verketten if( 0 != length % fat.secPerClust ) tmp_length+=1; // wenn z.b. ein sektor mehr beschrieben wurde muss ein ganzer cluster mehr verkettet werden fat_setCluster(file.lastCluster,newOffsetCluster); // ende der chain setzen do{ fat_setCluster( newOffsetCluster+i , newOffsetCluster+i+1 ); // verketten der cluster der neuen kette i++; }while( i < tmp_length ); i--; // damit ende cluster richtig gesetzt wird fat_setCluster(newOffsetCluster+i,0xfffffff); // ende der chain setzen file.lastCluster=newOffsetCluster+i; // ende cluster der kette updaten fat_writeSector(fat.currentSectorNr); return 0; } //*************************************************************************************************************** // setzt den cluster inhalt. errechnet den sektor der fat in dem cluster ist, errechnet das low byte von // cluster und setzt dann byteweise den inhalt:content. // prüft ob buffer dirty (zu setztender cluster nicht in jetzt gepuffertem). // prüfung erfolgt in fat_loadSector, dann wird alter vorher geschrieben, sonst gehen dort daten verloren !! //*************************************************************************************************************** unsigned char fat_setCluster(unsigned long int cluster, unsigned long int content){ unsigned char *bytesOfSec; // FAT 16**************FAT 16 if(fat.fatType==16){ unsigned long int i=cluster>>8; // (i=cluster/256)errechnet den sektor der fat in dem cluster ist (rundet immer ab) unsigned long int j=(cluster<<1)-(i<<9); // (j=(cluster-256*i)*2 == 2*cluster-512*i)errechnet das low byte von cluster if(0==fat_loadSector(i+fat.fatSec)){ // neu laden (fat_loadSector prüft ob schon gepuffert) bytesOfSec=&fat.sector[j]; // init des zeigers auf low byte void *vc=&content; // init des zeigers auf content *bytesOfSec++=*(unsigned char*)vc++; // setzen von 2 byte.. *bytesOfSec++=*(unsigned char*)vc++; fat.bufferDirty=1; // zeigt an, dass im aktuellen sector geschrieben wurde return (0); } } // FAT 32**************FAT 32 else{ unsigned long int i=cluster>>7; // (i=cluster/128)errechnet den sektor der fat in dem cluster ist (rundet immer ab) unsigned long int j=(cluster<<2)-(i<<9); //(j=(cluster-128*i)*4 == cluster*4-512*i)errechnet das low byte von cluster if(0==fat_loadSector(i+fat.fatSec)){ // neu laden (fat_loadSector prüft ob schon gepuffert) bytesOfSec=&fat.sector[j]; // init des zeigers auf low byte void *vc=&content; // init des zeigers auf content *bytesOfSec++=*(unsigned char*)vc++; // setzen von 4 byte.... *bytesOfSec++=*(unsigned char*)vc++; *bytesOfSec++=*(unsigned char*)vc++; *bytesOfSec++=*(unsigned char*)vc++; fat.bufferDirty=1; // zeigt an, dass im aktuellen sector geschrieben wurde return (0); } } return(1); // neuladen des fat sektors, in dem oneCluster ist, nötig !! } //*************************************************************************************************************** // löscht cluster chain, beginnend ab dem startCluster. // sucht cluster, setzt inhalt usw.. abschließend noch den cluster-chain ende markierten cluster löschen. //*************************************************************************************************************** void fat_delClusterChain(unsigned long int startCluster){ unsigned long int nextCluster=startCluster; // tmp variable, wegen verketteter cluster.. do{ startCluster=nextCluster; nextCluster=fat_getNextCluster(startCluster); fat_setCluster(startCluster,0x00000000); }while(!((nextCluster==0xfffffff&&fat.fatType==32)||(nextCluster==0xffff&&fat.fatType==16))); fat_writeSector(fat.currentSectorNr); } #endif //*************************************************************************************************************** // Initialisiert die Fat(16/32) daten, wie: root directory sektor, daten sektor, fat sektor... // siehe auch Fatgen103.pdf. ist NICHT auf performance optimiert! // byte/sector, byte/cluster, anzahl der fats, sector/fat ... (halt alle wichtigen daten zum lesen ders datei systems!) //*****************************************************************<********************************************** unsigned char fat_loadFatData(unsigned long int sec){ // offset,size unsigned int rootEntCnt; // 17,2 größe die eine fat belegt unsigned int fatSz16; // 22,2 sectors occupied by one fat16 unsigned long int fatSz32; // 36,4 sectors occupied by one fat32 if(0==mmc_read_sector(sec,fat.sector)){ // lesen von fat sector und bestimmen der wichtigen berreiche fat.bufferDirty = 0; // init wert des flags fat.secPerClust=fat.sector[13]; // fat.secPerClust, 13 only (power of 2) fat.fatSec=fat.sector[15]; // resvdSecCnt->1.fat sektor, 15 high nibble 14 low nibble fat.fatSec=fat.fatSec<<8; fat.fatSec+=fat.sector[14]; rootEntCnt=fat.sector[18]; // rootEntCnt, 18 high nibble 17 low nibble rootEntCnt=rootEntCnt<<8; rootEntCnt+=fat.sector[17]; fatSz16=fat.sector[23]; // fatSz16, 23 high nibble 22 low nibble fatSz16=fatSz16<<8; fatSz16+=fat.sector[22]; fat.rootDir = (((rootEntCnt <<5) + 512) /512)-1; // ist 0 bei fat 32, sonst der root dir sektor if(fat.rootDir==0){ // FAT32 spezifisch (die prüfung so, ist nicht spezifikation konform !). void *vFatSz32=&fatSz32; // void pointer auf fatSz32 zum schreiben von 4 bytes *(unsigned char*)vFatSz32++=fat.sector[36]; // lowest byte *(unsigned char*)vFatSz32++=fat.sector[37]; // 1. higher byte *(unsigned char*)vFatSz32++=fat.sector[38]; // 2. higher byte *(unsigned char*)vFatSz32=fat.sector[39]; // high byte void *rootDir=&fat.rootDir; // void pointer auf fat.rootDir zum schreiben von 4 bytes. *(unsigned char*)rootDir++=fat.sector[44]; // lowest byte *(unsigned char*)rootDir++=fat.sector[45]; // 1. higher byte *(unsigned char*)rootDir++=fat.sector[46]; // 2. higher byte *(unsigned char*)rootDir=fat.sector[47]; // high byte fat.dataDirSec = fat.fatSec + (fatSz32 * fat.sector[16]); // data sector (beginnt mit cluster 2) fat.fatType=32; // fat typ } else{ // FAT16 spezifisch fat.dataDirSec = fat.fatSec + (fatSz16 * fat.sector[16]) + fat.rootDir; // data sektor (beginnt mit cluster 2) fat.rootDir=fat.dataDirSec-fat.rootDir; // root dir sektor, da nicht im datenbereich (cluster) fat.rootDir+=sec; // addiert den startsektor auf " fat.fatType=16; // fat typ } fat.fatSec+=sec; // addiert den startsektor auf fat.dataDirSec+=sec; // addiert den startsektor auf (umrechnung von absolut auf real) fat.dataDirSec-=2; // zeigt auf 1. cluster fat.dir=0; // dir auf '0'==root dir, sonst 1.Cluster des dir return (0); } return (1); // sector nicht gelesen, fat nicht initialisiert!! } //************************************************************************************************<<*************** // int fat sucht den 1. cluster des dateisystems (fat16/32) auch VBR genannt, // wenn superfloppy==0 wird der MBR ausgelesen um an VBR zu kommen. //************************************************************************************************<<*************** unsigned char fat_initfat(void){ unsigned long int secOfFirstPartition=0; // ist 1. sektor der 1. partition aus dem MBR if(superfloppy==0){ // ist partitioniert if(0==mmc_read_sector(0,fat.sector)){ void *vSecOfFirstPartition=&secOfFirstPartition; *(unsigned char*)vSecOfFirstPartition++=fat.sector[454]; *(unsigned char*)vSecOfFirstPartition++=fat.sector[455]; *(unsigned char*)vSecOfFirstPartition++=fat.sector[456]; *(unsigned char*)vSecOfFirstPartition++=fat.sector[457]; return fat_loadFatData(secOfFirstPartition); // läd fat daten aus dem 1. sektor der patition } } else { return fat_loadFatData(secOfFirstPartition); // ist nicht partitioniert, läd fat daten aus sektor 0 } return (1); } #if (smallFileSys==0) // ***************************************************************************************************************** // bereitet str so auf, dass man es auf die mmc/sd karte schreiben kann. // wandelt z.b. "t.txt" -> "T TXT" oder "main.c" in "MAIN C " => also immer 8.3 und upper case letter // VORSICHT es werden keine Prüfungen gemacht ! // ***************************************************************************************************************** char * fat_str(char *str){ unsigned char i; unsigned char j=0; unsigned char c; char tmp[12]; // tmp string zum einfacheren umwandeln strcpy(tmp,str); for(i=0;i<11;i++)str[i]=' '; // als vorbereitung alles mit leerzeichen füllen str[11]='\0'; i=0; do{ c=toupper(tmp[j]); if(c=='\0')return str; if(c!='.')str[i]=c; else i=7; i++; j++; }while(i<12); return str; } #endif