* -*- outline -*- zfst 0.2 - (c) 1995,1997 Russell Marks A terminal emulator and XMODEM file transfer program for the Spectrum +3. * License This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. [The GNU GPL is in the file `COPYING'.] I specifically exempt the `zfst.tap' included here from the terms of the GPL, as I realise sticking the source in a TAP is unlikely to be useful. ;-) You may freely distribute the `zfst.tap' included here, in any manner you wish, as long as it remains unmodified. * About zfst zfst is a free terminal emulator and XMODEM file transfer program for the +3. It currently provides: - 64x24, 80x24 and 85x24 modes - a reasonably capable (though non-standard) terminal driver - simple XMODEM file send and receive I wrote zfst so that I could use my +3 as a fairly usable terminal for my Linux box. As such, there was no point in emulating an existing terminal; I could just write a termcap entry for zfst and forget about it. This manual is primarily aimed at those using zfst in this way, though the XMODEM transfer functions may be useful to those wishing to simply move files to/from other machines. zfst should in theory work on +2A's as well as +3's, though I can't test this. * Getting zfst to your +3 One problem with file transfer programs is getting them to your machine. After all, you wouldn't need them if you already had a file transfer program. :-) If you have some way of getting TAP files across, you can use zfst.tap and ignore the rest of this section. Failing that, what I've done is write a really minimal XMODEM receive program, which you unfortunately have to type in as a hex dump. In addition to this, you first have to type in a (fairly) short BASIC program which interprets the hex dump (and runs the resulting machine code). Here is the BASIC listing: 10 CLEAR 29999 20 POKE 23658,8 30 LET a=3e4 40 LET b=a: PRINT a;":"; 50 INPUT "hex> "; LINE a$ 60 IF a$="." THEN GO TO 170 70 IF a$="Q" THEN STOP 80 LET d=0 90 IF LEN a$/2<>INT (LEN a$/2) THEN PRINT '"odd no of hex chars": BEEP .3,-20: GO TO 30 100 LET v=16*(CODE a$-48-7*(a$(1)>"9"))+CODE a$(2)-48-7*(a$(2)>"9") 110 LET d=d+v: POKE a,v: LET a=a+1 120 PRINT a$( TO 2);: LET a$=a$(3 TO ): IF a$<>"" THEN GO TO 100 130 INPUT "chksum> ";c 140 IF c<>d THEN PRINT '"error - checksums don't match": BEEP .3,-20: LET a=b: GO TO 40 150 PRINT "=";c: BEEP .1,5 160 GO TO 40 170 CLS : PRINT "saving that just in case..." 180 SAVE "getzfst.bin"CODE 3e4,a-3e4 190 PRINT "now start the xmodem send" 200 LET l=USR 3e4 210 IF l=0 THEN PRINT '"error, trying again": GO TO 200 220 PRINT '"ok, saving zfst.bin..." 230 SAVE "zfst.bin"CODE 32768,l 240 PRINT "done" Once you've typed this in, run it (saving it first is probably a good idea), and type in the hex as listed in the file `noddyget.hex'. You should type in the hex WITHOUT THE SPACES; these are included in the file for the sake of readability. After entering each line of hex, you should type in the number to the right of the `=' - this is the checksum for the hex on that line. If an error is reported, you should type the line (and checksum) again. You might recognise this hex dump format as the one used by "Your Sinclair" in their Program Pitstop section (back when YS was still going). Note that although the checksum should catch some errors, you should still be careful when typing in the hex. In particular, be *very* careful not to miss out or repeat lines of hex - if you do this, no error will be reported! When you have typed in all the hex, type in `.' (full stop). The program will then save the machine code, and proceed to run it. When it prompts you "now run the xmodem send", you should send the file `zfst.bin' with a comms program using the XMODEM protocol. Under MS-DOS, Telemate is a popular program capable of doing this; under Unix, `sx' (from the rz/sz package) is a popular choice. With `sx', you should run it like `sx zfst.bin /dev/ttyS0' (replacing /dev/ttyS0 with the serial device the +3 is connected to). Be sure to enable RTS/CTS (or `hardware') handshaking before starting the transfer! If you don't, there is almost no chance of it working! Under Unix, you would do this with `stty crtscts '. I suppose you could always play it safe and redirect stdin *and* stdout... :-) If the transfer is successful, the program will save zfst as `zfst.bin'. You should then reset the machine and type in a second BASIC program, which will load and run zfst: 10 CLEAR 32767 20 LOAD "zfst.bin" CODE 32768 30 RANDOMIZE USR 32768 You should save this with SAVE "zfst" LINE 10. RUN this to test zfst. If it works, you can delete the hex loader and `getzfst.bin', which you shouldn't be needing any more. * Using zfst Firstly, don't forget - always enable hardware handshaking (RTS/CTS) when using zfst. It'll hardly work at all without it. When zfst starts up, it immediately starts acting like a terminal. It displays characters received from the serial port, and sends characters you type. ** The Keyboard zfst treats the keyboard differently than normal. In particular, `true video' acts as an Esc key, `extend mode' acts as a `control' key, and many symbols such as `{' and `}' which are normally obtained via extend mode and symbol shift are obtained using symbol shift alone. The result is a keyboard which behaves mostly like the way it does under Locomotive's CP/M+ for the +3. This diagram shows the keys given with no shifts pressed: +-----------------------------------------------------------------------------+ | ESC | TAB | | | | | | | | | | | ESC | | | | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | | |-----------------------------------------------------------------------------| | DEL | | | | | | | | | | | | | | | ^@ | q | w | e | r | t | y | u | i | o | p | | |-------------------------------------------------------------------------+ | | CONTROL | | | | | | | | | | | ENTER | | | \ | a | s | d | f | g | h | j | k | l | | |-----------------------------------------------------------------------------| | CAPS SHIFT |CAPS | | | | | | | | |CAPS SHIFT| | |LOCK | z | x | c | v | b | n | m | . | | |-----------------------------------------------------------------------------| | SYM | | | | | | | | | SYM | |SHIFT| ; | " | ^B | ^F | SPACE | ^N | ^P | , |SHIFT| +-----------------------------------------------------------------------------+ [NB: caps lock doesn't do anything at the moment] With caps shift pressed: +-----------------------------------------------------------------------------+ | ESC | TAB | |CAPS | ESC | TAB | | | | | | DEL | ESC | | | | \ |LOCK | | | ^B | ^N | ^P | ^F | ^@ | | | |-----------------------------------------------------------------------------| | DEL | | | | | | | | | | | | | | | ^@ | Q | W | E | R | T | Y | U | I | O | P | | |-------------------------------------------------------------------------+ | | CONTROL | | | | | | | | | | | ENTER | | | \ | A | S | D | F | G | H | J | K | L | | |-----------------------------------------------------------------------------| | CAPS SHIFT |CAPS | | | | | | | | |CAPS SHIFT| | |LOCK | Z | X | C | V | B | N | M |ENTER| | |-----------------------------------------------------------------------------| | SYM | | | | | | | | | SYM | |SHIFT| ^O | ^P | ^B | ^F | ESC | ^N | ^P | ^N |SHIFT| +-----------------------------------------------------------------------------+ With symbol shift pressed: +-----------------------------------------------------------------------------+ | | | | | | | | | | | | | | | ^X | ^X | ! | @ | # | $ | % | & | ' | ( | ) | _ | ^@ | |-----------------------------------------------------------------------------| | | | | | | | | | | | | | | | ^_ | ^] | q | w | e | < | > | [ | ] | ` | ; | " | | |-------------------------------------------------------------------------+ | | CONTROL | | | | | | | | | | | ENTER | | | ^\ | ~ | | | \ | { | } | ^ | - | + | = | | |-----------------------------------------------------------------------------| | CAPS SHIFT | | | | | | | | | |CAPS SHIFT| | | ^@ | : | ` | ? | / | * | , | . | . | | |-----------------------------------------------------------------------------| | SYM | | | | | | | | | SYM | |SHIFT| ; | " | ^X | ^[ | SPACE | ^^ | ^^ | , |SHIFT| +-----------------------------------------------------------------------------+ With `extend mode' (or caps and symbol shift) pressed: +-----------------------------------------------------------------------------+ | | | | | | | | | | | | | | | ^X | ^X | ^\ | ^@ | ^X | ^X | ^X | ^^ | ^^ | ^[ | ^] | ^_ | ^@ | |-----------------------------------------------------------------------------| | | | | | | | | | | | | | | | ^_ | ^] | ^Q | ^W | ^E | ^R | ^T | ^Y | ^U | ^I | ^O | ^P | | |-------------------------------------------------------------------------+ | | CONTROL | | | | | | | | | | | | | | ^\ | ^A | ^S | ^D | ^F | ^G | ^H | ^J | ^K | ^L | ^J | |-----------------------------------------------------------------------------| | CAPS SHIFT | | | | | | | | | |CAPS SHIFT| | | ^@ | ^Z | ^X | ^C | ^V | ^B | ^N | ^M |ENTER| | |-----------------------------------------------------------------------------| | SYM | | | | | | | | | SYM | |SHIFT| ^O | ^P | ^X | ^[ | SPACE | ^^ | ^^ | ^N |SHIFT| +-----------------------------------------------------------------------------+ Some of the keys I wasn't too sure what to assign to; if anyone has any suggestions for sym-q, sym-w, sym-e, extend-truevideo (extend-3), extend-invvideo (extend-4), extend-left (extend-5), caps-enter, and/or sym-enter, I'd be interested to hear them. For technical reasons, you should probably avoid using the BREAK key or any combination of keys which involve both caps shift and space at once. The technical reason being, of course, that I use the ROM serial routines. :-) zfst waits until BREAK is released before calling any ROM routine, but I presume that if you were really determined and have very good micromotor skills, you could somehow press it again in the fraction of a millisecond you get to do so. (This can actually be fairly easy to do if the remote computer is continually sending data.) If you do manage this, you'll just get dumped to BASIC (there are no other ill effects unless you were doing an XMODEM transfer, when all manner of interesting things concerning unclosed files could happen). The layout probably looks pretty confusing, but most of the weirdness results from the way some of the +3 keyboard is just emulating certain `real' key combinations, e.g. DELETE emulates caps-0. For the rest of the manual I'll refer to the codes the keys generate, rather than the actual keys which give those codes, e.g. DEL (for the delete key), ^\ (for extend-edit), Esc (for true video or break), etc. ** Escape options (configuration, quitting, etc.) Some aspects of the way the terminal emulator runs can be changed while it's running. All of these involve typing ^\ (which is canonically called, confusingly enough, the `escape' character - you can get this by pressing extend-edit) then a key. ^\ 6 sets the screen size to 64x24. ^\ 8 sets the screen size to 80x24. ^\ ( sets the screen size to 85x24. (Note: `(' is sym-8.) This is the mode zfst starts off in. ^\ | toggles `smooth scroll'. Only upwards scrolling is smooth scrolled. In addition to the configuration options, there are... ^\ ^\ send a single ^\ character. ^\ q quits zfst and returns to BASIC. ^\ r receives a file using the XMODEM protocol. ^\ s sends a file using the XMODEM protocol. For more details on the last two functions, see `XMODEM transfers'. ** XMODEM transfers zfst supports file transfers using the XMODEM protocol. This is quite widely supported on a variety of systems. In the examples given here, I've used the `rx' and `sx' programs for Unix to demonstrate how to send and receive. *** About headers Before we go into how to send and receive files, we need to look at how zfst deals with +3DOS headers. Whenever you save a file from BASIC, it's saved with a 128-byte header which contains the file type, length, etc. However, you may have files which have no headers - for example, Multiface 3 snapshots or files created using CP/M. zfst allows you to add headers to files received, so that you can transfer a headerless file (a file containing a machine code program, say) from another machine which knows nothing about +3DOS, and still be able to load the file from BASIC. Similarly, you can choose to omit any +3DOS header on files you send. Whether you choose to keep/add headers or not depends mainly on whether the files are ultimately intended for a +3, since the +3DOS header will probably be completely useless to anything else. When sending, you should usually keep the header for BASIC files, as the header contains quite important information in that case, and the files will obviously be of little use on other computers other than in speccy emulators. :-) *** Receiving Before telling zfst to start receiving a file, you should get the remote computer to start sending. The reason for this is that the sender just waits until the receiver sends a certain byte, at which point the transfer proper begins. Here is an example using `sx' to send a file: It's easy to make malloc() return NULL under Windows: there is no fork() system call, and nobody expects the machine to stay up anyway, so who cares? When you say "I wrote a program that crashed Windows", people just stare at you blankly and say "Hey, I got those with the system, *for free*". -- Linus Torvalds, on comp.os.linux.development.apps rus@lifeson:601:/home/rus/speccy/src/zfst>ls -l zfst.bin -rw------- 1 rus users 6229 Apr 15 21:56 zfst.bin rus@lifeson:602:/home/rus/speccy/src/zfst>sx zfst.bin Sending zfst.bin, 49 XMODEM blocks. Give your local XMODEM receive command now. At this point, you should follow the instructions and type ^\ then `r'. zfst will prompt you for the filename to save the received file under. Type the filename and press Enter, or press Esc to abort the receive operation. If you do press Esc, you might have to cancel the remote computer's send operation by hand - see `Manually aborting an XMODEM transfer' for how to do this. Otherwise, you'll now be prompted for whether to add a +3DOS header to the file or not. Press the letter in [square brackets] to select the option. Here are the options and what they mean: [B]ASIC header (save as a BASIC file) This is for BASIC files *which do not already have headers*. If you're sending a BASIC file which already has a header, use the `Leave file alone' option instead. WARNING - THIS OPTION DOES NOT YET WORK. For now, you'll have to send only BASIC files which already have headers. [C]ODE header (save as a CODE file) This is for binary files *which do not already have headers*. Again, use `Leave file alone' if transferring one which does have a header. Note that you can only send ~40K if you want to be able to load it from +3DOS with `LOAD "foo" CODE'. [L]eave file alone (for already-headed files, etc.) Use this for files which should not have a header added to them. This includes files which already have +3DOS headers and files without headers you want to remain headerless (like Multiface 3 snaps and CP/M files). You can also press Esc here to abort the operation. When you've chosen one of these options, the transfer should start. (If not, there was a disk error of some sort - maybe you gave an invalid filename or the disk is write-protected. Just do ^\ r again after fixing any problem there might be.) zfst shows how many 128-byte packets have been received, how many K this rounds up to (not including any header to be added), and how many errors have occurred. You shouldn't worry too much if a few errors occur; the packet is resent, so the file should be ok. If you want to abort the transfer, press ^C. *** Sending Sending is pretty similar to receiving, except, uh, the other way around. :-) Ideally, you should start zfst sending before the remote end starts receiving. If this isn't possible (as with `rx') then just start the receiver first. All that happens is that you have to wait a few seconds for the transfer to start. Here's an example again: 640K ought to be enough for anybody. -- Bill Gates in 1981 rus@lifeson:601:/home/rus/speccy/src/zfst>rx foo rz: ready to receive foo The screen will scroll up as soon as you see this - don't worry, this is just because the character `rx' is sending to (attempt to) start the transfer happens to be interpreted by zfst's terminal driver as `scroll the screen up'. :-) Start the send operation by doing ^\ then `s'. Again, you'll be prompted for the file to send. After that, you'll be asked whether to include a +3DOS header if the file contains one. The options are: [Y]es, include header if there is one This will generally be the safest option, unless you know that the file has a header and you definitely want to remove it. [N]o, omit any header Use this if you want to be sure the file is sent without a +3DOS header no matter what. Then the file will start sending (probably after a short delay, since the receiving end will wait a while before sending the `start transfer' character again). If you want to abort the transfer, press ^C. *** Manually aborting an XMODEM transfer In some situations, you may end up with the remote computer still expecting to send or receive data. In this case, you should send the ASCII CAN character, which is used by (some) XMODEM send/receive programs to cancel a transfer in mid-operation. (Some only allow it at the start of a transfer; fortunately, if you send enough CAN's, the remote send/receive program will give up because it was expecting either ACK or SOH, depending on whether it was sending or receiving.) The CAN character is ^X. If the remote program allows cancellation in the middle of a transfer, you should only have to press it twice. Otherwise, you may have to hold it down for a few seconds. ** Control codes You can use zfst as a dumb terminal (or `glass tty') without any problems. If you want to use it as something a bit more useful, though, you'll need to know the control codes for moving the cursor, etc. (Unix users should skip straight to the next section which has termcap and terminfo entries for zfst.) Codes listed as `(reserved)' have no effect now, but may do in future versions. Code Hex Dec Description ^@ 00h 0 (ignored) ^A 01h 1 clear screen, home cursor ^B 02h 2 move cursor up (ignored on top line) ^C 03h 3 cursor on ^D 04h 4 cursor off ^E 05h 5 move cursor right (ignored at rightmost column) ^F 06h 6 draw pixel - see note (5) below ^G 07h 7 bell (the screen is flashed) ^H 08h 8 backspace ^I 09h 9 tab (8 chars wide, i.e. 1,9,17,25,33,...) ^J 0Ah 10 linefeed ^K 0Bh 11 repeat character - see note (1) below ^L 0Ch 12 (reserved) ^M 0Dh 13 carriage return ^N 0Eh 14 underline off ^O 0Fh 15 underline on ^P 10h 16 move cursor - see note (2) below ^Q 11h 17 (ignored) ^R 12h 18 insert line ^S 13h 19 (ignored) ^T 14h 20 delete line ^U 15h 21 scroll up ^V 16h 22 draw line - see note (5) below ^W 17h 23 scroll down ^X 18h 24 true video (i.e. turn off reverse video) ^Y 19h 25 reverse video ^Z 1Ah 26 delete multiple lines - see note (3) below ^[ 1Bh 27 (reserved) ^\ 1Ch 28 insert multiple lines - see note (3) below ^] 1Dh 29 clear to end of screen - see note (4) below ^^ 1Eh 30 home cursor without clearing screen ^_ 1Fh 31 clear to end of line FFh 255 line bitmap - see note (6) below (1) Repeat character repeats the next character sent N times, where N is the next character sent after that, minus 32. For example, sending ^K then `Z' then `*' would send 10 Z's like this - `ZZZZZZZZZZ'. I added support for this in the hope that (in particular) Emacs would use it to draw its' mode lines (which usually contain a lot of minus signs). Unfortunately, I have yet to find a program which actually uses this. :-( (2) Cursor move, on the other hand, *lots* of programs use. :-) After the ^P, send y+32 (as a character, with y=0 being the top line), then send x+32 similarly. (3) Ins/del multiple lines is extremely useful for editors, and most good ones will use it as it lets you ins/del several lines in the same time or less than it takes to do one. After the ^Z or ^], send the number of lines to ins/del plus 32 (as a character). (4) Clear to end of screen is surprisingly important for some programs, in particular modern shells like bash and zsh. It clears all lines from the current one to the bottom line inclusive. (5) From version 0.2, zfst includes a couple of simple graphics codes. ^F draws a pixel, and should be followed by two bytes - the first is the X position, the second the Y. ^V draws a line, and should be followed by the start and end points (four bytes) in a similar way. Note that you need an 8-bit link for these codes to work properly. If you write something for your host machine which uses these codes, it may speed things up if you turn the cursor off before drawing (and turn it back on after). For the time being, you can only draw pixels/lines in black, and not white - i.e. you can draw things, but not erase them; unless you count clearing the screen! (6) This provides a crude way of sending a bitmap. After FFh you send a byte containing a pixel line number (0-191), then 32 bytes to write into that line onscreen. There is as yet no facility allowing you to draw a smaller portion of a line than this. *** Unix termcap and terminfo entries Here's a termcap entry for zfst: # zfst termcap entry zfst|zfst-w|zgedneil's feeble speccy terminal:\ :cl=^A:co#85:li#24:cm=^P%+ %+ :bs:le=^H:do=^J:nd=^E:up=^B:\ :am:sb=^W:sf=^U:ce=^_:cd=^]:\ :ms:so=^Y:se=^X:mr=^Y:us=^O:ue=^N:me=^X^N:\ :vi=^D:ve=^C:vb=^G:cr=^M:ta=^I:nl=^J:\ :al=^R:AL=^\%+ :dl=^T:DL=^Z%+ :rp=^K%.%+ :\ :it#8:kl=^B:kr=^F:ku=^P:kd=^N: Just insert this into your /etc/termcap file, set $TERM to `zfst', and get running Nethack. :-) For those of you who use terminfo (which these days will be almost everyone :-)), here's one of those for zfst too (though this hasn't been as well-tested): [XXX doesn't include ^b or ^e yet (up and right, respectively)] # zfst terminfo entry zfst, clear=^A, cols#85, lines#24, cup=^P%p1%' '%+%c%p2%' '%+%c, cub1=^H, am, ms, npc, it#8, cps#380, bel=^G, flash=^G, cr=^M, cud1=^J, cnorm=^C, civis=^D, ind=^U, ri=^W, el=^_, ed=^], rev=^Y, sgr0=^X^N, smso=^Y, rmso=^X, smul=^O, rmul=^N, il1=^R, dl1=^T, il=^\%p1%' '%+%c, dl=^Z%p1%' '%+%c, kcud1=^N, kcub1=^B, kcuf1=^F, kcuu1=^P, Yes, the final comma *is* intentional. :-) Copy that to a file /usr/lib/terminfo/zfst (the terminfo dir. might be elsewhere on your system, but that's the usual place), and run `tic zfst' as root. Then make sure /usr/lib/terminfo/z/zfst is world-readable, and you're all set. * Hints and Tips on using zfst with Unix ** Screen - multiple virtual terminals `screen' is a *very* useful program if you use terminals. Here's an extract from the man page: > DESCRIPTION > Screen is a full-screen window manager that multiplexes a > physical terminal between several processes (typically > interactive shells). Each virtual terminal provides the > functions of the DEC VT100 terminal and, in addition, sev- > eral control functions from the ANSI X3.64 (ISO 6429) and > ISO 2022 standards (e.g. insert/delete line and support > for multiple character sets). There is a scrollback his- > tory buffer for each virtual terminal and a copy-and-paste > mechanism that allows moving text regions between windows. If you can't see how useful this is, you obviously haven't been using Unix very long. ;-) If you don't have it on your machine, I definitely recommend you get hold of a copy (it's free software). Screen is available from any FTP site that mirrors the GNU software; as a last resort, you can get it from prep.ai.mit.edu in /pub/gnu. ** GNU Emacs You shouldn't have any problem using ^S and ^Q with zfst. RTS/CTS handshaking renders XON/XOFF rather unnecessary. :-) The way the +3 does serial comms (by bit bashing rather than using a UART) means that zfst has to receive a byte, then stop receiving while it displays it. This in turn means that when you're doing serial I/O at 9600 baud, you'll only get an effective terminal throughput of about 4800 baud, if that. You may want to include something like: (if (equal (getenv "TERM") "zfst") (setq baud-rate 4800)) in your ~/.emacs file to clue Emacs up on this. It makes no difference to the actual transmission speed, but may incline Emacs a bit more towards using insert/delete line etc. where it would otherwise consider using them as `slow'. ** XMODEM transfers The XMODEM protocol requires an 8-bit link. If you try to do XMODEM transfers across a 7-bit link, there's no way it'll work. Even ASCII files will fail because of the way the packet numbers and checksums rely on 8-bit links. If you're connecting via a null-modem lead, this usually isn't a problem. At worst you'll have to do `stty cs8 -istrip' before sending - this will probably be the default setting anyway. Watch out for other things which can get in the way or filter the data; the otherwise very useful program `screen' is a common culprit. If you run screen you should do ^A ^Z, which suspends it, before sending. And of course, `fg' afterwards. :-) * Techie info This section contains a few bits and pieces on how zfst works, and what limitations it has. Boy, does it have limitations... :-) ** Terminal driver The 64x24 mode is done in the usual way, using 4-bit wide characters. The 80x24/85x24 modes use 3-bit wide characters, along with lookup tables for the various positions and masks to speed things up a bit. I hope it isn't too unreadable... :-) The only nice things missing from the terminal driver at the moment are a `scroll window', and `insert/delete character' codes. These would obviously save a lot of characters being re-sent, but they would be an absolute pain in the backside to do. ** Keyboard reading Ok, it *is* strange having a keyboard-reading routine that isn't called from an interrupt handler. But when you have to disable interrupts to use the serial port, using an interrupt handler isn't anywhere near good enough. What zfst does instead is to do a halt then read the keyboard if no character was received last time it checked; if there was, it reads from the keyboard once every 8 characters sent if at 9600 baud, every 4 if at 4800, every 2 if at 2400, and for every character sent at lower speeds. This gives a fair approximation to 50-times-a-second without relying on the dodgy interrupts. The auto-repeat is set by default to be similar to a PC keyboard going full tilt, which curiously enough is the default for a Linux console too. Wonder why I chose that. :-) ** XMODEM stuff The XMODEM send/receive routines are loosely based on the C ones in xmodem 3.9, as posted to comp.sources.unix (or was it .misc? my memory fails me :-/). Except, of course, *I* only implemented the minimum possible XMODEM protocol. ;-) 128-byte packets only, 8-bit mod 256 checksum only. This is usually known as `XMODEM checksum' rather than the `XMODEM CRC' or `XMODEM-1K' variants. zfst uses an 8K send/receive buffer, to save on disk thrashing. * Contacting the Author You can email me at russell.marks@ntlworld.com.