Gert van der Knokke
/
C1541III
C1541-III mbed edition
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, §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); }