C1541-III mbed edition

Dependencies:   mbed

D64_decoder.c

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

File content as of revision 1:0cbbb66a6100:

/*----------------------------------------------------------------------------------*/
/*    These routines are designed to decode a file according the D64 format           */
/*----------------------------------------------------------------------------------*/
/*                                                                                  */

/*  History:                                                                        
    -------- 
    2007-03-30    added a buffer pointer to the D64blockread function, which is now called D64blockread_new, which gives some room to test the function before changing the entire software at 1000 places... to find out after 3 months i made a small mistake, therefore a temporarily routine with a different name
                and for d64blockwrite the same
    2007-03-25    changed the independent BAM_buffer to the DOS_buffer at buffer location #4 (as on a real 1541 drive)
    2006-11-21    added the truncation of everything behind the , or = sign in a save filename (or actually when adding a directory entry)
    2006-10-25    fixed bug in the seekfreeblock, the routine pointed a free block inside track18, this is evil. This bug is fixed. Now a free block for saving purposes will never be allocated in track-18
    2006-09-09    scratch routine was not completed, it did not set the flags of the used blocks to FREE, FIXED
    2006-09-07    write is maturing, now it is possible to write multiple files to one disk without problems, stil required is working on related actions like file checking error handling
    2006-09-05     a tiny error in buffer copying caused mutilation of the BAM (disk label), fixed
                D64SeekFreeBlock did not return correct info causing the previous odd block to be overwritten 
                added routines "read/write-freeblockspertrack"
    2006-09-04    a small step further with write support, calculation of the track-sector flag was one byte off, fixed
    2006-09-03    oopsie... accidentally swapped the names of the D64 read and write routines, creating all sorts of wierd problems
    2006-09-02    worked on the D64BAMflagtest routine...
    2006-09-01    renamed all routines within this source, now ALL routines start with D64      
    2006-08-28    added 2 more routines to calculate track and sector from block address and vice versa
    2006-07-09    it appears that some files use track=0 sector=0 to indicate that this was the last directory block
                this is not compatible with the docs I found which clearly states track=0 sector=255
    2006-02-03    embedded the calcbyteaddress routine inside a file read routine, makes D64 file access sourcecode much nicer to read
    2006-02-02    improvements in code layout... i.o.w. making it more readable
    2005-09-23    raw design of D64 decoder
    2005-10-18    minor modifications in textual layout (code-cleanup)
*/

/*  TO DO:                                                                          
    ------
    - routine "D64LoadFile_X_Bytes" needs to be updated using the 'newer' D64 routines

    - seek functie plaatsen in "fat16_on_PIC18.C", daar hoort 'ie thuis en niet in de D64 decoding routines
    - routines die gebruik maken van stringbuffers in minder code opschrijven        
*/

/*----------------------------------------------------------------------------------*/

extern void OutputToRS232();
extern void OutputToLCD();

/*--------------------------------------------------------*/
/*                        includes                        */
/*--------------------------------------------------------*/
#include <mbed.h>
#include <stdio.h>
#include <main.h>
#include <hardware.h>
#include <fat.h>
#include <delay.h>
#include <D64_decoder.h>

/*--------------------------------------------------------*/
/*                   (tunable) constants                  */ 
/*--------------------------------------------------------*/


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

/*--------------------------------------------------------*/
/*                         table                          */
/*--------------------------------------------------------*/
/*SPT (SectorsPerTrack) decoding table*/
/*Attention: TRACK counting starts at '1' (not at '0')*/
/*           SECTOR counting starts at '0' (not at '1')*/
const unsigned char SPT[41]= {0,                                                    /*track 0 does not excist*/
                             21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,/*track 1-17*/
                             19,19,19,19,19,19,19,                                /*track 18-24*/
                             18,18,18,18,18,18,                                    /*track 25-30*/
                             17,17,17,17,17,17,17,17,17,17};                        /*track 31-40*/


/*variables*/
extern struct            file2TYPE             file;            /*file handle*/
extern struct            directory_entry        dir_entry;        /*directory structure inside the D64*/

extern unsigned char    error_code;                /*this holds the error-message generated by one of the disk routines*/
extern unsigned char    LastTrack;                /*last accessed track variable*/
extern unsigned char    LastSector;                /*last accessed sector variable*/

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

/*************************************************************************************/
/*External functions*/
/*************************************************************************************/
/*this routine clears the entire block_buffer*/
void Clear_RAM_buffer(void)
{
    unsigned char lp;

    lp=0;
    do
    {
        RAM_buffer[lp] = 0x00;
        lp++;
    }
    while(lp!=0);
}


/*this routine will calculate the track and sector based on the given (256bytes, since D64 blocks are 256bytes) block*/
void D64ConvertBlockToTrackSector(unsigned int block, unsigned char *track, unsigned char *sector)
{
    *track = 1;        /*Attention:  track starts at 1 */
    *sector = 0;    /*Attention: sector starts at 0 */
    while(block)
    {
        *sector = *sector + 1;
        if (*sector > (SPT[*track] - 1))
        {
            *sector = 0;
            *track = *track + 1;            
        }
        block--;
    }
}

/*calculate the D64 block (D64 blocksize is 256 bytes) address determined by the D64-track-sector-byte numbers*/
unsigned int D64ConvertTrackSectorToBlock(unsigned char track, unsigned char sector)
{
    unsigned int block;

    block = 0;
    while(track--)
    {
        block = block + SPT[track];        /*retrieve number of sector per track from table and multiply the number of sectors with 256 (256bytes per sector), add this to the total*/
    }
    block = block + sector;
    return(block);
}

/*this routine will read the BAM (and stores it in the BAM_buffer (DOS_buffer[4].buffer[..]), this should be done everytime a new D64 image is selected*/
void D64ReadBAM(void)
{
    /*this routine only supports 35 track disks, since I lack the knowledge of 40 track size disks*/
    
    unsigned int lp, block, offset;

    block = D64ConvertTrackSectorToBlock(18,0);                /*the block number is a 256byte blocksize, so for a card this would have to be devided by 2*/
    if (block%2 == 0)                                        /*determine is the value was odd ('1' = upper halve) or even ('0' = lower halve)*/
        offset = 0;                                            /*data in lower halve of 512byte block*/
    else
        offset = 256;                                        /*data in upper halve of 512byte block*/
    block = block/2;                                        /*convert to a 512byte blocksize (this devides by two and truncates)*/
    FileReadSector_X(&file, block);                            /*read a 512byte block from the medium*/
    lp = 4;                                                    /*copy the data from source to destination*/
    while (lp < 144)
    {
        DOS_buffer[4].buffer[lp-4] = block_buffer[offset+lp];
        lp++;
    }
}

/*this routine writes the BAM (as stored in the BAM_buffer (DOS_buffer[4].buffer[..]) back to the D64*/
void D64WriteBAM(void)
{
    /*this routine only supports 35 track disks, since I lack the knowledge of 40 track size disks*/
    unsigned char lp;    

    D64BlockRead(18,0);                                        /*read the block holding the BAM information*/

    lp = 0;                                                    /*alter the bytes holding the BAM info*/
    while (lp < 140)
    {
        RAM_buffer[lp+4] = DOS_buffer[4].buffer[lp];        /*copy source to destination*/
        lp++;
    }

    D64BlockWrite(18,0);                                    /*write the modified block*/
}

/*this routine request the free blocks per sector*/
unsigned char D64ReadFreeBlocksPerTrack(unsigned char track)
{
    unsigned char bytepointer;

    bytepointer = (track-1) << 2;                    /*multiply value by another 4*/
    return(DOS_buffer[4].buffer[bytepointer]);        /*return with requested value*/
}

/*this routine request the free blocks per sector*/
unsigned char D64WriteFreeBlocksPerTrack(unsigned char track, unsigned char value)
{
    unsigned char bytepointer;

    bytepointer = (track-1) << 2;            /*multiply value by another 4*/
    DOS_buffer[4].buffer[bytepointer] = value;
    D64WriteBAM();                            /*write the modified BAM to the medium*/
    return(TRUE);                            /*return with requested value*/
}


/*test the status of the corresponding block-flag, return True if set and False if cleared*/
unsigned char D64BAMFlagTest(unsigned char track, unsigned char sector)
{
    unsigned char bytepointer, bitpointer, lp, mask;
    
    /*determine in which byte the required track/sector-flag (bit) is located*/
    bytepointer = 1 + (4 * (track-1)) + (sector/8);
    bitpointer = sector%8;
        
    mask = 0x01;                                        /*use a mask to alter the correct flag (bit)*/
    for (lp=bitpointer; lp>0; lp--)
    {
        mask<<=1;            /*shift the byte one bit to the left*/
    }

    if ((DOS_buffer[4].buffer[bytepointer] & mask) == 0)
        return(FALSE);
    else
        return(TRUE);    
}

/*this routine can set/clear (TRUE/FALSE) the appropriate flag of the sepcified track or sector*/
void D64BAMFlagModify(unsigned char track, unsigned char sector, unsigned status)
{
    unsigned char bytepointer, bitpointer, lp, mask;
    
    /*determine in which byte the required track/sector-flag (bit) is located*/
    bytepointer = 1 + (4 * (track-1)) + (sector/8);
    bitpointer = sector%8;
        
    mask = 0xfe;                                        /*use a mask to alter the correct flag (bit)*/
    for (lp=bitpointer; lp>0; lp--)
    {
        mask<<=1;            /*shift the byte one bit to the left*/
        mask = mask + 1;    /*make the LSB 1, since the shift left inserts 0's*/
    }

    DOS_buffer[4].buffer[bytepointer] = DOS_buffer[4].buffer[bytepointer] & mask;
    mask = 0xFF - mask;            /*invert the mask in order to use the mask to set the bit of the required flag*/
    if (status == TRUE)            /*test if the flag needs to be set or cleared*/
        DOS_buffer[4].buffer[bytepointer] =    DOS_buffer[4].buffer[bytepointer] | mask;
}

/*this routine will search for the first free block within the D64 according it's BAM, it returns the track and sector of that block*/
unsigned char D64SeekFreeBlock(unsigned char *track, unsigned char *sector)
{
    /*this routine only supports 35 track disks, since I lack the knowledge of 40 track size disks*/
    *track = 1;
    *sector = 0;

    while(!D64BAMFlagTest(*track, *sector))        /*scan the BAM for a free block*/
    {
        *sector = *sector + 1;
        if (*sector == SPT[*track])
        {
            *sector = 0;
            *track = * track + 1;
            if (*track == 18)                    /*prevent writing in the directory track*/
                *track = 19;                    /*so if we reach it... just skip it!!!*/
        }
        if (*track > 35)
            return(FALSE);                        /*exit when all tracks are scanned*/
    }
    return(TRUE);                                /*exit with the track and sector of the first free block*/
}

/*this routine clear a flag that indicates that the corresponding track is set*/
unsigned char D64BlockAllocate(unsigned char track, unsigned char sector)
{
    if (D64BAMFlagTest(track, sector) == TRUE)
    {
        D64BAMFlagModify(track, sector, 0);        /*clear the flag that indicates the specified track and sector*/
        D64WriteBAM();                            /*write the modified BAM to the medium*/
        return(TRUE);                            /*operation succesfully performed*/
    }
    else
    {
        return(FALSE);                            /*error:flag was allready cleared*/
    }
}

/*this routine sets a flag that indicates that the corresponding track is free*/
unsigned char D64BlockFree(unsigned char track, unsigned char sector)
{
    if (D64BAMFlagTest(track, sector) == FALSE)
    {
        D64BAMFlagModify(track, sector, 1);        /*set the flag that indicates the specified track and sector*/
        D64WriteBAM();                            /*write the modified BAM to the medium*/
        return(TRUE);                            /*operation succesfully performed*/
    }
    else
    {
        return(FALSE);                            /*error:flag was allready set*/
    }
}

/*this routine reads a block of a req. track-sector of a D64 into the RAM_buffer*/
void D64BlockRead(unsigned char track, unsigned char sector)
{
    unsigned int lp, block, offset;

    block = D64ConvertTrackSectorToBlock(track, sector);    /*the block number is a 256byte blocksize, so for a card this would have to be devided by 2*/
    if (block%2 == 0)                                        /*determine is the value was odd ('1' = upper halve) or even ('0' = lower halve)*/
        offset = 0;                                            /*data in lower halve of 512byte block*/
    else
        offset = 256;                                        /*data in upper halve of 512byte block*/
    block = block/2;                                        /*convert to a 512byte blocksize (this devides by two and truncates)*/
    FileReadSector_X(&file, block);                            /*read a 512byte block from the medium*/
    lp = 0;                                                    /*copy the data from source to destination*/
    while (lp < 256)
    {
        RAM_buffer[lp] = block_buffer[offset+lp];
        lp++;
    }
}

/*this routine reads a block of a req. track-sector of a D64 into the RAM_buffer*/
/*THIS IS THE FUTURE ROUTINE*/
void D64BlockRead_new(unsigned char buffer, unsigned char track, unsigned char sector)
{
    unsigned int lp, block, offset;

    block = D64ConvertTrackSectorToBlock(track, sector);    /*the block number is a 256byte blocksize, so for a card this would have to be devided by 2*/
    if (block%2 == 0)                                        /*determine is the value was odd ('1' = upper halve) or even ('0' = lower halve)*/
        offset = 0;                                            /*data in lower halve of 512byte block*/
    else
        offset = 256;                                        /*data in upper halve of 512byte block*/
    block = block/2;                                        /*convert to a 512byte blocksize (this devides by two and truncates)*/
    FileReadSector_X(&file, block);                            /*read a 512byte block from the medium*/
    lp = 0;                                                    /*copy the data from source to destination*/
    while (lp < 256)
    {
        DOS_buffer[buffer].buffer[lp] = block_buffer[offset+lp];    /*read (or to be precise) copy, the data from the media buffer to the DOS_buffer as specified by the user*/
        lp++;
    }
}

/*this routine write the contents of the RAM_buffer to the req. track-sector of the D64 file*/
void D64BlockWrite(unsigned char track, unsigned char sector)
{
    unsigned int lp, block, offset;

    block = D64ConvertTrackSectorToBlock(track, sector);    /*the block number is a 256byte blocksize, so for a card this would have to be devided by 2*/
    if (block%2 == 0)                                        /*determine is the value was odd ('1' = upper halve) or even ('0' = lower halve)*/
        offset = 0;                                            /*data in lower halve of 512byte block*/
    else
        offset = 256;                                        /*data in upper halve of 512byte block*/
    block = block/2;                                        /*convert to a 512byte blocksize (this devides by two and truncates)*/
    FileReadSector_X(&file, block);                            /*read a 512byte block from the medium*/
    lp = 0;                                                    /*copy the data from source to temp destination*/
    while (lp < 256)
    {
        block_buffer[offset+lp] = RAM_buffer[lp];
        lp++;
    }

    FileWriteSector_X(&file, block);                        /*write the altered block back to the medium*/
}

/*this routine write the contents of the RAM_buffer to the req. track-sector of the D64 file*/
/*this is the future routine*/
void D64BlockWrite_new(unsigned char buffer, unsigned char track, unsigned char sector)
{
    unsigned int lp, block, offset;

    block = D64ConvertTrackSectorToBlock(track, sector);    /*the block number is a 256byte blocksize, so for a card this would have to be devided by 2*/
    if (block%2 == 0)                                        /*determine is the value was odd ('1' = upper halve) or even ('0' = lower halve)*/
        offset = 0;                                            /*data in lower halve of 512byte block*/
    else
        offset = 256;                                        /*data in upper halve of 512byte block*/
    block = block/2;                                        /*convert to a 512byte blocksize (this devides by two and truncates)*/
    FileReadSector_X(&file, block);                            /*read a 512byte block from the medium*/
    lp = 0;                                                    /*copy the data from source to temp destination*/
    while (lp < 256)
    {
        block_buffer[offset+lp] = DOS_buffer[buffer].buffer[lp];
        lp++;
    }

    FileWriteSector_X(&file, block);                        /*write the altered block back to the medium*/
}

/*This routine will search for the first dir entry within track 18, it returns the track and sector of the corresponding file*/
/*mode: 0=first,1=next*/
unsigned char D64SeekDirEntry(unsigned char mode, unsigned char *track, unsigned char *sector, unsigned char *entry_cnt)
{
    static unsigned char     entry_counter, CurrentDirTrack, CurrentDirSector, NextDirTrack, NextDirSector;
    unsigned char            offset;

    switch(mode)
    {
        case 0:    /*read from first directory block (Track 18, Sector 1)*/
        {
            NextDirTrack = 18;        
            NextDirSector = 1;
            entry_counter = 0;
            break;
        }

        case 1:    // read from next directory block (Track/Sector)
        {
            entry_counter++;
            if (entry_counter > 7)
                entry_counter = 0;
            break;
        }
    }

    *entry_cnt = entry_counter;

    if (entry_counter == 0)
    {
        if ((NextDirTrack == 0) && ((NextDirSector == 0) || (NextDirSector == 255)))    /*officially the only exit would be track=0 sector=255, but also track=0 sector=0 is very common to indicate the last block of an directory*/
        {
            return(FALSE);        /*end of directory allready reached*/
        }
        else
        {
            D64BlockRead(NextDirTrack, NextDirSector);
            CurrentDirTrack =  NextDirTrack; 
            CurrentDirSector = NextDirSector;
            NextDirTrack = RAM_buffer[0];
            NextDirSector = RAM_buffer[1];
        }
    }

    *track = CurrentDirTrack;
    *sector = CurrentDirSector;

    offset = entry_counter * 32;                                /*each dir entry consists of 32bytes*/
    dir_entry.filetype = RAM_buffer[offset+2];
    dir_entry.track_first_block = RAM_buffer[offset+3];
    dir_entry.sector_first_block = RAM_buffer[offset+4];
    dir_entry.filename[0] = RAM_buffer[offset+5];
    dir_entry.filename[1] = RAM_buffer[offset+6];
    dir_entry.filename[2] = RAM_buffer[offset+7];
    dir_entry.filename[3] = RAM_buffer[offset+8];
    dir_entry.filename[4] = RAM_buffer[offset+9];
    dir_entry.filename[5] = RAM_buffer[offset+10];
    dir_entry.filename[6] = RAM_buffer[offset+11];
    dir_entry.filename[7] = RAM_buffer[offset+12];
    dir_entry.filename[8] = RAM_buffer[offset+13];
    dir_entry.filename[9] = RAM_buffer[offset+14];
    dir_entry.filename[10] = RAM_buffer[offset+15];
    dir_entry.filename[11] = RAM_buffer[offset+16];
    dir_entry.filename[12] = RAM_buffer[offset+17];
    dir_entry.filename[13] = RAM_buffer[offset+18];
    dir_entry.filename[14] = RAM_buffer[offset+19];
    dir_entry.filename[15] = RAM_buffer[offset+20];
    dir_entry.track_first_block_relfile = RAM_buffer[offset+21];
    dir_entry.sector_first_block_relfile = RAM_buffer[offset+22];
    dir_entry.record_size_relfile = RAM_buffer[offset+23];
    dir_entry.unused_1[0] = RAM_buffer[offset+24];
    dir_entry.unused_1[1] = RAM_buffer[offset+25];
    dir_entry.unused_1[2] = RAM_buffer[offset+26];
    dir_entry.unused_1[3] = RAM_buffer[offset+27];
    dir_entry.track_first_block_replacementfile = RAM_buffer[offset+28];
    dir_entry.sector_first_block_replacementfile = RAM_buffer[offset+29];
    dir_entry.blocksize_low_byte = RAM_buffer[offset+30];
    dir_entry.blocksize_high_byte = RAM_buffer[offset+31];    
    dir_entry.unused_2[0] = RAM_buffer[offset+32];
    dir_entry.unused_2[1] = RAM_buffer[offset+33];
    
    return(TRUE);        /*there is more info stored on other track(s)*/
}

/*this routine will seek for the next block within the specified file, the first/current block is indicated by track and sector and the next block is returned over the same pointer*/
/*this routine is usefull for file DELETING/SCRATCHING and VALIDATING of files*/
unsigned char D64SeekNextBlock(unsigned char *track, unsigned char *sector)
{
    D64BlockRead(*track, *sector);
    *track = RAM_buffer[0];
    *sector = RAM_buffer[1];

    if (*track == 0)                /*track = 0 indicates the last sector of the file*/
        return(FALSE);                /*end of file reached, no further blocks*/
    else
        return(TRUE);
}

/*this routine will add another entry inside the D64*/
unsigned char D64AddDirEntry(unsigned char ftype, unsigned char tfblock, unsigned char sfblock, unsigned char *fname, unsigned int blocksize, unsigned char tfblock_rel, unsigned char sfblock_rel, unsigned char size_rel, unsigned char tfblock_replace, unsigned char sfblock_replace)
{
    unsigned char    lp, lp2, offset, result, entry_cnt, fbpt;
    unsigned char    CurrentDirTrack, CurrentDirSector;
    unsigned char    NextDirSector;

    result = D64SeekDirEntry(0, &CurrentDirTrack, &CurrentDirSector, &entry_cnt);
    while(1)
    {    
        if((result == TRUE) && (dir_entry.filetype == 0x00))
        {
            break;
        }

        if(result == FALSE)
        {
            NextDirSector = CurrentDirSector + 1;
            if (NextDirSector > (SPT[CurrentDirTrack] -1))
            {
                return(FALSE);    /*directory is full*/
            }
            else
            {
                D64BlockRead(CurrentDirTrack,CurrentDirSector);                    /*read the directory block where we need to create our new entry*/
                RAM_buffer[0] = CurrentDirTrack;                                /*update the next track field, since this was 0 indicating that this was the last dir sector, but now it is the second last*/
                RAM_buffer[1] = NextDirSector;                                    /*update the next sector field*/
                D64BlockWrite(CurrentDirTrack,CurrentDirSector);                /*update the new info to the card*/                
                CurrentDirSector = NextDirSector;                                /*now we can state that the new t-s are the current one, since the pointer has been updated*/
                D64BlockAllocate(CurrentDirTrack, CurrentDirSector);            /*claim the next block, update the BAM*/
                fbpt = D64ReadFreeBlocksPerTrack(CurrentDirTrack) - 1;            /*decrement counter*/
                D64WriteFreeBlocksPerTrack(CurrentDirTrack, fbpt);                 /*save new value to BAM*/
                break;
            }
        }
        result = D64SeekDirEntry(1, &CurrentDirTrack, &CurrentDirSector, &entry_cnt);
    }
    D64BlockRead(CurrentDirTrack,CurrentDirSector);                                /*read the (new) dir-block before we can alter it*/
    offset = entry_cnt * 32;                                                    /*each dir entry consists of 32bytes*/

    RAM_buffer[offset+2] = ftype;
    RAM_buffer[offset+3] = tfblock;
    RAM_buffer[offset+4] = sfblock;

    /*derive the filename from the command string*/
    lp = 0;
    lp2 = 0;
    while(lp<16)
    {
        if ((fname[lp2] !=0) && (fname[lp2] !=',') && (fname[lp2] !='='))    /*check for end of filename, if the string ends with 0 (null-byte, or if the string is separated by a ','-sign or if the string is separated by an '='-sign*/
        {
            RAM_buffer[offset+5+lp] = fname[lp2];
            lp2++;
        }
        else
        {
            RAM_buffer[offset+5+lp] = 160;                    /*'padd' the filename with shifted spaces*/
        }
        lp++;
    }    

    RAM_buffer[offset+21] = tfblock_rel;
    RAM_buffer[offset+22] = sfblock_rel;
    RAM_buffer[offset+23] = size_rel;

    RAM_buffer[offset+24] = 0x00;
    RAM_buffer[offset+25] = 0x00;
    RAM_buffer[offset+26] = 0x00;
    RAM_buffer[offset+27] = 0x00;

    RAM_buffer[offset+28] = tfblock_replace;
    RAM_buffer[offset+29] = sfblock_replace;
    RAM_buffer[offset+30] = blocksize%256;
    RAM_buffer[offset+31] = blocksize/256;

    RAM_buffer[offset+32] = 0x00;
    RAM_buffer[offset+33] = 0x00;

    D64BlockWrite(CurrentDirTrack,CurrentDirSector);
    return(TRUE);
}

/*this routine will scratch (alias DELETE) a file entry. Actually, it sets the direntry to scratched and sets all blocks to free, the data is still present and can be retreived if not overwritten by another file*/
unsigned char D64ScratchDirEntry(unsigned char dirtrack, unsigned char dirsector, unsigned char direntry)
{
    unsigned char offset, track, sector, fbpt;

    offset = direntry * 32;                                    /*each dir entry consists of 32bytes*/
    D64BlockRead(dirtrack, dirsector);                        /*load the directory block of interest*/
    RAM_buffer[offset+2] = 0x00;                            /*make file of type "SCRatched"*/
    D64BlockWrite(dirtrack, dirsector);                        /*save the (altered) block back*/
    track = RAM_buffer[offset+3];                            /*track of the first block of the file that is to be deleted*/
    sector =  RAM_buffer[offset+4];                            /*sector of the first block of the file that is to be deleted*/
    D64BlockFree(track, sector);                            /*free the first block of the file in the BAM*/
    fbpt = D64ReadFreeBlocksPerTrack(track) + 1;            /*increment the FreeBlockPerTrack counter*/
    D64WriteFreeBlocksPerTrack(track, fbpt);                 /*save new value to BAM*/

    while(D64SeekNextBlock(&track, &sector))
    {
        D64BlockFree(track, sector);                        /*free the ... block of the file in the BAM*/
        fbpt = D64ReadFreeBlocksPerTrack(track) + 1;        /*increment the FreeBlockPerTrack counter*/
        D64WriteFreeBlocksPerTrack(track, fbpt);             /*save new value to BAM*/
    }
    return(TRUE);
}

/*this routine will rename a directory entry*/
/*the filename to be changed is specified by it's dirtrack, dirsector and entry number within the directory track*/
/*the new filename is specified in filename*/
unsigned char D64RenameDirEntry(unsigned char *fname, unsigned char dirtrack, unsigned char dirsector, unsigned char direntry)
{
    unsigned char offset, lp, lp2;

    D64BlockRead(dirtrack, dirsector);                        /*read the block of interest*/

    offset = direntry * 32;                                    /*each dir entry consists of 32bytes*/

    /*derive the filename from the command string*/
    lp = 0;
    lp2 = 0;
    while(lp<16)
    {
        if (fname[lp2] !=0)
        {
            RAM_buffer[offset+5+lp] = fname[lp2];
            lp2++;
        }
        else
        {
            RAM_buffer[offset+5+lp] = 160;                    /*'padd' the filename with shifted spaces*/
        }
        lp++;
    }    

    D64BlockWrite(dirtrack, dirsector);                        /*write back the altered block*/
    return(TRUE);
}


/*this routine will read one sector containing up to 8 filename entries from the D64 image directory*/
/*mode: 0=first,1=next*/
unsigned char D64LoadFileNameSector(unsigned char mode, unsigned char *dirtrack, unsigned char *dirsector)
{
    static unsigned char     NextDirTrack, NextDirSector;

    switch(mode)
    {
        case 0:    /*read from first directory block (Track 18, Sector 1)*/
        {
            NextDirTrack = 18;        
            NextDirSector = 1;
            break;
        }

        case 1:    /*read from next directory block (Track , Sector )*/
        {
            if ((NextDirTrack == 0) && ((NextDirSector == 0) || (NextDirSector == 255)))    /*officially the only exit would be track=0 sector=255, but also track=0 sector=0 is very common to indicate the last block of an directory*/
                return(FALSE);        /*end of directory allready reached*/
            break;
        }
    }

    *dirtrack = NextDirTrack;
    *dirsector = NextDirSector;

    D64LoadFile_X_Bytes(&file,NextDirTrack,NextDirSector,0,256);        /*location of next directory block*/        
    NextDirTrack = block_buffer[0];
    NextDirSector = block_buffer[1];
    return(TRUE);        /*there is more info stored on other track(s)*/
}


/*this routine will read the D64 file and adds calculates the total number of free blocks within the D64-file*/
unsigned int D64LoadFreeBlocks(void)
{
    unsigned int    FreeBlocks;
    unsigned char    lp;

    D64LoadFile_X_Bytes(&file,18,0,0,256);    /*directory block*/        
    FreeBlocks = 0;
    lp = 1;        
    while(lp<=35)                        /*calculate the number of free blocks that can be used for actual user DATA using all 35 tracks stored in the BAM*/
    {
        if (lp != 18)                    /*exclude the DIRECTORY track, since this track can not store user DATA (it is used by the system)*/
        {
            FreeBlocks = FreeBlocks + block_buffer[4*lp];        /*the number of usable blocks is stored every 4 bytes*/
        }
        lp++;
    }
    return(FreeBlocks);
}



/*----------------------------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------------------------*/

/*this routine will search (inside the D64) for a file that matches the given filename search pattern*/
/*If found (TRUE), it return the Track and sector of the first block, as well as the blocksize of the file*/
unsigned char D64SeekFile(unsigned char *filename, unsigned char *track, unsigned char *sector, unsigned int *blocksize, unsigned char *dirtrack, unsigned char *dirsector, unsigned char *direntry)
{
    unsigned char cnt, lp, offset, mode, dtrack, dsector;

 error_code = 0;    /*unless we fail we will exit with no error*/
    mode=0;    /*set sector read to first sector*/
    while(D64LoadFileNameSector(mode, &dtrack, &dsector))        /*get directory filename sector*/
    {
        mode= 1;    /*set sector read to next sector*/
        cnt = 0;    /*clear file index counter within this sector*/
        while(cnt <8)
        {
            *dirtrack = dtrack;
            *dirsector = dsector;
            *direntry = cnt;
            offset = 2 + cnt*32;                            /*calculate the offset for each entry within this sector*/
            if ((block_buffer[offset+0] != 0x00) && (block_buffer[offset+0] != 0x80))    /*scratched files (0x00) are NOT displayed in the directory, and deleted files (0x80) cannot be opened*/    
            {
                *track = block_buffer[offset+1];                /*the first block with the data of this is stored in track/sector*/                
                *sector = block_buffer[offset+2];
                *blocksize = block_buffer[offset+28] + (256*(block_buffer[offset+29]));    /*calculate the size of this file (in blocks)*/            
                lp = 2;            
                do
                {
                //    OutputToRS232();                                /*set standard output to RS232*/
                //    printf("\r\nblock_buffer[%d]=%c filename[%d]=%c",(offset+lp),block_buffer[offset+lp],(lp-3),filename[lp-3]);
                //    OutputToLCD();                                    /*set standard output to LCD*/
                    lp++; 
                    if (lp == 19)        /*when we have reached all to the max number of chars there is no chr$(160)... but we do have a 100% match*/
                        return(TRUE);    /*we have a 100% match*/

                    if((filename[lp-3] == 0x0D) && (block_buffer[offset+lp] == 160))    /*test if this searchstring ends with a CarriageReturn if so then we DO have a 100% match*/
                        return(TRUE);    /*we have a 100% match*/

                    if((filename[lp-3] != 0) && (block_buffer[offset+lp] == 160))    /*when the search string has not been ended but the filename has... no match*/
                        break;    /*we have no match*/

                    if((filename[lp-3] == 0) && (block_buffer[offset+lp] != 160))    /*when the search string has been ended but the filename not... no match*/
                        break;    /*we have no match*/

                    if((filename[lp-3] == 0) && (block_buffer[offset+lp] == 160))    /*when we have reached all to the end of both strings... we have a 100% match*/
                        return(TRUE);    /*we have a 100% match*/
                    
                    /*wildcard filter*/
                    if (filename[lp-3] == '?')        /*when we encounter an '?', it does not matter what the real char of the filename is*/
                        block_buffer[offset+lp] = '?';    /*therefore we can replace the real char by a '?' so that the comparison (at the end of this loop) can still be valid*/

                    if (filename[lp-3] == '*')    /*when we have come so far and detected a * in our search string... we may consider this a match*/
                        return(TRUE);    /*we have a partial or possible 100% match... but good enough to return with TRUE*/
                }
                while(block_buffer[offset+lp] == filename[lp-3]);    /*do the compare of current char of both strings*/
            }
            cnt++;
        }
    }

    OutputToRS232();                                /*set standard output to RS232*/
    printf("\r\nfile not found, exitting");
    OutputToLCD();

 error_code = 62;    /*FILE NOT FOUND*/
    return(FALSE);        /*no match could be found*/
}

unsigned char D64LoadFile_X_Bytes(struct file2TYPE *file, unsigned char track, unsigned char sector, unsigned char byte, unsigned int NmbrOfBytes)
{
    unsigned long ByteAddress;

    /*update the variable regarding the last accesses track and sector*/
    LastTrack = track;        /*this values is required by the error-read routine*/
    LastSector = sector;    /*this values is required by the error-read routine*/
    
    /*calculate the byte address determined by the D64-track-sector-byte numbers*/
    ByteAddress = 0;
    while(track--)
    {
        ByteAddress = ByteAddress + 256 * SPT[track];        /*retrieve number of sector per track from table and multiply the number of sectors with 256 (256bytes per sector), add this to the total*/
    }
    ByteAddress = ByteAddress + 256 * sector;
    ByteAddress = ByteAddress + byte;

    /*read the required data from the card located at the calculated address*/
    FileRead_X_Bytes(file,ByteAddress,NmbrOfBytes);        

    return(TRUE);
}