DNA Lounge Payphone

by Jamie Zawinski
January 2016.

In 2015, we threw a party called Cyberdelia, celebrating the 20th anniversary of the movie Hackers. It was epic: we built skate ramps and everything.

We're having a second Cyberdelia in two weeks, on Friday, Jan 22. Except this time, the hackers will be watching Tank Girl instead of Hackers! For the costume contest, either Hackers or Tank Girl attire is considered "on message".

You will join us, yes?

One of the props that I picked up to decorate DNA Lounge at the first Cyberdelia was an old payphone. It wasn't hooked up for the first party, but just in time for the second party, it now runs Linux.

When I was trying to decide what I wanted the phone to do, "making phone calls" was obviously the least useful thing. Nobody needs that: that's why payphones are extinct in the wild. It's also why we no longer have Internet kiosks.

So instead, when you pick up this phone, it "rings" and connects you to a "voicemail" system. Press 1 to listen to our schedule of upcoming events (the same message you hear when you call us at 415-626-1409); press 2 to listen to your saved messages; press 3 to record a message.

Here is the sordid tale of how I made a payphone run Linux. I'm not so great at hardware hacks, and it shows. My bumbling exists for your amusement.

Phase One: The Keypad

My first goal was to turn the telephone's keypad into a USB keyboard. The plan: take a $5 USB numeric keypad; pull the USB chip out of it; and hook that up to the phone's buttons.

Behind the buttons on the telephone keypad is the same sort of design as exists inside most computer keyboards. The obvious way to do this would be for there to be a switch for each key, attached to a pin on the chip to tell it when the switch was pressed. But for a keyboard, that would mean your chip would need 100+ inputs. So instead, the way they work is, the keyboard is wired up in a grid: there is a set of horizontal wires, and a set of vertical wires, and pressing a key makes an electrical contact between one horizontal and one vertical wire: so pressing 5 connects wires X and B. The chip figures out which keys are pressed by polling thousands of times a second: it squirts some electrons down W, and if they come back on A, then 1 is pressed. Then it squirts some electrons down X, and if they come back on C, then 6 is pressed, and so on.

So for a simple keypad like this, it's a false economy, since this chip needs 7 inputs instead of 12. But for a full-sized keyboard, you reduce the number of inputs from about 100 to about 20. But, it is what it is.

The logical electrical layout of the phone's keypad is exactly what you'd expect: it's the drawing above. The logical layout of the generic USB numeric keypad is a bit weirder.

Physical layout:

Logical layout:


It's like the Platonic ideal of a keyboard: you think you're typing on the thing on the left, but that's just a shadow on the wall. The real keyboard is the thing on the right.

The positive numbers line up properly, but there's no choice of mappings here that will make the "*0#" row work. So, I used the "T/*" row for that and I re-map the keys in software. (The blank cells don't send any keys at all).

First I needed to get electrical connections out of the phone's keypad. The key contacts are printed on one side of a two-sided circuit board. I was able to use the "via" holes (where one side of the board connects to the other) to connect in. That looked like this:

That chip on the board is both the keyboard decoder and a DTMF (touch-tone) generator: the output of this board is audio. So that wasn't going to do me any good.

(Fun fact: the noises that telephone buttons make are chords of two notes played simultaneously, and those notes are also arranged in a grid just like the above, low frequencies vertically and high frequencies horizontally. Other notes and chords did other things on the old phone networks: one of the more famous frequencies was 2600 Hz, and that's why both the Atari 2600 and the magazine are called that. Fun fact two: Wozniak and Jobs funded Apple Computer by selling blue boxes that let you make phone calls for free.)

The next step was to connect those new wires to the inputs on the USB keyboard chip. Easier said than done, because that keyboard had a flat plastic membrane as its input: its socket accepted a paper-thin piece of flexible plastic with contacts printed on it that are 0.5mm wide and 1mm apart on center. I wasn't able to find a breakout board that had a socket that small on it: I found some blanks, but they required you to surface-mount the socket to it (and I couldn't find the socket either). So I did it the hard way: I manufactured a connector that would fit into that socket.

Yeah, those are sewing needles.

First: let me draw your attention to the plastic shim holding those needles at 1mm spacing. Let me draw your attention to how hard it was to manufacture that thing. Though I have 0.5mm drill bits, I had to tape them to make them fit into the dremel at all without just vanishing. And even though I have a drill-press stand for my dremel, my first plan of drawing a pattern then lining up the drill and dropping it was totally not working at all. So in the end, I just eyeballed it: drop the drill; lift ever so slightly; give the plastic the slighest kick with my fingernail; drop the drill again. It only took me three tries to get it right!

Second: though those are the thinnest needles that I had in my house at the time, they weren't thin enough to fit into the socket. So I had to file them down. It was like I was making the world's tiniest shivs. I turned the dremel sideways, put a sanding wheel on it, and held the needles to it until they were flat and about 0.1mm thick. I was doing this while wearing a 20x magnification monocle, so all of this action was taking place with my face so close to the spinny bit that I had to exercise great care to avoid sanding off the tip of my nose.

When I described this to a friend he said, "So basically, you're looked like some guy I have to find to send me on a side-quest in Fallout." Pretty much.

Ok, remember that shim I was so proud of constructing? It didn't really work. It was still too hard to get every pin to make contact at the same time. So instead, I tore the top off of the jack and jammed the pins into the underside of the contacts in it, then used the tip of a needle to secure each with a drop of superglue.

Once everything was tested, I wrapped the whole mess of wires inside some Sugru (this amazing play doh-like stuff that dries into flexible rubber).

I did waste a few days trying to track down what I thought was series of bad connections that actually turned out to be: to make some keys work at all, you had to press really fucking hard. I solved this problem by shimming with a thin piece of cardboard between each key and the domes on the rubber membrane. I suspect this phone would also have had that problem when it was still a phone.

Phase Two: The Handset

Fortunately, telephone speaker and microphone design has not changed significantly since like, 1870 or something. Scoping out the four wires coming from the telephone's handset was pretty straightforward: one pair showed 150 Ω (that's the speaker); one pair showed 200 kΩ (that's the mic).

If you're like me, and do these sorts of projects at 4am without really planning ahead, you don't have, for example, a solderable TRRS plug when you need one. So you take what's lying around, and tear apart an old pre-made TRRS cable and solder a stacking header onto it. What, soldering onto wires that are just slightly thicker than a human hair? I'm getting used to it. Then a big old glob of epoxy to finish it off.

Best iPhone headset ever.

Phase Three: The Computer

I got a Raspberry Pi 2 B to drive it, which is probably a more powerful computer than your typical PC was at the time that this payphone was originally in service.

The Pi has an audio output, but it's shit, and it's not powerful enough to drive the speaker in this handset. But that doesn't matter since the Pi does not have an audio input, meaning I needed a different audio card anyway. I got a Cirrus Logic, which, conveniently enough, also has a TRRS headset input.

You know what this means, right? I voluntarily and of my own free will recompiled my kernel in order to get my audio card to work. I don't even know who I am any more. I don't even know what year this is. "And you did this on your home phone?"

Because of course Raspbian doesn't come with the modules pre-built. Of course it doesn't.

Anyway, after the usual jiggery-pokery, I had audio ouput via aplay and audio input via arecord and all was right with the world, except for the fact that I had hoped I would never hear the word "ALSA" again in my life. (It's "Advanced", you know. The "A" stands for "Advanced".)

So then I wrote some code: phonebooth.pl. It sits there reading characters from the keyboard (the phone keypad) and responding to them by playing MP3 files, or recording and saving new ones. Most of the MP3 files are pre-recorded (generated by the Makefile using the free online text-to-speech service at voicerss.org -- which doesn't do a fantastic job, but it's adequate). The infoline is downloaded from the DNA Lounge web site every morning and re-converted to an MP3 in the same way.

I launch it as a getty from /etc/inittab on console 0 so that the machine boots up into the Perl script:

Phase Four: The Switch Hook

Now I just need to detect when the handset has been taken off hook and hung up. This part should be easy, right? After all, the Pi 2 has about a zillion readable pins on it, and unlike the Arduino, they even come with built-in software-configurable pull-up and pull-down resistors, which saves a lot of soldering.

Well, no. Not so much. This next part took me days to figure out.

If you were me, you might assume that an audio card wouldn't consume all forty pins on the Pi's GPIO header. Well, it does... sorta...

The manual is pretty unclear about whether any of the GPIO pins are intended to be available for non-soundcard-related use, but in the tables it does describe some of them as "EXP", which I interpreted as "Expansion", which I further interpreted as "you can use these."

Also, the board has an "expansion header" (sometimes called a "feature header") on it. It has 20 pins. The manual describes a header that has 13 pins. Further, the 13 pins described in the manual bear no relation to the first 13 pins, or any pins, on that 20 pin header. What the hell, Cirrus.

Scoping out its continuity shows that the expansion header corresponds to these pins on the Pi's header. This table is looking at the board with the ethernet jack on the bottom left. The header is not numbered and I won't hazard a guess as to which corner the designers of this board thought of as "up".

? ? ? ? ? BCM 5 BCM 25 BCM 12 BCM 26
5v ? ? BCM 3 BCM 2 ? BCM 6 BCM 16

So, just pick a pin, like BCM 26 let's say, and go to town, right?

Well, no. Not so much.

It turns out that if you try to use any of these pins, they all behave as if they're "floating": you get random data, as if the software was unable to attach a pull-up or pull-down resistor to them. Or maybe it's not reading the pin at all but is reading something else entirely. Who knows! The pins I tried worked properly when the Cirrus card was not plugged in, but with it plugged in, they didn't function.

So we're dead in the water, right? Time to spin the wheel and buy a different audio card?

But I had an idea. Why is this card touching these pins at all? Does it really need to? So I got out the needle-nose pliers and very carefully bent one of the pins down, then plugged the audio card back in, denying it access to that pin.

Pin 40: Audio card doesn't function. Bend it back and try again.
Pin 38: Audio card doesn't function. Bend it back and try again.
Pin 36: Audio card doesn't function. Bend it back and try again.

Yup, I did that. I'm not proud. Or maybe I am. I can't tell.

I suppose it's possible that by doing this I have broken some feature of this audio card, but since both playback and recording work, it's not a feature that I use, so, so what!

Except the story didn't play out in quite so straightforward a way as all that, because there were multiple failures happening at the same time, as is my way, because I am cursed.

It turns out that, on this Pi, with this version of Raspbian, reading a pin state with Python works great:

But doing it from Perl doesn't work at all. The pins always act like they're floating:

This is weird, because both of these libraries appear to be a thin wrapper on top of the underlying bcm2835 library, which is written in C. Ok, fine, let's do it in C:

Oh hey, the C version doesn't work either! What the hell is Python doing under the covers that the Perl and C versions aren't?

Ok, fine, I guess I'll read the pins by having my Perl code call out to a Python script. (I tend to write my junk in Perl because I still just can't get past Python's whitespace thing. I know, you all think it's not a big deal, but I can't. I just can't.)

So that fixed it.

Update: Someone explained why Python worked but C and Perl didn't: they use different pin numbering schemes! Python (and all the documentation of anything ever) use "BCP" numbers, but the C and Perl interfaces use Pi header pin numbers instead. So changing the "12" to a "32" in the C code makes it work.

But you know what else is monumentally moronic? Only root can read BPIO pins. And I don't mean "only users who have read permission on /dev/mem", I mean literally "only root". So either you have to run everything as root, or your pin-reader helper has to be setuid. Which you can't do with a Python script without putting a C wrapper around it. This rat hole goes deep.

Phase Five: Profit

I kind of wanted to make use of a few more pins, to do things like detect when a coin was inserted (at least to have it say "Thank you, and remember to tip your bartenders!") or to be able to ring the physical bell, but after my pin-bending hijinks on the audio card, I figured I had better quit while I was ahead. Maybe the next pin I bend blows up the board.

And here it is, the complete "payphone", before being re-inserted into its massive cast-iron chassis:

In conclusion, Hack the Planet.