It's a crisp autumn day. Shortly after the sun goes down, the outside temperature drops enough that it's time to go inside. After washing up and eating some dinner, you have a choice. Watch the latest episode of "Cheers" or fire up the 386, log into The Hotel BBS, and play a round of Tradewars. For 12-year-old me, there was only one choice. (and for the record, 40-year-old me would still pick the same one.)
Back in the 90s, I had a blazing fast 9600 baud modem. Set next to my VGA monitor, this box tied up our family's only phone line while I communicated on message boards connected with FidoNet, spent countless hours trading ore in Tradewars, and used it for my earliest Internet access (PPP)! The modem was a Practical Peripherals (or sometimes called Practical Modems) 9600SA. As the name suggests, its maximum baud rate was 9600. It was a big clucky box. Also, it was loud. Not just the big speaker, but it had some very clicky relays. They would click when it turned on and again when connecting to the phone line.
Today, Bulletin Board Services (BBSes) are still running. However, instead of connecting by phone lines, they operate with TCP/IP protocols like telnet and ssh. While modern computers have no problem connecting to these boards, vintage computers need an internet-capable modem. A popular option is a device that is generally called "WiFi232." It is an ESP8266 that talks serial to a computer and WiFi to the internet. It emulates correct modem speeds. In comparison, I could have just bought one of those but that would not have been much fun.
For almost three years, I searched eBay and vintage computer shows for a 9600SA from Practical Modems, without success. Then earlier this year, my brother handed me a box from storage. Not only did it contain my old 9600SA, but it was also at the top of the contents! So I instantly knew I needed to convert it to a WiFi modem. Side note, about two weeks after putting my hands on my actual childhood modem, an automatic eBay search uncovered another 9600SA. What are the odds?!
Want to Jump to the end? Check out Part 4 where I connect to a local and remote BBS with WiFi9600 modem!
Before embarking on the project, I came up with a few requirements.
- Do not damage the original electronics and avoid permanent changes to the case/enclosure.
- Use the original front panel's LEDs, power button, and answer button to emulate as much functionality as possible.
- Add a speaker for authentically fake modem sounds.
- Add relays for authentically authentic clicking sounds.
- Use MAX232 (or variant) to protect vintage computers.
Ideally, I wanted the design to be compatible with Commodore VIC-20 / C64 / C128, Apple II, and IBM PCs. I do not mean to limit to these, they were just the main part of my vintage collection (at the time I started.)
Step 1: The first WiFi9600 Prototype
The very first prototype combined all of the requirements except for MAX 232 protection. Since the Commodore 64's User Port does not support level voltages, this initial test was TTL only. However, it allowed me to test using the C64 with a modern terminal called CCGMS 2020. This program has built-in support for WiFiModem style hardware which does not use flow control. Regardless, I was able to connect at both 2400 and 9600 baud rates easily. Here is a clip of me connecting to Level 29 BBS with an actual Commodore 64. Make sure you unmute the video!
The first prototype tested out the basic blocks. The microcontroller board in this test was an ESP8266 in the NodeMCU form factor. For playing sounds, I used a SparkFun Qwuiic MP3 board. The relays were generic relay modules. Literally, this prototype was a breadboard connection between the ESP8266 and a Commodore 64. For interfacing to the C64, I designed a User Port breakout board and an board.
Side note: C64 User-Port / Board
This board isn't essential to the WiFi9600, but I want to address how I plan to connect to the Commodore computer series (eventually.)
At first, I intended to design a single board that broke out the user-port and wired-up the signals. However, that layout got really nasty. Then it occurred to me. I wanted two different boards. I have never designed a PCB with "mouse bites" before, so I used this board as a test. Half the board breaks out the C64 User Port while the other half interfaces header pins (TTL) to a DB25 connector () levels. The boards can be connected with jumper wires when used together. For this project, I picked the chip. It is similar in design to the MAX232. However, the 3241E has more transceivers and built-in ESD protection. My hope is that the MAX3241E provides a little bit of protection to the relatively vulnerable I/O chip inside the C64.
SparkFun Qwuiic MP3 Board
I picked a board with an I2C interface and digital I/O pins to play MP3s from a MicroSD card. I found some public domain sounds and used them to create MP3s: a dial tone with 7 DTMF tones and a modem connection sequence. Later I learned how to use the SparkFun Arduino library to poll the board to determine if it is done playing one of the authentically fake sounds. This feature made integrating the code into the WiFi modem firm significantly easier. (More on that later.)
ESP8266 and NodeMCU Form Factor
The NodeMCU form factor is a great way to work with an ESP8266. There is a serial interface, reset buttons, and I/O pins broken out into a breadboard friendly design. That said, while it worked great in the prototype, I decided I wanted an ESP8266 that supported an external antenna. One, I thought I would get better reception if the antenna is mounted outside of the box. And for two, it looks hella-cool to have a modem with a 2.4 GHz antenna sticking out the back!
Step 2: Reverse-Engineering the Front Panel
A key component of WiFi9600 is making the front panel LEDs work. In the original hardware, the front panel is an edge-connector and socket connection. It was rather easy to make a PCB that plugs into the panel's socket. It was a little less easy to figure out how the LEDs were wired. There are a total of 12 LEDs. Physically there are only nine, but two of them are bi-color. The 12th LED is the MR, or Modem Ready, indicator. It is wired to the front panel's VCC and not individually controllable. On the board there were only two ICs: a 74HC244 and a 74HC14. For some reason, some of the LEDs are driven through the HC244 buffer, while the others are driven directly from the modem's logic board. All LEDs have a 220 ohm resistor in series. The TX and RX lights were the only lights that were wired to VCC. The others were wired to GND. I'm not certain why these two were wired in this manner. I suspect it has to do with how fast they could be switched on and off.
There are also two push buttons. These took a little more troubleshooting exercise to figure out. The answer button is straight forward. One pin is floating, and the other pin is connected to GND. Interfacing with it needs an input pin and a pull-up resistor. The power button, however, was a shock to me. This 1990 device featured "soft power." Pressing the power button caused a relay to engage, which powered up the rest of the modem. I assumed it was wired directly to the relay, but I was wrong. (Shhhh, don't tell anyone.) The 74HC14 is a Schmidt trigger. These gates are commonly used to clean-up a signal's edges. In this case, it appears to be part clean-up and part de-bounce. The power button connects to one input on the `14 through a 100uF capacitor and resistor. And then, the output of that gate is connected to an adjacent gate's input. That output goes back to the modem's logic board.
This arrangement means the power switch circuit has constant power. Since I wanted to retain the front panel's functionality, I had to think about how I was going to utilize this unexpected circuit.
Eventually, I built a table of the edge connector's pins. Using that and some mechanical measurements with my calipers, I designed a simple breakout board. The board served two purposes. First, I wanted to make sure I designed my edge connector correctly. Keeping the board small meant that it was not a huge investment to spin it again if I was wrong. Second, I wasn't sure how I would handle 11 outputs and 1 input with an ESP8266. I knew a shift register would be involved. So I wanted to be able to breadboard some circuits before committing to a PCB design.
Step 3: Front Panel Driver Board
After I received back my breakout board, I did some basic tests to make sure I could toggle LEDs and correctly fit the board. Next, I turned to the design of a control board for this front panel. It had to support three circuits:
- LED drivers
- Soft power controller for modem
- Load Switch for the front panel
Front Panel LED Drivers
For the LED drivers, I cascaded two 74HCT595 shift registers. These registers are great for LED applications because you can shift in a new value without updating their outputs. If they did not have this latch, you'd see the LEDs flickering while updating! Using three pins from the ESP8266, I could easily control up to 16 LEDs. However, this design only had 11. I did use one additional bit of the shift register as an enable control for the front panel. So, in theory, the ESP8266 could turn off the LEDs. However, my modified code doesn't implement this option. It does mean there are four unused bits when shifting out LEDs, but such is life.
I did borrow one design idea from the 9600SA! They drove some of the LEDs directly from the outputs of a 74HC244, but not all of them. So on my driver, I buffered the LEDs they did not buffer through a 74HCT245. I picked a `245 because I keep those in my kit. (I did a Workbench Wednesdays episode on active components/ICs to keep in your kit.) I like these over a `244 because the `245 is bi-directional. So same general idea, but slightly more versatile in a new design.
Soft Power Switch
As mentioned above, the power button for the original 9600SA is a "soft power" button. Soft power means the switch itself does not break the input line. While almost all modern digital devices use a soft power configuration, this was a new thing back in the day. The power switch is always powered. When pressed, it creates a rising edge pulse that lasts as long as the button push. My challenge was to create a circuit that could toggle power on and off for the rest of the modem whenever seeing a button press. Knowing that there was a sharp rising edge from the 74HC14s, I immediately thought of a Flip-Flop. Most have a clock-edge input and output both the data and inverted data state. The challenge came when I tried to simulate a circuit in iCircuit that would respond to the button presses. (If you are new to flip-flops, check out How Flip-Flops Work on The Learning Circuit.)
Seems simple enough, right? Well, what I forgot is that I am NOT dealing with a switch. I only get a pulse, no button!. So after wasting two hours trying to come up with a clever circuit, I finally realized it is rather simple. Connect the power button's 74HC14 (Schmidt trigger) output to the clock input of the 74HCT74. Then connect the Q-bar (or Q-not) output of the `74 to the D input. Each press of the power button results in the output of Q toggling. You could even call it... flip-flopping! The Q output drives the gate of a p-channel FET, enabling VCC to the rest of the front panel board and the rest of the modem.
This design does have a flaw. There isn't a good way to force the modem to be "OFF" when powered-up. So sometimes, when connecting USB power, the modem starts up. Sometimes, it doesn't. I toyed with the idea of power-on reset circuits and various pull-up/down options. But in the end, I decided that it was charming to have an early 1990s soft-power "feature" as part of the design.
Load Switch for Front Panel
Since the MR light is only controlled by the VCC of the front panel board, I decided to add a second enable for the front panel. One bit on the `595 shift registers can control the front panel's LED buffer. Bit 0 of the first shift register drives another p-channel FET gate, enabling the front panel's output buffer. In both cases, using a P-channel FET as a high-side switch worked great. The Nexperia can easily handle one amp in a SOT-23 with a 5 volt gate signal.
During design, I thought I would use this circuit to turn on MR to indicate when the ESP8266 was booted and ready. However, forcing everything to turn-on with a known state became more effort than I thought necessary. The ESP8266 boots fast enough that it would not have really mattered. Instead, I decided to use the Terminal Ready (TR) light to indicate when the ESP8266 connects to WiFi. That's a more important indicator anyway.
Originally I was going to make a huge circuit board connecting the modem's back into the front panel. But for cost and time reasons, I decided to create two PCBs: one for the front panel and one for the back.
Step 4: Back Panel Carrier Board
After I sent the front panel board off to be manufactured, I turned my attention to the ESP8266. Since I did not want to modify the original case, I had to find a way to mount a microcontroller board inside the modem's enclosure. Then it occurred to me: I could edge mount a DB25 connector to a PCB and bolt that to the metal back panel. That board could act as a carrier for my ESP8266, break out connections to the MP3 player, relays, front panel, and DC voltage in. This concept became the back panel carrier board. Just a side note, while designing this board, I made extensive use of KiCad's 3D board viewer. It really helped me see where connectors were going to be and help visualize how wires would get routed in my final design.
Just like on my C64 breakout board, I decided not to leave the ESP8266's I/O pins exposed. Instead, I decided to add a MAX232 variant, , between the ESP and DB25 connector. This chip provides some ESD protection, and it also means the ESP8266 only sees 3.3 volt logic while making the modem compatible with level voltages. (Which can go to +/- 12 volts!) Unlike the C64 breakout, I used the MAX232 variant with only two transceivers. The tradeoff here is that the ESP8266 is not fully compatible because it is missing a bunch of control signals. However, to telnet to a BBS at 9600 baud, it seems to work fine.
DTE vs. DCE -- It isn't just alphabet soup
While routing the DB25 connector, I got to thinking about how TX and RX should work. Is TX on the connector the same as TX on the ESP8266? And what about the MAX232 chip in between them. To save time, I put two 2x2 header blocks on the board. These allowed me to cross the signals from the DB25 into the MAX232. And then the MAX232 into the ESP8266. As it turns out, this small decision totally saved my project.
I forgot that serial connectors have two different pinouts. There is the Data Terminal Equipment (DTE) and Data Communications Equipment (DCE). The host or computer is the DTE, and the modem is the DCE. One has a male 25-pin (or 9-pin) connector, and the other has a female. DTE or computers, typically are the male connector while DCE or modems are the female connectors. While they have, roughly, the same signals, how they get wired is different. For example, on the DTE/male host side of a 25-pin connector, pin 2 is TX, and pin 3 is RX. While on the DCE/modem female side, pin 2 is RX, and pin 3 is TX! Other signal pairs are switched as well, like RTS and CTS.
My problem was that I wired the DB25 connector on my modem as if it were a DTE! Since I did not wire-up any of the other signals, I got lucky. Using the 2x2 header blocks, I could easily re-wire my connector to be a DCE connection, at least partially.
WeMos D1 Mini Lite
Knowing that I wanted to use an external antenna, I had to find an alternative to the ESP8266 NodeMCU board I prototyped with. Here I made a minor mistake. I searched for ESP8266-based boards with SMA connectors. However, I only found one that matched. What I should have searched for is an ESP8266 with a uFL connector. I could have found more options. On this type of board, there is a resistor that switches between an internal and external antenna. So you do need to do a little bit of SMD rework to use the external.
Other Back Panel Carrier Changes
During testing, I found that brown-out conditions might occur when the front panel board powered the back panel carrier. The first time I noticed it was during a connection sequence. The ESP8266 could latch the relays and connect to a remote host. But the MP3 player would not play. So I kludged in a few huge capacitors to help. I put a 16V/47uF ceramic on the 3.3 volt rail and a 560uF on the 5.0 volt rail. With these, the transient current draw dropped significantly, and the modem worked as expected. Fortunately, I could make a few measurements with my oscilloscope and current probe to see what was happening.
When I picked the WeMos D1 Mini Lite, I did not think about the usage restrictions of the GPIO pins. While the WeMos had 8 digital IO pins, there were some limits. There are pull-ups on a couple of the pins on its board, and one of the pins, D8, has to be low for the board to boot properly. These constraints caused me to make some last-minute changes. Instead of using two relays (one for power and one for line connection), I tied them together and used a single I/O pin to turn them both on. Then I used the other relay input (D3) as the push button's input since the pin has an input resistor on the board. (The ESP8266 did NOT have a pull-up on this pin! but the WeMos board does!)
Last, I found once I connected the ESP8266's TX line to the MAX's RX input that the WeMos stopped booting again. So I found a pull-up to 5 volts, not 3.3 volts, was necessary.
Once I got both boards back and populated their components, it was time to tackle the WiFi-modem firmware. At this point in the project, I had a good feeling I could make something work. I just was not sure how much of the front panel functionality I could make happen. In the next WiFi9600 blog post, I show the firmware I found, the changes I made, and the mechanical pieces I used to tie everything together.