Sunday, July 2, 2017
C64 Telnet Server
Of late, I have not been able to get enough of my Commodore user-port wireless Ethernet modems. Yes, the same modem I described before >here<.
Since that last blog post, we've added hardware flow control, and gone through two more revisions of the hardware. Changes to the firmware have slowed down at this point, as I focus more of my energy on different applications of my new internet toy.
In addition to all the programs mentioned in the previous post, I've since added a version of WGET specifically for downloading .D64 (or D81, etc..) disk image and writing the sectors directly to a blank floppy. This is perfect for users who want to enjoy games on the internet in .D64 format, but only have a single 1541 disk drive and our modem. The program is called D64WGET on our disk.
I also ported one of my favorite old Commodore PET games, "weather", to the C64, and then made it playable over the internet using our modems. I got my brother to help me play test it several times during testing, and I was soundly defeated. :(
I even managed to hook my Commodore SuperPET's RS232 port to the FTDI pins on an old rev 2 version of our modem (after going through a RS232/TTL converter), and playing around with it online. This little project did require adding some more features to the firmware, since the SuperPET needed 7 bit characters and Even parity. The fact that it uses 7-bit characters instead of the standard 8-bit was especially hard to discern, since neither the computer manual nor the uart setup menu mentioned it. It was only after hooking up a logic analyzer to the TX/RX pins that this was figured out.
But my latest project has been a telnetd server for the C64. From the internet you can connect to my C64 using a telnet-client of some sort, or even another ethernet modem like I'm doing here, and "take over" the C64's READY prompt. You can write, run, load, and save programs, and so long as they limit themselves to text and keyboard input, everything works great.
In the picture above, the breadbox C64 on the left is running the server using a prototype of the rev 4 modem, while the C64C on the right is running a little four-line BASIC terminal program at 1200 baud on a rev 3.
The telnetd server resides in C64 memory at $C000 and is hard coded to initialize the modem and listen on port 6400. The server injects itself into all the the Kernal vectors and thereby redirects modem input to the keyboard buffer, and screen output to the modem. I've been learning quite a bit about the way the C64 Kernal RS232 routines and Kernal IEC (disk drive/printer) routines share CIA timers and thereby step all over each other. At one point running the telnetd server all but ensured that programs LOADed would be corrupted, while also disabling remote user input. It was a mess. But since then I've gotten it to the point where you can remotely do disk access commands and maintain your control, which I debugged by simple disabling all modem output during LOAD, SAVE, and OPEN kernal calls.
My next mission was security. One wrong POKE or SYS and the server is toast. This was fixed by injecting code into the 'IGONE' BASIC vector that converted the token values for POKE and SYS into PRINT. :)
An idle timer, and an overall time limit was then put in, so that tinkerers can't hog the system forever, or just sit around doing nothing. I chose an overall limit of 1 hour, and idle time of 5 minutes, though I'm sure that will be configurable in the future. I tried using the ability of the TOD clock to generate interrupts to handle my time limits, but then discovered that i/o and the c64 kernal's default NMI step all over those as well. I mean, the first thing the C64 Kernal NMI interrupt does is turn OFF all interrupts on CIA#2. What the hell?! In the end, I just had my normal interrupt code watch the two TOD clocks for timeouts.
Lastly, I needed a welcome message for when users connected, and, to enforce my time limits, the ability to send the delayed "+++" (pause) "ath" commands to the modem. Since I was detecting users coming online and time limit timeouts in the standard periodic interrupt, that was where I handled this 'forced disconnect' feature as well by simply adding a state machine and letting the TOD clock used for the idle timer do double duty as a delay-pause timer as well.
When completed, this program will join its brothers over in my Zimodem/C64Net WiFi project, which you can follow at https://github.com/bozimmerman/Zimodem.
I'm sure there will be more on this forthcoming.. unless some other shiny C= bauble catches my eye of course.