Title: Altair on WiFi
Date: December 26, 2018
Tags: altair hardware
========================================

Putting the Altair 8800 on the internet is easy and cheap.  Just takes a bit of
hardware and some firmware emulating a Hayes modem.  You can get on a BBS in
minutes.

I had heard about serial WiFi modems for retro computers but the device being
talked about was no longer being made.  I sort of forgot about it for a while
and then recently looked again for available options.  I found a blog post[0]
detailing the assembly of your own from a couple of components and the
Zimodem[1] firmware by Bo Zimmerman that was written to interface with a
Commodore 64 over it's serial connection.

I chose to use the ESP8266-12E module, a "5-wire" RS-232 to TTL adapter, a DB25F
to DB9F adapter, an old cell phone charger and a null modem adapter I already
had.  Note that the "5-wire" adapter only came with 4 jumper wires which, after
power and ground, only actually allows for Rx and Tx without any flow control.
To hook up flow control, I also bought a variety of jumper wires which can be
used for future projects, too, but I still haven't used flow control anyway.  So
actually, Rx and Tx with the jumper wires it came with is all you need.  You
could probably find a DB25 to DB9 adapter that is also a null modem adapter.  I
didn't know I would need one until I was confused for a day by the modem not
working on the Altair.  Plugged into my laptop, it worked fine so it took me a
night's sleep before it clicked that it might need a null modem adapter.

The blog author had to modify the Zimodem firmware because the Commodore 64
serial port flips high for low as compared to normal RS-232 lines.  His changes
mostly just flip those by default.  The firmware is fully configurable if you
were able to talk to the device in the first place.  But, if you couldn't you'd
be stuck.  The modified version is a year or so out of date now and the blog
author is not maintaining it going forward.  It builds easily with the Arduino
1.6.x IDE.  Version 1.6 is important.  It will not build as is with 1.8.  I'll
describe building the firmware below.  When starting this article, I did
everything using the build from the blog post so updating is not critical.

The ESP8266-12E has a built in USB serial adapter: CP2102 USB to UART Bridge
Controller.  My OpenBSD laptop could not flash the ESP module over this device
but after the firmware was loaded, could talk to the firmware.  My Mac, needed a
driver[2] installed and was then able to flash the Zimodem firmware.

I was then able to connect to the device using OpenBSD and configure my wireless
access point.  It supports WPA2 with a passphrase and DHCP just fine.  I could
immediately start making network connections through the modem using my
terminal.  I set the baud rate to 9600, it defaults to 1200, and disabled any
flow control options.  Make sure you save your configuration with AT&W so when
you plug the modem into your retro computer, you don't have to reconfigure it.
The Zimodem README[3] is a must for a command reference.

Initially I wrote a long command entry interface based on string echo[4] for the
Altair to communicate with the modem and receive data back from it.  At the
time, I hadn't yet realized I needed a null modem adapter and couldn't figure
out why the modem didn't seem to be doing anything.  I then wrote a quick test
program that simply sends terminal input to the modem and modem output the
terminal character by character.  That was really all I needed to get started.
I works pretty smoothly for poking around the internet with the modem.

Here is the simple test program:


000     LXI SP          061 ; Set stack pointer
001             000Q    000
002             100Q    100
003     MVI A           076 ; Reset ACIA
004             003Q    000
005     OUT             323 ; for terminal port
006             020Q    020
007     OUT             323 ; for modem port
010             022Q    022
011     MVI A           376 ; Set to 9600 baud 8N1
012             225Q    225 ; and enable receive interrupts
013     OUT             323 ; for terminal port
014             020Q    020
015     OUT             323 ; for modem port
016             022Q    022
017     EI              373
020     NOP             000 ; Wait loop
021     JMP             303
022             020Q    020
023             000Q    000

; Modem handler
024     IN              333 ; Get character from modem
025             023Q    023
026     MOV B,A         107 ; Save in B register
027     IN              333 ; Check if terminal is ready
030             020Q    020 ; to send
031     RRC             017
032     RRC             017
033     JNC             322
034             027Q    027
035             000Q    000
036     MOV A,B         170 ; Write character to terminal
037     OUT             323
040             021Q    021
041     RET             311

; Terminal handler
042     IN              333 ; Get character from terminal
043             021Q    021
044     MOV B,A         107 ; Save in B register
045     IN              333 ; Check if modem is ready
046             022Q    022 ; to send
047     RRC             017
050     RRC             017
051     JNC             322
052             045Q    045
053             000Q    000
054     MOV A,B         170 ; Write character to modem
055     OUT             323
056             023Q    023
057     RET             311

; Interrupt handler
070     IN              333 ; If modem has data
071             022Q    022
072     RRC             017
073     CC              334 ; goto modem handler
074             024Q    024
075             000Q    000
076     IN              333 ; If terminal has data
077             020Q    020
100     RRC             017
101     CC              334 ; goto terminal handler
102             042Q    042
103             000Q    000
104     EI              373
105     RET             311


I cleaned this up a bit from it's original thrown together code.  Short and
sweet, it lets you talk back and forth with the modem allowing you to access all
the functions of the modem.  It's without any fancy output or parsing, no
backspace, and it relies on the Zimodem firmware's character echo to show you
what you're entering.

## Breaking it down ##
# Main program #
If you've followed along with the previous echo articles, the main program
should look familiar but with the addition of a second serial port.  The 2SIO
board in an Altair 8800 had 2 serial ports.  The Altair clone defaults to the
first port with the status register at address 020Q and data register at address
021Q.  The second port has the status register at 022Q and data register at
023Q.  My terminal is plugged into port 1 and the modem into port 2.  We don't
need any heap space here as we're not writing anything to memory, just passing
it straight through to the ports.  We reset both ports and then configure both
ports to 9600 baud 8N1 with receive interrupts enabled.  My original hack and
slash version reset port 1 then configured port 1 then reset port 2 and then
configured port 2.  I had to keep loading the Accumulator with commands.
Reordering to send the same command to both ports then changing commands saves
quite a few bytes of code.  Then we enable interrupts, which will fire if either
port receives a character.  And spin in our familiar wait loop.

# Interrupt handler #
Going in execution order instead of memory order, I'll cover the interrupt
handler next.  This will also look similar to our other echo programs.  Here,
since we enabled receive interrupts on both 2SIO ports, we don't know which one
triggered the interrupt.  The data register's bit 7 will be a 1 if that port has
generated an interrupt.  But the data register full bit, bit 0, will also be 1
if there is something for us to read.  So instead of caring where the interrupt
came from, I just check both ports for a character ready and process it.  I
check the modem's status first and if the data register full bit is 1, call the
modem handler to read what's there.  Then check the terminal's data register and
call the terminal handler if that port has a character ready.  You'll see that
I've basically in-lined write char from the string echo program to do the
writing.

# Modem handler #
The modem handler is called from the interrupt handler if a character is ready
in the modem port data register.  It simply reads the character from the modem
port then checks the terminal data register until the terminal port is ready to
send a character and then writes the character out to the terminal.

# Terminal handler #
The terminal handler is the same thing as the modem handler with the port
addresses switched.  It reads a character from the terminal, waits for the modem
port to be ready to send, then sends the character to the modem.

## Altair on the internet ##
That's enough to get the Altair on the modern internet.  They Hayes command-set
is supposed to allow you to use old terminal programs.  I haven't reached that
era of Altair computing yet so I don't know how well that works.  If you've ever
used netcat or telnet to connect to a web server or other server that usually
has a specialty client, that's what using the WiFi modem is like with this
simple program.  You have to know the protocol and what messages to send to the
server to get the right output.  And then all you get is the raw output.

The Zimodem firmware does have a telnet client built in, however.  You can use
that to get onto a BBS and you're back in the 80's without any further effort.
Use `atdt"SomeTelnetBBSHost:23"` to connect and you can interact directly with
the BBS in telnet mode.  Check out the list of telnet BBS severs[5].  Be careful
with terminal size.  If my terminal is too large, it doesn't clear the screen
correctly and I get a jumble of output.  Might be the server software the BBS I
tested with is running, though.  Also make sure you have your terminal is set up
correctly for color and ANSI, etc.  Just like the old days.


Altair on a BBS[6]


Websites are a bit trickier.  They can be very picky about proper usage of
carriage return and newline sequences and may require certain headers be
present.  Since our program only sends exactly what you type to the modem, if
you hit enter and send a carriage return, nothing is going to process that and
add a newline if it's needed.  Everything has to be explicitly entered.  Try it
with the following commands (<^j> is a control+j to send a newline)
`atde"altairclone.com:80"<enter>
GET / HTTP/1.1<enter><^j>
Host: altairclone.com<enter><^j>
User-Agent: Altair<enter><^j>
<enter><^j>`
to get a dump of the altairclone homepage.  User-Agent isn't necessary but maybe
Mike will notice it in is logs and wonder what's going on.  :)  Careful doing
this with even "simple" web sites like google.com or you'll be waiting a long
time while it dumps tons of formatting garbage and scripts to your terminal.  If
you want to experience just how bloated websites have become, try them at 9600
baud.

There is no support for TLS (https, port 443) web sites so that is a bit
limiting.  Also, some web servers will close the connection if you don't send a
request within a certain time and you probably won't be able to type quickly
enough.

## Upgrading firmware ##
Updating the firmware to the latest version (3.4.1 from Dec 11 2018) is pretty
straight forward.  I re-applied the change to the defaults for non-C64 systems,
plus defaulting to 9600 baud and rebuilt it.  I had to do this on a Mac and the
instructions should work on Windows and Linux.  I am assuming the ESP8266 board
as that is the one I have.  The code should support the other boards but
configuring the Arduino IDE and flashing is up to you to figure out since I
can't test anything I don't have.


* Start by installing version 1.6.13[7] of the Arduino IDE.
* Follow the directions to install[8] the ESP8266 board definitions and libraries.  At this time the version is 2.5.0-beta2.
* Select the NodeMCU 1.0 (ESP-12E Module) from the Board list under ESP8266Boards.
* Set Flash Size to "4M (1M SPIFFS)" and CPU Frequency to "80 MHz".
* Check out the Zimodem software[9] from Github.
* Apply the changes to the code for the Altair.  Diff for Zimodem 3.4.1[10].
* Open the zimodem.ino file from the Arduino IDE which loads the project.
* From the Sketch menu, select Export compiled Binary.

A binary named zimodem.ino.nodemcu.bin should be created in the same directory
as the zimodem.ino file.  I followed the original blog instructions for
flashing[11] without the Arduino IDE.  To flash the ESP module, you have to
disconnect the RS-232 to TTL adapter otherwise the USB port is used for serial
output, also, and you can't flash the memory through it.

Modify the UPDATE_URL to your own location if you want to host your own
over-the-air updates.


[0] https://subethasoftware.com/2018/02/28/wire-up-your-own-rs-232-wifi-modem-for-under-10-using-esp8266-and-zimodem-firmware/
[1] https://github.com/bozimmerman/Zimodem
[2] https://www.silabs.com/products/development-tools/software/usb-to-uart-bridge-vcp-drivers
[3] https://github.com/bozimmerman/Zimodem/blob/master/README
[4] https://blog.kagu-tsuchi.com/articles/8080_IO_string_echo.html
[5] https://www.telnetbbsguide.com/
[6] gopher://kagu-tsuchi.com:70/I/blog/images/altair_wifi_bbs.png
[7] https://www.arduino.cc/en/Main/OldSoftwareReleases#previous
[8] https://github.com/esp8266/Arduino#installing-with-boards-manager
[9] https://github.com/bozimmerman/Zimodem
[10] gopher://kagu-tsuchi.com:70/0/blog/files/zimodem-altair.diff
[11] http://subethasoftware.com/2018/02/25/how-to-load-zimodem-firmware-to-an-esp8266-without-arduino-ide/