Gert van der Knokke
/
C1541III
C1541-III mbed edition
Diff: D64_decoder.c
- Revision:
- 0:28557a4d2215
diff -r 000000000000 -r 28557a4d2215 D64_decoder.c --- /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, §or)) + { + 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); +}