C1541-III mbed edition

Dependencies:   mbed

main.c

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

File content as of revision 1:0cbbb66a6100:

/*==================================================================================*/
/*==   This software is designed to be compiled by the Hi-Tech PIC Ccompiler      ==*/
/*==                                                                              ==*/
/*==   Attention, make sure to compile with the following options selected:       ==*/
/*==           printf: integer + long + float                                        ==*/
/*==================================================================================*/
/*  1541-III (simply said: a 1541 clone that uses MMC/SD-cards)                     */
/*                                                                                  */
/*                                  This is MAIN                                    */
/*                                  ------------                                    */
/*                                                                                  */
/* This program is designed to control the 1541-III project:                        */
/* The 1541-III project is a device to be connected to the IEC-bus of a C64         */
/* The device will act as if it was a 1541 diskdrive. The diskimages are to be      */
/* stored on a MMC or SD-card in the D64 file format (the most common emulator file */
/* for C64 disk images. By selecting a specific D64 file on the card you select the */
/* diskimage to be seen by the connected C64. By mimmicing a 1541 drive the C64 does*/
/* not require any extra software while keeping the flexability of a modern medium. */
/* This way the huge amount of software on the WEB becomes available on your stock  */
/* C64, like the good old days, checking out your new 'disks' full with hours of fun*/
/*                                                                                  */
/* Note:                                                                            */
/* a sector on a 5,25" disk has the size of 256 bytes, this is also called a block  */
/*                                                                                  */
/*      ATTENTION: all settings are calculated for a crystal freq. of 20MHz         */
/*                                                                                  */
/*----------------------------------------------------------------------------------*/

#define            RELEASE_VERSION            8    /*last 2 digits of Year    */
#define            RELEASE_VERSION_SUB        2    /*Month                    */
#define            RELEASE_VERSION_SUB_SUB    27    /*Day                    */

/*  History:
    --------

    IMPORTANT to implement ASAP, IEC abort: the computer sends an ATN during data transfer from device to computer, the device sees that this is a special situation and aborts, freeing up the bus and the computer will get it's prompt back (test this by loading a program and pressing run/stop during loading)
    (this information was supplied by: Dirk (a.k.a. SKERN, from www.dienstagstreff.de)

    debug datahandler!!!
    2011-08-22  First version of this software ported to mbed by Gert van der Knokke
    2008-02-27    release date of this wonderfull version
    2008-02-20    removed the T64 detection in the filefilter routine. Simply because the T64 is not supported yet and showing the T64 files in the card directory would give the wrong impression or simply said it would be confusing.
    2008-02-17    fixed the spaces at the end of a filename-bug (in routine D64Directory()). When a filename has normal (0x20) spaces at the end these are filtered out, so you do not see them in the loaded directory. But since the fileseek routines encounter them they never will report a match (because the last two chars (spaces) are missing)
                The routine ImageDirectory is renamed to D64Directory simply because the D64 directory routine cannot easily be transformed into something universal
    2008-02-15    added a default value to error_code declaration
                made the separation line in the card-directory a bit nicer and added an extra check that removed the undesired first seperator line
    2008-02-14    changed the serial debugging output to some nice ASCII/art looking debugging output (filling some spare minutes)
                did some T64-file preparations...
    2008-02-12    The save bug as reported 21-08-2007 by: Andreas Ekmark    - "File not found error" if the save was successful.    - "File found ok" if the save failed
                As suggested this is indeed the status from the "does file exist" check that must occur prior tosaving that is still reported after the save...
                The probem lies in the not correctly updating of the display and the incorrect updating of the register error_code in the routine set errorcode
    2008-02-11    fixed a problem with the 1541-III powered directly by the VIC20's cassetteport. The 1541-III will hang with the drive LED=green and the LCD in the splash-screen mode. This problem does not occur when the 1541-III is in bootloader-mode. It appears that the VIC20's IEC bus is not stable directly after powerup (causing the 1541-III to trigger falsely and wainting endlessly for signals that never come. Waiting for 2 seconds (as a normal drive does) and then enabling the ATN interrupt solves this problem.
    2008-02-10    removed write protect check as it does not have any value and can be very anoying
                so now you can use a card wether it is or isn't write protected with the "switch" on the side (SD-card card only)
    2008-02-08    fixed the problem in FAT.c (filesearch) regarding the backwards searching within subdirectories.
                As this only is a problem with the use of the buttons... it was discovered at the last moment and now it is fixed. Subdirectories are now FULLY functional <hurray>
    2008-02-05    tested the VIC20 mode on a real vic20, and as expected, there where still too much chars on one line, fixed
    2008-02-04    fixed a smull bug in seekfileoncard() routine. it failed in finding a file of exactly 8 characters long (8.3 name). This situation was not checked, it is now fixed.
    2008-02-01    improved (fat.c) filesearch routine for subdirectory support, it appears to work
    2008-01-31    testing of subdirs
    2008-01-25    added some extra output on the LCD contrast setting, when a user presses a button it shows on the serial port
    2008-01-15    countfiles now show the user that it is counting files (message to display)
                loading of carddirectory now displays the progressbar as it should, during loading you can clearly see the 3 different passes (notice the change in barspeed) this is caused by the fact that the number of files does not match the number of subdirectories and does not match the number of images (ie D64)
    2008-01-12    fixed problem with root selection when using buttons (these routines required changes due to the added subdir functionality)
                during selection using the buttons, the display uses a bar. This bar was a simple progress bar which is confusing as file selection has nothing to do with progress,
                so this is now changed to sort of slider, like you may know from "modern" operating systems like Windows
                Seekfileoncard return the file index (again)
                Print_file_info routine has become obsolete, as this information is allready in the display (bottom right) in the form of the mode of operation
                The directory is shown in 3 passes (pass-1=subdirs, pass-2=images, pass-3=files), the third pass shows filesize in blocks (as in any other directory)
                Added the suggestions made by jussi, to the LCD routines for better LCD clone compatibillity
    2008-01-11    restoring of the button functions, these functions required changes due to the added subdir functionality
    2008-01-10    added countfiles routine (counting files can be usefull after all)
    2008-01-08    Playing with subdirs (part...+2)
                nu is er de uitzondering Root (index 0) maar eigenlijk is dit geen uitzondering.
                Alle subdirs heben deze optie ook. index 0 betekent eigenlijk niets meer dan dat er geen D64 file geselecteerd is en dat we in de harddiskmode zitten
    2008-01-07    Playing with subdirs (part...+1)
    2008-01-05    Playing with subdirs (part...)
    2008-01-04    The routine D64Directory is renamed to ImageDirectory, this because in the future not only D64 will be supported, by keeping all filetypes under the same directory routine, the software stays easy to read. But the name D64Directory is misleading if it reads more the D64's, so the name D64Directory is changed into ImageDirectory as it will show the contents of the image-file in directory style
    2008-01-03    REQUIRES MANUAL CHANGE: the file pointer (when a directory is loaded is no longer a reference to the fileindex. since the fileindex principle has been dropped as it will be no longer practical when used in combination with subdirectories)
    2008-01-02    removal of code that uses index number to refer to files
                REQUIRES MANUAL CHANGE- it is no longer possible to use $0 bla bla bla for D64 file searches, although simple in use. It is no longer practical when files are stored in subdirs. It would take to long to scan the card after insertion and the filenumber would have to be 5 digits to address all possible files on a 1 GByte card
    2007-12-26    counting the number of files on the card is a silly thing to do when we want to break open the 512 file barier by using subdirectories, so these routines are removed
                the files are now displayed in groups when the carddirectory is loaded. Dir, D64, PRG-files this makes it easier to read (looks more organised as well (but's thats because its organised offcourse)
                Sorting on alfabetical order is not going to happen as it would take too much memory or would be too time consuming
    2007-12-23    added the routines to show a directory, the difficult part has yet to come... using these directories, something for the next few... weeks?!?!
    2007-12-23    worked on directory formatting (i.o.w. the results caused by LOAD"$CARD"), now the directory width is different for the normal and the VIC20 mode (select by using the UI+ command to set the IEC speed)
                when used in VIC-20 mode the directory width is limitted to 20 characters, so it displays nicely on a VIC-20
                when used in normal mode the directory width is limitted to 28 characters, so that it holds the max amount of info, while being compatible with normal directory sizes
                Every entry that needs to be loaded as a directory now is display with a proceeding $-sign.
                This because the .PRG and .D64 files are no longer printed with their extension in the filename, but displayed as TYPE at the end of the line.
                On a SX this might be a bit difficult to read (if you are in a hurry). By adding the $-sign, it becomes more clear how to load it AND
                it saves the user the trouble of inserting the $-sign in the directory entry when he/she wants to load it.
                Changed the search routine "SeekFileOnCard" in order to work with the longer filenames and to accept filenames without extensions
    2007-12-21    worked on directory formatting (making sure that it looks OK after LOAD"$")
                also created 2 different directory looks. A small look for the VIC20 and a normal look for others.
                Also the VIC20 mode (25% higher IEC-speed is kept in EEPROM, so the user has to configure this only once as long as he/she uses a VIC20)
                Simply use the standard UI- and UI+ commands to toggle between normal and VIC20 mode (see manual)
    2007-12-20    worked on longfilenames
    2007-12-19    now that longfilenames profe to be functional, let's apply them in the carddirecory routine(s)
    2007-12-18    experimenting with FAT extra's (playing with longfilenames)
    2007-10-27    a small change in LCD_nokia_3310.c (see it's history) solved the inverted character problem, now lines of inverted
                char look beter and the contrast is not disturbed. I expect that this would solve other contrast problem as well,
                there are people out there with LCD's that for some reason have a very "light" contrast and are difficult to read when
                the display's content changes rapidly, it must be something likes this.
    2007-10-25    removed the 1541-III SX detection as the 1541-III inside my SX is nothing more then a v1.0 upgraded to v1.1
    2007-10-24    added the 1541-III dtv C64 edition to the list of recognized devices
    2007-10-18    added the 1541-III second batch to the list of recognized devices
    2007-10-17    added some extra features for hardware testing
                when no card is inserted and the user pushes the i-button then the hardwaretestmenu is entered
    2007-10-11    used the enum statement for the first time, it simplifies constant coding... a little
    2007-08-15    still lot's of work to be done, but this version is suitable for beta-release... so release it!
                people have been waiting long enough for a more stable release... so give it to them although it's not 100%
                it IS better then the previous versions.
    2007-06-30    added a mode of operation indicator, to show if we are operating in D64 mode or HD mode (root dir of card)
                during button selection the progress-bar indicates where we are in the directory
                during button selection some additional file information is shown on the third line
    2007-06-28    small changes in display layout, moved index to error-line
    2007-06-26    placed sample at seterrorcode. This is the best location because this requires only one place where the same sound can be connected to multiple error situations
                display line-2 now shows the last error code (if not 0 or 73 (directly after reset))
                the filename that is being loaded or saved is not displayed to the display any more (only visible via serial port)
    2007-06-25    added the sound samples made by Willem K.(Thanks a lot Willem for your excellent work, unfortunatley the
                hardware does not allow it to play the samples to it's full quality, but the sounds are still very
                distinctive and recognisable as 1541 drive sounds)
    2007-05-17    added a clear display line after the execution of LOAD, SAVE etc.
    2007-05-15    the last few days have been spend with typing old listings from books to further test the current firmware
    2007-05-10    the main do, while loop that checked for ATN was changed to a while(ATN... loop, that had a check for the release of the data line, this solved all my problems
                set the delay to 1000uSec, no problems any more.
    2007-05-09    the new delay location and new value of 100uS was set back to 200uS (still at the new (better) location (the main loop)
    2007-04-25    IEC_bus.c CheckForCommand had an delay of 200uS to ensure the "frame to release of ATN'-time" of min 20uS, this is removed and now in the higher level IEC staemachine (main.c)
                the new location of this delay ensure a quicker response time when waiting for a command
    2007-04-24    stared at the code tried to analyze what went wrong, failed to solve it
    2007-04-23    IECUNDOTURNAROUND should not check on clock, corrected in IEC_bus.C
    2007-04-21    demonstration of project at Maarssen, a very pleasant day. Learned that directories on the card make the 1541-III fail completely although it looks like it all works at first.
                timing within the GET# handling is not 100% correct, adding some printf's for more info and suddenly there np problme no more, investigate further...
    2007-04-18    added interrupt disabling within the datahandler, when the drive becomes a talker (caused by GET# statements) we must disable interrupts otherwise when the computer indicates the last GET# by pulling ATN low, we'd lock up because the interrupt pulls the data-line low and we still need to undo the turnaround (this was a tricky one, thank you my dear (DIY, 5Euro and self written visual basic software for windows PC's) PC logic analyzer
    2007-04-15    removed the: print_device_status("              ");        this was the last statement of the openhandler, this statement should not be needed at this location in the code!
                removed the: print_device_status("              ");        this was the last statement of the datahandler, this statement should not be needed at this location in the code!
    ----------    Vacation @ Lommersbergen
    2007-04-09    set the ATN interrupt filter value back to 25, tested with different values but 5 gives problems, 25 not, so we keep it at 25 (for now, keep this in mind, we need to get to the bottom of this someday)
                note to myself: it apears that disabling of the buttons solves a lot of my problems, perhaps the AD conversion eats up so much time that it disturbs the IEC communication when it's not meant for us!
    ATTENTION    improved readbuttons() routine, it now FIRST checks if a button is pressed and THEN checks which button, this saves a lot of conversion time when no button is pressed, this time becomes available to the statemachine which now can respond much faster to events
            |    the LED RITHM blinking routines interfere with the IEC timing! DAMN! (those blinking routines I liked the most)
             ->    LED RITHM routines removed (all that beautifull work for nothing). But what is the use of a beautifull blinking LED when it interferes with the IEC-bus...
    2007-04-07    - Bugfix in FAT.C reported and fixed by Mattias Olsson
                - Intensive trafic on a different device may cause the 1541-III to trigger false, disturbing the communication between the CBM computer and the other device
                  Some additional checks are added to make sure that the 1541-III handles the UNTALK and UNLISTEN event ONLY when the 1541-III allready has left the IEC IDLE state
    2007-04-05    added the function to readout the result of the opened buffer (GET#1, A$ directly after OPEN 1,8,2,"#")
    2007-04-03    'fixed' bug in B-P command, it appeared that the real bug was in my BASIC program on my C64 (stupid typo regarding dev ID's,
                so it worked on a real drive (8) but not on the 1541-III (9), if I had only swapped the devices to the other ID's the problem
                would appread to be in the 1541 drive, which made it obvious that it was in the C64 program all along. But I had to find it
                out the hard way (offcourse))
    2007-04-02    worked on the same 'problem' again
    2007-04-01    continue of the prev. day
                the check IEC_CLOCK == 1 in UNDOTURNAROUND now has a time-out, simply to improve reliablillity... it helps a lot!
                separated B-R and U1, since the first is 254 bytes and the second if the full 256 byte block-read
                separated B-W and U2, since the first is 254 bytes and the second if the full 256 byte block-write
    2007-03-31    data command (in IEC statemachine) now holds the check if the selected channel is opened, if the selected channel is not opened then the DATA command will be ignored (as it would on a normal drive)
                testing and debugging the effects on the 1541-III when the C64 uses the GET# and INPUT# statement in a directory reading program that does not use the LOAD"$" syntax but U1 and B-P, the results are promissing, I'm on the right track...
    2007-03-30    worked on the U1 and U2 command
                added a buffer pointer to the D64blockread function and named this function D64blockread_new
                added a buffer pointer to the D64blockwrite function and named this function D64blockwrite_new
                replaced the code located under "errochannelhandler" under the openhandler (where it belongs)
    2007-03-29    worked on the U1 and U2 command, these commands are handled in an identical way as the B-P command
    2007-03-28    worked on the b-p command to get an idea of how the info is send towards the 1541 (this low level stuf is described nowhere and examples are very diverse,
                although the mean the same, it is very confusing to say the least. But it becomes more and more clearer everyday...)
                Improved the routine "valuefromstring" so it can now scan for a number, the first character in the tested string does not has to be a number. This makes it more flexible to use.
                Also this routine returns the input string with a pointer to the last location (so you know where to find the second number etc.)
    2007-03-27    worked on the open command and the b-p command
    2007-03-26    created the DOS_buffer and DOS_channel structures to hold all the required information
    2007-03-25    complete rework on the open command and on the buffer definitions... I was wrong all along (damn...)
                removed the independent BAM_buffer in order to use the DOS_buffer at buffer location #4 (DOS_buffer[4].buffer[..]) as you'd expect it to found as it was a real drive
                replaced the variable Dos_buffer.status to NextAction in order to keep track of the next action of this device
    2007-03-23    added more comments and worked on the openhandler (made some small progress, but lots of work to be done)
    2007-03-22    added extra comments (over serial) for easier debugging of new code
    2007-03-20    just staring at the code...
    2007-03-18    worked on the channel handling, lots of work to do... but very important so it must be done,
                but it takes a lot of time before i will get it right, it's very confusing to implement (although
                the concept is very clear and logical, the low level handling makes it complex and therefore
                confusing if not written down correctly the first time
    2007-03-15    changed the blinking routines to use only green in the first batch of 1541-III's (they do not have a tri-color LED)
                added filter on ATN-line, to prevent possible glitches from false triggering the ATN-interrupt
    2007-03-12    Created the color cycle routine
                Created a small blink at every transmitted/received block
                The LED fade on and fade off function is discarded because it function as expected.
                The results are not worth the effort of coding the huge line of exeptions (fading leds are wanted at startup blabla but not during loading,
                you might miss an important event, it creates additional loading delays which are anoying with small files etc.)
    2007-03-08    LED fade-on/off function, the LED does not go on and off its fades gently to the required state
    2007-03-07    replaced the labels RITHM and normal by LED_RITHM and LED_ERROR which is the correct and non confusing label that it should be all along. The new colors are: on=green, error=red, rithm=green+red
    2007-03-05    tri-color led support, for new batch 1541-III DTV a red/green LED has been added to compensate for the lack of a display
    2007-01-30    ...
    2007-01-25    started with the coding of the following commands: B-P:, U1: and U2:
    2006-12-27    start of EEPROM read/write support, this will be finished when sequential file handling is supported, since the EEPROM is best to be handled as a seq. file
    2006-12-06    release date of firmware version
    2006-11-21    reworked improvement... now also the disk-ID is used (if given by user)
                simplified the splitstring on comma, column and equal into one routine: splitstringon_sign, where the sign to 'split on' must be given
    2006-11-20    improved formatting routine, now the diskname is actually used (if given by user)
    2006-11-15    Added some extra print to serial port, so you don't need the display if you're connected to the serial port (can't see why, as a terminal is larger then a nokia display)
                BUG:direct loading of a prg file from root does not seem to work any more !?!?! thought it was fixed
                Fixed: caused by checking for FILE_PRESENT, which should be !=FALSE, because the new routine have more output then TRUE or FALSE
    2006-11-13    Added contrast setting under iec command control: open15,device,15,"LCDCONTRAST=ddd";close15
    2006-11-12    Implemented the copy function, there was allready a beginning for several weeks, but never really implemented until now.
    2006-11-11    Sint Maarten, dus de bel gaat vaak...
                Finished the routines and testing of the D64 file selection (directory loading) by name entry
                I.o.w. instead of LOAD"$24",8 you can now specify the filename LOAD"$filename.D64" (where filename must be exactly 8 chars and for the lazy ones, just use the *-wildcard)
                Setting of device ID using software is functional
    2006-11-09    started with the D64 file selection by name (user request, because currently it is D64 file selection by index only)
    2006-11-08    did some additional testing on the save situation where no card is present, but it apears that this is vitually not responding to the data.
                According to the logic analyser a real drive handles identical. This was not what I expected because this means that on a real drive and the 1541-III
                when a user want to save data to a drive without a disk the user has to wait several seconds before the drive returns and then no confirmation is given until the errorchannel is read.
    2006-11-07    added some extra checkpoints for card removal, there were some situations where the user could bypass the card removal checking routines,
                causing unexpected behavior. This is now fixed.
    2006-11-06    did some testing on the load with and without card inserted
    2006-11-05    BUG: when trying to load from device 10 (on a computer where nothing is connected as device-10, the 1541-III prevent the error "device not present"from happening
                BUGFIX: the FREEIEC routine in combination with the disabling of the ATN-based interrupt solved the problem
    2006-11-03    BUG: the "unsigned char index_cnt;" in "void CardDirectory(void)" prevented the user from using more then 255 files on a single card
                BUGFIX:  "unsigned int index_cnt;", unfortunately I could not test this myself, since I could only store max. 247 files to my SD-card, strange, why !?!?! (they promissed me 512max.)
                User request: added an extra space so that when more then 99files are stored on the card, the directory is still nicely aligned
                BUG:loading of .PRG files does not seem to work when the whole filename is entered,
                but it does work when a part of the filename followed by a * is entered... curious, but true?
                BUGFIX: the CBM computers do not recognize the '~'-sign and when printed to screen
                they show a pi-sign. Unfortunately, this sign cannot be entered during load/save.
                so when doing this a 0xff value is substituted. Very unfortunate because this means
                the comparison for the filenamesearch fails. By replacing the '~'-sign by the '/'-sign
                these problems are simply avoided and all works as intended.
    2006-11-02    ALL routines are functional again, hurray for me, wahoo!!!
    2006-11-02    making all 1541-III functions functional again as it was intended. So that you can use
                OPEN 15,9,15,"S:blabla"
                as well as:
                OPEN 15,9,15
                PRINT#15,"S:blabla"
    2006-11-01    1541-III is functional again HURRAY !!!
                New statemachine functions, the big difference between the new staemachine and the old one is basiccally that the old statemachine
                executed the open command BEFORE the UNLISTEN command, while the new statemachine executes the OPEN command AFTER the UNLISTEN
                command, this is a big difference, suddenly some mysterious delays that could not been found in the specs are not required any
                more. Suddenly it becomes clear that the strange delays were not neccessary after all as long as the proper statemachine was used.
    2006-10-31    statemachine is better but not funcional yet... getting there
    2006-10-30    fucked up the statemachine pretty bad... but it's the only way to build something better. Start with rebuilding it
                tomorrow (in the mean time I feel like crying and I am very glad that I made beackups of the previous version, just in case I can't put it back together)
    2006-10-25    placed the LOAD routines in channel-0 (thats the location where these routine belong in the real 1541)
                placed the SAVE routines in channel-0 (thats the location where these routine belong in the real 1541)
                fixed serious bug in the seekfreeblock(D64_decoder.c), the routine could point to 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-10-24    changed LOAD"$0" for LOAD"$CARD" and make the LOAD"$"=LOAD"$0" this should provide enough support for the Prophet64 to operate with the 1541-III
                load and save routines are only avaiable under channel 0 and 1
    2006-10-23    the errorchannel was threated as a single channel only used for error messages, but in fact it is used for much more... which I only started to realize when I tried to implement more commands that also used the channel 15 (errorchannel)
                because of this it was possible to use the command :
                OPEN 15,9,15,"N:blabla"
                but not the command:
                OPEN 15,9,15
                PRINT#15,"N:blabla"
                this is now fixed (both commands work) since the errorchannel is not only used for the handling of the errormessages
    2006-10-21    timing selection possible by using the UI- and UI+ command. for the DTV users this is not required as timings are automatically set to the fastest possible value (as determined by Jussi S.)
                .D64-file selection by using the command sequence: OPEN1,8,1,"$x":CLOSE1 Did not change the display of the 1541-III, this is fixed. No the D64 filename on the display is only changed when a new file is selected
                changed the routine print_device_status(const unsigned char *message), it accepted only values that it decoded into a string, that was nonsens and creates only large unreradable code, now that is changed so it accepts constant strings
                this also makes it easier to print the same line to the serial port (usefull if you don't have an LCD connected or want to log the actions)
    2006-10-20    made a beginning in implementing the 'adjusted' IEC-bus timings for the DTV (also required for the faster VIC-20 mode (user-command UI-)
    2006-10-16    replaced the '.' in the errorcode 73 for '-' which should be better regarding readabillity
    2006-10-15    shortened the default errorcode by nine characters (removed 1541-III<space>), it now only shows the versionnumber of the software
                added a new device-type 1541-III v1_1 (to indicate the second batch. Actually this is only a detail, since there is no real difference in the first and second batch.
    2006-10-13    changed to MPLAB v7.40, did nothing else, was to busy handling pre-orders, packing 1541-III's and sticking address labels on the box...
    2006-10-11    tested the use of deselectingt the card, this did not hep in reducing operating current, therefore no changes where made regrading the CS-line
    2006-10-02    added the 1541-III DTV splash screen (so you can see if the correct system is detected, even if you have no terminal attached, well you have to have a display offcourse.... But if you do... it would really nice)
                made also the definition for the SX version of the 1541-III... why? Because that's what this projects started, so if I come to the point of building the 1541-III into my SX then it at least has an appropriate startupscreen.
    2006-10-01    added the autodetect routines (detect which PCB where dealing with, 1541-III or 1541-III dtv). This makes distribution of new firmware versions much easier. Also it is much clearer to the outside world to understand that the 1541-III and the 1541-III DTV use the same firmware, how do you explain to a non-technical user that the 1541-III and the DTV version use the same software if you cannot use the same hex-file...
    2006-09-13    when browsing through my 1541-II user's guide I found a different replcae command then I (assumed was correct) found in the "werken met de commodore disk drive" book (R0:<newname>=0:<oldname>). Changed it into the version the 1541-II manual describes (R0:<newname>=<oldname>)
                the replace command functions very well regarding the highscore of Int. Karate, but for some reason Commando cannot read back the highscore svaed by the same routines, after loading highscore the program crashes
    2006-09-12    REPLACE-command (combination of SCRATCH and SAVE), tested it and it works, commando does not work with it ?!?!? further testing required
    2006-09-11    RENAME-command is functional
                scratch command now includes the correct error handling, the error-code 1 shows the number of files scratched in the last track value
    2006-09-10    scratch function nows also includes the use of wildcards (identical to file-loading wildcards)
                also an harmless bug was found, 'the 16th char of each dir entry was not printed when the directory was loaded' (<15 should have been <16) FIXED
    2006-09-05    fixed a small directory problem which made the first file invisible, this was OK but due to the introduction of the new routines a small thinking error was made.
    2006-09-04    a small step further with write support
    2006-09-03    spend all day searching for a bug that wasn't there. The 1541-III behaved strange after I modified my code heavily. It looked like a pointer problem, But no such problem was in my code. At the end it was clear, my 1541-II was switched off and caused erratic behaviour on the bus, resetting my 1541-III at the strangest moments
    2006-09-02    added struct for each directory entry and changed the directory loading routines so that the use the new and simplified block read routines
                also now all large buffers are defined in main.c (cause there is where you want to keep an overview of your resources
    2006-08-31    moved all low level D64 acces routines to: D64_decoder.c
    2006-08-30    created the BLOCK-WRITE routine, which is actually a very simple command, just dump some data to the D64 (only read the 512 block, change 256bytes then write back)
                created the BLOCK-READ routine, which is even easier then BLOCK-WRITE
                created the BLOCK-ALLOCATE routine,...
                created the BLOCK-FREE routine,...
                The actual command using the above routines still has to be written... (so much to do in so little time)
    2006-08-28    added the testing function 'n:' this function tests the block write to card routine
                so now we can format a d64 according to default settings, this only works for the smallest D64 files, other files will NOT be reset completely, thats why this command is for testing only!!!
    2006-08-23    some cards had problems, it apears that these cards where not functioning according specs, read the whole story in the file:ata.c
                improved filefilter routines and combined them into one single routine, this makes the software easier to maintain
                simplified some areas of the code thanks to the Lcd_CharBold() function, saves a lot of putch(...)
    2006-08-21    added more debugging info in order to find the problem regarding the problems with some card not being supported...
    2006-08-17    improved contrast setting button response. The firmware version is now shown on the display when no card is inserted (was allready shown on the serial port at startup but normally this option is never used (only for firmware upgrades))
    2006-08-16    the contrast settings are now stored in EEPROM, so you configure it only once and use it forever without the need of changing it again at every startup
    2006-08-15    added subroutines to set the displays contrast, very important since there seems to be some slight difference between the old and new types of display
                contrast can only be changed when no card is inserted !!!
    2006-08-12    added PWM-output on RB3, this for future support of speaker (thinks of clicks on every track change, disk swap, buttonpress etc.) Now at power-up or reset it plays "halleluj.wav", as a small easter egg since nobody is informed about this feature.
    2006-07-09    changed the read file statemachine, now the read is combined with write, since the command sequence is allmost identical
                corrected the file-locked indicator (it was printed BEFORE the filetype while it should be printed AFTER... silly me)
                track & sector values print to display routine were printed after loading of the block, it is better to print BEFORE loading cause this makes more sense
                added an extra print track and sector routine to properly display the last track and sector of the loaded file
                routine 'Count_files_on_card' only counted the D64 files but it should count ALL files, otherwise you can have an indexnumber higher then the 'number of files on card', that would look stupid!
                removed stupid, stupid, stupid little BUG which prevented the second-last byte from being transferred during load, causing some files to fail after loading
    2006-07-05    improved start-up behaviour, now the 1541-III does not 'hang-up' when accessed without card (basically removal of some busyloops
                added textual message 'LOADING' to the loading related actions (SAVING, DELETING etc. is offcourse to be expected)
    2006-07-04    changed release version number into release version data (thats easier to track changes in the history, you never know...)
    2006-07-03    buttons, functions great, you cannot select a non D64 file
                detection of card removal during operation
    2006-07-02    added functional button selection, but it functions only once?!?!
                added a simple retry mechanism in 'Init_Card_SPI'
    2006-06-30    fixed silly bug in card detect & write protect detection routines
    2006-06-27    changed the ADC registers to the correct 18F2620 ADC registers settings (the 18F2620 has not 2 but 3 regsiters)
    2006-06-23    changed the device to 18F2620 (the prototype device was 18252 the 2620 can do MUCH more for allmost the same price)
                removed the small demo-sequence
    2006-05-20    hacked in a small demo-sequence for the next HCC-meeting in Maarsen, this for use on the "poormans 4K-pixel beamer"
    2006-04-20    improvement in startup screen, now the splash screen stays partially visible exposing only the 1541-III logo (nice)
    2006-04-12    implementation of the ATN under interrupt, this is required for future routine (like file selection using buttons)    2006-04-03    added splash screen at power-up
                ATN under interrupt has the advantage that the computer is confirmed that the device is present while being busy with other things, now we do not have to leave every loop within 1mS or except 'device not present', it is all handled in the interrupt (hurray!!)
    2006-04-02    added extra display functionality, like a progress bar (for loading and saving)
    2006-03-31    2nd day of testing the nokia 3310 lcd, it works
    2006-02-28    some modifications required for the new PCB design and some testing routines
    2006-03-13    when the user tries to acces a directory that is not there, future actions will refer to the card.
    2006-03-10    the file not found problem solved, I needed to release the bus, hurray. Attila, thanks for the information, really appreciate it
    2006-02-22    added frame_handshake signal for later use (trying to solve the file not found situation)
    2006-02-20  Loading of .PRG files is now possible, the search routine will check the filename up to the first 8 chars
                Preparing INT0 for interrupt handling of the ATN-line
    2006-02-19  Loading of .PRG files from the ROOT of the MMC/SD-card is now possible, still have the program the file search routine, it now only recognizes the * wildcard
    2006-02-18    Today was the day of the big presentation at Commdore GG in Maarsen. Well.. it was not exactly a big presentation. But the interest for this project exceeded my wildest dreams. A giant motivation boost!!
                preparing code for the loading of .PRG file from the root directory, this may be usefull for loading a special start-up program for exploring the MMC/SD-card or whatever (it's a 'future' user request)
    2006-2-9/17    Nothing, code is stable now, do nothing untill the presentation at commodore GG has passed
    2006-02-08    added a routine 'print_D64_TSB' to make sure that the same things (Track Sector Blocks) are printed in the same manor
                added the DOT in the 8.3 filename representation in the 'card directory' routine, also added an extra space for better alligment
    2006-02-07    added file selection directly (and only) after reset
                also added a routine 'print_D64_name' to make sure the same things (filename) are printed in the same manor (the best way to achieve this is by a single routine)
    2006-02-05    added LED blinking codes to the existing error messages
    2006-02-04    added interrupt routines to realise the LED blinking (req. for the original LED blinking error indicators)
    2006-02-03  implemented filter on filesize and extension, this means only D64 files are shown (command: LOAD"$0",DEVICE)
    2006-02-02    improvements in code layout... i.o.w. making it more readable, fixed some FAT bugs, tremendous speed improvement !!!
                Benchmark results:    |     filename         | #blocks |    1541-II  | 1541-III | Conclusion
                --------------------+-------------------+---------+----------+----------+----------------
                                       |  Flimbo's Quest   |   172   |   1:42   |   1:20   | (78% of the time req. by a real 1541, i.o.w. this drives operates at 127,5% of the speed of a real 1541)
                                       |                   |         |          |          |

    2006-01-29  Removal of the redundant block_buffer and dat_buf registers, as a result of better 'fat' and 'ata' routines
    2006-01-26    Loading of deleted files was possible, this is now fixed
    2006-01-22    Adjusted the 'help' section in the $0 (card directory) for proper reading on a VC-20
    2006-01-20  it appeared that the presence of a real 1541-II on the bus, creates the situation where some delays are not required. Make sure we test WITH AND WITHOUT other devices on the bus !!! A 100uS delay is required after det. of the first checkforcommand in our 'statemachine'
    2006-01-19    removed unnecessary PRINTF's, added printf filename near LOADD64FILE
    2006-01-19  fixed ValueFromString bug (didn't clear the variable, worked 1 time) fixed directory loading bug (it failed LOAD"$1",9 but not the rest)
    2006-01-18    finished send-error-code routine (although Track and Sector are still hardcoded to 0
    2006-01-16    still searching for problem of the previous day... found the problem was in the release of the bus, fixed in unlisten with FREEIEC routine.
    2006-01-15  continued search for the 'loadin works only the first time' problem
    2006-01-12    renamed some routines, rewritten part of the statemachine
    2006-01-11    rewritten the main decoder loop (statemachine)
    2006-01-10    TALK and LISTEN definitions were mixed up, is corrected    improved the FreeIEC routine
    2006-01-09    interference problem with other devices on the bus has been solved
    2006-01-04    better command decoder
    2006-01-02    begining of real/serious command decoder
    2006-01-01    corrected small error in directory, now text allignment is correct
    2005-12-24  implementation of the actual directory of an D64 emulator file
    2005-12-22  fixed the directory, now we can load a dir into the C64
    2005-12-18  testing of the IEC-write and TurnAround routines
    2005-10/12  gathering data about the IEC-bus, build a logic ananlyser to monitor the IEC-bus activity of a real C64 and 1541-II
    2005-09-20    raw design of fileselection routine
    2005-09-21    design of ADC button decoder
    2005-09-22    design of user interface
    2005-09-26    figured out how to read the disks name from the correct track sector
    2005-09-02    figured out how to decode the ImageDirectory, file by file, algoRITHM
    2005-09-02  started with the free sectors routine
*/

/*  TO DO:
    ------

    for specific "to do" (pieces of missing code) use the following keyword (use search function of editor):
    //to do:

    -replace D64blockread functioncall(s) for D64blockread_new and discard the D64blockread, then rename the D64blockread_new to D64blockread
    -replace D64blockwrite functioncall(s) for D64blockwrite_new and discard the D64blockwrite, then rename the D64blockwrite_new to D64blockwrite

    - the index number can only display 999 entries, theorectically a 2GB card can store 11000 entries (spread over several directories and in 8.3 to save space)
      so there are two options... leave out the index number or enlarge the indexnumber to 5 digits instead of 3

    - controleren of er nog (andere) plekken zijn waar "extractfilenamefromstring" gebruikt kan worden
    - controleren of er nog op plaatsen gebruik word gemaakt van IEC_undoturnaround, dit zou IEC_letgo moeten zijn simpelweg omdat undo_turnaround niet gedefinieerd is in de IEC specs

    - hoe zit het met de 1541-III dtv in de versie met de tri-color LED, zit daar ook een condensator aan de ingang om te detetcteren dat het een andere versie is?

    - loading of a directory without typeing LOAD"$",8 (zie de boeken voor voorbeeld programma's)
    - block read and write... B-W en B-R, deze zijn nu nog voor de 256byte maar moeten uiteraard voor de 254 byte versie zijn, de 1e twee bytes overslaan !?!?

    - the 1541-III fails to function in combination with a C128

    - the routine "void SendErrorMessage(void)" is designed to transmit ALL 4 values(byte,byte,string,byte) of the error message, but what if a user request only the first(byte), how is this handled by a real 1541?
      check for EOI bij elke stap

    - Make note in manual about unrecognised characters (see bugfix of 2006-11-03)

    - support for eror-bytes in extended 35- and 40-track .D64 files
*/

/*    Notes to myself:
    ----------------
    -C128 problem NOT 1541-III: CAN'T LOAD OUTRUN.PRG ANY MORE IF LOADED CBM CRASHES!!!    THE ABOVE IS CAUSED SIMPLY BECAUSE THIS FILE FAILS TO FUNCTION ON MY C128 ON WHICH I TEST MOSTLY. IT FUNCTIONS PERFECTLY ON MY C64

    -when teh C64 screen is "blanked" it should be possible to adjust the timings from 60uS to 20uS, since the VIC is not interfering (or doesn't it work like this)

*/

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

// example of sd card access
#include "mbed.h"
#include <main.h>
#include <hardware.h>
#include <delay.h>
#include <ata.h>
#include <fat.h>
#include <D64_decoder.h>
#include <T64_decoder.h>
#include <IEC_bus.h>

// #include "string"
// #include "SDHCFileSystem.h"
//
// SDFileSystem sd(p5, p6, p7, p8, "sd"); // mosi, miso, sclk, cs
//
// int main() {
//
//       FILE *fp = fopen("/sd/myfile.txt", "w");
//       fprintf(fp, "\n\rHello World!\n\r");
//       fclose(fp);
// }
// IEC hardware connections
DigitalInOut nSRQ(p18);     // DIN6 pin 1
DigitalInOut nATN(p17);     // DIN6 pin 3
DigitalInOut nCLK(p16);     // DIN6 pin 4
DigitalInOut nDATA(p15);    // DIN6 pin 5
// DigitalInOut nRESET(p19);

InterruptIn nIRQ(p30);      // external loop: connect to nATN
InterruptIn nRESET(p29);    // DIN6 pin 6

DigitalIn JUMPER_J2(p21);
DigitalIn JUMPER_J3(p22);

DigitalOut myled1(LED1);
DigitalOut myled2(LED2);
DigitalOut myled3(LED3);
DigitalOut myled4(LED4);

#define LED_GREEN myled1
#define LED_RED   myled2

Timer timeout;
Serial linktopc(USBTX,USBRX);

// #define IEC_ATN_REL()    IEC_DDR &= ~IEC_BIT_ATN
void IEC_ATN_REL() {
    nATN=1;
    nATN.input();
}

// #define IEC_ATN_PULL()   IEC_DDR |= IEC_BIT_ATN
void IEC_ATN_PULL() {
    nATN.output();
    nATN=0;
}

// #define IEC_CLOCK_REL()  IEC_DDR &= ~IEC_BIT_CLOCK
void IEC_CLOCK_REL() {
    nCLK=1;
    nCLK.input();
}

// #define IEC_CLOCK_PULL() IEC_DDR |= IEC_BIT_CLOCK
void IEC_CLOCK_PULL() {
    nCLK.output();
    nCLK=0;
}

// #define IEC_DATA_REL()   IEC_DDR &= ~IEC_BIT_DATA
void IEC_DATA_REL() {
    nDATA=1;
    nDATA.input();
}

// #define IEC_DATA_PULL()  IEC_DDR |= IEC_BIT_DATA
void IEC_DATA_PULL() {
    nDATA.output();
    nDATA=0;
}

void IEC_SRQ_REL() {
    nSRQ=1;
    nSRQ.input();
}

void IEC_SRQ_PULL() {
    nSRQ.output();
    nSRQ=0;
}

int IEC_ATN() {
    nATN.input();
    return    nATN;
}

int IEC_CLOCK() {
    nCLK.input();
    return  nCLK;
}

int IEC_DATA() {
    nDATA.input();
    return   nDATA;
}

int IEC_SRQ() {
    nSRQ.input();
    return nSRQ;
}

/*--------------------------------------------------------*/
/*                       EEPROM                           */
/*--------------------------------------------------------*/
/*
__EEPROM_DATA('-','-','-','-','-','-','-','-');
__EEPROM_DATA('-','-','-','-','-','-','-','-');
__EEPROM_DATA('-','-','-','-','-','-','-','-');
__EEPROM_DATA('-','-','-','-','-','-','-','-');
__EEPROM_DATA('-','-','-','-','-','-','-','-');
*/
/*--------------------------------------------------------*/

/*--------------------------------------------------------*/
/*                        constants                       */
/*--------------------------------------------------------*/

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

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

/*PCB types and versions*/
enum PCBTYPE {v1=10, v1_1, DTV, DTV_C64};

/*defines for the IEC-bus statemachine*/
enum IEC_bus_statemachine {IDLE=0, ACTIVE_LISTEN, ACTIVE_TALK};

/*blink modes*/
enum LED_modes {LED_OFF=0, LED_ON, LED_ERROR, LED_GR, LED_RD, LED_OR};

/*disk-state*/
enum DiskState {NO_CARD=0, CARD_ACTIVE, INVALID_POINTER};

/*1541-III commands*/
enum Commandset {ABORT=0, ABORT_SENDING, ABORT_RECEIVING, NO_FILE, FILE_OPEN, NEW_D64, CARD_DIRECTORY, DIRECTORY, RD_FILE, RD_FILE_FROM_ROOT, WR_FILE, WR_FILE_TO_ROOT, REPLACE_FILE, SCRATCH_FILE, RENAME_FILE, COPY_FILE, SET_DEVICEADDR, USER_IEC_SPD_UP, USER_IEC_SPD_DWN, MODIFY_FILE, MODIFY_FILE_TO_ROOT};

/*filetypes*/
enum Filetypes {SEQUENTIAL=1, RELATIVE, PROGRAM, USER, LENGTH};

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

#define            BUTTON_SELECTION_RATE 350        /*this value determines the button repetition rate*/

/*MMC/SD-card*/
#define            MMCCARD                2            /*card type found reference*/
#define            SDCARD                3            /*card type found reference*/
#define            FILENOTFOUND         4            /*filenotfound reference*/
#define            SUPPVOLT            0x3C        /*mask and compare value for cards that support 3.0-3.1, 3.1-3.2, 3.2-3.3, 3.3-3.4 Volt*/

/*buttons*/
#define            button_none            0            /*numerical value of ADC when no button is pressed*/
#define            button_tolerance    15            /*max. alowable deviation of expected button values*/
#define            button_1             870            /*numerical value of ADC when button-1 is pressed*/
#define            button_2            721            /*numerical value of ADC when button-2 is pressed*/
#define            button_3            575            /*numerical value of ADC when button-3 is pressed*/
#define            button_4            431            /*numerical value of ADC when button-4 is pressed*/
#define            button_5             288            /*numerical value of ADC when button-5 is pressed*/
#define            button_6            145            /*numerical value of ADC when button-6 is pressed*/

/*1541-III operational modes/filefilter results*/
#define            NONE                0        /*the 1541-III has currently no file selected. I.o.w. the 1541-III works in the root directory and can load files directly from the card*/
#define            PRG_FILE            1
#define            D64_35T_MODE        2        /*the 1541-III has opened a .D64 file (35 tracks no errors) and works as of your working with a real 1541 disk drive*/
#define            D64_35T_ER_MODE        3        /*the 1541-III has opened a .D64 file (35 tracks with errors) and works as of your working with a real 1541 disk drive*/
#define            D64_40T_MODE        4        /*the 1541-III has opened a .D64 file (40 tracks no errors) and works as of your working with a real 1541 disk drive*/
#define            D64_40T_ER_MODE        5        /*the 1541-III has opened a .D64 file (40 tracks with errors) and works as of your working with a real 1541 disk drive*/
#define            T64_MODE            6        /*the 1541-III has opened a .T64 file*/
#define            SUBDIRECTORY        100        /*the 1541-III has encountered a subdirectory*/
#define            UNKNOWN                255        /*the 1541-III has encountered a file that has no extension*/

#define            FILE_NOT_PRESENT    0
#define            FILE_PRESENT        1

/*text printing definitions*/
#define            PLAIN                0
#define            BOLD                1
#define            INVERTED            2

/*--------------------------------------------------------*/
/*                         macro's                        */
/*--------------------------------------------------------*/
#define            disable()     GIE=0                /*disable interrupts*/
#define            enable()     GIE=1                /*enable interrupts*/

/*--------------------------------------------------------*/
/*                         globals                        */
/*--------------------------------------------------------*/

unsigned char    RAM_buffer[256];            /*this is the buffer capable of holding one 256 byte block, a memory area to which the user or the 1541-III can write/read data to/from*/
//unsigned char    BAM_buffer[162];            /*this buffer holds the Block Allocation Map, required for when we want to write to the D64 (max 40 tracks)*/
unsigned char     block_buffer[512];            /*this buffers the data 'as read from' or 'to be written to' the card*/
struct            DOS_buffer_struct    DOS_buffer[MAX_NUMBER_OF_DOS_BUFFERS];    /*this array of structs holds the information about the possible channels*/
struct            DOS_channel_struct    DOS_channel[16];                        /*this array of structs holds this information about the currently used channels*/

/*--------------------------------------------------------*/
unsigned char     PCB_type;                    /*this value contains the PCB type/version*/
unsigned int    PCB_type_timer;                /*this timer determines the actual PCB type detection*/
unsigned char    setting_contrast;            /*this is the value belonging to the contrast setting as found in EEPROM*/
unsigned char    VIC20_mode;                    /*this is the value belonging to the IEC-speed setting as found in EEPROM*/

unsigned char    devicenumber;                /*this var. holds the device number 8,9,10 or 11*/
unsigned char    device_command;

unsigned char    IEC_state;                    /*talk, listen or idle*/
unsigned char    channel;                    /*this register holds the channel value*/
unsigned char    nextfreebuffer;                /*this register holds the buffernumber of the next buffer to be used*/
unsigned char    ChannelUsesBuffer[16];        /*small array to keep track of which channel uses what buffer (to drive you mad... MAD I SAY!$#%$#%$#$%#)*/
unsigned char    command;                    /*this is the unfiltered (as received for the IEC-bus) command*/
unsigned char    command_string[41];            /*this string holds the command details/options*/
unsigned char    filename_string[41];        /*this string (is suppost to) hold(s) the filename*/
unsigned char    oldfilename_string[41];        /*this string (is suppost to) hold(s) the new filename (for renaming routines)*/
unsigned char    value_string[17];            /*this string (is suppost to) hold(s) a value*/
unsigned char    string_pntr;
unsigned char    string_pntr_2;
unsigned long    value_long;
unsigned char    value_1;
unsigned char    value_2;
unsigned char    value_3;
unsigned char    value_4;
unsigned char    filetype_string[41];        /*filetype can be sequential, program, user, etc.*/
unsigned char    RW_string[41];                /*file read or write*/

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

unsigned char    Response_data[5];

unsigned char    file_type;                    /*this holds the type of the current file or NONE if no file is selected*/
unsigned int    file_number;                /*the current file index number, this number is used as a reference for button actions*/
unsigned int    CountedFiles;                /*the number of files in the current (root/sub)-directory*/

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

bit                button_prev;
bit                button_select;
bit                button_next;

unsigned char    Blink_mode;                    /*mode of operation of the blink routine*/
bit                Blink_dir;                    /*direction of intensity change (up or down)*/
unsigned char    Blink_block;                /*holds the byte-number on which the LED should go off in order to create a blink at every block*/
unsigned char    LED_OFF_delay;                /*holds the delay timing value for the LED-OFF time*/
bit                LED_status;                    /*the current state of the LED is stored here*/
unsigned char    LED_color;                    /*value to keep track of current LED-color*/
unsigned char    next_LED_color;                /*value to keep track of current LED-color*/
unsigned char    DiskState;                    /*state of the disk (image) inside the drive (1541-III)*/

bit             EOI;                        /*End Of Indicator: this flag (when TRUE) indicates that the last byte is being transmitted or received*/
bit             TimeOut;                    /*Timeout-flag*/

unsigned char     dirtrack, dirsector, direntry;
unsigned long    lp, lp2;
unsigned int    blocksize;
unsigned char    track, sector;
unsigned char    file_status;

/*--------------------------------------------------------*/
/*                     local functions                    */
/*--------------------------------------------------------*/
void WaitForString(unsigned char *outputstring, unsigned frame_handshake);
unsigned char ValueFromString(unsigned char *inputstring, unsigned char *outputvalue);
unsigned char LongValueFromString(unsigned char *inputstring, unsigned long *outputvalue);
void ExtractFilenameFromString(unsigned char *input_string, unsigned char *output_string);
unsigned char SplitStringOn_Sign(unsigned char sign, unsigned char *beforesign_string, unsigned char *aftersign_string);

void IEC_direction_statemachine(void);
void OpenHandler(void);
void DataHandler(void);
void AutoDetectPcbType(void);
void NoCardMenu(void);
void HardWareTestMenu(void);
unsigned char CardStatus(void);
void CountFiles(void);
unsigned char Init_Card_SPI(void);
unsigned char FileFilter(void);

unsigned char SearchFreeBuffer(void);

void Clear_block_buffer(void);
void SelectD64Image(void);
void CardDirectory(void);
void D64Directory(void);
void T64Directory(void);
unsigned int SeekFileOnCard(unsigned char *filename, struct file2TYPE *file);
void LoadFileFromCard(struct file2TYPE *file);
void LoadD64File(unsigned char trk, unsigned char sec, unsigned int filesizeinblocks);
unsigned char SaveD64File(void);
unsigned char CopyD64File(unsigned char trk, unsigned char sec, unsigned int filesizeinblocks);

void SetErrorCode(unsigned char error, unsigned char LEDmode);
void SendErrorMessage(void);

void print_device_status(const unsigned char *message);
void print_D64_name(unsigned char mode);
void print_D64_TSB(unsigned char trk, unsigned char sec, unsigned int blk, unsigned int total_blk);

unsigned char ReadDeviceJumper(void);
unsigned char ReadButtons(void);

void FormatD64File(unsigned char *diskname, unsigned char *diskid);
/*****************************************************************************************************************/
/*****************************************************************************************************************/
/*****************************************************************************************************************/
/*Interrupt service routines*/
/*****************************************************************************************************************/
/*****************************************************************************************************************/
/*Low-priority interrupt entry point*/
void NotTimeCritical(void) {

}

/*High-priority interrupt entry point*/
void high_priority(void) {
    unsigned char    filter_cnt;
    /*By putting the ATN-line detection on an interrupt-line we detect the ATN-situation independent of*/
    /*other actions, like selecting a new D64 image. This method makes IEC programming less complex*/
    /*the small filter also creates a hold-off time, for some reason this is required*/
    filter_cnt = 25;            /*check the ATN line it must be kept low for a few cycles at least otherwise it might have been a glitch*/
    while (IEC_ATN() == 0) {         /*although this filter does add some latency to the start of a data transfer, it is not noticeable in practice*/
        /*it does however add a more secure ATN-line detection, since the inputlines are not filtered in any other way*/
        wait_us(1);
        filter_cnt--;
        if (filter_cnt == 0)    /*when the ATN signal has been proven not to be a glitch*/
        {                        /*we can safely handle the ATN-signal*/
            IEC_DATA_PULL();/*join the bus...*/
            myled3=1;

            break;
        }
    }
}

extern "C" void mbed_reset();

void iec_reset_interrupt(void) {
    nIRQ.fall(NULL);
    nRESET.fall(NULL);
    mbed_reset();
}

/*macro*/
// #define        disable_ATN_interrupt()    INT0IE = 0    /*disable interrupts on ATN line*/
// #define        enable_ATN_interrupt()    INT0IE = 1    /*enable interrupts on ATN line*/

void enable_ATN_interrupt() {
    nIRQ.mode(PullUp);
    nIRQ.fall(&high_priority);
}

void enable_RESET_interrupt() {
    nRESET.mode(PullUp);
    nRESET.fall(&iec_reset_interrupt);
}

void disable_ATN_interrupt() {
    nIRQ.fall(NULL);
}
/*****************************************************************************************************************/
/*****************************************************************************************************************/
/*Main*/
/*****************************************************************************************************************/
/*****************************************************************************************************************/

int main(void) {

    HardwareInit();                                    /*init controller registers and I/O-lines*/
//    GetSettingsFromEEPROM();                        /*read EEPROM settings*/
    devicenumber = ReadDeviceJumper();                /*read the devicenumber jumper*/
    InitIEC();                                        /*initialize the IEC-bus levels*/
    /*initialize SPI*/


    linktopc.baud(115200);

    timeout.start();     // start timer

//   InitLcd();                                        /*initialize the LCD*/
    AutoDetectPcbType();                            /*measure the button capacitor to determine PCB type*/
    OutputToRS232();                                /*set standard output to RS232*/
    printf("\r\n  -----------------------------------------");
    printf("\r\n |                                         |");
    printf("\r\n |                                         |");
    printf("\r\n |        --==   1541 - III    ==--        |");
    printf("\r\n |             (by J.Derogee)              |");
    printf("\r\n |      (http://jderogee.tripod.com)       |");
    printf("\r\n |                                         |");
    printf("\r\n |                                         |");
    printf("\r\n |                                         |");
    printf("\r\n |                                         |");
    printf("\r\n |                                         |");
    printf("\r\n |                                         |");
    printf("\r\n |                                         |");
    printf("\r\n |                                         |");
    printf("\r\n |                                         |");
    printf("\r\n |                                         |");
    printf("\r\n |     --------------------------------    |");
    printf("\r\n | ( ) |Firmware vers.: v20%02d-%02d-%02d   |    |",RELEASE_VERSION,RELEASE_VERSION_SUB,RELEASE_VERSION_SUB_SUB);
    printf("\r\n |     |J2 (Device-ID): ID=%1d          |    |",devicenumber);
    printf("\r\n |     |J3 (Bootldr)  : ");
    if (JUMPER_J3 == 0)
        printf("ACTIVE        |    |");
    else
        printf("DISABLED      |    |");

    printf("\r\n | ( ) |Contrast      : 0x%02x          |    |",setting_contrast);    /*show the settings*/
    printf("\r\n |     |VIC20-mode    : ");
    if (VIC20_mode == TRUE)
        printf("TRUE          |    |");
    else
        printf("FALSE         |    |");

    printf("\r\n |     |PCB type det. : %05d         |    |",PCB_type_timer);    /*check which kind of PCb we are dealing with...*/

    /*adjust the startup sequence accordingly and settings depending on the PCB version*/
    if (PCB_type == v1) {
        printf("\r\n | ( ) |Detected PCB  : 1541-III v1.0 |    |");
//        Lcd_show_1541_III();                        /*show splash screen*/
        SetIEC_timings(TIMINGS_DEFAULT);            /*set timings to default*/
        Blink_block = 235;                            /*i.e. set the value to 225 to get a short off-time (it count to 254 and then goes on again), set value to 255 and it never blinks*/
    }

    if (PCB_type == v1_1) {
        printf("\r\n | ( ) |Detected PCB  : 1541-III v1.1 |    |");
        //      Lcd_show_1541_III();                        /*show splash screen*/
        SetIEC_timings(TIMINGS_DEFAULT);            /*set timings to default*/
        Blink_block = 235;                            /*i.e. set the value to 225 to get a short off-time (it count to 254 and then goes on again), set value to 255 and it never blinks*/
    }

    if (PCB_type == DTV) {
        printf("\r\n | ( ) |Detected PCB  : 1541-III DTV  |    |");
        //    Lcd_show_1541_III_DTV();                    /*show splash screen*/
        SetIEC_timings(TIMINGS_DTV);                /*set timings according the settings as requested by Jussi (DTV tested settings)*/
        Blink_block = 235;                            /*i.e. set the value to 225 to get a short off-time (it count to 254 and then goes on again), set value to 255 and it never blinks*/
    }

    if (PCB_type == DTV_C64) {
        printf("\r\n | ( ) |Detected PCB : 1541-III DTV   |    |");
        //  Lcd_show_1541_III_DTV();                     /*show splash screen*/
        SetIEC_timings(TIMINGS_DEFAULT);             /*set default timings */
        Blink_block = 235;
    }

    printf("\r\n |     --------------------------------    |");
    printf("\r\n |                                         |");
    printf("\r\n |     O                             O     |");
    printf("\r\n |   POWER                         DRIVE   |");
    printf("\r\n |                                         |");
    printf("\r\n  -----------------------------------------");
    printf("\r\n");

    if (VIC20_mode == TRUE)                            /*when the user has selected the VIC20 mode, respect that setting and use it again. This is more userfriedly then setting it every time the system start/resets*/
        SetIEC_timings(TIMINGS_VIC20);                /*the VIC20_mode is not only a speed setting. It is a mode where the card directory is adjusted for a smaller (24 instead of 40 columns) screen*/
    /*set timings according the VIC-20 settings (25% faster mode)*/

    printf("\r\n");                                    /*set cursor to the beginning of the next line (prepare for future (optional) debug printing)*/
    OutputToLCD();                                    /*set standard output to LCD*/
    SetErrorCode(73, LED_ON);                        /*all is OK, but show ID first, LED is ON as on a real 1541*/

    for (lp=0; lp<MAX_NUMBER_OF_DOS_BUFFERS; lp++) { /*clear the channels*/
        DOS_channel[lp].channel_in_use = FALSE;
        DOS_channel[lp].filename[0] = 0;
        DOS_channel[lp].filetype = 0;
        DOS_channel[lp].RW = 0;
        DOS_channel[lp].track = 0;
        DOS_channel[lp].sector = 0;
        DOS_channel[lp].buffer_pointer = 0;
        DOS_channel[lp].used_buffer = 255;
        DOS_channel[lp].status = NO_FILE;
    }

    for (lp=0; lp<5; lp++) {                         /*clear the buffers*/
        DOS_buffer[lp].buffer_in_use = FALSE;
        for (lp2=0; lp2<256; lp2++) {
            DOS_buffer[lp].buffer[lp2] = 0;
        }
    }
    DOS_buffer[4].buffer_in_use = TRUE;                /*this buffer location (or channel) is used for holding the disks BAM, therefore it is not free to be used by the user*/

    // DelayBigMs(2000);                                /*a small delay to keep the splash-screen visible and to ensure that the connected computer has powered up correctly, this is mainly required for the VIC20. Although the DTV version does not have an LCD (mostly) waiting 2 seconds after powerup is good practice anyway, as the IEC-bus may not be stable yet (a real drive has the same delay)*/
    IEC_state = IDLE;
    file_type = NONE;                                /*after reset or card insertion there is no D64 file selected, so all actions regarding current refer to the card*/
    DiskState = NO_CARD;                            /*no card detected yet, so no D64 is selected*/
    file_type = NONE;                                /*and because the user has selected nothing yet we are in the root, the selected file_type = NONE, as there is no image file selected and we are operating in harddiskmode*/
    enable_ATN_interrupt();                            /*enabling the interrupt makes the system ready for use on the IEC-bus*/
    enable_RESET_interrupt();
    
    while (1) {
        IEC_direction_statemachine();
    }
}

/*****************************************************************************************************************/
/*****************************************************************************************************************/
#define CARD_DETECT 0   // this should be a hardware pin

void IEC_direction_statemachine(void) {
    DelayBigUs(1000);                                    /*'frame to release of ATN'-time is at least 20uS, so we wait a bit longer before we check the status of the ATN-line... otherwise we may be interpret it incorrectly*/
//    DelayBigUs(200);                                    /*'frame to release of ATN'-time is at least 20uS, so we wait a bit longer before we check the status of the ATN-line... otherwise we may be interpret it incorrectly*/
    device_command = CheckForCommand(&command, TRUE);
    while (device_command == FALSE) {                      /*no commands are received so we have time for others things...*/

        if (CARD_DETECT == 1)                           /*check if the card is present*/
            DiskState = NO_CARD;                        /*no card detected, so no D64 is selected*/

        if (DiskState == NO_CARD) {
            DelayBigMs(1000);
            SetErrorCode(73, LED_OFF);                    /*all is OK, but show ID first, LED is OFF as on a real 1541*/
            //   Lcd_clr();                                    /*clear screen to prepare for more serious info.*/
            NoCardMenu();                                /*check if a setting button has been pressed and handle accordingly*/
            if (CardStatus()) {                          /*this routine will only pass until a valid card is present*/
                CountFiles();                            /*count all files in the current directory (which is root)*/
                SetErrorCode(73, LED_OFF);                /*all is OK (but show ID first) set LED to color cycle to indicate that this is the first time we enter the root after card insertion or reset. Meaning that the selected file is 0 (the card itself)*/
                file_type = NONE;                    /*after reset or card insertion there is no D64 file selected, so all actions regarding current refer to the card*/
                //        Lcd_clr();
                print_D64_name(PLAIN);
                print_D64_TSB(0, 0, 0,0);                /*print Track, Sector, Block*/
            }
        }
//       else
//       {
//           SelectD64Image();                            /*check for user interaction via buttons*/
//       }
        device_command = CheckForCommand(&command, TRUE);
    }

    if (CARD_DETECT == 1)                               /*check again if the card is present, some @#$#@$#@% might have removed it*/
        DiskState = NO_CARD;                            /*no card detected, so no D64 is selected*/


    switch (device_command) {
        case OPEN: {  /*here we decode the command string and we check if we are capable of executing the requested action*/
            DOS_channel[channel].channel_in_use = TRUE;        /*claim this channel*/
            WaitForString(command_string, TRUE);            /*wait for an operator string that ends with an EOI*/
            break;
        }

        case DATA: {
//            if (DOS_channel[channel].channel_in_use == TRUE)    /*check if this channel has been opened, if not ignore*/
//            {
            DataHandler();
//            }
//            else
//            {
//                OutputToRS232();                                        /*set standard output to RS232*/
//                printf("\r\nChannel not open! Ignore DATA command");    /*!!! DEBUG ONLY !!!*/
//                OutputToLCD();                                            /*set standard output to LCD*/
//            }
            break;
        }

        case CLOSE: {
//            if (channel == 15)                                    /*when the error/command channel is closed, then all files stored in the DOS buffer are closed also*/
//            {
            /*to do: close all open files properly*/
//            }
//            else
//            {
//            }

            if (DOS_channel[channel].used_buffer != 255) {  /*check if there is a buffer connected to this channel*/
                DOS_buffer[DOS_channel[channel].used_buffer].buffer_in_use = FALSE;    /*free the buffer that was connected to this channel. now this buffer is free to use for newly opened channels that might require a buffer*/
            }

            /*set the channel information back to default, although i doubt that the original 1541 does this...*/
            DOS_channel[channel].channel_in_use = FALSE;
            DOS_channel[channel].filename[0] = 0;
            DOS_channel[channel].filetype = 0;
            DOS_channel[channel].RW = 0;
            DOS_channel[channel].track = 0;
            DOS_channel[channel].sector = 0;
            DOS_channel[channel].buffer_pointer = 0;
            DOS_channel[channel].used_buffer = 255;
            DOS_channel[channel].status = NO_FILE;

            OutputToRS232();                        /*set standard output to RS232*/
            printf("\r\nClose");                    /*!!! DEBUG ONLY !!!*/
            OutputToLCD();                            /*set standard output to LCD*/
            break;
        }

        case UNLISTEN: {
            if (IEC_state != IDLE) {                  /*make sure that this command is not the last command of a different device, if it is our device we are not IDLE anymore since the this device would have it's status set to a different thing the IDLE*/
                if (DOS_channel[channel].channel_in_use == TRUE) {  /*check if the previous command on this channel was open*/
                    OpenHandler();
                }

                //turn LED OFF
//    OutputToRS232();                /*set standard output to RS232*/
//    printf("\r\nUnlisten\r\n");            /*!!! DEBUG ONLY !!!*/
//    OutputToLCD();                    /*set standard output to LCD*/
                IEC_state = IDLE;
            }
            break;
        }

        case UNTALK: {
            if (IEC_state != IDLE) {                  /*make sure that this command is not the last command of a different device, if it is our device we are not IDLE anymore since the this device would have it's status set to a different thing the IDLE*/
                //turn LED OFF
                IEC_state = IDLE;
//    OutputToRS232();                    /*set standard output to RS232*/
//    printf("\r\nUntalk\r\n");                /*!!! DEBUG ONLY !!!*/
//    OutputToLCD();                        /*set standard output to LCD*/

            }
            break;
        }

        default: {
            if (device_command == (LISTEN | devicenumber)) {
                //turn LED ON
                IEC_state = ACTIVE_LISTEN;
//    OutputToRS232();                /*set standard output to RS232*/
//    printf("\r\nListen");            /*!!! DEBUG ONLY !!!*/
//    OutputToLCD();                    /*set standard output to LCD*/
                break;
            }

            if (device_command == (TALK | devicenumber)) {
                //turn LED ON
                IEC_state =    ACTIVE_TALK;
//    OutputToRS232();                /*set standard output to RS232*/
//    printf("\r\nTalk");                /*!!! DEBUG ONLY !!!*/
//    OutputToLCD();                    /*set standard output to LCD*/
                break;
            }

            /*--------------------------------------------------------------------------------------*/
            /* current communication on the bus is incorrect or meant for another device on the bus */
            /*--------------------------------------------------------------------------------------*/
            disable_ATN_interrupt();    /*By disabling the ATN interrupt we do not interfer with the data that is meant for another device on the bus*/
            FreeIEC();                    /*get of the bus...*/
            enable_ATN_interrupt();        /*all is back to normal, enable interrupts on ATN line*/
            IEC_state = IDLE;
            break;
        }
    }

    myled3=0;
}


void OpenHandler(void) {
//    OutputToRS232();                        /*set standard output to RS232*/
//    printf("\r\nOPENHANDLER: ");                /*!!! DEBUG ONLY !!!*/
//    printf("command_string:%s",command_string);    /*!!! DEBUG ONLY !!!*/
//    printf("\r\nchannel:%d",channel);        /*!!! DEBUG ONLY !!!*/
//    OutputToLCD();                            /*set standard output to LCD*/

    switch (channel) {
        case 0: {              /*this channel is used for reading of files*/
            if (DiskState == NO_CARD) {
                DOS_channel[channel].next_action = ABORT_SENDING;
                break;
            }

            /*------------------*/
            /* '$' = DIRECTORY  */
            /*------------------*/
            if ((strlen((char *)command_string) == 5) && (strncmp((char *)command_string,"$CARD", 5) == 0 ))        /*check the COMPLETE string*/
            {    /*ROOT directory of the card*/
                file_type = NONE;                                        /*all later actions refer to the CARD and not a D64 file*/
                DiskState = CARD_ACTIVE;                                    /*this command overrules the buttons*/
                DOS_channel[channel].next_action = CARD_DIRECTORY;            /*show the directory of the MMC/SD-card*/
                print_D64_name(PLAIN);
                break;
            }

            if (((strlen((char *)command_string) == 1) && (strncmp((char *)command_string,"$",  1) == 0 )) || ((strlen((char *)command_string) == 2) && (strncmp((char *)command_string,"$0",  2) == 0 )))        /*check the COMPLETE string*/
            {    /*current directory, which may be D64 or ROOT depending on the previous selection*/
                if ((file_type == NONE) || (file_type == SUBDIRECTORY))        /*check for the currently selected file, if 0 refer to the card and not a D64 file*/
                    DOS_channel[channel].next_action = CARD_DIRECTORY;        /*show the directory of the MMC/SD-card*/
                else
                    DOS_channel[channel].next_action = DIRECTORY;            /*show the directory of the currently selected D64 file*/
                break;
            }

            if (strncmp("$", (char *)command_string, 1) == 0 ) {                      /*check the 1st char of the string)*/
                file_status = SeekFileOnCard(&command_string[1], &file);    /*check if file is present or not*/
                if (file_status == FALSE) {
                    SetErrorCode(62,LED_ERROR);                                /*file not found*/
                    DOS_channel[channel].next_action = ABORT_SENDING;        /*the requested directory does not exist*/
                } else {
                    DiskState = CARD_ACTIVE;                                /*this command overrules the buttons*/
                    file_type = FileFilter();                                /*check the type of file to determine the mode of operation*/
                    if (file_type == SUBDIRECTORY) {                         /*check if the user wants to enter a subdirectory*/
                        OpenSubDirectory(&file);                            /*the user request to enter a subdirectory, so we call the routine that setts all registers in the correct way in order to use subdirectories properly*/
                        file_number = 0;                                    /*the file_number counter needs to be reset*/
                        file_type = NONE;                                    /*and because the user has selected a (sub)directory, the selected file_type = NONE, as there is no image file selected and we are operating in harddiskmode*/
                        CountFiles();                                        /*count all files in the opened directory*/
                        DOS_channel[channel].next_action = CARD_DIRECTORY;    /*show the (sub)directory of the MMC/SD-card*/
                        print_D64_name(PLAIN);                                /*update the display*/
                    } else {
                        file_number = file_status;
                        DOS_channel[channel].next_action = DIRECTORY;        /*show the directory of the requested D64 file (but only if the actions below do not fail offcourse)*/
                        print_D64_name(PLAIN);                                /*update the display*/
                        FileSectorScan(&file);                                /*update the sector location table cache*/
                        D64ReadBAM();                                        /*update the BAM*/
                    }
                }
                break;                                                        /*leave the case*/
            }

            /*----------------------*/
            /* LOAD filename        */
            /*----------------------*/
            if (file_type == NONE) {                                      /*check for the currently selected file, if 0 refer to the card and not a D64 file*/
                file_status = SeekFileOnCard(command_string, &file);    /*check if file is present on the card*/
                DOS_channel[channel].next_action = RD_FILE_FROM_ROOT;
                break;
            } else {
                file_status = D64SeekFile(command_string, &track, &sector, &blocksize, &dirtrack, &dirsector, &direntry);    /*check if file is present within a D64 file*/
                DOS_channel[channel].next_action = RD_FILE;
                break;
            }
        }

        case 1: {              /*this channel is used for writing of files*/
            if (DiskState == NO_CARD) {
                DOS_channel[channel].next_action = ABORT_RECEIVING;
                break;
            }

            /*------------------------------------------------------------*/
            /* '@' = REPLACE                                              */
            /* syntax: SAVE"@0:<filename>",x,1                            */
            /* syntax: SAVE"@S:<filename>",8,1 (special for game:commando, int karate, donkey kong)*/
            /*------------------------------------------------------------*/
            if ((strncmp("@:", (char *)command_string, 2) == 0 ) || (strncmp("@0:",(char *) command_string, 3) == 0 ) || (strncmp("@S:", (char *)command_string, 3) == 0 )) {          /*check the beginning of the string)*/
                SplitStringOn_Sign(':', command_string, filename_string);
                file_status = D64SeekFile(filename_string, &track, &sector, &blocksize, &dirtrack, &dirsector, &direntry);    /*check if file is present or not*/
                DOS_channel[channel].next_action = REPLACE_FILE;                            /*replace a file within the currently selected D64 file*/
                break;
            }

            /*---------------*/
            /* SAVE filename */
            /*---------------*/
            if (file_type == NONE) {      /*check for the currently selected file, if 0 refer to the card and not a D64 file*/
                file_status = SeekFileOnCard(command_string, &file);    /*check if file is present or not*/
                DOS_channel[channel].next_action = WR_FILE_TO_ROOT;
                break;
            } else {
                file_status = D64SeekFile(command_string, &track, &sector, &blocksize, &dirtrack, &dirsector, &direntry);    /*check if file is present or not*/
                DOS_channel[channel].next_action = WR_FILE;
                break;
            }
        }


        /*the channels 2-14 are used for the actual file handling that do not use the BASIC LOAD or SAVE commands*/
        case 2:
            ;
        case 3:
            ;
        case 4:
            ;
        case 5:
            ;
        case 6:
            ;
        case 7:
            ;
        case 8:
            ;
        case 9:
            ;
        case 10:
            ;
        case 11:
            ;
        case 12:
            ;
        case 13:
            ;
        case 14: {
            if (command_string[0] == '#') {                                      /*if the user/computer specifies a buffer then handle accordingly...*/
                if (DOS_channel[channel].used_buffer == 255) {                  /*check if this channel allready has a buffer connected*/
                    if (ValueFromString(&command_string[0], &value_1)) {          /*check if the user has specified it's own buffer preference*/
                        if (DOS_buffer[value_1].buffer_in_use == FALSE) {          /*check if this buffer is still available*/
                            DOS_buffer[value_1].buffer_in_use = TRUE;            /*this buffer is still free, so we can claim this buffer*/
                            DOS_channel[channel].used_buffer = value_1;            /*connect the free buffer to this channel*/
                        } else {
                            SetErrorCode(70, LED_ERROR);                        /*the requested buffer is allready in use, close the current situtation properly before we let the new situation claim this buffer*/
                        }
                    } else {
                        nextfreebuffer = SearchFreeBuffer();                    /*since the user does not care which buffer it uses, so the 1541-III may decide which buffer is available*/
                        if (nextfreebuffer == 255) {
                            SetErrorCode(70, LED_ERROR);                        /*No channels available or in other words: no more free buffers */
                        } else {
                            DOS_buffer[nextfreebuffer].buffer_in_use = TRUE;    /*claim this buffer*/
                            DOS_channel[channel].used_buffer = nextfreebuffer;    /*connect the free buffer to this channel*/
                        }
                    }
                }
            } else {
                ExtractFilenameFromString(command_string, filename_string);    /*extract the filename from the commandstring given by the user/computer*/
                SplitStringOn_Sign(',', command_string, filetype_string);
                SplitStringOn_Sign(',', filetype_string, RW_string);
                strcpy((char *)&DOS_channel[channel].filename[0], (char *)filename_string);    /*copy the filename into the DOS buffer*/

                /*check for filetype*/
                if ((strncmp("A", (char *)filetype_string, 1) == 0 ) || (strncmp("APPEND",(char *) filetype_string, 6) == 0 )) {
                    DOS_channel[channel].filetype = SEQUENTIAL;
//to do: zoek hier naar het einde van de sequentiele file en zet de bufferpointer track en sector waardes in de DOS buffer op de correcte waardes
                } else {
                    /*check for the filetype SEQ, REL, PRG, USR, LENGTH (checking for only the first letter is sufficient to check for all variations of the word sequential, program, etc)*/
                    if (strncmp("S", (char *)filetype_string, 1)) {
                        DOS_channel[channel].filetype = SEQUENTIAL;
                    }
                    if (strncmp("R", (char *)filetype_string, 1)) {
                        DOS_channel[channel].filetype = RELATIVE;
                    }
                    if (strncmp("P", (char *)filetype_string, 1)) {
                        DOS_channel[channel].filetype = PROGRAM;
                    }
                    if (strncmp("U", (char *)filetype_string, 1) == 0 ) {
                        DOS_channel[channel].filetype = USER;
                    }
//                    if (strncmp("L", filetype_string, 1))
//                    {
//                        DOS_channel[channel].filetype = USER;
//                    }


                    /*check if file is to be used as a Read, Write or Modify (checking for only the first letter is sufficient to check for all variations of the word)*/
                    if ((RW_string[0]==0) || (strncmp("R", (char *)RW_string, 1) == 0 )) {  /*when not defined or defined as R, then the file is to be used for READ functions*/
                        DOS_channel[channel].RW = RD_FILE;
                        file_status = D64SeekFile(filename_string, &track, &sector, &blocksize, &dirtrack, &dirsector, &direntry);    /*check if file is present or not*/
                        if (file_status == FILE_PRESENT) {
                            DOS_channel[channel].status = FILE_OPEN;    /*the file could be found*/
                            DOS_channel[channel].track = track;            /*save, the location of the first byte regarding this file on the "disk", to the appropriate registers*/
                            DOS_channel[channel].sector = sector;
                            DOS_channel[channel].buffer_pointer = 0;
                        } else {
                            DOS_channel[channel].status = NO_FILE;        /*the file could not be found*/
                            SetErrorCode(62,LED_ERROR);                    /*file not found*/
                        }
                    }

                    if ((strncmp("W", (char *)RW_string, 1) == 0 ) || (strncmp("WRITE",(char *) RW_string, 5) == 0 )) {
                        DOS_channel[channel].RW = WR_FILE;
                        file_status = D64SeekFile(filename_string, &track, &sector, &blocksize, &dirtrack, &dirsector, &direntry);    /*check if file is present or not*/
                        if (file_status == FILE_PRESENT) {
                            DOS_channel[channel].status = NO_FILE;        /*the file could not be found*/
                            SetErrorCode(63,LED_ERROR);                    /*file exists*/
                        } else {
                            DOS_channel[channel].status = FILE_OPEN;    /*the file could be found*/
//to do: maak in de directory structuur een nieuwe file aan maar sluit deze (uiteraard niet af), deze file word ook wel een 'splat' file genoemd

                            DOS_channel[channel].track = track;            /*save, the location of the first byte regarding this file on the "disk", to the appropriate registers*/
                            DOS_channel[channel].sector = sector;
                            DOS_channel[channel].buffer_pointer = 0;
                        }
                    }
                    if ((strncmp("M", (char *)RW_string, 1) == 0 ) || (strncmp("MODIFY", (char *)RW_string, 6) == 0 )) {
                        DOS_channel[channel].RW = MODIFY_FILE;
//to do: uitzoeken wat modify precies inhoud...
                    }

                }
            }

            OutputToRS232();                        /*set standard output to RS232*/
            printf("\r\nOpen, channel %d", channel);    /*!!! DEBUG ONLY !!!*/
            printf("\r\n  channel_in_use:%03d",DOS_channel[channel].channel_in_use);
            printf("\r\n  next_action   :%03d",DOS_channel[channel].next_action);
            printf("\r\n  filename[0]   :%s",DOS_channel[channel].filename);
            printf("\r\n  filetype      :%03d",DOS_channel[channel].filetype);
            printf("\r\n  RW            :%03d",DOS_channel[channel].RW);
            printf("\r\n  track         :%03d",DOS_channel[channel].track);
            printf("\r\n  sector        :%03d",DOS_channel[channel].sector);
            printf("\r\n  buffer_pointer:%03d",DOS_channel[channel].buffer_pointer);
            printf("\r\n  used_buffer   :%03d",DOS_channel[channel].used_buffer);
            printf("\r\n  status        :%03d",DOS_channel[channel].status);
            printf("\r\n");                            /*!!! DEBUG ONLY !!!*/
            OutputToLCD();                            /*set standard output to LCD*/
            break;
        }

        case 15: {
            /*------------------------------------------------------*/
            /* Set LCD's contrast                                   */
            /* Syntax: "LCDCONTRAST=<value>"                        */
            /* Example: OPEN15,device,15,"LCDCONTRAST=ddd"<RETURN>  */
            /*          CLOSE 15<RETURN>                            */
            /*------------------------------------------------------*/
            if (strncmp("LCDCONTRAST=",(char *)command_string,12) == 0 ) {      /*check the beginning of the string)*/
                SplitStringOn_Sign('=', command_string, value_string);
                ValueFromString(value_string, &value_1);
                if (value_1>0 && value_1<255) {
                    setting_contrast = value_1;                    /*copy new value to the correct register*/
                    // SetContrast();                                /*apply new setting*/
                    // SaveSettingsToEEPROM();                        /*save value to EEPROM*/
                    print_device_status("  CONTRAST... ");
                } else {   /*incorrect value*/
                    FreeIEC();                                    /*BUT... since there's no use in receiving data we cannot process, free the bus and the computer will detect this as an valid error situation*/
                }
                DOS_channel[channel].channel_in_use = FALSE;    /*no further actions required*/
            }

            /*----------------------------------------------------------------*/
            /* 'N' = NEW - Format a floppy disk                               */
            /* Syntax: "NEW:<diskname>,<id>"                                  */
            /* Example: OPEN 15,8,15,"N:diskname,01"<RETURN>                  */
            /*          CLOSE 15<RETURN>                                      */
            /* <diskname> can be up to 16 characters                          */
            /* <id> can either be omitted or must be exactly 2 characters long*/
            /*----------------------------------------------------------------*/
            if ((strncmp("N:",(char *)command_string,2) == 0 ) || (strncmp("N0:",(char *)command_string,3) == 0 ) || (strncmp("NEW:",(char *)command_string,4) == 0 ) || (strncmp("NEW0:",(char *)command_string,5) == 0 )) {                      /*check the beginning of the string)*/
                if (file_type == D64_35T_MODE) {  //future or TODO: D64_35T_ER_MODE, D64_40T_MODE, D64_40T_ER_MODE
                    print_device_status(" FORMATTING.. ");
                    SplitStringOn_Sign(':', command_string, filename_string);
                    SplitStringOn_Sign(',', filename_string, value_string);
                    FormatD64File(filename_string, value_string);
                } else {   /*creating a disk in the root directory is not supported*/
                    FreeIEC();                                    /*BUT... since there's no use in receiving data we cannot process, free the bus and the computer will detect this as an valid error situation*/
                }
                DOS_channel[channel].channel_in_use = FALSE;    /*no further actions required*/
            }

            /*----------------------------------------------------------------------------------------*/
            /* 'S' = SCRATCH (also referred to as 'delete')                                           */
            /* Syntax: "SCRATCH:<file>"                                                               */
            /* Example: OPEN 15,8,15,"S:filename"<RETURN>                                             */
            /*          CLOSE 15<RETURN>   (do not forget otherwise remaining commands may not work)  */
            /* You can use the wild cards '?' and '*' to delete several files at once.                */
            /*----------------------------------------------------------------------------------------*/
            if ((strncmp("S:",(char *)command_string,2) == 0 ) || (strncmp("S0:",(char *)command_string,3) == 0 ) || (strncmp("SCRATCH:",(char *)command_string,8) == 0 ) || (strncmp("SCRATCH0:",(char *)command_string,9) == 0 )) {  /*check the beginning of the string)*/
                SplitStringOn_Sign(':', command_string, filename_string);
                file_status = D64SeekFile(filename_string, &track, &sector, &blocksize, &dirtrack, &dirsector, &direntry);    /*check if file is present or not*/
                if (file_status == FILE_PRESENT) {
                    files_scratched = 0;                    /*the error message abuses this variable for the number of files scratched, so... we must do this also to simulate the 1541 as good as possible*/
                    SetErrorCode(0,LED_ON);                    /*unless we fail we will exit with no error*/
                    while (file_status == FILE_PRESENT) {     /*this function uses wildcards, so the same function needs to be repeated, keep checking untill false*/
                        print_device_status(" SCRATCHING.. ");
                        D64ScratchDirEntry(dirtrack, dirsector, direntry);
                        files_scratched++;
                        file_status = D64SeekFile(filename_string, &track, &sector, &blocksize, &dirtrack, &dirsector, &direntry);    /*check if file is present or not*/
                    }
                    SetErrorCode(1,LED_OFF);
                } else {
                    SetErrorCode(62,LED_ERROR);                    /*file not found*/
                    FreeIEC();                                    /*BUT... since there's no use in receiving data we cannot process, free the bus and the computer will detect this as an valid error situation*/
                }
                DOS_channel[channel].channel_in_use = FALSE;    /*no further actions required*/
            }

            /*--------------------------------------------------*/
            /* 'R' = RENAME - Rename a file                     */
            /* Syntax: "RENAME:<newname>=<oldname>"             */
            /* Example:    OPEN 15,8,15,"R:newfilename=oldfilename"*/
            /*          CLOSE 15<RETURN>                        */
            /*--------------------------------------------------*/
            if ((strncmp("R:",(char *)command_string,2) == 0 ) || (strncmp("R0:",(char *)command_string,3) == 0 ) || (strncmp("RENAME:",(char *)command_string,7) == 0 ) || (strncmp("RENAME0:",(char *)command_string,8) == 0 )) {  /*check the beginning of the string)*/
                SplitStringOn_Sign(':', command_string, filename_string);
                SplitStringOn_Sign('=', filename_string, oldfilename_string);
                file_status = D64SeekFile(oldfilename_string, &track, &sector, &blocksize, &dirtrack, &dirsector, &direntry);    /*check if file is present or not*/
                if (file_status == FILE_PRESENT) {              /*although the '=0' has to be given in the command, we do not check for it*/
                    print_device_status("  RENAMING..  ");
                    SetErrorCode(0,LED_ON);                        /*unless we fail we will exit with no error*/
                    D64RenameDirEntry(filename_string, dirtrack, dirsector, direntry);
                    SetErrorCode(0,LED_OFF);                    /*we exit without error*/
                } else {
                    SetErrorCode(62,LED_ERROR);                    /*file not found*/
                    FreeIEC();                                    /*BUT... since there's no use in receiving data we cannot process, free the bus and the computer will detect this as an valid error situation*/
                }
                DOS_channel[channel].channel_in_use = FALSE;    /*no further actions required*/
            }


            /*----------------------------------------*/
            /* INITIALIZE - re-read the BAM from disk */
            /* Abbreviation: I                        */
            /* Syntax: "INITIALIZE"                   */
            /*----------------------------------------*/
            /*Currently, this command is not supported            */


            /*----------------------------------------------------*/
            /* VALIDATE - Check and Fix Disk Consistency           */
            /* Abbreviation: V                                       */
            /* Syntax: "VALIDATE"                                  */
            /*----------------------------------------------------*/
            /*Currently, this command is not supported            */
            /*Validate will fix inconsistencies that can be caused by files that where opened but never closed. Beware: Validate also erases all random files! */


            /*-------------------------------------------------------*/
            /* 'C' = COPY - Create a copy of a file on the same disk */
            /* Syntax: "COPY:<destfile>=<sourcefile>" or "COPY:<destfile>=<sourcefile1>, <sourcefile2>, ..."*/
            /* If several source files are listed, than the destination file will contain the concatenated contents of all source files. */
            /*-------------------------------------------------------*/
            if ((strncmp("C:",(char *)command_string,2) == 0 ) || (strncmp("C0:",(char *)command_string,3) == 0 ) || (strncmp("COPY:",(char *)command_string,5) == 0 ) || (strncmp("COPY0:",(char *)command_string,6) == 0 )) {          /*check the beginning of the string)*/
                SplitStringOn_Sign(':', command_string, filename_string);
                SplitStringOn_Sign('=', filename_string, oldfilename_string);
                file_status = D64SeekFile(oldfilename_string, &track, &sector, &blocksize, &dirtrack, &dirsector, &direntry);    /*check if file is present or not*/
                if (file_status == FILE_PRESENT) {
                    print_device_status("  COPYING...  ");
                    CopyD64File(track, sector, blocksize);
                } else {
                    SetErrorCode(62,LED_ERROR);                    /*file not found*/
                    FreeIEC();                                    /*BUT... since there's no use in receiving data we cannot process, free the bus and the computer will detect this as an valid error situation*/
                }
                DOS_channel[channel].channel_in_use = FALSE;    /*no further actions required*/
            }

            /*-------------------------------------------------------*/
            /* 'M-W' = memory write command                           */
            /* Syntax: OPEN 15,8,15,"M-W"CHR$(lowbyteaddr)CHR$(highbyteaddr)CHR$(numberofmemorylocations)CHR$(data)CHR$(data)CHR$(data):CLOSE 1<RETURN>    */
            /*-------------------------------------------------------*/
            if ((strncmp("M-W",(char *)command_string,3) == 0 )) {  // || (strncmp("M-W:", command_string, 4) == 0 ))        /*check the COMPLETE string*/
                if ((command_string[3] == 119) && (command_string[4] == 0) && (command_string[5] == 2)) {
                    if ((command_string[6] - 32) == (command_string[7] - 64)) { /*check for new device address*/
                        devicenumber = command_string[7] - 64;            /*the new IEC device address of this device*/
                        print_device_status("  NEW DEVICE# ");
                        SetErrorCode(0,LED_ON);                            /*unless we fail we will exit with no error*/
                        print_D64_TSB(0,0,0,0);                            /*update display with the new device address*/
                        SetErrorCode(0,LED_OFF);                        /*we exit without error*/
                        DOS_channel[channel].channel_in_use = FALSE;    /*no further actions required*/
                    }
                }
            }

            /*--------------------------------------------------------------------------------------------------------*/
            /* 'B-P' = buffer pointer command (i.o.w. Set the buffer pointer used by CHANNEL ??? to point to BYTE ??? */
            /* Syntax: OPEN 15,8,15,"B-P:";channel;byte:CLOSE 15<RETURN>                                              */
            /* Example: OPEN 15,8,15,"B-P:";5;2:CLOSE 15<RETURN>                                                      */
            /* Example: OPEN 15,8,15,"B-P";5;2:CLOSE 15<RETURN>                                                          */
            /* Example: OPEN 15,8,15,"B-P 5 2":CLOSE 15<RETURN>                                                          */
            /*--------------------------------------------------------------------------------------------------------*/
            if ((strncmp("B-P",(char *)command_string,3) == 0 )) {      /*check the string*/
                string_pntr = 0;
                string_pntr_2=ValueFromString(&command_string[string_pntr],&value_1);            /*search for the 1st number: channel*/
                if (string_pntr_2!=FALSE) {
                    string_pntr = string_pntr + string_pntr_2;
                    string_pntr_2=ValueFromString(&command_string[string_pntr],&value_2);        /*search for the 2nd number: channel*/
                    if (string_pntr_2 != FALSE) {
                        DOS_channel[value_1].buffer_pointer = value_2;    /*the BufferPointer of this channel (used when reading/writing the connected buffer), needs to be set to value_2*/
                        OutputToRS232();                        /*set standard output to RS232*/
                        printf("\r\nB-P command, channel:%02d, BP:%03d",value_1,DOS_channel[DOS_channel[value_1].used_buffer].buffer_pointer);
                        OutputToLCD();                            /*set standard output to LCD*/
                    }
                }
            }


            /*-------------------------------------------------------------------------*/
            /* 'B-R' = USER-command 1 (254 bytes, byte 0-1 are skipped)                */
            /* Syntax: OPEN 15,8,15,"B-R"channel;drive;track;sector":CLOSE 15<RETURN>  */
            /*-------------------------------------------------------------------------*/
            if ((strncmp("B-R",(char *)command_string,3) == 0 )) {      /*check the string*/
                string_pntr = 2;        /*whatever the command, skip the first 2 characters in searching for the first number. Otherwise the 1 from U1 might be recognised as a value, which it is not*/
                string_pntr_2=ValueFromString(&command_string[string_pntr],&value_1);                /*search for the 1st number: channel*/
                if (string_pntr_2!=FALSE) {
                    if (DOS_channel[value_1].used_buffer!=255) {  /*check if the specified channel has been connected to a buffer, if not ignore the rest of the command*/
                        string_pntr = string_pntr + string_pntr_2;
                        string_pntr_2=ValueFromString(&command_string[string_pntr],&value_2);            /*search for the 2nd number: channel*/
                        if (string_pntr_2 != FALSE) {
                            string_pntr = string_pntr + string_pntr_2;
                            string_pntr_2=ValueFromString(&command_string[string_pntr],&value_3);        /*search for the 2nd number: channel*/
                            if (string_pntr_2 != FALSE) {
                                string_pntr = string_pntr + string_pntr_2;
                                string_pntr_2=ValueFromString(&command_string[string_pntr],&value_4);    /*search for the 2nd number: channel*/
                                if (string_pntr_2 != FALSE) {
                                    DOS_channel[value_1].track = value_3;                                /*we have all the info we need, so save this info the the appropriate registers and we're done*/
                                    DOS_channel[value_1].sector = value_4;                                /*save track and sector info*/
                                    D64BlockRead_new(DOS_channel[value_1].used_buffer,value_3,value_4);    /*read the desired block of the D64 image and store it into the desired buffer*/

                                    OutputToRS232();                        /*set standard output to RS232*/
                                    printf("\r\nB-R command, t:%03d, s:%03d",DOS_channel[value_1].track,DOS_channel[value_1].sector);
                                    OutputToLCD();                            /*set standard output to LCD*/
                                }
                            }
                        }
                    }
                }
            }


            /*-------------------------------------------------------------------------*/
            /* 'U1' or 'UA' = USER-command 1 (block read, 256 bytes)                   */
            /* Syntax: OPEN 15,8,15,"U1:"channel;drive;track;sector":CLOSE 15<RETURN>  */
            /* Example: OPEN 15,8,15,"U1:";5;0;18;1:CLOSE 15<RETURN>                   */
            /* Example: OPEN 15,8,15,"U1";5;0;18;1:CLOSE 15<RETURN>                       */
            /* Example: OPEN 15,8,15,"U1 5 0 18 1":CLOSE 15<RETURN>                       */
            /*-------------------------------------------------------------------------*/
            if (((strncmp("UA",(char *)command_string,2) == 0 )) || ((strncmp("U1",(char *)command_string,2) == 0 ))) {      /*check the string*/
                string_pntr = 2;        /*whatever the command, skip the first 2 characters in searching for the first number. Otherwise the 1 from U1 might be recognised as a value, which it is not*/
                string_pntr_2=ValueFromString(&command_string[string_pntr],&value_1);                /*search for the 1st number: channel*/
                if (string_pntr_2!=FALSE) {
                    if (DOS_channel[value_1].used_buffer!=255) {  /*check if the specified channel has been connected to a buffer, if not ignore the rest of the command*/
                        string_pntr = string_pntr + string_pntr_2;
                        string_pntr_2=ValueFromString(&command_string[string_pntr],&value_2);            /*search for the 2nd number: channel*/
                        if (string_pntr_2 != FALSE) {
                            string_pntr = string_pntr + string_pntr_2;
                            string_pntr_2=ValueFromString(&command_string[string_pntr],&value_3);        /*search for the 2nd number: channel*/
                            if (string_pntr_2 != FALSE) {
                                string_pntr = string_pntr + string_pntr_2;
                                string_pntr_2=ValueFromString(&command_string[string_pntr],&value_4);    /*search for the 2nd number: channel*/
                                if (string_pntr_2 != FALSE) {
                                    DOS_channel[value_1].track = value_3;                                /*we have all the info we need, so save this info the the appropriate registers and we're done*/
                                    DOS_channel[value_1].sector = value_4;                                /*save track and sector info*/
                                    D64BlockRead_new(DOS_channel[value_1].used_buffer,value_3,value_4);    /*read the desired block of the D64 image and store it into the desired buffer*/

                                    OutputToRS232();                        /*set standard output to RS232*/
                                    printf("\r\nU1 command, t:%03d, s:%03d",DOS_channel[value_1].track,DOS_channel[value_1].sector);
                                    OutputToLCD();                            /*set standard output to LCD*/
                                }
                            }
                        }
                    }
                }
            }


            /*-------------------------------------------------------------------------*/
            /* 'B-W' = USER-command 2 (254 bytes block write)                               */
            /* Syntax: OPEN 15,8,15,"U2:"channel;drive;track;sector":CLOSE 15<RETURN>  */
            /*-------------------------------------------------------------------------*/
            if ((strncmp("B-W",(char *)command_string,3) == 0 )) {
                string_pntr = 2;        /*whatever the command, skip the first 2 characters in searching for the first number. Otherwise the 2 from U2 might be recognised as a value, which it is not*/
                string_pntr_2=ValueFromString(&command_string[string_pntr],&value_1);                /*search for the 1st number: channel*/
                if (string_pntr_2!=FALSE) {
                    if (DOS_channel[value_1].used_buffer!=255) {  /*check if the specified channel has been connected to a buffer, if not ignore the rest of the command*/
                        string_pntr = string_pntr + string_pntr_2;
                        string_pntr_2=ValueFromString(&command_string[string_pntr],&value_2);            /*search for the 2nd number: channel*/
                        if (string_pntr_2 != FALSE) {
                            string_pntr = string_pntr + string_pntr_2;
                            string_pntr_2=ValueFromString(&command_string[string_pntr],&value_3);        /*search for the 2nd number: channel*/
                            if (string_pntr_2 != FALSE) {
                                string_pntr = string_pntr + string_pntr_2;
                                string_pntr_2=ValueFromString(&command_string[string_pntr],&value_4);    /*search for the 2nd number: channel*/
                                if (string_pntr_2 != FALSE) {
                                    DOS_channel[value_1].track = value_3;                                /*we have all the info we need, so save this info the the appropriate registers and we're done*/
                                    DOS_channel[value_1].sector = value_4;                                /*save track and sector info*/
                                    D64BlockWrite_new(DOS_channel[value_1].used_buffer,value_3,value_4);                                        /*write the desired block of the D64 image*/

                                    OutputToRS232();                        /*set standard output to RS232*/
                                    printf("\r\nB-W command, t:%03d, s:%03d",DOS_channel[value_1].track,DOS_channel[value_1].sector);
                                    OutputToLCD();                            /*set standard output to LCD*/
                                }
                            }
                        }
                    }
                }
            }

            /*-------------------------------------------------------------------------*/
            /* 'U2' or 'UB' = USER-command 2 (256 byte block write)                    */
            /* Syntax: OPEN 15,8,15,"U2:"channel;drive;track;sector":CLOSE 15<RETURN>  */
            /* Example: OPEN 15,8,15,"U2:";5;0;18;1:CLOSE 15<RETURN>                   */
            /* Example: OPEN 15,8,15,"U2";5;0;18;1:CLOSE 15<RETURN>                       */
            /* Example: OPEN 15,8,15,"U2 5 0 18 1":CLOSE 15<RETURN>                       */
            /*-------------------------------------------------------------------------*/

            if (((strncmp("U2",(char *)command_string,2) == 0 )) || ((strncmp("UB",(char *)command_string,2) == 0 ))) {      /*check the string*/
                string_pntr = 2;        /*whatever the command, skip the first 2 characters in searching for the first number. Otherwise the 2 from U2 might be recognised as a value, which it is not*/
                string_pntr_2=ValueFromString(&command_string[string_pntr],&value_1);                /*search for the 1st number: channel*/
                if (string_pntr_2!=FALSE) {
                    if (DOS_channel[value_1].used_buffer!=255) {  /*check if the specified channel has been connected to a buffer, if not ignore the rest of the command*/
                        string_pntr = string_pntr + string_pntr_2;
                        string_pntr_2=ValueFromString(&command_string[string_pntr],&value_2);            /*search for the 2nd number: channel*/
                        if (string_pntr_2 != FALSE) {
                            string_pntr = string_pntr + string_pntr_2;
                            string_pntr_2=ValueFromString(&command_string[string_pntr],&value_3);        /*search for the 2nd number: channel*/
                            if (string_pntr_2 != FALSE) {
                                string_pntr = string_pntr + string_pntr_2;
                                string_pntr_2=ValueFromString(&command_string[string_pntr],&value_4);    /*search for the 2nd number: channel*/
                                if (string_pntr_2 != FALSE) {
                                    DOS_channel[value_1].track = value_3;                                /*we have all the info we need, so save this info the the appropriate registers and we're done*/
                                    DOS_channel[value_1].sector = value_4;                                /*save track and sector info*/
                                    D64BlockWrite_new(DOS_channel[value_1].used_buffer,value_3,value_4);                                        /*write the desired block of the D64 image*/

                                    OutputToRS232();                        /*set standard output to RS232*/
                                    printf("\r\nU2 command, t:%03d, s:%03d",DOS_channel[value_1].track,DOS_channel[value_1].sector);
                                    OutputToLCD();                            /*set standard output to LCD*/
                                }
                            }
                        }
                    }
                }
            }


            /*-------------------------------------------------------*/
            /* 'UI-' = USER-command speed up drive by 25%             */
            /* Syntax: OPEN 15,8,15,"UI-":CLOSE 1<RETURN>                 */
            /*-------------------------------------------------------*/
            if (strncmp("UI-",(char *)command_string,3) == 0 ) {      /*check the string*/
                print_device_status("  VIC20-MODE  ");
                SetErrorCode(0,LED_ON);                            /*unless we fail we will exit with no error*/
                SetIEC_timings(TIMINGS_VIC20);                    /*set timings according the VIC-20 settings (25% faster mode)*/
                VIC20_mode = TRUE;                                /*raise flag*/
                // SaveSettingsToEEPROM();                            /*store new setting*/
                SetErrorCode(0,LED_OFF);                        /*we exit without error*/
                DOS_channel[channel].channel_in_use = FALSE;    /*no further actions required*/
            }

            /*-------------------------------------------------------*/
            /* 'UI+' = USER-command restore drive speed to normal     */
            /* Syntax: OPEN 15,8,15,"UI+":CLOSE 1<RETURN>                 */
            /*-------------------------------------------------------*/
            if (strncmp("UI+",(char *)command_string,3) == 0 ) {      /*check the string*/
                print_device_status("   C64-MODE   ");
                SetErrorCode(0,LED_ON);                            /*unless we fail we will exit with no error*/
                SetIEC_timings(TIMINGS_DEFAULT);                /*set timings according the default settings (C64 compatible mode)*/
                VIC20_mode = FALSE;                                /*raise flag*/
                // SaveSettingsToEEPROM();                            /*store new setting*/
                SetErrorCode(0,LED_OFF);                        /*we exit without error*/
                DOS_channel[channel].channel_in_use = FALSE;    /*no further actions required*/
            }

            /*------------------------------*/
            /* In case none of the above... */
            /*------------------------------*/
            //to do:syntax error
            DOS_channel[channel].channel_in_use = FALSE;    /*no further actions required*/
//            print_device_status("              ");                /*remove the 'action' message from the display*/
        }
    }
}

void DataHandler(void) {
//    OutputToRS232();                        /*set standard output to RS232*/
//    printf("\r\nDATAHANDLER");                /*!!! DEBUG ONLY !!!*/
//    printf("\r\nData, channel %d",channel);    /*!!! DEBUG ONLY !!!*/
//    printf("\r\ncmd_string:%s",command_string);    /*!!! DEBUG ONLY !!!*/
//    printf("\r\nchannel:%d",channel);        /*!!! DEBUG ONLY !!!*/
//    OutputToLCD();                            /*set standard output to LCD*/

    switch (channel) {                       /*-------------------------------------------*/
        case 0:                /* this channel is used for reading of files */
        {                    /*-------------------------------------------*/
            if ((DiskState == NO_CARD) || (DiskState == INVALID_POINTER)) {      /*escape sequence when no D64 is selected or no card is present*/
                DOS_channel[channel].next_action = ABORT_SENDING;
            }

            switch (DOS_channel[channel].next_action) {
                case ABORT_SENDING: {          /*file not found situation*/
                    SetErrorCode(62,LED_ERROR);                /*file not found*/
                    IEC_turnaround();        /*we now SEND data to the bus so... make our device a talker*/
                    FreeIEC();                /*BUT... since there's nothing to send, free the bus and the computer will detect this as an valid error situation*/
                    break;
                }

                case CARD_DIRECTORY: {
                    print_device_status("  LOADING...  ");
                    CardDirectory();                        /*send the MMC/SD_card Directory information*/
                    print_device_status("             ");
                    break;
                }

                case DIRECTORY: {
                    print_device_status(" LOADING DIR. ");
                    D64Directory();                        /*send ImageDirectory information of the selected drive*/
                    print_device_status("              ");
                    break;
                }

                case RD_FILE_FROM_ROOT: {
                    if (file_status != FALSE) {
                        print_device_status("  LOADING...  ");
                        OutputToRS232();
                        printf("%s",command_string);        /*print filename on first line of LCD*/
                        OutputToLCD();
                        LoadFileFromCard(&file);
                        print_device_status("              ");
                    } else {
                        SetErrorCode(62,LED_ERROR);                /*file not found*/
                        IEC_turnaround();        /*we now SEND data to the bus so... make our device a talker*/
                        FreeIEC();                /*BUT... since there's nothing to send, free the bus and the computer will detect this as an valid error situation*/
                        DOS_channel[channel].next_action = ABORT_SENDING;
                    }
                    break;
                }

                case RD_FILE: {
                    if (file_status == FILE_PRESENT) {
                        print_device_status("  LOADING...  ");
                        OutputToRS232();
                        printf("%s",command_string);            /*print filename to LCD*/
                        OutputToLCD();
                        LoadD64File(track, sector, blocksize);     /*load the actual file from the D64-file*/
                        print_device_status("              ");
                    } else {
                        SetErrorCode(62,LED_ERROR);                /*file not found*/
                        IEC_turnaround();        /*we now SEND data to the bus so... make our device a talker*/
                        FreeIEC();                /*BUT... since there's nothing to send, free the bus and the computer will detect this as an valid error situation*/
                        DOS_channel[channel].next_action = ABORT_SENDING;
                        print_device_status("              ");
                    }
                    break;
                }
            }
            break;
        }

        /*-------------------------------------------*/
        case 1:                /* this channel is used for writing of files */
        {                    /*-------------------------------------------*/
            if ((DiskState == NO_CARD) || (DiskState == INVALID_POINTER))        /*escape sequence when no D64 is selected or no card is present*/
                DOS_channel[channel].next_action = ABORT_RECEIVING;

            switch (DOS_channel[channel].next_action) {
                case ABORT_RECEIVING: {      /*file not found situation*/
                    SetErrorCode(28,LED_ERROR);/*write error (a message that normally would not be possible but was created for completeness in the DOS. Now we can use it...)*/
                    FreeIEC();                /*BUT... since there's no use in receiving data we cannot process, free the bus and the computer will detect this as an valid error situation*/
                    break;
                }

                case WR_FILE_TO_ROOT: {
                    SetErrorCode(28,LED_ERROR);/*write error (a message that normally would not be possible but was created for completeness in the DOS. Now we can use it...)*/
                    FreeIEC();                /*BUT... since there's no use in receiving data we cannot process, free the bus and the computer will detect this as an valid error situation*/
                    DOS_channel[channel].next_action = ABORT_RECEIVING;
                    break;
                }

                case WR_FILE: {
                    if (file_status == FILE_NOT_PRESENT) {
                        print_device_status("   SAVING...  ");
                        OutputToRS232();
                        printf("%s",command_string);            /*print filename on first line of LCD*/
                        OutputToLCD();
                        SaveD64File();                            /*save the actual file to the D64-file*/
                        print_device_status("              ");
                    } else {
                        SetErrorCode(63,LED_ERROR);                /*file exists*/
                        FreeIEC();                /*BUT... since there's no use in receiving data we cannot process, free the bus and the computer will detect this as an valid error situation*/
                        DOS_channel[channel].next_action = ABORT_RECEIVING;
                    }
                    break;
                }

                case REPLACE_FILE: {
                    if (file_status == FILE_PRESENT) {
                        print_device_status("  REPLACING.. ");
                        D64ScratchDirEntry(dirtrack, dirsector, direntry);    /*remove entry*/
                        files_scratched = 1;
                        strcpy((char *)command_string,(char *) filename_string);            /*make sure the save routine uses the correct data, the command without the @0:*/
                        SaveD64File();                                        /*save the actual file to the D64-file*/
                        print_device_status("              ");
                    }
                    break;
                }
            }
            break;
        }

        case 2:;        /*these channels are used for...*/
        case 3:
            ;
        case 4:
            ;
        case 5:
            ;
        case 6:
            ;
        case 7:
            ;
        case 8:
            ;
        case 9:
            ;
        case 10:
            ;
        case 11:
            ;
        case 12:
            ;
        case 13:
            ;
        case 14: {
            if (IEC_state == ACTIVE_TALK) {  /*if the drive is expected to TALK... speak now*/
                EOI = FALSE;
                LED_GREEN = 1;                            /*drive LED-ON*/
                disable_ATN_interrupt();                /*since we are a talker now and the listener may interrupt us with an ATN, we must disable interrupts on ATN line, otherwise we create a lock up situation (ATN interrupt pulls data-line low)*/
                IEC_turnaround();                        /*we now SEND data to the bus so... make our device a talker*/
                while (IEC_ATN() == 1) {                     /* the listener (computer) indicates (by making ATN=0) it requires no more data (for now)*/
                    if (command_string[0] == '#') {                      /*if the user's/computer's last command specified opening a buffer, then handle accordingly...*/
                        command_string[0] = 0;                            /*make sure the command string is discarded to prevent looping*/
                        IEC_send(DOS_channel[channel].used_buffer);        /*send the buffer number of the just opened buffer*/
                    } else {
//                        if (DOS_channel[channel].buffer_pointer == 255)        /*when the last byte is going to been send*/
//                        {
//                            EOI = TRUE;                                        /*indicate that this is the last byte of the buffer*/
//                        }
                        IEC_send(DOS_buffer[DOS_channel[channel].used_buffer].buffer[DOS_channel[channel].buffer_pointer]);    /*get the data from the buffer connected to this channel at the bufferposition as pointed to by the buffer-pointer*/
                        DOS_channel[channel].buffer_pointer++;                /*increment buffer pointer by one*/
                    }
                    /*wait for the listener (computer) to release the data-line (ready to receive data), this may take forever... (according the IEC-bus definition)*/
                    while (IEC_DATA() == 0);            /*data is released when new data can be handled by the listener (the computer at this stage)*/
                    /*OR*/
                    /*data is released when ATN goes low because NO MORE data is required*/
                }
                IEC_undoturnaround();
                enable_ATN_interrupt();                            /*all is back to normal, enable interrupts on ATN line*/
                SetErrorCode(0,LED_OFF);                        /*error-code is 0, LED is OFF*/
            }

            if (IEC_state == ACTIVE_LISTEN) {  /*if the drive is expected to listen then... we're all ear*/
                OutputToRS232();    /*set standard output to RS232*/
                printf("\r\ntp10 active listen");    /*!!! DEBUG ONLY !!!*/
                OutputToLCD();        /*set standard output to LCD*/
            }

            break;
        }

        /*---------------------------------------*/
        case 15:                /* this channel is used for DOS-commands */
        {                        /*---------------------------------------*/
            if (IEC_state == ACTIVE_TALK)
//            if ((IEC_state == ACTIVE_TALK) && (DOS_channel[15].channel_in_use == TRUE))
            {
                /*-------------------------------------------------------*/
                /* Reading the error channel is a special situation      */
                /* Example: OPEN 15,8,15<RETURN>                         */
                /*          INPUT#15, A, B$, C, D<RETURN>                */
                /*          CLOSE 15<RETURN>                             */
                /*-------------------------------------------------------*/
                SendErrorMessage();            /*this is handled immediately*/
            } else {
                DOS_channel[channel].channel_in_use = TRUE;        /*claim this channel*/
                WaitForString(command_string, TRUE);            /*wait for an operator string that ends with an EOI*/
            }

            break;
        }
    }
}

/*****************************************************************************************************************/
/*The following routine will check for the PCB type by testing for the capacitor value on port RA0*/
/*During this testing procedure no buttons may be pressed*/
void AutoDetectPcbType(void) {

    PCB_type = v1_1;                                            /*typical timer value: 10771 - 10835*/
}

void NoCardMenu(void) {
    // Lcd_XY_address(0,0);
    putch('o');
//   Lcd_XY_address(0,2);
    putch(0x16);
//   Lcd_XY_address(0,4);
    putch('i');
    while (ReadButtons()) {
        if    (button_prev == TRUE)                        /*decrease contrast (lighter)*/
        {                                                /*---------------------------*/
            setting_contrast--;
            if (setting_contrast < 0x81) {
                setting_contrast = 0x81;                /*lower limit*/
                //             Lcd_XY_address(0,1);
                printf(" Min. reached ");
                DelayBigMs(350);
            } else {
//                SetContrast();                            /*apply new setting*/
                //           Lcd_XY_address(0,1);
                //         Lcd_ProgressBar((0xff-setting_contrast), 0x81);
                //       SaveSettingsToEEPROM();                    /*save value to EEPROM*/
                DelayBigMs(200);
            }
            OutputToRS232();                            /*set standard output to RS232*/
            printf("\r\nLCD-Lighter, contrast =%02x",setting_contrast);
            OutputToLCD();                                /*set standard output to LCD*/
        }

        if    (button_select == TRUE)                        /*increase contrast (darker)*/
        {                                                /*--------------------------*/
            setting_contrast++;
            if (setting_contrast > 0xFE) {
                setting_contrast = 0xFE;                /*upper limit*/
                //     Lcd_XY_address(0,1);
                printf(" Max. reached ");
                DelayBigMs(350);
            } else {
                //             SetContrast();                            /*apply new setting*/
                //   Lcd_XY_address(0,1);
                // Lcd_ProgressBar((0xff-setting_contrast), 0x81);
                //  SaveSettingsToEEPROM();                    /*save value to EEPROM*/
                DelayBigMs(200);
            }
            OutputToRS232();                            /*set standard output to RS232*/
            printf("\r\nLCD-Darker, contrast =%02x",setting_contrast);
            OutputToLCD();                                /*set standard output to LCD*/
        }

        if    (button_next == TRUE) {                      /*info button*/
            OutputToRS232();                            /*set standard output to RS232*/
            printf("\r\nInfo button pressed");
            OutputToLCD();                                /*set standard output to LCD*/
            //     Lcd_clr();
            HardWareTestMenu();
            //   Lcd_clr();
            break;
        }
    }
}

void HardWareTestMenu(void) {
//   Lcd_clr();
//   Lcd_XY_address(0,0);
    printf("LED test");
//   Lcd_XY_address(0,2);
    printf("IO & settings");
//    Lcd_XY_address(0,4);
    printf("Exit");
    DelayBigMs(1000);
    while (1) {
        ReadButtons();
        if    (button_prev == TRUE)                        /*LED-test routines*/
        {                                                /*-----------------*/
            //          Lcd_clr();
            //        Lcd_XY_address(5,2);
            printf("OFF");
            LED_GREEN = 0;
            LED_RED = 0;
            DelayBigMs(2000);
            //      Lcd_XY_address(4,2);
            printf("green");
            LED_GREEN = 1;
            LED_RED = 0;
            DelayBigMs(2000);
            //    Lcd_XY_address(4,2);
            printf(" red ");
            LED_GREEN = 0;
            LED_RED = 1;
            DelayBigMs(2000);
            //  Lcd_XY_address(3,2);
            printf("red+green");
            LED_GREEN = 1;
            LED_RED = 1;
            DelayBigMs(2000);
            LED_GREEN = 0;
            LED_RED = 0;
            break;
        }

        if    (button_select == TRUE)                        /*IO & settings*/
        {                                                /*-------------*/

            //        Lcd_XY_address(0,4);
            printf("Contrast:%02X",setting_contrast);
            //        Lcd_XY_address(0,5);
            printf("PCBtimer:%05d",PCB_type_timer);

            DelayBigMs(3000);
            break;
        }

        if    (button_next == TRUE)                        /*Exit-button*/
        {                                                 /*-----------*/
            break;
        }
    }
}


/*this routine wait for a card to be inserted, once inserted it will be initialised, when all is OK this routine will exit*/
unsigned char CardStatus(void) {
    unsigned char err_code;

    if (CARD_DETECT == 1) {
        //     Lcd_XY_address(4,1);
        //    Lcd_CharBold();
        printf("INSERT");
        //     Lcd_XY_address(5,3);
        printf("CARD");
        //     Lcd_CharNormal();
        //     Lcd_XY_address(0,5);
        printf("  (20%02d%02d%02d)",RELEASE_VERSION,RELEASE_VERSION_SUB,RELEASE_VERSION_SUB_SUB);
        DiskState = NO_CARD;
        return(FALSE);
    }

    //  Lcd_clr();
//   Lcd_XY_address(0,0);
    printf("Card detected ");

    //if(WR_PROTECT == 1)                        /*check if the SD-cards write protect "switch" has been set*/
    //{
    //    Lcd_XY_address(0,1);
    //    printf("Card wr. prot.");
    //    DiskState = NO_CARD;
    //    return(FALSE);
    //}

    DelayMs(250);                                    /*do not access card immediatly, wait for card to stabelise*/
//    Lcd_XY_address(0,1);
    printf("Init. card:   ");
//    Lcd_XY_address(0,2);                        /*set cursor to next line to print error messages*/
    if (Init_Card_SPI()) {
        DelayMs(100);                                /*do not access card immediatly...*/
        err_code = FindDrive();
        if (err_code != TRUE) {
            //          Lcd_XY_address(0,3);
            switch (err_code) {
                case ERROR_ATAREAD_CMD17: {
                    printf("ATA:err. CMD17");        /*CMD17 does not respond, the command is not accepted...*/
                    break;
                }

                case ERROR_ATAREAD_TIMEOUT: {
                    printf("ATA:rd timeout");        /*timeout on waiting for start of data transfer*/
                    break;
                }

                case ERROR_FAT_READBOOTSECTOR: {
                    printf("FAT:read boots");
                    break;
                }

                case ERROR_FAT_JUMPOPCODE: {
                    printf("FAT:jump opcode");
                    break;
                }

                case ERROR_FAT_BLOCKSIZE: {
                    printf("FAT:blocksize  ");
                    break;
                }

                case ERROR_FAT_MEDIUM: {
                    printf("FAT:wr. medium ");
                    break;
                }

                default: {
                    printf("Undefined.....");
                    break;
                }
            }
            //        Lcd_XY_address(0,4);
            printf("Card not supp.");
        } else {
            //      Lcd_XY_address(11,1);
            printf("OK");
            DiskState = CARD_ACTIVE;
            return(TRUE);
        }
    }
    DelayMs(100);                        /*when initialise failed wait before retry, otherwise the error message could not be read*/
    DiskState = NO_CARD;
    return(FALSE);
}


/*initialise MMC/SD-card in SPI-mode*/
unsigned char Init_Card_SPI(void) {
    if (CARD_Init() == FALSE);                    /*The official initialisation routines as described in most of the documentation*/
    {                                            /*If the official init fails, try the alternative init*/
        if (CARD_AlternativeInit() == FALSE) {  /*The alternative init, required ONLY because SanDisk does not follow the world's standards... <zucht>*/
            return(FALSE);
        }
    }

  //  Card_CID();                                    /*request Card - ID*/
  //  Card_CSD();                                    /*request Card Specific Data*/

    if (CARD_OperatingConditions(Response_data) == FALSE) {
        printf("CARD:err CMD58");
        return(FALSE);
    } else {
        if ((Response_data[2] & SUPPVOLT) != SUPPVOLT) {  /*mask and compare for cards that support 3.0-3.1, 3.1-3.2, 3.2-3.3, 3.3-3.4 Volt*/
            printf("CARD:voltage  ");
            return(FALSE);
        }

        printf("CARD:OK       ");
        return(TRUE);
    }
}

/*This routine will count ALL files within the current directory (which could be root or subdirectory)*/
void CountFiles(void) {
    print_device_status("COUNTING FILES");    /*inform the user about a possible time consuming task*/

    if (FileSearch(&file,0)) {              /*search for the first file on the card*/
        CountedFiles = 1;
        while (FileSearch(&file,1)) {          /*goto the next file*/
            /*count ALL files (even the irrelevant files, since they do occupy diskspace, max 512 files in root you know)*/
            CountedFiles++;                    /*increment file-counter*/
        }
        FileSearch(&file,0);                /*set the search routines back to the first file*/
    } else {
        CountedFiles = 0;
    }

    //  OutputToRS232();                                /*set standard output to RS232*/
    printf("\r\nNumber of files in current (sub)dir: %d",CountedFiles);
    //  OutputToLCD();                                    /*set standard output to LCD*/
}

/*This routine will 'filter' the currently 'selected' file,*/
/*when the file does not meet the expected standards it returns 'FALSE'*/
unsigned char FileFilter(void) {
    /* Disk type                 | Size   */
    /* --------------------------+--------*/
    /* 35 track, no errors       | 174848 */
    /* 35 track, 683 error bytes | 175531 */
    /* 40 track, no errors       | 196608 */
    /* 40 track, 768 error bytes | 197376 */

    if ((file.name[8] == 'P') && (file.name[9] == 'R') && (file.name[10] == 'G')) {
        return(PRG_FILE);
    }

    if ((file.name[8] == 'D') && (file.name[9] == '6') && (file.name[10] == '4')) {
        if (file.size == 174848)
            return(D64_35T_MODE);

        if  (file.size == 175531)
            return(D64_35T_ER_MODE);

        if (file.size == 196608)
            return(D64_40T_MODE);

        if (file.size == 177376)
            return(D64_40T_ER_MODE);
    }

//    if((file.name[8] == 'T') && (file.name[9] == '6') && (file.name[10] == '4'))
//    {
//        return(T64_MODE);
//    }

    if ((file.size == 0) && (file.cluster!=0))
        return(SUBDIRECTORY);    /*normal subdirectories are files with a length 0 and only the rootdirectory points to cluster=0, meaning that subdirectories NEVER point to cluster 0*/

    if ((file.name[0] == '.') && (file.name[1] == ' ') && (file.name[2] == ' ') && (file.name[3] == ' ') && (file.name[4] == ' ') && (file.name[5] == ' ') && (file.name[6] == ' ') && (file.name[7] == ' '))
        return(SUBDIRECTORY);    /*this subdirectory points to the current directory*/

    if ((file.name[0] == '.') && (file.name[1] == '.') && (file.name[2] == ' ') && (file.name[3] == ' ') && (file.name[4] == ' ') && (file.name[5] == ' ') && (file.name[6] == ' ') && (file.name[7] == ' '))
        return(SUBDIRECTORY);    /*this subdirectory points to the parent directory (which could be root)*/

    if ((file.name[0] != 0x20) && (file.name[8] == 0x20) && (file.name[9] == 0x20) && (file.name[10] == 0x20))
        return(UNKNOWN);        /*when a filename has no extension, show it simply because it could be a file belonging to an IDE64 fixed game*/

    return(FALSE);
}

/*this routine will search for the next available buffer, when no buffer can be found it responds with 255*/
unsigned char SearchFreeBuffer(void) {
    unsigned char lp;

    lp=0;
    while (lp<MAX_NUMBER_OF_DOS_BUFFERS) {
        if (DOS_buffer[lp].buffer_in_use == FALSE) {  /*TRUE means that this channel is in use, FALSE means it is available*/
            return(lp);                                /*return with the number of the available channel*/
        }
        lp++;
    }
    return(255);                                    /*an error has occurred, there are no free channels left*/
}

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

/*this routine will wait untill a string has been loaded that is terminated by an EOI*/
void WaitForString(unsigned char *outputstring, unsigned frame_handshake) {
    unsigned char cnt;

    TimeOut = FALSE;
    EOI = FALSE;
    cnt = 0;
    while ((TimeOut == FALSE) && (EOI == FALSE)) {             /*get filename/instruction, this is all data untill an EOI is received*/
        outputstring[cnt] = IEC_receive(frame_handshake);    /*save the received char to a string specified by the caller of this routine*/
// printf("%02x", outputstring[cnt]);                        /*print string to be captured for debug purposes...*/
        cnt++;
    }
    outputstring[cnt] = 0;    /*close the string with a "nul"*/
}


/*This routine will search for the first 'number' and puts this number into a register*/
/*it returns 0 (FALSE) when the number does not fit into an unsigned char*/
/*it returns the position of the character AFTER the number. so that this can be used for the next number search...*/
unsigned char ValueFromString(unsigned char *inputstring, unsigned char *outputvalue) {
    unsigned char lp;

    lp = 0;
    *outputvalue = 0;

    while ((inputstring[lp] < '0') || (inputstring[lp] > '9')) {  /*check if this character is not a number*/
        lp++;                        /*keep looping until a number is found*/
        if (inputstring[lp] == 0) {  /*when the end of the string has been reached, exit false*/
            return(FALSE);            /*if there were no numbers at the beginning of this string, return FALSE*/
        }
    }

    while ((inputstring[lp] >= '0') && (inputstring[lp] <= '9')) {  /*check if this character is a number*/
        if (*outputvalue > 25) {
            return(FALSE);    /*the number in the string is larger the 255 and is not a 'unsigned char' exit routine*/
        } else {
            *outputvalue = *outputvalue * 10;
            *outputvalue = *outputvalue + (inputstring[lp] - '0');
            lp++;
        }
    }

    return(lp);        /*the first position directly after the number*/
}


/*This routine will search for the first 'number' and puts this number into a register*/
/*the number has to start a the first character otherwise it returns false*/
unsigned char LongValueFromString(unsigned char *inputstring, unsigned long *outputvalue) {
    unsigned char lp;

    lp = 0;
    *outputvalue = 0;

    while ((inputstring[lp] >= '0') && (inputstring[lp] <= '9')) {  /*check if this character is a number*/
        *outputvalue = *outputvalue * 10;
        *outputvalue = *outputvalue + (inputstring[lp] - '0');
        lp++;
    }

    return(lp);        /*the first position directly after the number*/
}


/*this routine extract the filename from the command string, it will remove all unwanted options and leaves the filename only    */
/*Some of the possible entries to indicate the problem to be solved by this routine:                                            */
/*normal open    : commandstring = "0:filename,s,r"                                                                                */
/*simplified open: commandstring = "filename,s,r"                                                                                */
/*simplified open: commandstring = "filename"                                                                                    */
/*simplified open: commandstring = "0:filename"                                                                                    */
/*replacement    : commandstring = "@0:filename,s,r"                                                                            */
/*copy           : commandstring = "C0:backup=original"                                                                            */
/*multiple copy  : commandstring = "COPY0:<destfile>=<sourcefile>" or "COPY:<destfile>=<sourcefile1>, <sourcefile2>, ..."        */
/*therefore we may conclude that everything AFTER ':' and BEFORE ',' (or end-of-string) is the filename                            */
void ExtractFilenameFromString(unsigned char *input_string, unsigned char *output_string) {
    unsigned char tempstring[41];

    strcpy((char *)tempstring, (char *)input_string); /*this is required because the splitstring_on function destroys the inputvalues*/
    if (!SplitStringOn_Sign(':', tempstring, output_string))    /*remove all characters BEFORE the ':'-sign*/
    {                                                            /*if this succeeds the ':'-sign was found we can continue 'stripping' the string*/
        strcpy((char *)output_string, (char *)input_string);                     /*when the commandstring does not contain a ':' the outputstring is empty, so we must fill it with the inputstring in order to continue*/
    }
    SplitStringOn_Sign(',', output_string, tempstring);            /*remove all characters after the ','-sign and store the result in outputstring. If does not matter if this fails (because there is no ','-sign) because the outputstring is still correct. as it contains all caracters BEFORE the ','-sign (even if it isn't there*/
}



/*this routine will strip all characters before the given sign*/
/*it will return the characters BEFORE the first sign in BEFORE_STRING (sign is not included in the result)*/
/*it will return the characters AFTER the first sign in AFTER_STRING (sign is not included in the result)*/
unsigned char SplitStringOn_Sign(unsigned char sign, unsigned char *beforesign_string, unsigned char *aftersign_string) {
    unsigned char lp, lp2;

    lp = 0;
    while (beforesign_string[lp]) {
        if (beforesign_string[lp] == sign) {
            lp++;
            lp2 = 0;
            while (beforesign_string[lp+lp2]) {
                aftersign_string[lp2] = beforesign_string[lp+lp2];
                lp2++;
            }
            beforesign_string[--lp] = 0;                            /*terminate the command_string, the :-sign is not included any more in te string*/
            aftersign_string[lp2] = 0;                                /*terminate the copied string*/
            return(TRUE);                                            /*indicate that the conversion (removal of all chars before :-sign) has succeeded*/
        }
        lp++;
    }
    return(FALSE);                                                    /*indicate that the conversion (removal of all chars before :-sign) has failed*/
}


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

/*this routine print some prefedined text to the display AND serial port*/
void print_device_status(const unsigned char *message) {
//    Lcd_XY_address(0,2);
//    Lcd_CharBold();
    printf("%s",message);
//    Lcd_CharNormal();

    OutputToRS232();                    /*set standard output to RS232*/
    printf("\r\n%s",message);
    OutputToLCD();                        /*set standard output to LCD*/
}

/*this routine print the name of the current file (which is suppost to be a D64 file)*/
void print_D64_name(unsigned char mode) {
    unsigned char i;

    if (mode == INVERTED)                            /*depending on requested mode print in normal or inverse-mode*/
//        Lcd_CharInvert();

//    Lcd_XY_address(0,0);
        printf("%05d in dir. ",CountedFiles);            /*show the total number of files (sub)directory*/
//    Lcd_XY_address(0,1);                            /*set cursor to line we want to use*/

    if (file_type == NONE) {
        printf("%05d=        ",file_number);        /*show the current selection and clear the line*/
//        Lcd_XY_address(6,1);                        /*set cursor back...*/
    } else {
        printf("%05d=        ",file_number);        /*show the current selection and clear the line*/
//        Lcd_XY_address(6,1);                        /*set cursor back...*/
        for (i=0; i<8; i++)                         /*print selection (or currently selected) 8.3-filename*/
            putch(file.name[i]);                    /*character after character*/

        OutputToRS232();                            /*output the same info to the serial port also*/
        printf("\r\nfilename:");
        for (i=0; i<8; i++)                         /*print selection (or currently selected) 8.3-filename*/
            putch(file.name[i]);                    /*character after character*/
        OutputToLCD();                                /*set standard output to LCD*/
    }

//    Lcd_CharNormal();
//    Lcd_XY_address(0,5);
    printf("%c=%02d ",0x0d,devicenumber);            /*print the device number on the display*/
    if (file_type == NONE)                           /*indicate on the display we are working in the root-dir of the card (HD-mode*/
        printf("Hard-disk");
    if (file_type == SUBDIRECTORY)                   /*indicate on the display we are working in the root-dir of the card (HD-mode*/
        printf("Hard-disk");
    if (file_type == PRG_FILE)                       /*...*/
        printf("PRG-file ");
    if (file_type == UNKNOWN)                       /*...*/
        printf("-UNKNOWN-");
    if (file_type == D64_35T_MODE)                   /*indicate on the display the D64 file 35 tracks no errors*/
        printf(".D64 35T ");
    if (file_type == D64_35T_ER_MODE)               /*indicate on the display the D64 file 35 tracks with errors*/
        printf(".D64 35Te");
    if (file_type == D64_40T_MODE)                   /*indicate on the display the D64 file 40 tracks no errors*/
        printf(".D64 40T ");
    if (file_type == D64_40T_ER_MODE)               /*indicate on the display the D64 file 40 tracks with errors*/
        printf(".D64 40Te");
    if (file_type == T64_MODE)                       /*indicate on the display the T64*/
        printf(".T64-mode");
}

/*this routine prints Track Sector and (remaining/loaded) blocks*/
void print_D64_TSB(unsigned char trk, unsigned char sec, unsigned int blk, unsigned int total_blk) {
    static unsigned char previous_track;
    unsigned int blockcounter;

    blockcounter = total_blk - blk;                                    /*calculate the current block*/

    //  Lcd_XY_address(0,3);                                            /*set the LCD coordinates*/
//   Lcd_ProgressBar(blk, total_blk);                                /*draw a progress bar*/
//   Lcd_XY_address(0,4);                                            /*set the LCD coordinates*/
    printf("%c=%02d T=%02d S=%02d",0x0e,error_code,trk,sec);        /*show the error code, track and sector*/

    OutputToRS232();                                                /*output the same info to the serial port also*/
    printf("\r\n%02d,%02d,%d/%d",trk,sec,blockcounter,total_blk);    /*send to serial the Track and sector info*/
    OutputToLCD();                                                    /*set standard output to LCD*/

    //Sound_TrackChange(trk-previous_track);                            /*play a sound (if required) of a moving head*/
    previous_track = trk;                                            /*keep track of the number of tracks we move within the disk, this in order to simulate the sound properly*/
}



/*this routine is to be used to select a D64 image from the inserted card*/
void SelectD64Image(void) {
    unsigned char filefilter_result;
    unsigned char blink_loop;

    ReadButtons();
    if    (button_prev == TRUE) {
        if (file_number == 1) {
            file_number=0;                                /*file counter is now '0' which means 'ROOT directory'*/
            file_type = NONE;                            /*and because the user has selected root, the selected file_type = NONE*/
        } else {
            if (file_number > 1) {
                if (FileSearch(&file,2)) {              /*goto the previous D64 file*/
                    file_number--;                        /*decrease selected file counter*/
                }
                filefilter_result = FileFilter();        /*check the selected file*/
                file_type = filefilter_result;
            }
        }
        DiskState = INVALID_POINTER;
        //     Lcd_XY_address(0,3);
        //    Lcd_SelectionBar((CountedFiles-file_number), CountedFiles);
        print_D64_name(INVERTED);                        /*write the selection to display in inverted mode*/
        DelayBigMs(BUTTON_SELECTION_RATE);                /*delay determines selection repetition rate*/
    }

    if    (button_next == TRUE) {
        if (file_number < CountedFiles) {
            if (file_number == 0)                        /*the first file on the card needs no search since it is allready found*/
                file_number++;                            /*increase selected file counter*/
            else if (FileSearch(&file,1))               /*goto the next D64 file*/
                file_number++;                        /*increase selected file counter*/
        }
        filefilter_result = FileFilter();                /*check the selected file*/
        file_type = filefilter_result;
        DiskState = INVALID_POINTER;
        //     Lcd_XY_address(0,3);
        //      Lcd_SelectionBar((CountedFiles-file_number), CountedFiles);
        print_D64_name(INVERTED);                        /*write the selection to display in inverted mode*/
        DelayBigMs(BUTTON_SELECTION_RATE);                /*delay determines selection repetition rate*/
    }

    if    (button_select == TRUE) {
        filefilter_result = FileFilter();                /*check the selected file*/
        file_type = filefilter_result;

        if (file_number==0) {                              /*file counter is now '0' which means 'ROOT directory'*/
            file_type = NONE;                            /*and because the user has selected root, the selected file_type = NONE*/
            //        Lcd_XY_address(0,2);                        /*set cursor*/
            printf("              ");                    /*clear the file_info information*/
            print_D64_name(PLAIN);                        /*write the selection to display in normal-mode*/
            DiskState = CARD_ACTIVE;                    /*the 1541-III is now functioning as a harddisk*/
            DelayBigMs(BUTTON_SELECTION_RATE);            /*delay determines selection repetition rate*/
        } else {
            if (filefilter_result == SUBDIRECTORY) {
                OpenSubDirectory(&file);                    /*the user request to enter a subdirectory, so we call the routine that setts all registers in the correct way in order to use subdirectories properly*/
                file_number = 0;                            /*the file_number counter needs to be reset*/
                file_type = NONE;                            /*and because the user has selected a (sub)directory, the selected file_type = NONE, as there is no image file selected and we are operating in harddiskmode*/

                print_D64_name(PLAIN);                        /*write the selection to display in normal-mode, this clears up the display, but with the incorrect filecount values*/
                CountFiles();                                /*count all files in the opened directory*/
                print_D64_name(PLAIN);                        /*write the selection to display in normal-mode, the countvalues are updated*/
                //          Lcd_XY_address(0,2);                        /*set cursor*/
                printf("              ");                    /*clear the file_info information*/
                DiskState = CARD_ACTIVE;                    /*the 1541-III is now functioning as a harddisk*/
                DelayBigMs(BUTTON_SELECTION_RATE);            /*delay determines selection repetition rate*/
            } else {
                if ((filefilter_result != PRG_FILE) && (filefilter_result != UNKNOWN)) {  /*pass all supported D64 files and leave out PRG and unknown files*/
                    FileSectorScan(&file);                    /*update the sector location table cache*/
                    D64ReadBAM();                            /*update the BAM*/
                    DiskState = CARD_ACTIVE;                /*the 1541-III is now accessable*/
                    //            Lcd_XY_address(0,2);                    /*set cursor*/
                    printf("              ");                /*clear the file_info information*/
                    print_D64_name(PLAIN);                    /*write the selection to display in normal-mode*/
                } else {
                    for (blink_loop=4; blink_loop>0; blink_loop--) { /*create a blinking effect to draw attention to this line*/
                        //              Lcd_CharInvert();
                        //            Lcd_XY_address(0,1);
                        printf("Selection err.");
                        DelayBigMs(250);                    /*delay to make sure the message can be read properly*/
                        //          Lcd_CharNormal();
                        //        Lcd_XY_address(0,1);
                        printf("Selection err.");
                        DelayBigMs(250);                    /*delay to make sure the message can be read properly*/
                    }
                    print_D64_name(INVERTED);                /*write the selection to display in inverted mode*/
                }
            }
        }
    }
}

/*****************************************************************************************************************/
/*almost identical to loading a directory (seen from a C64)*/
/*This routine shows 'all' the files on the card*/

/*Note: 'all' means the files that are OK according the filefilter routine*/
void CardDirectory(void) {
    unsigned pass_counter;
    unsigned char separation_line=FALSE;
    unsigned char filefilter_result;
    unsigned int index_cnt;
    unsigned char lp;
    unsigned char dir_width;
    unsigned int blocksize;

    SetErrorCode(0,LED_ON);        /*unless we fail we will exit with no error*/
    EOI = FALSE;
    IEC_turnaround();            /*we now SEND data to the bus so... make our device a talker*/

    /*----------------*/
    /*directory header*/
    /*----------------*/
    IEC_send(0x01);                /*load this "program" to start address 0x0401*/
    IEC_send(0x04);

    if (VIC20_mode == TRUE)        /*for better readabillity on a VIC-20 the card directory is displayed in a smallscreen and a widescreen version*/
    {                            /*                                                                                                       |              |*/ /*useable area of a VC-20 dir line*/
        dir_width = 10;            /*the number of places that a VIC20 file entry may occupy in order to fit the screen width of 22 chars*/
        IEC_send(0x01);
        IEC_send(0x01);
        IEC_send(0x00);
        IEC_send(0x00);
        IEC_send(0x20);
        IEC_send(0x12);
        IEC_send(0x20);
        IEC_send(0x22);
        IEC_send_string("CARD DIRECTORY");
        IEC_send(0x22);
        IEC_send(0x00);    /*VIC-20 Directory header*/
        IEC_send(0x01);
        IEC_send(0x01);
        IEC_send(0x00);
        IEC_send(0x00);
        IEC_send(0x20);
        IEC_send(0x20);
        IEC_send(0x22);
        IEC_send_string("u``````````i");
        IEC_send(0x22);
        IEC_send(0x00);    /*top-line*/
        IEC_send(0x01);
        IEC_send(0x01);
        IEC_send(0x00);
        IEC_send(0x00);
        IEC_send(0x20);
        IEC_send(0x20);
        IEC_send(0x22);
        IEC_send_string("} 1541-III }");
        IEC_send(0x22);
        IEC_send(0x00);    /*model*/
        IEC_send(0x01);
        IEC_send(0x01);
        IEC_send(0x00);
        IEC_send(0x00);
        IEC_send(0x20);
        IEC_send(0x20);
        IEC_send(0x22);
        IEC_send_string("}J. DEROGEE}");
        IEC_send(0x22);
        IEC_send(0x00);    /*credits*/
        IEC_send(0x01);
        IEC_send(0x01);
        IEC_send(0x00);
        IEC_send(0x00);
        IEC_send(0x20);
        IEC_send(0x20);
        IEC_send(0x22);
        IEC_send_string("}VIC20-MODE}");
        IEC_send(0x22);
        IEC_send(0x00);    /*credits*/
        IEC_send(0x01);
        IEC_send(0x01);
        IEC_send(0x00);
        IEC_send(0x00);
        IEC_send(0x20);
        IEC_send(0x20);
        IEC_send(0x22);
        IEC_send_string("j``````````k");
        IEC_send(0x22);
        IEC_send(0x00);    /*separation-line*/
    } else {
        dir_width = 17;            /*the number of places that a C64/C128/C16 etc. file entry may occupy in order to fit the screen width of 40 chars*/
        IEC_send(0x01);
        IEC_send(0x01);
        IEC_send(0x00);
        IEC_send(0x00);
        IEC_send(0x20);
        IEC_send(0x12);
        IEC_send(0x20);
        IEC_send(0x22);
        IEC_send_string(" CARD DIRECTORY ");
        IEC_send(0x22);
        IEC_send_string(" 00 2A");
        IEC_send(0x00);    /*Normal Directory header*/
        IEC_send(0x01);
        IEC_send(0x01);
        IEC_send(0x00);
        IEC_send(0x00);
        IEC_send(0x20);
        IEC_send(0x20);
        IEC_send(0x22);
        IEC_send_string("u````````````````i");
        IEC_send(0x22);
        IEC_send(0x00);    /*top-line*/
        IEC_send(0x01);
        IEC_send(0x01);
        IEC_send(0x00);
        IEC_send(0x00);
        IEC_send(0x20);
        IEC_send(0x20);
        IEC_send(0x22);
        IEC_send_string("} 1541-III MBED  }");
        IEC_send(0x22);
        IEC_send(0x00);    /*model*/
        IEC_send(0x01);
        IEC_send(0x01);
        IEC_send(0x00);
        IEC_send(0x00);
        IEC_send(0x20);
        IEC_send(0x20);
        IEC_send(0x22);
        IEC_send_string("}J.DEROGEE & KGE }");
        IEC_send(0x22);
        IEC_send(0x00);    /*credits*/
        IEC_send(0x01);
        IEC_send(0x01);
        IEC_send(0x00);
        IEC_send(0x00);
        IEC_send(0x20);
        IEC_send(0x20);
        IEC_send(0x22);
        IEC_send_string("j````````````````k");
        IEC_send(0x22);
        IEC_send(0x00);    /*separation-line*/
    }

    /*-----------------*/
    /*directory content*/
    /*-----------------*/

    pass_counter = 0;
    index_cnt = 0;
    while (pass_counter++ < 3) {
        if (pass_counter != 1)            /*print a seperator line BETWEEN the different file types, pass_counter 1 means the first and between means ALL EXCEPT 1 (because thee is nothing before 1, so the line could bever be in between)*/
            separation_line = FALSE;

        if (FileSearch(&file,0)) {
            do {
                //OutputToRS232();                                                        /*set standard output to RS232*/
                //printf("\r\n8.3:%c%c%c%c%c%c%c%c",file.name[0],file.name[1],file.name[2],file.name[3],file.name[4],file.name[5],file.name[6],file.name[7]);        /*for debug purposes only !!!*/
                //printf("\r\nlfn:%c%c%c%c%c%c%c%c%c%c%c%c",file.name_lfn[0],file.name_lfn[1],file.name_lfn[2],file.name_lfn[3],file.name_lfn[4],file.name_lfn[5],file.name_lfn[6],file.name_lfn[7],file.name_lfn[8],file.name_lfn[9],file.name_lfn[10],file.name_lfn[11]);        /*for debug purposes only !!!*/
                //OutputToLCD();                                                            /*set standard output to LCD*/

                print_D64_TSB(0, 0, (3*CountedFiles-index_cnt), 3*CountedFiles);    /*print track, sector and progress bar, since were are making 3 passes, the counter is used 3 times (3 passes)*/
                index_cnt++;    /*for the best results... arrange the files on filetype, directories first, the D64's of all types, then PRG-files*/
                filefilter_result = FileFilter();
                if ((pass_counter == 1) && (filefilter_result == SUBDIRECTORY) ||
                        ((pass_counter == 2) && ((filefilter_result == D64_35T_MODE) || (filefilter_result == D64_35T_ER_MODE) || (filefilter_result == D64_40T_MODE) || (filefilter_result == D64_40T_ER_MODE))) ||
                        ((pass_counter == 3) && ((filefilter_result == PRG_FILE) || (filefilter_result == T64_MODE) || (filefilter_result == UNKNOWN)))) {
                    if (separation_line == FALSE) {      /*for better readabillity... add a small separation-line (but only if required)*/
                        separation_line = TRUE;
                        IEC_send(0x01);
                        IEC_send(0x01);
                        IEC_send(0x00);
                        IEC_send(0x00);
                        IEC_send(0x20);
                        IEC_send(0x20);
                        IEC_send(0x22);
                        for (lp=0; lp<(dir_width+1); lp++)
                            IEC_send('`');
                        IEC_send(0x22);
                        IEC_send(0x00);
                    }

                    IEC_send(0x01);
                    IEC_send(0x01);

                    if (pass_counter == 3) {              /*in the third pass we show all the file information, as these are not images or directories, but actual files*/
                        blocksize = file.size / 254;    /*calculate blocksize(1 block=254 bytes) from filesize(bytes)*/
                        IEC_send(blocksize%256);        /*low-byte of blocksize of file*/
                        IEC_send(blocksize/256);        /*high-byte of  blocksize of file*/
                        if (blocksize < 10)               /*if required, add extra space for better allignment*/
                            IEC_send(0x20);

                        if (blocksize < 100)               /*if required, add extra space for better allignment*/
                            IEC_send(0x20);
                    } else {
                        IEC_send(0);                    /*low-byte of blocksize of file*/
                        IEC_send(0);                    /*high-byte of blocksize of file*/
                        IEC_send(0x20);
                        IEC_send(0x20);
                    }

                    IEC_send(0x22);                 /*each entry must be starting with the "-sign*/
                    if ((filefilter_result != PRG_FILE) && (filefilter_result != UNKNOWN))
                        IEC_send('$');                /*proceed each image (.D64 or similar) or subdirectory with a $-sign, to indicate that it has to be loaded as an directory*/

                    if (file.name_lfn[0] == 0) {     /*check if this entry has an 8.3-name or LFN-name*/
                        IEC_send(file.name[0]);        /*8.3 filename WITHOUT the extra spaces (looks much better as the LFN has the same look by nature)*/
                        lp=7;
                        if (((file.name[1]) != ' ') || ((file.name[2]) != ' ') || ((file.name[3]) != ' ') || ((file.name[4]) != ' ') || ((file.name[5]) != ' ') || ((file.name[6]) != ' ') || ((file.name[7]) != ' ')) {
                            IEC_send(file.name[1]);
                            lp=6;
                        }
                        if (((file.name[2]) != ' ') || ((file.name[3]) != ' ') || ((file.name[4]) != ' ') || ((file.name[5]) != ' ') || ((file.name[6]) != ' ') || ((file.name[7]) != ' ')) {
                            IEC_send(file.name[2]);
                            lp=5;
                        }
                        if (((file.name[3]) != ' ') || ((file.name[4]) != ' ') || ((file.name[5]) != ' ') || ((file.name[6]) != ' ') || ((file.name[7]) != ' ')) {
                            IEC_send(file.name[3]);
                            lp=4;
                        }
                        if (((file.name[4]) != ' ') || ((file.name[5]) != ' ') || ((file.name[6]) != ' ') || ((file.name[7]) != ' ')) {
                            IEC_send(file.name[4]);
                            lp=3;
                        }
                        if (((file.name[5]) != ' ') || ((file.name[6]) != ' ') || ((file.name[7]) != ' ')) {
                            IEC_send(file.name[5]);
                            lp=2;
                        }
                        if (((file.name[6]) != ' ') || ((file.name[7]) != ' ')) {
                            IEC_send(file.name[6]);
                            lp=1;
                        }
                        if ((file.name[7]) != ' ') {
                            IEC_send(file.name[7]);
                            lp=0;
                        }

                        lp = (dir_width - 7) + lp;                    /*calculate the remaining spaces to fit the VIC20 mode*/
                    } else {
                        for (lp=0; lp<(dir_width-1); lp++) {           /*print the LFN string*/
                            IEC_send(file.name_lfn[lp]);
                            if ((file.name_lfn[lp+1] == '.') && (file.name_lfn[lp+5] == 0))        /*print the string, BUT without the last for characters (but only for files with a 3 letter extension, which are the .D64, .PRG, etc)*/
                                break;

                            if (file.name_lfn[lp+1] == 0)            /*otherwise on end of string, stop*/
                                break;
                        }

                        if (lp==(dir_width-1))                        /*check if the filename was displayed partially, if so, then add a *-sign*/
                            IEC_send('*');                            /*the max ammount of displayable characters was printed, but there where more characters to print, so we add a *-sign to keep compatible with the search routines*/

                        lp = dir_width  - lp;                        /*calculate the remaining number of spaces*/
                    }

                    IEC_send(0x22);                                    /*each entry must end with the "-sign*/
                    if (filefilter_result == PRG_FILE)
                        lp++;                                        /*since this entry did not start with the $-sign, we must add an extra space at the end to keep length of each line identical*/

                    while (lp--)                                       /*the remaining location must be filled with spaces*/
                        IEC_send(' ');

                    switch (filefilter_result) {
                        case PRG_FILE: {
                            IEC_send('P');                            /*print PRG*/
                            IEC_send('R');
                            IEC_send('G');
                            break;
                        }

                        case D64_35T_MODE:
                            ;
                        case D64_35T_ER_MODE:
                            ;
                        case D64_40T_MODE:
                            ;
                        case D64_40T_ER_MODE: {
                            IEC_send('D');                            /*print D64*/
                            IEC_send('6');
                            IEC_send('4');
                            break;
                        }

                        case T64_MODE: {
                            IEC_send('T');                            /*print T64*/
                            IEC_send('6');
                            IEC_send('4');
                            break;
                        }

                        case SUBDIRECTORY: {
                            IEC_send('D');                            /*print DIR*/
                            IEC_send('I');
                            IEC_send('R');
                            break;
                        }

                        default: {
                            break;                                    /*print nothing*/
                        }
                    }

                    IEC_send(0x00);
                }
            } while (FileSearch(&file,1));
        }
    }

    FileSearch(&file,0);                    /*select the first file on the card, this to please all other routines using the filesearch() routine, this since selected_D64file is set to 0*/

    /*PROPERLY END THIS DIRECTORY, BUT DO NOT PRINT THE FREE BLOCKS TEXT... IT WOULD NOT MAKE ANY SENSE, since the limitation is in the 512 files in root-dir limit*/
    IEC_send(0x00);
    EOI = TRUE;                                /*indicate the last byte*/
    IEC_send(0x00);
    IEC_undoturnaround();                    /*were done talking towards the bus*/
    SetErrorCode(0, LED_OFF);                /*all is OK, set the LED blinking mode to 'RITHM' to indicate that we have done somthing on a higher level then something within a D64-file*/
}


void D64Directory(void) {
    unsigned char lp, mode, extra_spaces, track, sector, unused;
    unsigned int blocksize, blocksfree, read_blocks;

    SetErrorCode(0,LED_ON);         /*unless we fail we will exit with no error*/
    EOI = FALSE;
    IEC_turnaround();                /*we now SEND data to the bus so... make our device a talker*/

    /*some bytes required for sending a directory entry to a VIC20, C64, C128, etc.*/
    IEC_send(0x01);                    /*load this "program" to start address 0x0401*/
    IEC_send(0x04);

    /*Directory header*/
    /*----------------*/
    D64BlockRead(18,0);
    read_blocks = 1;
    print_D64_TSB(18,0,read_blocks, 0);
    IEC_send(0x01);                    /*...*/
    IEC_send(0x01);                    /*...*/
    IEC_send(0);        /*drive-number of this device, in the beginning of this project used as file pointer/indicator*/
    IEC_send(0);        /*drive-number of this device, in the beginning of this project uses as file pointer/indicator*/
    IEC_send(0x12);                    /*RVS-ON (invert characters)*/
    IEC_send(0x22);                    /*"-sign*/
    for (lp=144; lp<160; lp++) {
        IEC_send(RAM_buffer[lp]);    /*send the Diskname*/
    }

    IEC_send(0x22);                    /*"-sign*/
    IEC_send(0x20);                    /*space*/
    IEC_send(RAM_buffer[162]);        /*send the disk-ID byte-0*/
    IEC_send(RAM_buffer[163]);        /*send the disk-ID byte-1*/
    IEC_send(0x20);                    /*space*/
    IEC_send(RAM_buffer[165]);        /*send the DOS-version and format-type byte-0*/
    IEC_send(RAM_buffer[166]);        /*send the DOS-version and format-type byte-1*/
    IEC_send(0x00);                    /*a byte indicating the end of this "directory-line"*/

    /*Directory entry ...*/
    /*-------------------*/
    mode=0;    /*set sector read to first entry*/
    while (D64SeekDirEntry(mode, &track, &sector, &unused)) {     /*get directory entry and request the current track and sector*/
        mode=1;    /*set sector read to next entry*/
        print_D64_TSB(track,sector,read_blocks,0);
        if (dir_entry.filetype != 0x00) {               /*scratched files are NOT displayed in the directory*/
            IEC_send(0x01);                                /*bytes indicating the beginning of a "directory-line"*/
            IEC_send(0x01);
            IEC_send(dir_entry.blocksize_low_byte);        /*size of this file low-byte*/
            IEC_send(dir_entry.blocksize_high_byte);    /*size of this file high-byte*/
//    dir_entry.record_size_relfile = 0x00;
            blocksize = ((256 * dir_entry.blocksize_high_byte) + dir_entry.blocksize_low_byte);
            if (blocksize < 10)                            /*add an extra space(s) to adjust line length*/
                IEC_send(0x20);                            /*                                           */
            if (blocksize < 100)                        /*                                           */
                IEC_send(0x20);                            /*                                           */
            if (blocksize < 1000)                        /*                                           */
                IEC_send(0x20);                            /*                                           */
            IEC_send(0x22);                                /*"-sign*/

            extra_spaces = 0;
            for (lp=0; lp<16; lp++) {
                if (dir_entry.filename[lp]== 160)
                    extra_spaces++;
                else
                    IEC_send(dir_entry.filename[lp]);        /*filename of this entrynumber*/

            }

            IEC_send(0x22);                            /*"-sign*/
            while (extra_spaces != 0) {
                IEC_send(0x20);                        /*add some extra spaces for proper allignment*/
                extra_spaces--;
            }

            /*filetype*/
            /*--------*/
            if (dir_entry.filetype > 127)            /*when MSB has been set the file has been properly closed*/
                IEC_send(0x20);                        /*print a space before the filetype*/
            else
                IEC_send(0x2A);                        /*print a asterix before the filetype to indicate that the file has not been closed (yet)*/

            switch (0x07 & dir_entry.filetype) {      /*the type of file is stored in the first byte (MSB is file open/closed, 3 lowest bits are of interest here ...*/
                case 0: {
                    IEC_send(0x44);                    /*file type = DELeted */
                    IEC_send(0x45);
                    IEC_send(0x4C);
                    break;
                }

                case 1: {
                    IEC_send(0x53);                    /*file type = SEQuential */
                    IEC_send(0x45);
                    IEC_send(0x51);
                    break;
                }

                case 2: {
                    IEC_send(0x50);                    /*file type = PRoGram */
                    IEC_send(0x52);
                    IEC_send(0x47);
                    break;
                }

                case 3: {
                    IEC_send(0x55);                    /*file type = USeR */
                    IEC_send(0x53);
                    IEC_send(0x52);
                    break;
                }


                case 4: {
                    IEC_send(0x52);                    /*file type = RELative */
                    IEC_send(0x45);
                    IEC_send(0x4C);
                    break;
                }

                default: {
                    IEC_send(0x55);                    /*file type = UNKnown (is only shown if someone uses these values out of spec...*/
                    IEC_send(0x4E);
                    IEC_send(0x4B);
                    break;
                }
            }

            if (dir_entry.filetype > 191)
                IEC_send(0x3C);                        /*print a "<" to indicate a locked file*/
            else
                IEC_send(0x20);

            IEC_send(0x20);
            IEC_send(0x20);
            IEC_send(0x20);
            IEC_send(0x00);
        }
    }

    /*Blocks free "directory-line"*/
    /*----------------------------*/
    IEC_send(0x01);
    IEC_send(0x01);
    blocksfree = D64LoadFreeBlocks();        /*read the number of free blocks from the D64 file*/
    IEC_send(blocksfree%256);                /*low-byte of free blocks value*/
    IEC_send(blocksfree/256);                /*high-byte of free blocks value*/
    IEC_send_string("BLOCKS FREE.               ");    /*"Blocks free."*/
    IEC_send(0x00);
    IEC_send(0x00);
    EOI = TRUE;                                /*indicate the last byte*/
    IEC_send(0x00);
    IEC_undoturnaround();                    /*were done talking towards the bus*/
    SetErrorCode(0, LED_OFF);                /*all is OK*/
}

void T64Directory(void) {
    unsigned char lp, mode, extra_spaces, track, sector, unused;
    unsigned int blocksize, blocksfree, read_blocks;

    SetErrorCode(0,LED_ON);         /*unless we fail we will exit with no error*/
    EOI = FALSE;
    IEC_turnaround();                /*we now SEND data to the bus so... make our device a talker*/

    /*some bytes required for sending a directory entry to a VIC20, C64, C128, etc.*/
    IEC_send(0x01);                    /*load this "program" to start address 0x0401*/
    IEC_send(0x04);

    /*Directory header*/
    /*----------------*/
    D64BlockRead(18,0);
    read_blocks = 1;
    print_D64_TSB(18,0,read_blocks, 0);
    IEC_send(0x01);                    /*...*/
    IEC_send(0x01);                    /*...*/
    IEC_send(0);        /*drive-number of this device, in the beginning of this project used as file pointer/indicator*/
    IEC_send(0);        /*drive-number of this device, in the beginning of this project uses as file pointer/indicator*/
    IEC_send(0x12);                    /*RVS-ON (invert characters)*/
    IEC_send(0x22);                    /*"-sign*/
    for (lp=144; lp<160; lp++) {
        IEC_send(RAM_buffer[lp]);    /*send the Diskname*/
    }

    IEC_send(0x22);                    /*"-sign*/
    IEC_send(0x20);                    /*space*/
    IEC_send(RAM_buffer[162]);        /*send the disk-ID byte-0*/
    IEC_send(RAM_buffer[163]);        /*send the disk-ID byte-1*/
    IEC_send(0x20);                    /*space*/
    IEC_send(RAM_buffer[165]);        /*send the DOS-version and format-type byte-0*/
    IEC_send(RAM_buffer[166]);        /*send the DOS-version and format-type byte-1*/
    IEC_send(0x00);                    /*a byte indicating the end of this "directory-line"*/

    /*Directory entry ...*/
    /*-------------------*/
    mode=0;    /*set sector read to first entry*/
    while (D64SeekDirEntry(mode, &track, &sector, &unused)) {     /*get directory entry and request the current track and sector*/
        mode=1;    /*set sector read to next entry*/
        print_D64_TSB(track,sector,read_blocks,0);
        if (dir_entry.filetype != 0x00) {               /*scratched files are NOT displayed in the directory*/
            IEC_send(0x01);                                /*bytes indicating the beginning of a "directory-line"*/
            IEC_send(0x01);
            IEC_send(dir_entry.blocksize_low_byte);        /*size of this file low-byte*/
            IEC_send(dir_entry.blocksize_high_byte);    /*size of this file high-byte*/
//    dir_entry.record_size_relfile = 0x00;
            blocksize = ((256 * dir_entry.blocksize_high_byte) + dir_entry.blocksize_low_byte);
            if (blocksize < 10)                            /*add an extra space(s) to adjust line length*/
                IEC_send(0x20);                            /*                                           */
            if (blocksize < 100)                        /*                                           */
                IEC_send(0x20);                            /*                                           */
            if (blocksize < 1000)                        /*                                           */
                IEC_send(0x20);                            /*                                           */
            IEC_send(0x22);                                /*"-sign*/

            extra_spaces = 0;
            for (lp=0; lp<16; lp++) {
                if (dir_entry.filename[lp]== 160)
                    extra_spaces++;
                else
                    IEC_send(dir_entry.filename[lp]);        /*filename of this entrynumber*/

            }

            IEC_send(0x22);                            /*"-sign*/
            while (extra_spaces != 0) {
                IEC_send(0x20);                        /*add some extra spaces for proper allignment*/
                extra_spaces--;
            }

            /*filetype*/
            /*--------*/
            if (dir_entry.filetype > 127)            /*when MSB has been set the file has been properly closed*/
                IEC_send(0x20);                        /*print a space before the filetype*/
            else
                IEC_send(0x2A);                        /*print a asterix before the filetype to indicate that the file has not been closed (yet)*/

            switch (0x07 & dir_entry.filetype) {      /*the type of file is stored in the first byte (MSB is file open/closed, 3 lowest bits are of interest here ...*/
                case 0: {
                    IEC_send(0x44);                    /*file type = DELeted */
                    IEC_send(0x45);
                    IEC_send(0x4C);
                    break;
                }

                case 1: {
                    IEC_send(0x53);                    /*file type = SEQuential */
                    IEC_send(0x45);
                    IEC_send(0x51);
                    break;
                }

                case 2: {
                    IEC_send(0x50);                    /*file type = PRoGram */
                    IEC_send(0x52);
                    IEC_send(0x47);
                    break;
                }

                case 3: {
                    IEC_send(0x55);                    /*file type = USeR */
                    IEC_send(0x53);
                    IEC_send(0x52);
                    break;
                }


                case 4: {
                    IEC_send(0x52);                    /*file type = RELative */
                    IEC_send(0x45);
                    IEC_send(0x4C);
                    break;
                }

                default: {
                    IEC_send(0x55);                    /*file type = UNKnown (is only shown if someone uses these values out of spec...*/
                    IEC_send(0x4E);
                    IEC_send(0x4B);
                    break;
                }
            }

            if (dir_entry.filetype > 191)
                IEC_send(0x3C);                        /*print a "<" to indicate a locked file*/
            else
                IEC_send(0x20);

            IEC_send(0x20);
            IEC_send(0x20);
            IEC_send(0x20);
            IEC_send(0x00);
        }
    }

    /*Blocks free "directory-line"*/
    /*----------------------------*/
    IEC_send(0x01);
    IEC_send(0x01);
    blocksfree = D64LoadFreeBlocks();        /*read the number of free blocks from the D64 file*/
    IEC_send(blocksfree%256);                /*low-byte of free blocks value*/
    IEC_send(blocksfree/256);                /*high-byte of free blocks value*/
    IEC_send_string("BLOCKS FREE.               ");    /*"Blocks free."*/
    IEC_send(0x00);
    IEC_send(0x00);
    EOI = TRUE;                                /*indicate the last byte*/
    IEC_send(0x00);
    IEC_undoturnaround();                    /*were done talking towards the bus*/
    SetErrorCode(0, LED_OFF);                /*all is OK*/
}


/*this routine will search for a file ON THE CARD that matches the given filename search pattern*/
/*the return value (if file is found) will be the index-number of the file as stored on the card*/
unsigned int SeekFileOnCard(unsigned char *filename, struct file2TYPE *file) {
    signed char lp;
    unsigned int index;

    index = 0;                    /*reset the index counter, as we do whish to know what the index of this file (within this (sub)directory) is*/
    if (!FileSearch(file, 0))    /*search for the first file on the card. Attention: screws up secbuf!!*/
        return(FALSE);
    while (1) {
        index++;
        lp = -1;        /*reset loopcounter*/
        if (FileFilter() != FALSE) {                      /*files that are not recognized by the filefilter will be excluded from the search. Simply because these files are not shown to user when he/she requests the cards directory*/
            if (file->name_lfn[0] == 0)                   /*check if this entry has an 8.3-name or LFN-name*/
            {        /*this file has no LFN name so we must use the 8.3 information for further searching*/
                do {  /*----------------------------------------------------------------------------------*/
                    lp++;
                    //    OutputToRS232();                                                    /*set standard output to RS232*/
                    //    printf("\r\n8.3:lp=%02X, %c, %c",lp, file->name[lp], filename[lp]);    /*for debug purposes only !!!*/
                    //    OutputToLCD();                                                        /*set standard output to LCD*/

                    if ((filename[lp] == 0) && (lp==8))   /*when we've succesfully matched all 8 chars of the 8.3 name... we have a match*/
                        return(index);                    /*all the remaining characters of the current file are spaces, we have a match!!!*/

                    if (filename[lp] == 0)               /*when we have reached end of the searched filename but the current file has more characters then check if all further characters of file are spaces*/
                        while (lp<8) {
                            if (file->name[lp] != ' ')
                                break;
                            if (lp==7)
                                return(index);                /*all the remaining characters of the current file are spaces, we have a match!!!*/
                            lp++;
                        }

                    if (filename[lp] == 0)                /*when the search string has not been ended but the searched filename has... no match*/
                        break;                            /*we have no match*/

                    /*wildcard filter*/
                    if (filename[lp] == '?')            /*when we encounter an '?', it does not matter what the real char of the filename is*/
                        file->name[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] == '*')            /*when we have come so far and detected a * in our search string... we may consider this a match*/
                        return(index);                        /*we have a partial or possible 100% match... but good enough to return with TRUE*/
                } while (file->name[lp] == filename[lp]);  /*do the compare of current char of both strings*/
            } else   /*this file has an LFN entry, use this for searching*/
            {        /*--------------------------------------------------*/
                do {
                    lp++;
                    //    OutputToRS232();                                                        /*set standard output to RS232*/
                    //    printf("\r\nLFN:lp=%02X, %c, %c",lp, file->name_lfn[lp], filename[lp]);    /*for debug purposes only !!!*/
                    //    OutputToLCD();                                                            /*set standard output to LCD*/

                    if ((filename[lp] == 0) && (file->name_lfn[lp]== '.'))   /*when we have reached the extension if the file, we may consider this a match*/
                        return(index);                            /*we have a match and we may asume that the extension is correct as well because the filefilter has allready checked this as a OK file, so how big is the chance that there are a .PRG and a .D64 with identical names ?!?!*/

                    if ((filename[lp] == 0) && (file->name_lfn[lp]== 0))   /*when we have reached the end of both strings, this is the perfect match*/
                        return(index);                            /*we have a match and we may asume that the extension is correct as well because the filefilter has allready checked this as a OK file, so how big is the chance that there are a .PRG and a .D64 with identical names ?!?!*/

                    if (filename[lp] == 0)                    /*when the search string has not been ended but the searched filename has... no match*/
                        break;                                /*we have no match*/

                    /*wildcard filter*/
                    if (filename[lp] == '?')                /*when we encounter an '?', it does not matter what the real char of the filename is*/
                        file->name_lfn[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] == '*')                /*when we have come so far and detected a * in our search string... we may consider this a match*/
                        return(index);                            /*we have a partial or possible 100% match... but good enough to return with TRUE*/
                } while (file->name_lfn[lp] == filename[lp]);  /*do the compare of current char of both strings*/
            }
        }
        if (!FileSearch(file, 1))                    /*search for the next file on the card. Attention: screws up secbuf!!*/
            break;
    }
    return(FALSE);
}

/*this routine will load the file indicated by the given struct*/
void LoadFileFromCard(struct file2TYPE *file) {
    unsigned char    bytecount;
    unsigned int    lp, blocksrem, filesizeinblocks;
    unsigned long    remainingbytecounter;

    SetErrorCode(0,LED_ON);                    /*unless we fail we will exit with no error*/
    EOI = FALSE;
    IEC_turnaround();                        /*we now SEND data to the bus so... make our device a talker*/
    remainingbytecounter = file->size;
    lp = 0;
    bytecount = 0;

    /*calculate the blocksize of this file*/
    blocksrem = remainingbytecounter / 254;
    filesizeinblocks = blocksrem;
    if ((remainingbytecounter % 254) > 0)
        blocksrem++;
    blocksrem--;                    /*decrement by one, otherwise the countdown will stop at 1, and it must (offcourse) stop at 0*/

    FileReadSector(file);            /*read the first sector from the card (this is NOT a D64 sector) and contains MORE then 256 bytes*/
    while (remainingbytecounter != 0) {
        if (bytecount == 0)
            SetErrorCode(0,LED_ON);            /*turn LED on, to create a small blink at every block*/
        if (bytecount == Blink_block)
            SetErrorCode(0,LED_OFF);        /*turn LED off, to create a small blink at every block*/

        if (remainingbytecounter == 1) {      /*check for last byte*/
            EOI = TRUE;                        /*indicate the last byte*/
        }

        IEC_send(block_buffer[lp]);
        remainingbytecounter--;
        bytecount++;
        lp++;

        if (lp == 512) {
            FileNextSector(file);        /*we must set file pointer to the next sector before we can read the next sector*/
            FileReadSector(file);        /*its time to read another sector*/
            lp = 0;
        }

        if (bytecount == 254) {
            blocksrem--;                                        /*another block has been send... update counter*/
            print_D64_TSB(0, 0, blocksrem, filesizeinblocks);    /*print track, sector and remaining blocks*/
            bytecount = 0;
        }
    }

    IEC_undoturnaround();            /*were done talking towards the bus*/
    SetErrorCode(0, LED_OFF);        /*all is OK, set the LED blinking mode to 'RITHM' to indicate that we have done somthing on a higher level then something within a D64-file*/
}

void LoadD64File(unsigned char trk, unsigned char sec, unsigned int filesizeinblocks) {
    unsigned char lp;
    unsigned int blocksrem;
    unsigned char lasttrack, lastsector;

    blocksrem = filesizeinblocks;
    EOI = FALSE;
    IEC_turnaround();                        /*we now SEND data to the bus so... make our device a talker*/

    while (1) {
        SetErrorCode(0,LED_ON);                                    /*unless we fail we will exit with no error*/
        print_D64_TSB(trk, sec, blocksrem, filesizeinblocks);    /*print track, sector and remaining blocks*/
        lasttrack = trk;                                        /*keep extra buffer to remember what the last track was*/
        lastsector = sec;                                        /*keep extra buffer to remember what the last sector was*/
        D64LoadFile_X_Bytes(&file,trk,sec,0,256);                /*location of block to load and its size in bytes*/
        trk = block_buffer[0];                                    /*track position of the next block*/
        sec = block_buffer[1];                                    /*sector position of the next block*/
        blocksrem--;                                            /*decrement remaining blocks counter*/

        if (trk != 0) {                                          /*check on last block*/
            for (lp=2; lp!=0; lp++) {
                IEC_send(block_buffer[lp]);                    /*transmit the 254 bytes within this block to the listener*/
                if (lp == Blink_block)
                    SetErrorCode(0,LED_OFF);                /*turn LED off, to create a small blink at every block*/
            }
        } else {                                                 /*transmission of data of the last block*/
            print_D64_TSB(lasttrack, lastsector, blocksrem, filesizeinblocks);        /*print track, sector of the last block*/
            for (lp=2; lp<(sec); lp++)                         /*transfer the remainder of the loaded last block*/
                IEC_send(block_buffer[lp]);
            break;
        }
    }
    EOI = TRUE;                                /*indicate the last byte*/
    IEC_send(block_buffer[sec]);                /*the position of the last byte is indicated by the value in register 'Sector'*/
    IEC_undoturnaround();                    /*were done talking towards the bus*/
    SetErrorCode(0,LED_OFF);                /*all is OK*/
}

/*Save the file to the D64, this requires the complete DOS handling !!!, since the CBM does not send*/
/*the filesize, the exact filesize is only known when the file has allready been written. This is too*/
/*late to update the progressbar on the LCD, so that's why this bar does not behave as expected*/
unsigned char SaveD64File(void) {
    unsigned char lp, fbpt, firsttrack, firstsector, bytecounter;
    unsigned char track, sector, nexttrack, nextsector;
    unsigned int blocksize;

    blocksize = 0;

    /*search for the first block location of the file to be saved*/
    if (!D64SeekFreeBlock(&track, &sector)) {
        SetErrorCode(72,LED_ERROR);                            /*error: disk or directory full*/
        return(FALSE);
    }

    firsttrack = track;
    firstsector = sector;
    nexttrack = track;                                        /*update the track variable*/
    nextsector = sector;                                    /*update the track variable*/
    EOI = 0;
    while (EOI == 0) {
        blocksize++;                                        /*increment blocksize counter*/
        track = nexttrack;                                    /*update the track variable*/
        sector = nextsector;                                /*update the track variable*/
        if (!D64BlockAllocate(track, sector)) {              /*claim the next block, update the BAM*/
            SetErrorCode(71,LED_ERROR);                        /*error: BAM is corrupt a flag has allready been cleared*/
            return(FALSE);                                    /*somebody or somthing has been messing with the BAM*/
        }
        fbpt = D64ReadFreeBlocksPerTrack(track) - 1;        /*decrement counter*/
        D64WriteFreeBlocksPerTrack(track, fbpt);             /*save new value to BAM*/
        if (!D64SeekFreeBlock(&nexttrack, &nextsector)) {      /*search for the next block location of the file to be saved*/
            SetErrorCode(72,LED_ERROR);                        /*error: disk or directory full*/
            return(FALSE);
        }
        /*the first two bytes of each block consist the 'track' and 'sector' of the next block*/
        RAM_buffer[0] =    nexttrack;                            /*track of next block*/
        RAM_buffer[1] = nextsector;                            /*sector of next block*/

        /*collect enough bytes to fill a block*/
        bytecounter = 2;                                    /*byte counter to keep track of the position of the last byte within the file, since the first 2 bytes of the block are allways filled with non-data, we must add an offset of 2*/
        for (lp=2; lp!=0; lp++) {
            SetErrorCode(0,LED_ON);                            /*unless we fail we will exit with no error*/
            RAM_buffer[lp] = IEC_receive(TRUE);                /*receive a byte and acknowledge with a frame handshake*/
            bytecounter++;
// OutputToRS232();                    /*set standard output to RS232*/
// printf(",%02x", RAM_buffer[lp]);    /*dump all received bytes to serial port*/
// OutputToLCD();                        /*set standard output to LCD*/
            if (EOI == 1) {
                RAM_buffer[0] =    0;                            /*there is no next block so the track value is an impossible one*/
                RAM_buffer[1] = bytecounter;                /*there is no next block so the sector value is the position of the last byte*/
                do {
                    RAM_buffer[bytecounter] = 0x00;            /*fill the remaining area with 0x00*/
                    bytecounter++;
                } while (bytecounter!=0);
                break;
            }

            if (lp == Blink_block)
                SetErrorCode(0,LED_OFF);                    /*turn LED off, to create a small blink at every block*/
        }

        print_D64_TSB(track, sector, 0,blocksize);            /*print track, sector, remaining blocks and total number of blocks*/
        D64BlockWrite(track, sector);                        /*write the block to D64*/
    }

    /*write the filename to the directory*/
    if (!D64AddDirEntry(0x82,firsttrack,firstsector,command_string,blocksize,0,0,0,0,0)) {
        SetErrorCode(72,LED_ERROR);                            /*error: disk or directory full*/
        print_D64_TSB(track, sector, blocksize, blocksize);    /*print track, sector and remaining blocks and a fully filled bar*/
        return(FALSE);
    }

    SetErrorCode(0,LED_OFF);                                /*all is OK*/
    print_D64_TSB(track, sector, 0, blocksize);                /*print track, sector, remaining blocks creating a fully filled bar*/
    return(TRUE);
}

/*Copy a file within the D64, this requires the complete DOS handling !!!*/
/*the filename is stored in command_string*/
unsigned char CopyD64File(unsigned char trk, unsigned char sec, unsigned int filesizeinblocks) {
    unsigned int blocksrem;
    unsigned char fbpt, track, sector, nexttrack, nextsector;

    blocksrem = filesizeinblocks;
    SetErrorCode(0,LED_ON);                    /*unless we fail we will exit with no error*/

    /*search for the first block location of the new file to be saved*/
    if (!D64SeekFreeBlock(&track, &sector)) {
        SetErrorCode(72,LED_ERROR);                            /*error: disk or directory full*/
        return(FALSE);
    }

    /*check if there is enough room free on the disk for the required copy*/
    if (filesizeinblocks > D64LoadFreeBlocks()) {      /*read the number of free blocks from the D64 file*/
        SetErrorCode(72,LED_ERROR);                            /*error: disk or directory full*/
        return(FALSE);
    }

    /*write the filename to the directory, we can do that since we know the size of the file (ehhh. that's if it is written correctly*/
    /*but we may asume that this is the case for normal disk use. This saves us a lot of checkking. And creates a more readable code */
    D64AddDirEntry(0x82,track,sector,filename_string,filesizeinblocks,0,0,0,0,0);

    while (blocksrem--) {
        if (!D64BlockAllocate(track, sector)) {              /*claim the next block, update the BAM*/
            SetErrorCode(71,LED_ERROR);                        /*error: BAM is corrupt a flag has allready been cleared*/
            return(FALSE);                                    /*somebody or somthing has been messing with the BAM*/
        }
        fbpt = D64ReadFreeBlocksPerTrack(track) - 1;        /*decrement counter*/
        D64WriteFreeBlocksPerTrack(track, fbpt);             /*save new value to BAM*/

        /*search for the first block location of the new file to be saved*/
        if (!D64SeekFreeBlock(&nexttrack, &nextsector)) {
            SetErrorCode(72,LED_ERROR);                            /*error: disk or directory full*/
            return(FALSE);
        }
        print_D64_TSB(trk, sec, blocksrem, filesizeinblocks);    /*print track, sector and remaining blocks*/
        D64BlockRead(trk,sec);                                    /*this routine reads a block of a req. track-sector of a D64 into the RAM_buffer*/
        trk = RAM_buffer[0];                                    /*the next track to be read*/
        sec = RAM_buffer[1];                                    /*the next sector within that track*/
        RAM_buffer[0] =    nexttrack;                                /*track of next block*/
        RAM_buffer[1] = nextsector;                                /*sector of next block*/
        D64BlockWrite(track, sector);                            /*this routine write the contents of the RAM_buffer to the req. track-sector of the D64 file*/

        track = nexttrack;                                        /*for the next block, set the correct next track and sector*/
        sector = nextsector;
    }

    /*write last block of the file*/
    print_D64_TSB(trk, sec, blocksrem, filesizeinblocks);        /*print track, sector and remaining blocks*/
    D64BlockRead(trk,sec);                                        /*this routine reads a block of a req. track-sector of a D64 into the RAM_buffer*/
    D64BlockWrite(track, sector);                                /*this routine write the contents of the RAM_buffer to the req. track-sector of the D64 file*/
    SetErrorCode(0,LED_OFF);                                    /*all is OK*/
    return(TRUE);
}


/*this routine clears the entire block_buffer*/
void Clear_block_buffer(void) {
    unsigned int lp;

    lp=0;
    do {
        block_buffer[lp] = 0x00;
        lp++;
    } while (lp<512);
}

/*this routine formats the currently selected D64 image so it can be used to save your programs/data to*/
/*the abillity not being able to create a new file saves us the effort of implementing a lot of FAT related actions*/
/*Attention: this command does not implement the user options (disk label,disk ID). This command is for firmware & media testing purposes only*/
void FormatD64File(unsigned char *diskname, unsigned char *diskid) {   /* '*filename' is actually the complete command_string as given by the user, this referencename is misleading and needs to be changed*/

    unsigned int block_counter=0;
    unsigned char lp,lp2,tr,se;

    SetErrorCode(0,LED_ON);         /*unless we fail we will exit with no error*/
    print_D64_TSB(0,0,(341-block_counter),341);

    /*fill track 1 upto and including track 17 (all 21) sectors with 0x00*/
    /*each MMC/SD-card block = 512 bytes, each D64 block = 256 bytes     */
    /*17 tracks * 21 sectors = 357 D64 blocks or 178.5 MMC/SD-card blocks*/
    Clear_block_buffer();                            /*clear the block_buffer*/
    do {
        D64ConvertBlockToTrackSector((block_counter<<1), &tr, &se);
        print_D64_TSB(tr,se,(341-block_counter),341);
        FileWriteSector_X(&file, block_counter);
        block_counter++;
    } while (block_counter < 178);

    block_buffer[256+0] = 18;    /*track of next block*/
    block_buffer[256+1] = 18;    /*sector of next block*/
    block_buffer[256+2] = 65;
    block_buffer[256+3] =  0;
    block_buffer[256+4] = 0x15; /*number of sectors within track-1*/
    block_buffer[256+5] = 0xff;
    block_buffer[256+6] = 0xff;
    block_buffer[256+7] = 0x1f;
    block_buffer[256+8] = 0x15; /*number of sectors within track-2*/
    block_buffer[256+9] = 0xff;
    block_buffer[256+10] = 0xff;
    block_buffer[256+11] = 0x1f;
    block_buffer[256+12] = 0x15; /*number of sectors within track-3*/
    block_buffer[256+13] = 0xff;
    block_buffer[256+14] = 0xff;
    block_buffer[256+15] = 0x1f;
    block_buffer[256+16] = 0x15; /*number of sectors within track-4*/
    block_buffer[256+17] = 0xff;
    block_buffer[256+18] = 0xff;
    block_buffer[256+19] = 0x1f;
    block_buffer[256+20] = 0x15; /*number of sectors within track-5*/
    block_buffer[256+21] = 0xff;
    block_buffer[256+22] = 0xff;
    block_buffer[256+23] = 0x1f;
    block_buffer[256+24] = 0x15; /*number of sectors within track-6*/
    block_buffer[256+25] = 0xff;
    block_buffer[256+26] = 0xff;
    block_buffer[256+27] = 0x1f;
    block_buffer[256+28] = 0x15; /*number of sectors within track-7*/
    block_buffer[256+29] = 0xff;
    block_buffer[256+30] = 0xff;
    block_buffer[256+31] = 0x1f;
    block_buffer[256+32] = 0x15; /*number of sectors within track-8*/
    block_buffer[256+33] = 0xff;
    block_buffer[256+34] = 0xff;
    block_buffer[256+35] = 0x1f;
    block_buffer[256+36] = 0x15; /*number of sectors within track-9*/
    block_buffer[256+37] = 0xff;
    block_buffer[256+38] = 0xff;
    block_buffer[256+39] = 0x1f;
    block_buffer[256+40] = 0x15; /*number of sectors within track-10*/
    block_buffer[256+41] = 0xff;
    block_buffer[256+42] = 0xff;
    block_buffer[256+43] = 0x1f;
    block_buffer[256+44] = 0x15; /*number of sectors within track-11*/
    block_buffer[256+45] = 0xff;
    block_buffer[256+46] = 0xff;
    block_buffer[256+47] = 0x1f;
    block_buffer[256+48] = 0x15; /*number of sectors within track-12*/
    block_buffer[256+49] = 0xff;
    block_buffer[256+50] = 0xff;
    block_buffer[256+51] = 0x1f;
    block_buffer[256+52] = 0x15; /*number of sectors within track-13*/
    block_buffer[256+53] = 0xff;
    block_buffer[256+54] = 0xff;
    block_buffer[256+55] = 0x1f;
    block_buffer[256+56] = 0x15; /*number of sectors within track-14*/
    block_buffer[256+57] = 0xff;
    block_buffer[256+58] = 0xff;
    block_buffer[256+59] = 0x1f;
    block_buffer[256+60] = 0x15; /*number of sectors within track-15*/
    block_buffer[256+61] = 0xff;
    block_buffer[256+62] = 0xff;
    block_buffer[256+63] = 0x1f;
    block_buffer[256+64] = 0x15; /*number of sectors within track-16*/
    block_buffer[256+65] = 0xff;
    block_buffer[256+66] = 0xff;
    block_buffer[256+67] = 0x1f;
    block_buffer[256+68] = 0x15; /*number of sectors within track-17*/
    block_buffer[256+69] = 0xff;
    block_buffer[256+70] = 0xff;
    block_buffer[256+71] = 0x1f;
    block_buffer[256+72] = 0x11; /*number of sectors within track-18*/
    block_buffer[256+73] = 0xfc;
    block_buffer[256+74] = 0xff;
    block_buffer[256+75] = 0x07;
    block_buffer[256+76] = 0x13; /*number of sectors within track-19*/
    block_buffer[256+77] = 0xff;
    block_buffer[256+78] = 0xff;
    block_buffer[256+79] = 0x07;
    block_buffer[256+80] = 0x13; /*number of sectors within track-20*/
    block_buffer[256+81] = 0xff;
    block_buffer[256+82] = 0xff;
    block_buffer[256+83] = 0x07;
    block_buffer[256+84] = 0x13; /*number of sectors within track-21*/
    block_buffer[256+85] = 0xff;
    block_buffer[256+86] = 0xff;
    block_buffer[256+87] = 0x07;
    block_buffer[256+88] = 0x13; /*number of sectors within track-22*/
    block_buffer[256+89] = 0xff;
    block_buffer[256+90] = 0xff;
    block_buffer[256+91] = 0x07;
    block_buffer[256+92] = 0x13; /*number of sectors within track-23*/
    block_buffer[256+93] = 0xff;
    block_buffer[256+94] = 0xff;
    block_buffer[256+95] = 0x07;
    block_buffer[256+96] = 0x13; /*number of sectors within track-24*/
    block_buffer[256+97] = 0xff;
    block_buffer[256+98] = 0xff;
    block_buffer[256+99] = 0x07;
    block_buffer[256+100] = 0x12; /*number of sectors within track-25*/
    block_buffer[256+101] = 0xff;
    block_buffer[256+102] = 0xff;
    block_buffer[256+103] = 0x03;
    block_buffer[256+104] = 0x12; /*number of sectors within track-26*/
    block_buffer[256+105] = 0xff;
    block_buffer[256+106] = 0xff;
    block_buffer[256+107] = 0x03;
    block_buffer[256+108] = 0x12; /*number of sectors within track-27*/
    block_buffer[256+109] = 0xff;
    block_buffer[256+110] = 0xff;
    block_buffer[256+111] = 0x03;
    block_buffer[256+112] = 0x12; /*number of sectors within track-28*/
    block_buffer[256+113] = 0xff;
    block_buffer[256+114] = 0xff;
    block_buffer[256+115] = 0x03;
    block_buffer[256+116] = 0x12; /*number of sectors within track-29*/
    block_buffer[256+117] = 0xff;
    block_buffer[256+118] = 0xff;
    block_buffer[256+119] = 0x03;
    block_buffer[256+120] = 0x12; /*number of sectors within track-30*/
    block_buffer[256+121] = 0xff;
    block_buffer[256+122] = 0xff;
    block_buffer[256+123] = 0x03;
    block_buffer[256+124] = 0x11; /*number of sectors within track-31*/
    block_buffer[256+125] = 0xff;
    block_buffer[256+126] = 0xff;
    block_buffer[256+127] = 0x01;
    block_buffer[256+128] = 0x11; /*number of sectors within track-32*/
    block_buffer[256+129] = 0xff;
    block_buffer[256+130] = 0xff;
    block_buffer[256+131] = 0x01;
    block_buffer[256+132] = 0x11; /*number of sectors within track-33*/
    block_buffer[256+133] = 0xff;
    block_buffer[256+134] = 0xff;
    block_buffer[256+135] = 0x01;
    block_buffer[256+136] = 0x11; /*number of sectors within track-34*/
    block_buffer[256+137] = 0xff;
    block_buffer[256+138] = 0xff;
    block_buffer[256+139] = 0x01;
    block_buffer[256+140] = 0x11; /*number of sectors within track-35*/
    block_buffer[256+141] = 0xff;
    block_buffer[256+142] = 0xff;
    block_buffer[256+143] = 0x01;

    lp2=0;
    lp=144;

    while ((lp<160) && (diskname[lp2] != 0))       /*diskname*/
    {                                            /*--------*/
        block_buffer[256+lp] = diskname[lp2];    /*copy character*/
        lp2++;
        lp++;
    }
    while (lp<160) {
        block_buffer[256+lp] = 160;                /*fill unused locations with shifted spaces, default value*/
        lp++;
    }

    block_buffer[256+160] = 160;
    block_buffer[256+161] = 160;

    if (diskid[0] == 0)                            /*disk-ID*/
    {                                            /*-------*/
        block_buffer[256+162] = '0';            /*default value*/
        block_buffer[256+163] = '0';            /*default value*/
    } else {
        block_buffer[256+162] = diskid[0];        /*copy character*/
        if (diskid[1] == 0) {
            block_buffer[256+163] = 160;        /*default value*/
        } else {
            block_buffer[256+163] = diskid[1];    /*copy character*/
        }
    }

    block_buffer[256+164] = 160;
    block_buffer[256+165] = 50;    /*DOS VERSION*/
    block_buffer[256+166] = 65;    /*DOS VERSION*/
    block_buffer[256+167] = 160;
    block_buffer[256+168] = 160;
    block_buffer[256+169] = 160;
    block_buffer[256+170] = 160;

    lp = 171;
    while (lp != 0) {              /*fill remaining bytes from 171 up to and including 255 with 0x00*/
        block_buffer[256+lp] = 0x00;
        lp++;
    }

    D64ConvertBlockToTrackSector((block_counter<<1), &tr, &se);
    print_D64_TSB(tr,se,(341-block_counter),341);
    FileWriteSector_X(&file, block_counter);
    block_counter++;

    /*fill remaining tracks 18-1 to 35-16 with 0x00                      */
    /*each MMC/SD-card block = 512 bytes, each D64 block = 256 bytes     */
    Clear_block_buffer();                            /*clear the block_buffer*/
    do {
        D64ConvertBlockToTrackSector((block_counter<<1), &tr, &se);
        print_D64_TSB(tr,se,(341-block_counter),341);
        FileWriteSector_X(&file, block_counter);
        block_counter++;
    } while (block_counter < 342);
    SetErrorCode(0,LED_OFF);
}

/*this routine is to be used to handle the errorcode and the LED-blink-mode in an easy way*/
void SetErrorCode(unsigned char error, unsigned char LEDmode) {
    /*the original 1541 used the LED to display the results of the power-on selftest*/
    /* No Blink       Kernal (E000-FFFF) ROM or 6522 VIA Failure */
    /* One Blink      6116 RAM Failure                           */
    /* Two Blinks     Possible Zero Page RAM Failure             */
    /* Three Blinks   DOS (C000-CFFF) ROM Failure                */
    /* Four Blinks    DOS (C000-CFFF) ROM Failure                */
    /* Five Blinks    6116 RAM Failure                           */
    /* Six Blinks     6116 RAM Failure                           */
    /* Seven Blinks   6116 RAM Failure                           */
    /* Eight Blinks   6116 RAM Failure                           */
    /*Note: at this moment the selftest (and it's blinking modes) is/are not supported (yet)*/

    if ((error == 0) && (error_code == 73)) {  /*when there is no error-73 to maintain (ROM version), change to the new error_code*/
        /*do not change the error_code, because there is no error and the code 73 must be preserved*/
    } else {
        if (error != error_code)            /*only update the screen when the error_code has changed*/
        {                                    /*because when there is no new info... there is no reason to print to the display what is allready there*/
            error_code = error;
            //        Lcd_XY_address(2,4);            /*if there is any printing to the display to be done, it must be done on line...*/
            printf("%02d",error_code);        /*show the error code*/
        }

        //    if ((error == 21) || (error == 62)) /*these error(s) create this sound (i.e. error 62 = file not found)*/
        //        PlaySample_HeadBangRattle();    /*play sample that suits this error situation*/
    }

    switch (LEDmode) {
        case LED_OFF: {
            //          TMR0ON = 0;                    /*switch timer-0 OFF*/
            LED_GREEN = 0;                /*switch LED-OFF*/
            LED_RED = 0;                /*switch LED-OFF*/
            break;
        }

        case LED_ON: {
//            TMR0ON = 0;                    /*switch timer-0 OFF*/
            LED_GREEN = 1;                /*switch LED-ON*/
            LED_RED = 0;                /*switch LED-ON*/
            break;
        }


        case LED_ERROR: {
            Blink_mode = LED_ERROR;
            LED_status = 0;                /*status of the LED (0=OFF)*/
            //          TMR0H = 0xFF;                /*set registers to enter timer-o interrupt as quickly as possible*/
            //          TMR0L = 0xFF;
            //          TMR0ON = 1;                    /*switch timer-0 on*/
            break;
        }

        default: {
            //         TMR0ON = 0;                    /*switch timer-0 OFF*/
            LED_GREEN = 0;                /*switch LED-OFF*/
            LED_RED = 0;                /*switch LED-OFF*/
        }
    }
}

void SendErrorMessage(void) {
    EOI = FALSE;
    LED_GREEN = 1;                            /*drive LED-ON*/
    IEC_turnaround();                        /*we now SEND data to the bus so... make our device a talker*/
    IEC_send_number_as_ASCII(error_code);    /*send error-code*/
    IEC_send(0x2C);                            /*','*/

    switch (error_code) {
        case 0: {      /*OK (not an error*/
            IEC_send_string("OK");
            break;
        }

        case 1: {      /*files scratched (not an error)*/
            IEC_send_string("FILES SCRATCHED");
            break;
        }

        case 2:;    /*Unused error message (should be ingnored)*/
        case 3:;    /*Unused error message (should be ingnored)*/
        case 4:;    /*Unused error message (should be ingnored)*/
        case 5:;    /*Unused error message (should be ingnored)*/
        case 6:;    /*Unused error message (should be ingnored)*/
        case 7:;    /*Unused error message (should be ingnored)*/
        case 8:;    /*Unused error message (should be ingnored)*/
        case 9:;    /*Unused error message (should be ingnored)*/
        case 10:;    /*Unused error message (should be ingnored)*/
        case 11:;    /*Unused error message (should be ingnored)*/
        case 12:;    /*Unused error message (should be ingnored)*/
        case 13:;    /*Unused error message (should be ingnored)*/
        case 14:;    /*Unused error message (should be ingnored)*/
        case 15:;    /*Unused error message (should be ingnored)*/
        case 16:;    /*Unused error message (should be ingnored)*/
        case 17:;    /*Unused error message (should be ingnored)*/
        case 18:;    /*Unused error message (should be ingnored)*/
        case 19: {  /*Unused error message (should be ingnored)*/
            IEC_send_string("N/A");
            break;
        }

        case 20:;    /*Header descriptor byte not found ($08) Each sector is preceeded by an 8-byte header block, which starts with the value $08. If this value is not $08, this error is generated*/
        case 21:;    /*Each sector data block and header block are preceeded by SYNC marks. If *no* sync sequence is found, then the  whole track is unreadable, and likely unformatted.*/
        case 22:;    /*Data descriptor byte not found ($07)        Each sector data block is preceeded by the value $07, the[]= "data block" descriptor. If this value is not there, this error is generated. Each encoded sector has actually 260 bytes. First is the descriptor byte, then follows the 256 bytes of data, a checksum, and two[]= "off" bytes.*/
        case 23:;      /*Checksum error in data block                The checksum of the data read of the disk is calculated, and compared against the one stored at the end of the sector. If there's a discrepancy, this error is generated.*/
        case 24:;    /*Write verify (on format)                    */
        case 27: {  /*Checksum error in header block            The 8-byte header block contains a checksum  value, calculated by XOR'ing the TRACK,  SECTOR, ID1 and ID2 values. If this checksum is wrong, this error is generated.*/
            IEC_send_string("READ ERROR");
            break;
        }

        case 25:;     /*Write verify error                        Once the GCR-encoded sector is written out, the drive waits for the sector to come around again and verifies the whole 325-byte GCR block. Any errors encountered will generate this error.*/
        case 28: {  /*Write error                                In actual fact, this error never occurs, but it is included for completeness.*/
            IEC_send_string("WRITE ERROR");
            break;
        }

        case 26: {  /*Write protect on                            Self explanatory. Remove the write-protect tab, and try again.*/
            IEC_send_string("WRITE PROTECT ON");
            break;
        }

        case 29: {  /*Disk sector ID mismatch                    The ID's from the header block of the currently read sector are compared against the ones from the header of 18/0. If there is a mismatch, this error is generated.*/
            IEC_send_string("DISK ID MISMATCH");
            break;
        }

        case 30:;    /*general syntax error*/
        case 31:;    /*invalid command*/
        case 32:;    /*long line*/
        case 33:;    /*invalid fileSelectedFileName*/
        case 34:;    /*no file given*/
        case 39: {  /*command file not found*/
            IEC_send_string("SYNTAX ERROR");
            break;
        }

        case 50: {  /*record not present*/
            IEC_send_string("RECORD NOT PRESENT");
            break;
        }

        case 51: {  /*overflow in record*/
            IEC_send_string("OVERFLOW IN RECORD");
            break;
        }

        case 52: {  /*file too large*/
            IEC_send_string("FILE TOO LARGE");
            break;
        }

        case 60: {  /*File open for write*/
            IEC_send_string("WRITE FILE OPEN");
            break;
        }

        case 61: {  /*File not open*/
            IEC_send_string("FILE NOT OPEN");
            break;
        }

        case 62: {  /*File not found*/
            IEC_send_string("FILE NOT FOUND");
            break;
        }

        case 63: {  /*File exists*/
            IEC_send_string("FILE EXISTS");
            break;
        }

        case 64: {  /*File type mismatch*/
            IEC_send_string("FILE TYPE MISMATCH");
            break;
        }

        case 65: {  /*No block*/
            IEC_send_string("NO BLOCK");
            break;
        }

        case 66: {  /*Illegal track or sector*/
            IEC_send_string("ILLEGAL TRACK AND SECTOR");
            break;
        }

        case 67: {  /*Illegal system track or sector*/
            IEC_send_string("ILLEGAL SYSTEM T OR S");
            break;
        }

        case 70: {  /*No channels available*/
            IEC_send_string("NO CHANNEL");
            break;
        }

        case 71: {  /*Directory error*/
            IEC_send_string("DIRECTORY ERROR");
            break;
        }

        case 72: {  /*disk full or directory full*/
            IEC_send_string("DISK FULL");
            break;
        }

        case 73: {  /*DOS mismatch / Powerup message/write attempt with DOS mismatch*/
            IEC_send_string("V");
            IEC_send_number_as_ASCII(RELEASE_VERSION);
            IEC_send('-');
            IEC_send_number_as_ASCII(RELEASE_VERSION_SUB);
            IEC_send('-');
            IEC_send_number_as_ASCII(RELEASE_VERSION_SUB_SUB);
            break;
        }

        case 74: {  /*no disk in drive or no device 1 (8050 only)*/
            IEC_send_string("DRIVE NOT READY");
            break;
        }

        default: {
            IEC_send_string("ERROR UNKNOWN");
            break;
        }
    }

    DelayBigMs(50);                                    /*some small delay to give the computer time to process the string*/
    IEC_send(0x2C);                                    /*','*/
    if (error_code == 1)                            /*check for the FILES SCRATCHED-error*/
        IEC_send_number_as_ASCII(files_scratched);    /*last accessed track variable is replaced by the number of scratched files*/
    else
        IEC_send_number_as_ASCII(LastTrack);        /*last accessed track variable*/
    IEC_send(0x2C);                                    /*','*/
    IEC_send_number_as_ASCII(LastSector);            /*last accessed sector variable*/
    EOI = TRUE;                                        /*indicate the last byte*/
    IEC_send(0x0D);                                    /*CARRIAGE RETURN*/
    IEC_undoturnaround();                            /*were done talking towards the bus*/
    SetErrorCode(0,LED_OFF);                        /*error-code is 0, LED is OFF*/
}
/*****************************************************************************************************************/
/*****************************************************************************************************************/
/*****************************************************************************************************************/

unsigned char ReadDeviceJumper(void) {
    if (JUMPER_J2 == 0)                    /*check the device number jumper to see what the req. device number should be*/
        return(8);
    else
        return(9);
}

/*read the buttons using the ADC, the multiplexed buttons require only one IO-pin. The only thing is... only one button can be pressed/detected at the same time*/
unsigned char ReadButtons(void) {

    return(FALSE);                            /*the 1541-III DTV, does NOT support the use of buttons*/

}


/*
There's no shame in writing comments in your sourcecode.
*/