C1541-III mbed edition

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers fat.c Source File

fat.c

00001 /*-----------------------------------------------------------------------------------*/
00002 /* This is a simple FAT16 handler. It works on a sector basis to allow fastest acces */
00003 /* on disk images.                                                                   */
00004 /*                                                                                     */
00005 /* Attention: when using Roadkill sector editor, chose the physical disk, and not the*/
00006 /* drive number, otherwise the calculated sectors will not allways be the identical  */
00007 /*-----------------------------------------------------------------------------------*/
00008 /*    History:
00009     2008-02-08    fixed the problem regarding the backwards searching within subdirectories
00010                 As this only is a problem with the use of the buttons... it was discovered at the last moment and now it is fixed. Subdirectories are now FULLY functional <hurray>
00011     2008-02-01    improved filesearch routine for subdirectory support, it appears to work
00012     2008-01-18    worked on opendirectory
00013     2008-01-14    corrected a small bug, because of the ASCII to PETSCII conversiuon, the calculation of the 8.3 checksum was incorrect
00014                 by using the RAW-data (unconverted filename) the checksum can be calculated as it should and it all works while keeping readable characters on your retro computer
00015     2008-01-09    improved routine opensubdirectory(), suddenly it all works (hurray)
00016     2008-01-07    added routine opensubdirectory(), this makes suport of subdirectories a fact
00017     2007-12-20    added ASCII to PETSCII routines
00018     2007-12-19    playing with longfilenames
00019     2007-04-07    Mattias Olsson reported the following bugfix:
00020                 By changing every occurrence of: sb+=clustersize*(file->cluster-2);
00021                 to :                             sb+=(unsigned long)clustersize*(file->cluster-2); 
00022                 I can now load every file on the card. This bug caused problem when a lot of files were stored on the card (i.e. more then 340).
00023                 Thanks Mattias, this saved me a lot of work, these bugs are the worst to fix.
00024     2006-12-15    fixed a small bug important bug in the FATSTART calculation (566 and 567 instead of 556 and 557)
00025                 depending on your card it should not cause to much trouble...
00026     2006-09-03    renamed "databuffer" to "block_buffer" since this is a more appropriate name
00027     2006-08-21    added more debugging info in order to find the problem regarding the problems with some card not being supported...
00028     2006-04-11    improved 'FindDrive' routine to support cards without a partition table
00029     2006-02-03    added filesize to file structure (userfull for simple and quick file type validation of fixedsize files (i.e. D64-files))
00030     2006-02-02    improvements in code layout... i.o.w. making it more readable
00031     2006-02-02    also the sector number is relevant... fixed it
00032     2006-02-01    added cache-ing regarding sector locations
00033     2006-01-31    worked out how to write the byte addressable read routine
00034     2006-01-29    added first steps for byte addressable read routine (read X bytes from startaddress Y)
00035     2005-12-23    added current file search option
00036     2005-12-11    first version, ported from FAT1618.C
00037 */
00038 
00039 /* TO DO:
00040    ------
00041     - FileSectorScan(struct file2TYPE *file) routine iets aanpassen zodat we niet falen op de theoretisch laatste 'filenextsector'
00042 */
00043 
00044 /*----------------------------------------------------------------------------------*/
00045                 
00046 /*--------------------------------------------------------*/
00047 /*                        includes                        */
00048 /*--------------------------------------------------------*/
00049 #include <stdio.h>
00050 #include <main.h>
00051 #include <ata.h>
00052 #include <fat.h> 
00053 
00054 /*--------------------------------------------------------*/
00055 /*                        constants                       */   
00056 /*--------------------------------------------------------*/
00057 #define        FALSE                            0            /*FALSE*/
00058 #define        TRUE                            1            /*TRUE*/
00059 
00060 /*Since the size of a D64 file is fixed the number of sectors required for a D64 file is also fixed*/
00061 /*In order to keep compatibillity with most of the .D64 formats we must be able to handle the biggest,*/
00062 /*so thats 40tracks including error bytes*/
00063 #define        D64FileConsistsOfSectors        386            /*(768(40tracks disk) * 256(bytes per block)) / 2 = 384 x 512(bytes per block), including the 768 error bytes (1.5x512) that would make a total of 386 blocks*/
00064 
00065 /*--------------------------------------------------------*/
00066 /*                         globals                        */
00067 /*--------------------------------------------------------*/
00068 static unsigned long fatstart;                    /*start LBA of first FAT table*/
00069 static unsigned char fatno;                     /*number of FAT tables*/
00070 static unsigned long datastart;                   /*start LBA of data field*/
00071 static unsigned long rootstart;                   /*start LBA of rootdirectory table*/
00072 static unsigned short direntrys;                 /*number of entry's in directory table*/
00073 static unsigned short direntrys_root;              /*number of entry's in directory table*/
00074 static unsigned char clustersize;                 /*size of a cluster in blocks*/
00075 static unsigned short subdircluster_start;        /*starting cluster of subdirectory*/
00076 static unsigned short subdirsec_start;            /*starting cluster of subdirectory*/
00077 #define bit bool
00078 static bit root;
00079 
00080 
00081 unsigned short clusterlocationcache[D64FileConsistsOfSectors];            /*cache for the sector locations within the D64 file as stored in the Fat16*/
00082 
00083 /*--------------------------------------------------------*/
00084 /*                     local functions                    */
00085 /*--------------------------------------------------------*/
00086 
00087 unsigned char ASCII_to_PETSCII(unsigned char ASCII);
00088 
00089 /*****************************************************************************************************************/
00090 /*****************************************************************************************************************/
00091 
00092 /*FindDrive checks if a card is present. if a card is present it will check for
00093 a valid FAT16 primary partition*/
00094 unsigned char FindDrive(void)
00095 {
00096     unsigned char error_code;
00097     unsigned long fatsize;                /*size of fat*/
00098     unsigned long dirsize;                /*size of directory region in sectors*/
00099         
00100     error_code = AtaReadSector(0,block_buffer);    /*read partition sector*/
00101     if (error_code != TRUE)
00102     {
00103         return(error_code);
00104     }
00105     
00106     /*Check for partition table, when this can not be found then set "fatstart=0" (to support cards (SUPERFLOPPY's) that have no partition table) and to support extended partitions*/
00107     if(block_buffer[450]!=0x04 && block_buffer[450]!=0x05 && block_buffer[450]!=0x06)/*check partition type*/
00108         fatstart=0;
00109     else if(block_buffer[510]!=0x55 || block_buffer[511]!=0xaa)    /*check signature*/        
00110         fatstart=0;
00111     else
00112     {
00113         fatstart=(unsigned long)block_buffer[454];                /*get start of first partition*/
00114         fatstart+=(unsigned long)block_buffer[455]*256;
00115         fatstart+=(unsigned long)block_buffer[456]*65536;
00116         fatstart+=(unsigned long)block_buffer[457]*16777216;
00117     }
00118             
00119     if(!AtaReadSector(fatstart,block_buffer))                    /*read boot sector*/
00120         return(ERROR_FAT_READBOOTSECTOR);    
00121     
00122     if(block_buffer[0]!=0xe9 && block_buffer[0]!=0xeb)            /*check for near-jump or short-jump opcode*/
00123         return(ERROR_FAT_JUMPOPCODE);
00124     
00125     if(block_buffer[11]!=0x00 || block_buffer[12]!=0x02)        /*check if blocksize is really 512 bytes*/
00126         return(ERROR_FAT_BLOCKSIZE);
00127     
00128     if(block_buffer[21]!=0xf8)                                    /*check medium descriptorbyte, must be 0xf8 for hard drive*/
00129         return(ERROR_FAT_MEDIUM);
00130     
00131     direntrys=block_buffer[17]+(block_buffer[18]*256);            /*calculate drive's parameters from bootsector, first up is size of directory*/
00132     direntrys_root = direntrys;
00133     dirsize=((direntrys*32)+511)/512;                  
00134     
00135     fatstart=fatstart+block_buffer[14]+(block_buffer[15]*256);    /*calculate start of FAT,size of FAT and number of FAT's*/
00136     fatsize=block_buffer[22]+(block_buffer[23]*256);
00137     fatno=block_buffer[16];
00138     
00139      rootstart=fatstart+(fatno*fatsize);                            /*calculate start of root-directory*/
00140      clustersize=block_buffer[13];                                /*get clustersize*/
00141     datastart=rootstart+dirsize;                                  /*calculate start of data*/   
00142     root=TRUE;                                                     /*raise flag to indicate we are in the root directory*/
00143       return(TRUE);
00144 }
00145 
00146 /*this routine needs to be called when a subdirectory is entered*/
00147 /*this routine re-calculates the current directroy pointers and registers to those of the (sub)directory to be opened*/ 
00148 /*this routine returns TRUE when the subdirectory is a subdirectory and FALSE when it is root*/
00149 unsigned char OpenSubDirectory(struct file2TYPE *file)
00150 {
00151     /*calculate the location of the first byte of the new (sub)directory*/
00152     if(file->cluster == 0)                                    /*check if the user requests the root directory*/
00153     {                                                        /*---------------------------------------------*/
00154         root=TRUE;                                              /*raise flag to indicate we are in the root directory*/
00155         direntrys = direntrys_root;
00156         return(FALSE);                                        /*we are now back in root*/
00157     }
00158     else
00159     {
00160         root=FALSE;                                         /*lower flag to indicate we are NOT in the root directory*/
00161         direntrys = 1000;                                     /*a fixed value that is practically impossible to use on a CBM computer*/
00162         subdircluster_start = file->cluster;                /*starting cluster of subdirectory*/    
00163         subdirsec_start = file->sec;                        /*starting sector offset within cluster*/
00164         return(TRUE);                                        /*we are now in a subdirectory*/
00165     }    
00166 }
00167 
00168 /*scan directory, yout must pass a file handle to this function*/
00169 /*search modes: 0=first,1=next(8.3 AND LFN),2=previous(8.3 only),3=current*/
00170 unsigned char FileSearch(struct file2TYPE *file, unsigned char mode)
00171 {
00172     static unsigned short subdircluster_current;    /*current cluster of subdirectory*/
00173     static unsigned short subdirsec_current;        /*current sector offset within cluster*/
00174     static unsigned char sectorcounter;                /*a relative counter, to keep track of how many sectors we've read regarding this subdirectory*/
00175     /*sectorcounter: this is an unsigned char, meaning that this limits a subdir to have "only" 255*16 8.3 file entries. Which is a lot for a retro computer*/
00176 
00177     unsigned long sf,sb;
00178     unsigned short i;
00179     unsigned char j;
00180 
00181     unsigned short LFN_offset;
00182     unsigned char LFN_seq_nmbr;
00183     unsigned char LFN_string[27];    /*the length of the LFN name we use is max 26 characters (2 LFN entries)*/
00184     unsigned char LFN_checksum[2];    /*since we use only two LFN entries, we only need to store 2 checksums*/
00185     unsigned char REF_checksum;        /*the checksum which is our reference*/
00186 
00187     LFN_checksum[0] = 0;            /*clear the checksum value of the 1st LFN sequence*/
00188     LFN_checksum[1] = 0;            /*clear the checksum value of the 2nd LFN sequence*/
00189     
00190     sb=0;                            /*buffer is empty*/
00191     if(mode==0)            /*search for first entry*/
00192     {                    /*----------------------*/
00193         file->entry=0;
00194         if (root == FALSE)
00195         {
00196             file->cluster = subdircluster_start;            /*reset the cluster pointer back to the beginning of the directory, otherwise we fail with the filenextsector routine*/
00197             file->sec = subdirsec_start;                    /*starting sector offset within cluster*/
00198             subdircluster_current = file->cluster;
00199             subdirsec_current = file->sec;
00200             sectorcounter = 0;
00201         }
00202     }
00203     else if(mode==1)    /*search for next entry*/
00204     {                    /*---------------------*/
00205         file->entry++;
00206     }
00207     else if(mode==2)    /*search for previous entry*/
00208     {                    /*-------------------------*/
00209         file->entry--;
00210     }
00211 
00212     while(file->entry<direntrys)
00213     {    
00214         if (root == TRUE)            /*the root directory is one continuos chunk of entries*/
00215         {                            /*----------------------------------------------------*/
00216             sf=rootstart;            /*calculate sector and offset*/
00217             sf+=(file->entry)/16;    /*16 entries fit into one sector, so when entry = 16 (or 32,48, etc), we need to load a new sector (indicated by SF incremented by one)*/
00218     
00219             if(sb!=sf)                /*when buffer is empty or needs to be changed*/
00220             {
00221                 sb=sf;
00222                 if(!AtaReadSector(sb,block_buffer))
00223                     return(FALSE);    
00224             }
00225         }
00226         else                        /*subdirectory entries can be scattered all over the disk, so in order to determine where the next cluster is we need to lookup this info in the FAT*/
00227         {                            /*--------------------------------------------------------------------------------------------------------------------------------------------------*/
00228             if((mode==1) && (file->entry > 0) && (file->entry%16 == 0))    /*load sector if not in buffer*/
00229             {
00230                 file->cluster = subdircluster_current;                    /*retrieve the latest cluster value*/
00231                 file->sec = subdirsec_current;                            /*retrieve the latest sector value*/    
00232                 if (FileNextSector(file) == FALSE)                        /*attention: screws up block_buffer!!*/
00233                     return(FALSE);
00234                 sectorcounter++;                                        /*another sector loaded, increment counter*/
00235                 subdircluster_current = file->cluster;                    /*save the new value for later*/
00236                 subdirsec_current = file->sec;                            /*save the new value for later*/
00237     
00238                 if ((file->cluster & 0xFFF8) ==  0xFFF8)                /*check if this is the last cluster*/
00239                 {
00240                     file->len=0;    
00241                     return(FALSE);
00242                 }
00243             }
00244 
00245 
00246              if((mode==2) &&  ((file->entry + 1) > 0) && ((file->entry+1)%16 == 0))    /*load sector if not in buffer*/
00247             {
00248                 /*because directory are not designed to be read in a reverse direction, we need to rescan the previous clusterchain in order to find the previous cluster*/
00249                 /*this is the only way because FAT only stores the next cluster, which is useless if you want the previous. So we start at the first cluster and skip all cluster untill we reach the desired (previous from the current)*/
00250                 file->cluster = subdircluster_start;                    /*reset the cluster pointer back to the beginning of the directory, otherwise we fail with the filenextsector routine*/
00251                 file->sec = subdirsec_start;                            /*starting sector offset within cluster*/
00252                 if (sectorcounter > 0)
00253                 {
00254                     sectorcounter--;                                    /*previous sector found, decrement counter*/
00255                     for(j=0;j<sectorcounter;j++)
00256                     {
00257                         if (FileNextSector(file) == FALSE)                /*attention: screws up block_buffer!!*/
00258                             return(FALSE);
00259                     }        
00260                 }
00261                 subdircluster_current = file->cluster;                    /*save the new value for later*/
00262                 subdirsec_current = file->sec;                            /*save the new value for later*/
00263             }        
00264 
00265             sf=datastart;                                                /*start of data in partition*/
00266             sf+=(unsigned long)clustersize*(subdircluster_current-2);    /*cluster offset*/
00267             sf+=(subdirsec_current%clustersize);                         /*sector offset in cluster*/
00268             if(sb!=sf)                                                    /*when buffer is empty or needs to be changed*/
00269             {
00270                 sb=sf;
00271                 if(!AtaReadSector(sb,block_buffer))
00272                     return(FALSE);    
00273             }
00274         }
00275 
00276         i=(file->entry%16)*32;            /*i is the pointer that points to the address of the entry within the loaded sector*/
00277         if(block_buffer[i+0x0b]==0x0f)    /*check if this entry is an LFN entry*/
00278         {
00279             //if(block_buffer[i]<=0x55)    /*check the LFN sequence number the highest possible value would be 0x55 (20th entry which is the last entry (0x15 OR-ed with 0x40)*/
00280             if(block_buffer[i]<=0x42)    /*check the LFN sequence number. Although the highest possible value would be 0x55, this application only uses 2 LFN entries (26 chars), since we can only display 16 characters within a CBM directory*/
00281             {
00282                 LFN_seq_nmbr = block_buffer[i] & 0x3f;    /*remove the possible 0x40 in order to keep the bare LFN sequence number*/
00283                 LFN_offset = (LFN_seq_nmbr * 13) - 13;
00284 
00285                 /*save the LFN characters to the correct location of our string*/
00286                 LFN_string[LFN_offset + 0] = block_buffer[i+0x01];    /*5 UTF characters of which we only use the first byte*/
00287                 LFN_string[LFN_offset + 1] = block_buffer[i+0x03];
00288                 LFN_string[LFN_offset + 2] = block_buffer[i+0x05];
00289                 LFN_string[LFN_offset + 3] = block_buffer[i+0x07];
00290                 LFN_string[LFN_offset + 4] = block_buffer[i+0x09];
00291 
00292                 LFN_checksum[LFN_seq_nmbr-1] = block_buffer[i+0x0d];/*save the checksum*/
00293 
00294                 LFN_string[LFN_offset + 5] = block_buffer[i+0x0e];    /*6 UTF characters of which we only use the first byte*/
00295                 LFN_string[LFN_offset + 6] = block_buffer[i+0x10];
00296                 LFN_string[LFN_offset + 7] = block_buffer[i+0x12];
00297                 LFN_string[LFN_offset + 8] = block_buffer[i+0x14];
00298                 LFN_string[LFN_offset + 9] = block_buffer[i+0x16];
00299                 LFN_string[LFN_offset + 10] = block_buffer[i+0x18];
00300 
00301                 LFN_string[LFN_offset + 11] = block_buffer[i+0x1c];    /*2 UTF characters of which we only use the first byte*/
00302                 LFN_string[LFN_offset + 12] = block_buffer[i+0x1e];
00303     
00304             /*the following code is not required as we only use two LFN entries which we compare with a checksum later*/
00305             /*the code below is left for reference for LFN filenames which must be longer then 26chars*/
00306             //    if(block_buffer[i]&0x40 == 0x40)                    /*check if this entry was the last LFN entry belonging to this file*/
00307             //    {                                                    /*we do this by checking if the 6st bit was set*/
00308             //        LFN_string[LFN_offset + 13] = 0;                /*terminate string HERE*/
00309             //    }
00310             }
00311         }
00312 
00313         if(block_buffer[i]!=0x00 && block_buffer[i]!=0xe5)                /*check if valid file entry: 0x00 = entry is available*/
00314         {    /*                                                                                       0xE5 = entry has been erased*/
00315             if((block_buffer[i+0x0b]&0x0a)==0x00)                        /*check atributes: do not show hidden files, do not show volume labels, DO SHOW subdirectories*/
00316             {
00317                 for(j=0;j<11;j++)                                       /*copy name (8.3)*/
00318                     file->name[j] = ASCII_to_PETSCII(block_buffer[i+j]); /*copy each character and substitute the following ASCII-chars to PETSCII alternatives. Because we convert it here, we do not have to convert it back in the file search routines which effectively results in simpler and (even better) shorter code*/
00319                 file->name[j]=0x00;                                        /*terminate the string*/
00320             
00321                 file->len=(unsigned long)block_buffer[j+28];            /*get length of file in sectors, maximum is 16Mbytes*/
00322                 file->len+=(unsigned short)block_buffer[i+29]*256;
00323                 file->len+=511;
00324                 file->len/=512;
00325                 file->len+=(unsigned long)block_buffer[i+30]*128;
00326                         
00327                 file->cluster=(unsigned long)block_buffer[i+26]+((unsigned long)block_buffer[i+27]*256);    /*get first cluster of file*/            
00328                 file->size = (unsigned long)block_buffer[i+28]+((unsigned long)block_buffer[i+29]*256)+((unsigned long)block_buffer[i+30]*65536)+((unsigned long)block_buffer[i+31]*16777216);
00329                 file->sec=0;                                                                    /*reset sector index*/                        
00330 
00331                 REF_checksum = 0;                                    /*calculate the checksum of the 8.3 filename*/ 
00332                 for (j=0;j<11;j++)                                    /*this checksum is our reference to which we compare the LFN checksum(s) with*/
00333                     REF_checksum = (((REF_checksum & 1) << 7) | ((REF_checksum & 0xfe) >> 1)) + block_buffer[i+j]; 
00334 
00335                 if(LFN_checksum[0] == REF_checksum)                    /*using the checksum we determine wether we use the gathered LFN information*/
00336                 {
00337                     for(j=0;j<13;j++)                                   /*copy the first 13 characters of the LFN string (maintain case)*/
00338                         file->name_lfn[j] = ASCII_to_PETSCII(LFN_string[j]); /*substitute the following ASCII-chars to PETSCII alternatives. Because we convert it here, we do not have to convert it back in the file search routines which effectively results in simpler and (even better) shorter code*/
00339 
00340                     if(LFN_checksum[1] == REF_checksum)
00341                     {
00342                         for(j=12;j<26;j++)                           /*copy the last few characters of the LFN string so that we have a total of max. 16 characters (maintain case)*/
00343                             file->name_lfn[j] = ASCII_to_PETSCII(LFN_string[j]); /*substitute the following ASCII-chars to PETSCII alternatives. Because we convert it here, we do not have to convert it back in the file search routines which effectively results in simpler and (even better) shorter code*/
00344                         file->name_lfn[26]=0x00;                    /*terminate string*/
00345                     }
00346                     else
00347                         file->name_lfn[13]=0x00;                    /*terminate string*/
00348                 }
00349                 else
00350                 {
00351                     file->name_lfn[0]=0;            /*clear the LFN string by terminating at the first char*/
00352                 }
00353 
00354                 return(TRUE);
00355             }
00356         }
00357         if(mode==2)
00358             file->entry--;
00359         else
00360             file->entry++;
00361     }
00362     file->len=0;        
00363     return(FALSE);
00364 }
00365 
00366 
00367 /*this routine will scan for the startaddress of all possible sectors that hold a D64 file*/
00368 unsigned char FileSectorScan(struct file2TYPE *file)
00369 {
00370     unsigned int lp;
00371 
00372     for(lp=0; lp<(D64FileConsistsOfSectors-1); lp++)        
00373     {
00374         clusterlocationcache[lp] = file->cluster;
00375         if (FileNextSector(file) == FALSE)                /*attention: screws up block_buffer!!*/
00376             return(FALSE);
00377     }
00378     clusterlocationcache[D64FileConsistsOfSectors-1] = file->cluster;
00379 
00380     return(TRUE);
00381 }
00382 
00383 
00384 /*point to next sector in file*/
00385 unsigned char FileNextSector(struct file2TYPE *file)
00386 {
00387     unsigned long sb;
00388     unsigned short i;
00389     
00390     file->sec++;                        /*increment sector index*/
00391     if((file->sec%clustersize)==0)        /*if we are now in another cluster, look up cluster*/
00392     {
00393         sb=fatstart;                    /*calculate sector that contains FAT-link*/
00394         sb+=(file->cluster/256);
00395         i=(file->cluster%256);            /*calculate offset*/
00396         i*=2;
00397         
00398         if(!AtaReadSector(sb,block_buffer))    /*read sector of FAT*/
00399             return(FALSE);
00400             
00401         file->cluster=((unsigned short)block_buffer[i+1]*256)+(unsigned short)block_buffer[i];    /*get FAT-link*/
00402     }
00403     return(TRUE);
00404 }
00405 
00406 /*read current sector into buffer*/
00407 unsigned char FileReadSector(struct file2TYPE *file)
00408 {
00409     unsigned long sb;
00410     
00411     sb=datastart;                                        /*start of data in partition*/
00412     sb+=(unsigned long)clustersize*(file->cluster-2);    /*cluster offset*/
00413     sb+=(file->sec%clustersize);                         /*sector offset in cluster*/
00414                             
00415     if(!AtaReadSector(sb,block_buffer))                    /*read the data from the sector*/
00416         return(FALSE);
00417     else
00418         return(TRUE);
00419 }
00420 
00421 /*read specified sector into buffer*/
00422 unsigned char FileReadSector_X(struct file2TYPE *file, unsigned long block)
00423 {
00424     unsigned long sb;
00425     
00426     file->cluster = clusterlocationcache[block];        /*retrieve the sector address from the cache*/
00427     file->sec = block;                                    /*we need to indicate the exact sector number within this cluster*/
00428 
00429     sb=datastart;                                        /*start of data in partition*/
00430     sb+=(unsigned long)clustersize*(file->cluster-2);    /*cluster offset*/
00431     sb+=(file->sec%clustersize);                         /*sector offset in cluster*/
00432 //    sb+=pt;                                                /*add the pointer offset to the absolute address of the data position as stored on the card*/
00433 
00434     if(!AtaReadSector(sb,block_buffer))                    /*read the data from the sector*/
00435         return(FALSE);
00436     else
00437         return(TRUE);
00438 }
00439 
00440 /*Read xxx bytes from a sector into a specified buffer*/
00441 /*When only one or more bytes are required, then this routine comes in handy...*/
00442 unsigned char FileRead_X_Bytes(struct file2TYPE *file, unsigned long startaddress, unsigned int NmbrOfBytes)
00443 {
00444     unsigned long lp, pt, bytesfromcurrentsector, bytesfromnextsector;
00445     unsigned long sb;
00446 
00447     lp = startaddress/512L;                /*determine how many (512byte) sectors we must skip before we find our desired byte (512=size of a MMC and SD-card sector)*/
00448     pt = startaddress%512L;                /*the byte we are looking for is pointed to by "cardbuffer_pnt"*/
00449     
00450     /*check if the bytes we want to read beyond the sector border*/
00451     if ((pt + NmbrOfBytes) < 512L)
00452     {
00453         bytesfromcurrentsector = NmbrOfBytes;    /*the number of bytes that can be read from the now selected sector*/
00454         bytesfromnextsector = 0;                /*the number of bytes that can cannot be read from the now selected sector and must be read from the next sector*/
00455     }
00456     else
00457     {
00458         bytesfromcurrentsector = 512L - pt;                            
00459         bytesfromnextsector = NmbrOfBytes - bytesfromcurrentsector;    
00460     }
00461 
00462     file->cluster = clusterlocationcache[lp];        /*retrieve the sector address from the cache*/
00463     file->sec = lp;                        /*we need to indicate the exact sector number within this cluster*/
00464 
00465     sb=datastart;                        /*start of data in partition*/
00466     sb+=(unsigned long)clustersize*(file->cluster-2);    /*cluster offset*/
00467     sb+=(file->sec%clustersize);         /*sector offset in cluster*/
00468 //    sb+=pt;                                /*add the pointer offset to the absolute address of the data position as stored on the card*/
00469     if(!AtaRead_X_Bytes(sb, pt, block_buffer, bytesfromcurrentsector))        /*read data (a part of the current sector) from drive*/
00470         return(FALSE);
00471 
00472     if (bytesfromnextsector !=0)
00473     {
00474         file->cluster = clusterlocationcache[lp+1];    /*retrieve the sector address from the cache*/
00475         file->sec = lp+1;                    /*we need to indicate the exact sector number within this cluster*/
00476 
00477         sb=datastart;                        /*start of data in partition*/
00478         sb+=(unsigned long)clustersize*(file->cluster-2);    /*cluster offset*/
00479         sb+=(file->sec%clustersize);         /*sector offset in cluster*/
00480         if(!AtaRead_X_Bytes(sb, 0, &block_buffer[bytesfromcurrentsector+1], bytesfromnextsector))        /*read data (a part of the current sector) from drive*/
00481             return(FALSE);
00482     }
00483     return(TRUE);
00484 }
00485 
00486 /*Write the specified block to the card*/
00487 unsigned char FileWriteSector_X(struct file2TYPE *file, unsigned long block)
00488 {
00489     unsigned long sb;
00490     
00491     file->cluster = clusterlocationcache[block];    /*retrieve the sector address from the cache*/
00492     file->sec = block;                                    /*we need to indicate the exact sector number within this cluster*/
00493 
00494     sb=datastart;                        /*start of data in partition*/
00495     sb+=(unsigned long)clustersize*(file->cluster-2);    /*cluster offset*/
00496     sb+=(file->sec%clustersize);         /*sector offset in cluster*/
00497 //    sb+=pt;                                /*add the pointer offset to the absolute address of the data position as stored on the card*/
00498     if(!AtaWriteSector(sb,block_buffer))    /*write data to medium*/
00499         return(FALSE);
00500 
00501     return(TRUE);
00502 }
00503 
00504 
00505 /***************************************************************************************************************************************/
00506 
00507 /*convert ASCII to PETSCII: substitute the following ASCII-chars to PETSCII alternatives*/                
00508 unsigned char ASCII_to_PETSCII(unsigned char ASCII)
00509 {
00510     unsigned char PETSCII;
00511 
00512     if ((ASCII >= 'a') && (ASCII <= 'z'))    /*check if the ASCII character is lowercase*/
00513     {
00514         ASCII = ASCII - 0x20;     /*convert lowercase to UPPERCASE*/
00515     }
00516 
00517     switch (ASCII)
00518             {    
00519                 case 0x5e:            /*^-sign (caret)*/
00520                 {
00521                     PETSCII = 0xb1;    /*PETSCII small 4 pixel upsidedown T located at the top*/
00522                     break;
00523                 }
00524 
00525                 case 0x5F:            /*_-sign (underscore)*/
00526                 {
00527                     PETSCII = 0xa4;    /*PETSCII underscore*/
00528                     break;
00529                 }
00530 
00531                 case 0x60:            /*'-sign (single quote)*/
00532                 {
00533                     PETSCII = 0xbe;    /*PETSCII 4pixel square located top left*/
00534                     break;
00535                 }
00536 
00537                 case 0x7b:            /*{-sign (bracket left)*/
00538                 {
00539                     PETSCII = 0x5b;    /*PETSCII squared bracket left*/
00540                     break;
00541                 }
00542 
00543                 case 0x7d:            /*}-sign (bracket right)*/
00544                 {
00545                     PETSCII = 0x5d;    /*PETSCII squared bracket right*/
00546                     break;
00547                 }
00548 
00549                 case 0x7e:            /*~-sign (tilde as we say in Dutch)*/
00550                 {
00551                     PETSCII = 0xA8;    /*PETSCII tilde*/
00552                     break;
00553                 }
00554 
00555                 default:    /*in all other undefined situations leave the character "as it was"*/
00556                 {
00557                     PETSCII = ASCII;
00558                     break;    
00559                 }
00560             }
00561     return(PETSCII);
00562 }
00563 
00564 /***************************************************************************************************************************************/
00565 /***************************************************************************************************************************************/
00566 /***************************************************************************************************************************************/
00567 /***************************************************************************************************************************************/
00568 
00569