C1541-III mbed edition

Dependencies:   mbed

fat.c

Committer:
gertk
Date:
2011-08-22
Revision:
1:0cbbb66a6100
Parent:
0:28557a4d2215

File content as of revision 1:0cbbb66a6100:

/*-----------------------------------------------------------------------------------*/
/* This is a simple FAT16 handler. It works on a sector basis to allow fastest acces */
/* on disk images.                                                                   */
/*                                                                                     */
/* Attention: when using Roadkill sector editor, chose the physical disk, and not the*/
/* drive number, otherwise the calculated sectors will not allways be the identical  */
/*-----------------------------------------------------------------------------------*/
/*    History:
    2008-02-08    fixed the problem regarding the backwards searching within subdirectories
                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>
    2008-02-01    improved filesearch routine for subdirectory support, it appears to work
    2008-01-18    worked on opendirectory
    2008-01-14    corrected a small bug, because of the ASCII to PETSCII conversiuon, the calculation of the 8.3 checksum was incorrect
                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
    2008-01-09    improved routine opensubdirectory(), suddenly it all works (hurray)
    2008-01-07    added routine opensubdirectory(), this makes suport of subdirectories a fact
    2007-12-20    added ASCII to PETSCII routines
    2007-12-19    playing with longfilenames
    2007-04-07    Mattias Olsson reported the following bugfix:
                By changing every occurrence of: sb+=clustersize*(file->cluster-2);
                to :                             sb+=(unsigned long)clustersize*(file->cluster-2); 
                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).
                Thanks Mattias, this saved me a lot of work, these bugs are the worst to fix.
    2006-12-15    fixed a small bug important bug in the FATSTART calculation (566 and 567 instead of 556 and 557)
                depending on your card it should not cause to much trouble...
    2006-09-03    renamed "databuffer" to "block_buffer" since this is a more appropriate name
    2006-08-21    added more debugging info in order to find the problem regarding the problems with some card not being supported...
    2006-04-11    improved 'FindDrive' routine to support cards without a partition table
    2006-02-03    added filesize to file structure (userfull for simple and quick file type validation of fixedsize files (i.e. D64-files))
    2006-02-02    improvements in code layout... i.o.w. making it more readable
    2006-02-02    also the sector number is relevant... fixed it
    2006-02-01    added cache-ing regarding sector locations
    2006-01-31    worked out how to write the byte addressable read routine
    2006-01-29    added first steps for byte addressable read routine (read X bytes from startaddress Y)
    2005-12-23    added current file search option
    2005-12-11    first version, ported from FAT1618.C
*/

/* TO DO:
   ------
    - FileSectorScan(struct file2TYPE *file) routine iets aanpassen zodat we niet falen op de theoretisch laatste 'filenextsector'
*/

/*----------------------------------------------------------------------------------*/
                
/*--------------------------------------------------------*/
/*                        includes                        */
/*--------------------------------------------------------*/
#include <stdio.h>
#include <main.h>
#include <ata.h>
#include <fat.h> 

/*--------------------------------------------------------*/
/*                        constants                       */   
/*--------------------------------------------------------*/
#define        FALSE                            0            /*FALSE*/
#define        TRUE                            1            /*TRUE*/

/*Since the size of a D64 file is fixed the number of sectors required for a D64 file is also fixed*/
/*In order to keep compatibillity with most of the .D64 formats we must be able to handle the biggest,*/
/*so thats 40tracks including error bytes*/
#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*/

/*--------------------------------------------------------*/
/*                         globals                        */
/*--------------------------------------------------------*/
static unsigned long fatstart;                    /*start LBA of first FAT table*/
static unsigned char fatno;                     /*number of FAT tables*/
static unsigned long datastart;                   /*start LBA of data field*/
static unsigned long rootstart;                   /*start LBA of rootdirectory table*/
static unsigned short direntrys;                 /*number of entry's in directory table*/
static unsigned short direntrys_root;              /*number of entry's in directory table*/
static unsigned char clustersize;                 /*size of a cluster in blocks*/
static unsigned short subdircluster_start;        /*starting cluster of subdirectory*/
static unsigned short subdirsec_start;            /*starting cluster of subdirectory*/
#define bit bool
static bit root;


unsigned short clusterlocationcache[D64FileConsistsOfSectors];            /*cache for the sector locations within the D64 file as stored in the Fat16*/

/*--------------------------------------------------------*/
/*                     local functions                    */
/*--------------------------------------------------------*/

unsigned char ASCII_to_PETSCII(unsigned char ASCII);

/*****************************************************************************************************************/
/*****************************************************************************************************************/

/*FindDrive checks if a card is present. if a card is present it will check for
a valid FAT16 primary partition*/
unsigned char FindDrive(void)
{
    unsigned char error_code;
    unsigned long fatsize;                /*size of fat*/
    unsigned long dirsize;                /*size of directory region in sectors*/
        
    error_code = AtaReadSector(0,block_buffer);    /*read partition sector*/
    if (error_code != TRUE)
    {
        return(error_code);
    }
    
    /*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*/
    if(block_buffer[450]!=0x04 && block_buffer[450]!=0x05 && block_buffer[450]!=0x06)/*check partition type*/
        fatstart=0;
    else if(block_buffer[510]!=0x55 || block_buffer[511]!=0xaa)    /*check signature*/        
        fatstart=0;
    else
    {
        fatstart=(unsigned long)block_buffer[454];                /*get start of first partition*/
        fatstart+=(unsigned long)block_buffer[455]*256;
        fatstart+=(unsigned long)block_buffer[456]*65536;
        fatstart+=(unsigned long)block_buffer[457]*16777216;
    }
            
    if(!AtaReadSector(fatstart,block_buffer))                    /*read boot sector*/
        return(ERROR_FAT_READBOOTSECTOR);    
    
    if(block_buffer[0]!=0xe9 && block_buffer[0]!=0xeb)            /*check for near-jump or short-jump opcode*/
        return(ERROR_FAT_JUMPOPCODE);
    
    if(block_buffer[11]!=0x00 || block_buffer[12]!=0x02)        /*check if blocksize is really 512 bytes*/
        return(ERROR_FAT_BLOCKSIZE);
    
    if(block_buffer[21]!=0xf8)                                    /*check medium descriptorbyte, must be 0xf8 for hard drive*/
        return(ERROR_FAT_MEDIUM);
    
    direntrys=block_buffer[17]+(block_buffer[18]*256);            /*calculate drive's parameters from bootsector, first up is size of directory*/
    direntrys_root = direntrys;
    dirsize=((direntrys*32)+511)/512;                  
    
    fatstart=fatstart+block_buffer[14]+(block_buffer[15]*256);    /*calculate start of FAT,size of FAT and number of FAT's*/
    fatsize=block_buffer[22]+(block_buffer[23]*256);
    fatno=block_buffer[16];
    
     rootstart=fatstart+(fatno*fatsize);                            /*calculate start of root-directory*/
     clustersize=block_buffer[13];                                /*get clustersize*/
    datastart=rootstart+dirsize;                                  /*calculate start of data*/   
    root=TRUE;                                                     /*raise flag to indicate we are in the root directory*/
      return(TRUE);
}

/*this routine needs to be called when a subdirectory is entered*/
/*this routine re-calculates the current directroy pointers and registers to those of the (sub)directory to be opened*/ 
/*this routine returns TRUE when the subdirectory is a subdirectory and FALSE when it is root*/
unsigned char OpenSubDirectory(struct file2TYPE *file)
{
    /*calculate the location of the first byte of the new (sub)directory*/
    if(file->cluster == 0)                                    /*check if the user requests the root directory*/
    {                                                        /*---------------------------------------------*/
        root=TRUE;                                              /*raise flag to indicate we are in the root directory*/
        direntrys = direntrys_root;
        return(FALSE);                                        /*we are now back in root*/
    }
    else
    {
        root=FALSE;                                         /*lower flag to indicate we are NOT in the root directory*/
        direntrys = 1000;                                     /*a fixed value that is practically impossible to use on a CBM computer*/
        subdircluster_start = file->cluster;                /*starting cluster of subdirectory*/    
        subdirsec_start = file->sec;                        /*starting sector offset within cluster*/
        return(TRUE);                                        /*we are now in a subdirectory*/
    }    
}

/*scan directory, yout must pass a file handle to this function*/
/*search modes: 0=first,1=next(8.3 AND LFN),2=previous(8.3 only),3=current*/
unsigned char FileSearch(struct file2TYPE *file, unsigned char mode)
{
    static unsigned short subdircluster_current;    /*current cluster of subdirectory*/
    static unsigned short subdirsec_current;        /*current sector offset within cluster*/
    static unsigned char sectorcounter;                /*a relative counter, to keep track of how many sectors we've read regarding this subdirectory*/
    /*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*/

    unsigned long sf,sb;
    unsigned short i;
    unsigned char j;

    unsigned short LFN_offset;
    unsigned char LFN_seq_nmbr;
    unsigned char LFN_string[27];    /*the length of the LFN name we use is max 26 characters (2 LFN entries)*/
    unsigned char LFN_checksum[2];    /*since we use only two LFN entries, we only need to store 2 checksums*/
    unsigned char REF_checksum;        /*the checksum which is our reference*/

    LFN_checksum[0] = 0;            /*clear the checksum value of the 1st LFN sequence*/
    LFN_checksum[1] = 0;            /*clear the checksum value of the 2nd LFN sequence*/
    
    sb=0;                            /*buffer is empty*/
    if(mode==0)            /*search for first entry*/
    {                    /*----------------------*/
        file->entry=0;
        if (root == FALSE)
        {
            file->cluster = subdircluster_start;            /*reset the cluster pointer back to the beginning of the directory, otherwise we fail with the filenextsector routine*/
            file->sec = subdirsec_start;                    /*starting sector offset within cluster*/
            subdircluster_current = file->cluster;
            subdirsec_current = file->sec;
            sectorcounter = 0;
        }
    }
    else if(mode==1)    /*search for next entry*/
    {                    /*---------------------*/
        file->entry++;
    }
    else if(mode==2)    /*search for previous entry*/
    {                    /*-------------------------*/
        file->entry--;
    }

    while(file->entry<direntrys)
    {    
        if (root == TRUE)            /*the root directory is one continuos chunk of entries*/
        {                            /*----------------------------------------------------*/
            sf=rootstart;            /*calculate sector and offset*/
            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)*/
    
            if(sb!=sf)                /*when buffer is empty or needs to be changed*/
            {
                sb=sf;
                if(!AtaReadSector(sb,block_buffer))
                    return(FALSE);    
            }
        }
        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*/
        {                            /*--------------------------------------------------------------------------------------------------------------------------------------------------*/
            if((mode==1) && (file->entry > 0) && (file->entry%16 == 0))    /*load sector if not in buffer*/
            {
                file->cluster = subdircluster_current;                    /*retrieve the latest cluster value*/
                file->sec = subdirsec_current;                            /*retrieve the latest sector value*/    
                if (FileNextSector(file) == FALSE)                        /*attention: screws up block_buffer!!*/
                    return(FALSE);
                sectorcounter++;                                        /*another sector loaded, increment counter*/
                subdircluster_current = file->cluster;                    /*save the new value for later*/
                subdirsec_current = file->sec;                            /*save the new value for later*/
    
                if ((file->cluster & 0xFFF8) ==  0xFFF8)                /*check if this is the last cluster*/
                {
                    file->len=0;    
                    return(FALSE);
                }
            }


             if((mode==2) &&  ((file->entry + 1) > 0) && ((file->entry+1)%16 == 0))    /*load sector if not in buffer*/
            {
                /*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*/
                /*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)*/
                file->cluster = subdircluster_start;                    /*reset the cluster pointer back to the beginning of the directory, otherwise we fail with the filenextsector routine*/
                file->sec = subdirsec_start;                            /*starting sector offset within cluster*/
                if (sectorcounter > 0)
                {
                    sectorcounter--;                                    /*previous sector found, decrement counter*/
                    for(j=0;j<sectorcounter;j++)
                    {
                        if (FileNextSector(file) == FALSE)                /*attention: screws up block_buffer!!*/
                            return(FALSE);
                    }        
                }
                subdircluster_current = file->cluster;                    /*save the new value for later*/
                subdirsec_current = file->sec;                            /*save the new value for later*/
            }        

            sf=datastart;                                                /*start of data in partition*/
            sf+=(unsigned long)clustersize*(subdircluster_current-2);    /*cluster offset*/
            sf+=(subdirsec_current%clustersize);                         /*sector offset in cluster*/
            if(sb!=sf)                                                    /*when buffer is empty or needs to be changed*/
            {
                sb=sf;
                if(!AtaReadSector(sb,block_buffer))
                    return(FALSE);    
            }
        }

        i=(file->entry%16)*32;            /*i is the pointer that points to the address of the entry within the loaded sector*/
        if(block_buffer[i+0x0b]==0x0f)    /*check if this entry is an LFN entry*/
        {
            //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)*/
            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*/
            {
                LFN_seq_nmbr = block_buffer[i] & 0x3f;    /*remove the possible 0x40 in order to keep the bare LFN sequence number*/
                LFN_offset = (LFN_seq_nmbr * 13) - 13;

                /*save the LFN characters to the correct location of our string*/
                LFN_string[LFN_offset + 0] = block_buffer[i+0x01];    /*5 UTF characters of which we only use the first byte*/
                LFN_string[LFN_offset + 1] = block_buffer[i+0x03];
                LFN_string[LFN_offset + 2] = block_buffer[i+0x05];
                LFN_string[LFN_offset + 3] = block_buffer[i+0x07];
                LFN_string[LFN_offset + 4] = block_buffer[i+0x09];

                LFN_checksum[LFN_seq_nmbr-1] = block_buffer[i+0x0d];/*save the checksum*/

                LFN_string[LFN_offset + 5] = block_buffer[i+0x0e];    /*6 UTF characters of which we only use the first byte*/
                LFN_string[LFN_offset + 6] = block_buffer[i+0x10];
                LFN_string[LFN_offset + 7] = block_buffer[i+0x12];
                LFN_string[LFN_offset + 8] = block_buffer[i+0x14];
                LFN_string[LFN_offset + 9] = block_buffer[i+0x16];
                LFN_string[LFN_offset + 10] = block_buffer[i+0x18];

                LFN_string[LFN_offset + 11] = block_buffer[i+0x1c];    /*2 UTF characters of which we only use the first byte*/
                LFN_string[LFN_offset + 12] = block_buffer[i+0x1e];
    
            /*the following code is not required as we only use two LFN entries which we compare with a checksum later*/
            /*the code below is left for reference for LFN filenames which must be longer then 26chars*/
            //    if(block_buffer[i]&0x40 == 0x40)                    /*check if this entry was the last LFN entry belonging to this file*/
            //    {                                                    /*we do this by checking if the 6st bit was set*/
            //        LFN_string[LFN_offset + 13] = 0;                /*terminate string HERE*/
            //    }
            }
        }

        if(block_buffer[i]!=0x00 && block_buffer[i]!=0xe5)                /*check if valid file entry: 0x00 = entry is available*/
        {    /*                                                                                       0xE5 = entry has been erased*/
            if((block_buffer[i+0x0b]&0x0a)==0x00)                        /*check atributes: do not show hidden files, do not show volume labels, DO SHOW subdirectories*/
            {
                for(j=0;j<11;j++)                                       /*copy name (8.3)*/
                    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*/
                file->name[j]=0x00;                                        /*terminate the string*/
            
                file->len=(unsigned long)block_buffer[j+28];            /*get length of file in sectors, maximum is 16Mbytes*/
                file->len+=(unsigned short)block_buffer[i+29]*256;
                file->len+=511;
                file->len/=512;
                file->len+=(unsigned long)block_buffer[i+30]*128;
                        
                file->cluster=(unsigned long)block_buffer[i+26]+((unsigned long)block_buffer[i+27]*256);    /*get first cluster of file*/            
                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);
                file->sec=0;                                                                    /*reset sector index*/                        

                REF_checksum = 0;                                    /*calculate the checksum of the 8.3 filename*/ 
                for (j=0;j<11;j++)                                    /*this checksum is our reference to which we compare the LFN checksum(s) with*/
                    REF_checksum = (((REF_checksum & 1) << 7) | ((REF_checksum & 0xfe) >> 1)) + block_buffer[i+j]; 

                if(LFN_checksum[0] == REF_checksum)                    /*using the checksum we determine wether we use the gathered LFN information*/
                {
                    for(j=0;j<13;j++)                                   /*copy the first 13 characters of the LFN string (maintain case)*/
                        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*/

                    if(LFN_checksum[1] == REF_checksum)
                    {
                        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)*/
                            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*/
                        file->name_lfn[26]=0x00;                    /*terminate string*/
                    }
                    else
                        file->name_lfn[13]=0x00;                    /*terminate string*/
                }
                else
                {
                    file->name_lfn[0]=0;            /*clear the LFN string by terminating at the first char*/
                }

                return(TRUE);
            }
        }
        if(mode==2)
            file->entry--;
        else
            file->entry++;
    }
    file->len=0;        
    return(FALSE);
}


/*this routine will scan for the startaddress of all possible sectors that hold a D64 file*/
unsigned char FileSectorScan(struct file2TYPE *file)
{
    unsigned int lp;

    for(lp=0; lp<(D64FileConsistsOfSectors-1); lp++)        
    {
        clusterlocationcache[lp] = file->cluster;
        if (FileNextSector(file) == FALSE)                /*attention: screws up block_buffer!!*/
            return(FALSE);
    }
    clusterlocationcache[D64FileConsistsOfSectors-1] = file->cluster;

    return(TRUE);
}


/*point to next sector in file*/
unsigned char FileNextSector(struct file2TYPE *file)
{
    unsigned long sb;
    unsigned short i;
    
    file->sec++;                        /*increment sector index*/
    if((file->sec%clustersize)==0)        /*if we are now in another cluster, look up cluster*/
    {
        sb=fatstart;                    /*calculate sector that contains FAT-link*/
        sb+=(file->cluster/256);
        i=(file->cluster%256);            /*calculate offset*/
        i*=2;
        
        if(!AtaReadSector(sb,block_buffer))    /*read sector of FAT*/
            return(FALSE);
            
        file->cluster=((unsigned short)block_buffer[i+1]*256)+(unsigned short)block_buffer[i];    /*get FAT-link*/
    }
    return(TRUE);
}

/*read current sector into buffer*/
unsigned char FileReadSector(struct file2TYPE *file)
{
    unsigned long sb;
    
    sb=datastart;                                        /*start of data in partition*/
    sb+=(unsigned long)clustersize*(file->cluster-2);    /*cluster offset*/
    sb+=(file->sec%clustersize);                         /*sector offset in cluster*/
                            
    if(!AtaReadSector(sb,block_buffer))                    /*read the data from the sector*/
        return(FALSE);
    else
        return(TRUE);
}

/*read specified sector into buffer*/
unsigned char FileReadSector_X(struct file2TYPE *file, unsigned long block)
{
    unsigned long sb;
    
    file->cluster = clusterlocationcache[block];        /*retrieve the sector address from the cache*/
    file->sec = block;                                    /*we need to indicate the exact sector number within this cluster*/

    sb=datastart;                                        /*start of data in partition*/
    sb+=(unsigned long)clustersize*(file->cluster-2);    /*cluster offset*/
    sb+=(file->sec%clustersize);                         /*sector offset in cluster*/
//    sb+=pt;                                                /*add the pointer offset to the absolute address of the data position as stored on the card*/

    if(!AtaReadSector(sb,block_buffer))                    /*read the data from the sector*/
        return(FALSE);
    else
        return(TRUE);
}

/*Read xxx bytes from a sector into a specified buffer*/
/*When only one or more bytes are required, then this routine comes in handy...*/
unsigned char FileRead_X_Bytes(struct file2TYPE *file, unsigned long startaddress, unsigned int NmbrOfBytes)
{
    unsigned long lp, pt, bytesfromcurrentsector, bytesfromnextsector;
    unsigned long sb;

    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)*/
    pt = startaddress%512L;                /*the byte we are looking for is pointed to by "cardbuffer_pnt"*/
    
    /*check if the bytes we want to read beyond the sector border*/
    if ((pt + NmbrOfBytes) < 512L)
    {
        bytesfromcurrentsector = NmbrOfBytes;    /*the number of bytes that can be read from the now selected sector*/
        bytesfromnextsector = 0;                /*the number of bytes that can cannot be read from the now selected sector and must be read from the next sector*/
    }
    else
    {
        bytesfromcurrentsector = 512L - pt;                            
        bytesfromnextsector = NmbrOfBytes - bytesfromcurrentsector;    
    }

    file->cluster = clusterlocationcache[lp];        /*retrieve the sector address from the cache*/
    file->sec = lp;                        /*we need to indicate the exact sector number within this cluster*/

    sb=datastart;                        /*start of data in partition*/
    sb+=(unsigned long)clustersize*(file->cluster-2);    /*cluster offset*/
    sb+=(file->sec%clustersize);         /*sector offset in cluster*/
//    sb+=pt;                                /*add the pointer offset to the absolute address of the data position as stored on the card*/
    if(!AtaRead_X_Bytes(sb, pt, block_buffer, bytesfromcurrentsector))        /*read data (a part of the current sector) from drive*/
        return(FALSE);

    if (bytesfromnextsector !=0)
    {
        file->cluster = clusterlocationcache[lp+1];    /*retrieve the sector address from the cache*/
        file->sec = lp+1;                    /*we need to indicate the exact sector number within this cluster*/

        sb=datastart;                        /*start of data in partition*/
        sb+=(unsigned long)clustersize*(file->cluster-2);    /*cluster offset*/
        sb+=(file->sec%clustersize);         /*sector offset in cluster*/
        if(!AtaRead_X_Bytes(sb, 0, &block_buffer[bytesfromcurrentsector+1], bytesfromnextsector))        /*read data (a part of the current sector) from drive*/
            return(FALSE);
    }
    return(TRUE);
}

/*Write the specified block to the card*/
unsigned char FileWriteSector_X(struct file2TYPE *file, unsigned long block)
{
    unsigned long sb;
    
    file->cluster = clusterlocationcache[block];    /*retrieve the sector address from the cache*/
    file->sec = block;                                    /*we need to indicate the exact sector number within this cluster*/

    sb=datastart;                        /*start of data in partition*/
    sb+=(unsigned long)clustersize*(file->cluster-2);    /*cluster offset*/
    sb+=(file->sec%clustersize);         /*sector offset in cluster*/
//    sb+=pt;                                /*add the pointer offset to the absolute address of the data position as stored on the card*/
    if(!AtaWriteSector(sb,block_buffer))    /*write data to medium*/
        return(FALSE);

    return(TRUE);
}


/***************************************************************************************************************************************/

/*convert ASCII to PETSCII: substitute the following ASCII-chars to PETSCII alternatives*/                
unsigned char ASCII_to_PETSCII(unsigned char ASCII)
{
    unsigned char PETSCII;

    if ((ASCII >= 'a') && (ASCII <= 'z'))    /*check if the ASCII character is lowercase*/
    {
        ASCII = ASCII - 0x20;     /*convert lowercase to UPPERCASE*/
    }

    switch (ASCII)
            {    
                case 0x5e:            /*^-sign (caret)*/
                {
                    PETSCII = 0xb1;    /*PETSCII small 4 pixel upsidedown T located at the top*/
                    break;
                }

                case 0x5F:            /*_-sign (underscore)*/
                {
                    PETSCII = 0xa4;    /*PETSCII underscore*/
                    break;
                }

                case 0x60:            /*'-sign (single quote)*/
                {
                    PETSCII = 0xbe;    /*PETSCII 4pixel square located top left*/
                    break;
                }

                case 0x7b:            /*{-sign (bracket left)*/
                {
                    PETSCII = 0x5b;    /*PETSCII squared bracket left*/
                    break;
                }

                case 0x7d:            /*}-sign (bracket right)*/
                {
                    PETSCII = 0x5d;    /*PETSCII squared bracket right*/
                    break;
                }

                case 0x7e:            /*~-sign (tilde as we say in Dutch)*/
                {
                    PETSCII = 0xA8;    /*PETSCII tilde*/
                    break;
                }

                default:    /*in all other undefined situations leave the character "as it was"*/
                {
                    PETSCII = ASCII;
                    break;    
                }
            }
    return(PETSCII);
}

/***************************************************************************************************************************************/
/***************************************************************************************************************************************/
/***************************************************************************************************************************************/
/***************************************************************************************************************************************/