C1541-III mbed edition

Dependencies:   mbed

Revision:
0:28557a4d2215
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/D64_decoder.c	Mon Aug 22 05:48:51 2011 +0000
@@ -0,0 +1,765 @@
+/*----------------------------------------------------------------------------------*/
+/*    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);
+}