My payphone runs Linux now.








Phase One: The Keypad





Physical layout:

Logical layout:








Yeah, those are sewing needles.







Phase Two: The Handset



Best iPhone headset ever.

Phase Three: The Computer










Phase Four: The Switch Hook







5v ? ? BCM 3 BCM 2 ? BCM 6 BCM 16


Well, no. Not so much.









    import RPi.GPIO as GPIO
    import time
    import sys
    pin = 12

    GPIO.setmode (GPIO.BCM)
    GPIO.setup (pin, GPIO.IN, pull_up_down = GPIO.PUD_UP)

    while True:
      state = GPIO.input (pin)
      if state != last:
        if state == True:
          print ('CLOSED')
          print ('OPEN')
        last = state


    use Time::HiRes qw (sleep time);
    use Device::BCM2835;

    my $last = -1;
    while (1) {
      if ($state != $last) {
        $state = $last;
      sleep (0.1);


    #include <stdio.h>
    #include <bcm2835.h>

    #define PIN RPI_GPIO_P1_12

    int main (int argc, char **argv) {
      uint8_t last = ~0;
      if (!bcm2835_init()) return 1;
      bcm2835_gpio_fsel (PIN, BCM2835_GPIO_FSEL_INPT);
      bcm2835_gpio_set_pud (PIN, BCM2835_GPIO_PUD_UP);

      while (1) {
        uint8_t value = bcm2835_gpio_lev (PIN);
        if (value != last)
        last = value;
        delay (100);
      return 0;






Phase Five: Profit



In conclusion, Hack the Planet.

Post Script: 2018









It has amassed quite a nice collection of stickers, though!

Planet, Hacking Thereof:




Tags: , , , , , ,

65 Responses:

  1. Eddie says:

    Everything about this is spectacular.

  2. Joshka says:

    Sweet hack! You mentioned that the keypad sends audio. Did you consider using audio tones as a possible interface rather than the usb? Would be neat to be able to box the phone :)

    • jwz says:

      Thought about it, but getting realtime analysis of an audio stream sounded like exactly the sort of crap that ALSA would make impossible. (The "A" is for "Advanced", you know.) And if not "impossible" them certainly "exactly the kind of Linux crap I hate most."

      Also I never got as far as figuring out how to actually energize and read that board, which also sounded (at the time) like more work than what I did. Which may have turned out to be wrong, given how hard what I did turned out to be.

      • Aaron says:

        You probably made the right call; analyzing audio is complicated even when you don't have to find a way to get ALSA to turn it from analog signal into data. I'm still trying to find a way to do it reliably so I can write real functional tests around the SAME encoder I wrote for shits and grins.

        • Gabriel says:

          Dude! I was looking for a SAME encoder the other day! You wouldn't happen to be willing to share, would you?

          • Aaron says:

            Sure! It's on Github at aaron-em/same-encoder.

            Do note, it's written in Javascript; that said, it works both in Node (probably io.js as well, though haven't tried it) and in the browser, so you can use it in whichever of those ways suits you best. And, of course, as I already mentioned, there are no functional tests yet, because I haven't been able to find or write a decoder which I can build them around. As far as I can tell, it produces correct output, but I have as yet no way to prove that with certainty to myself or anyone else.

            With those caveats aside, of course you're more than welcome to it! If you find any bugs or see any opportunity for improvement, please oblige me by opening Github issues or pull requests. Thanks!

      • Jered says:

        I sincerely hope this is a reference to:

      • Tim says:

        Multimon-ng does DTMF decoding in real-time and can be piped to and from in shell.

        You can use sox to pipe the input audio to multimon. It also supports other encoding schemes so you could do some cool tricks to access/input some other features (Morse replay from smart phone? ;))

      • Jonathan says:

        "These days" Linux users are under the reign of terror of "Pulseaudio", and ALSA has been promoted in stature to fond, wistful memories of when things "just worked... slightly more."

        • gryazi says:

          It's Pulse on top of ALSA.

          • Jonathan says:

            I elided that because it wasn't relevant for my point: PA on top of ALSA still makes me pine for the "just ALSA" days; forgetting what exactly they were like.

            • ssl-3 says:

              I remember trying to use Pulse on purpose one time, trying to get networked audio to function between machines. With 4front's paid-for OSS drivers, and ALSA as a[nother] middle layer.

              Looking back, I may have had some masochistic tendencies in my youth.

              I pine for the days before universally-integrated AC'97 CODECs, when I could just pay 4front to make things work for me, and the sound card (if I chose carefully!) would do any required mixing in hardware.

              Also, more generally: I miss hardware that actually did stuff, including printers that inherently knew how to print words on paper.

              • jwz says:

                Come on, though, printers have always been awful.

                • ssl-3 says:

                  But they've gotten far, far worse.

                  (though admittedly, I've never written a VHS tape labeling system entirely in PostScript. So perhaps my hate is tempered differently.)

                  (I also keep 30-year-old TI thermal teletype around for posterity, though none of my machines currently have a serial port with which to operate it, and I tossed my expensive external Supra v.32bis modem over a decade ago. Not that it would have anyone to talk to, or a landline to plug into.)

                  (Ah, fuck. Is this what getting old is actually like? I thought it was supposed to be all titties and beer by now.)

                  • jwz says:

                    Dude you are talking to someone who is currently sitting on the floor of a filthy office wondering whether this cheap assed POE dingus scorched my Pi when titties and beer are happening literally on the other side of the door. So I dunno.

                    Thank you for making me realize the error of my ways, however.

                  • jwz says:

                    Exhibit A (titties, beer, not pictured; fully implied.)

                  • ChrisB says:

                    Technically ass not titties, although they're also fully implied.

  3. Mariachi says:

    Any reason not to, instead of converting it to USB, leave the original keypad hardware intact, use the original DTMF generator, have the Pi listen for tones on the audio card’s mic in, and recognize the waveforms? Or would that be more processing than it could handle?

  4. Photar says:

    One of your keypad layouts has two number 4 keys.

  5. Christian Vogel says:

    Congrats on your finished project, I can feel your pain from reading your writeup! I know that giving advice after the fact sounds cocky, but in case anyone wants to recreate your payphone, please....

    For Audio: Don't buy any of these overpriced "audio shields", just cut off the headphone part from an old USB headset and reuse the usb soundcard molded either into the USB plug or that small blob between the USB plug and the headphone part. It will just work out of the box on your PC, Mac, Raspberry-Pi, Beagle-Bone...

    Switch-Hook: This python library is a very ugly hack and started out as the only thing working when no kernel-drivers existed for the gpio yet. But people never stopped using this idiotic thing, even now the "slow but proper" way works beautifully from every programming language or shell script: Also it doesn't require root (for poking directly into the hardware, which is a pretty insane idea anyway) once you've chmod'ed the files. And it will be fast enough for your hook detection in any case.

    Keypad: If you redo it, just invest the saved time from not having to deal with the crap mentioned above in doing the keyboard scanning yourself ;-) using the freed GPIOs you no longer have to waste on the audio shield.

    • Nate says:

      I concur with all the above.

    • James says:

      Can sysfs be added without recompiling the kernel?

      • crtxc says:

        Why would you want to add sysfs? Why would he need a pseudo file system.

        I wouldn't want to do that if I didn't have to, especially if I were surrounded by grinning conssies looking for ideas to steal; or to paraphrase JWZ "tail lights to chase"

        • James says:

          What are conssies?

          I was simply trying to identify how long it took between jwz mentioning Linux and someone else suggesting kernel recompilation.

  6. The bit about the audio card is insane. Note I understand why do many people hook an Arduino up to their RasbPi via serial if they want to do i/o.

  7. phuzz says:

    I was wondering, can you get a USB sound card that would work with the pi?

    • Adam says:

      That's how I have audio working on my Raspberry Pi. Without compiling any kernel modules.

  8. Cody says:

    Awesome, so awesome. Wish I could listen to the messages.

  9. Aaron says:

    You recompiled your kernel to make your audio card work! Now that's getting into the spirit of the thing. I mean, most people will probably just dress up for the party or something.

  10. nwf says:

    Next Time Around (TM), you may find it easier to use a SIP adapter and VoIP software, rather than banging the audio and keyboard yourself. The adapters are nice in that they are (shitty) sound cards with DTMF decoding built in.

    I do not know for sure, but I expect the phone keypad to want to sit between the mic and the phone line without much in the way of external components.

    • Tim says:

      Yeah, a cheap ata with an fxo port might have done it. You could just wire a rj11 on to the line cord and run asterisk on the rpi2.

  11. frymaster says:

    One alternative I've found to suid C wrappers around scripts is using sudo, allow passwordless root invocation of that specific script only

  12. Lee says:

    Suck it up and go with Python.

    • MattyJ says:

      After reading this blog for the better part of a decade, I've concluded that JWZ is not one who sucks it up, in any manner.

  13. Gushi says:

    Perhaps build a web version of this so other folks can hear the audio files?

  14. Cyranix0r says:

    This is awesome, you're my hero.

  15. I'm horrified at how you did it, but I'm super impressed that you did it at all. My pay phone is still standard. It's fun when it rings, but...

    Anyway, here's a couple things that you could have done and might consider for version 2:

    A ringdown box makes the phone call a specific number when it goes off-hook. These are how you make inmate phones and security phones. They, and everything like this, cost way too much. But if you're insane, you can hook one up to an Asterisk box and get a full interactive voice response system. You can still run Asterisk on RasPi. However, you trade configuring ALSA with configuring Asterisk, and I don't think that's an improvement...

    I would have used a USB audio card instead of the shield. This one in particular is really cheap and works really well. You're still having to mess with ALSA, though... and now you've got the problem of ALSA and multiple audio cards. Fun. But you've got all your GPIO back!

    But the easiest option might be Adafruit's Audio FX boards. They turn a button press into a playing wav/mp3 file. That's it. They're perfect for something like this! Except now you've got to load it with new audio files once a week...

    • ssl-3 says:

      I'm puzzled why you would want a fancy ring-generator "ringdown box," when you could just use an FXS port (which is already designed to talk to a telephone) instead of an FXO and do the rest in software.

  16. Jorgen says:

    Hey! This got posted to Hacker News, but following the link from there seems to intermittently trigger the hotlinking warning.

    • jwz says:

      Hacker News is a steaming cesspool and I don't have time or desire to deal with their bandwidth demands, so I just block them.

  17. pir says:

    What I tend to do with the RPi rather than using the built in IO ports (which are 3.3V, very limited in current, wired directly into the chip so easy to fry and as you note only accessible by root) I use an expansion board that breaks out i2c to IO ports that can be 5V, easy to replace if you fry them and i2c IO can be done as a non-root user (there are sample libraries for Python and C at least, don't know about perl). This also leaves the non-i2c pins available for whatever other cards you may be using.

    I use this one from a small UK manufacturer, I'm sure there are similar ones more easily available in the US:

    Or you can build one:

    (one of the advantage I always found with Python over perl was other people can't screw up indentation).

  18. Drew Roos says:

    Please tell me there's an easter egg if you play a 2600Hz tone into the mic.

    And for the love of god get a USB sound card and free up all those pins.

  19. Chris Davies says:

    It seems a shame not to hook up the coin detector. Couldn't you just multiplex it over the same pin you used for the hook switch? Build a little board to feed it 3 frequencies of square wave and no signal for your 4 states.

  20. Angus says:

    I think I can explain the GPIO thing. There are two[*] GPIO numbering schemes in use on the Pi. There's the actual pin numbers on the Pi's 40-pin "P1" connector header, and there are the GPIO numbers as used by the Broadcom system-on-chip.

    In the Python code, GPIO.setmode(GPIO.BCM) tells the library to use raw Broadcom numbering. So you get GPIO 12. However in the other code RPI_GPIO_P1_12 is "sugar" for pin number 12 on the "P1" connector, so you get a different GPIO (I think 18).


    According to the enum definition elsewhere on that second page, RPI_V2_GPIO_P1_32 = 12.

    (Yay embedded systems?)

    [*] I think one of the other Python libraries actually invented a third incompatible pin numbering scheme.

    • jwz says:

      Oh holy crap, you're right! Changing it to 32 in the C code makes it work!

      • Angus says:

        Good to hear!

        I realised that might explain the other "EXP" pins on the audio breakout not working as well. The GPIO/pin mapping changed between RPi 1 & RPi 2, so if the numbers on the audio breakout are Broadcom GPIO numbers for RPi 1, they'll probably need translating to the equivalent GPIOs for RPi 2.

        PS I noticed a typo in the update - s/BCP/BCM/. Normally I wouldn't be pedantic about typos but I know people will find this blog post in the future while having this exact problem, and will go off looking for the meaning of BCP.

        • jwz says:

          Unfortunately, no, it doesn't explain that. Pins that worked while the audio card was detached failed to work while it was attached, and I determined which pins were "the same" by continuity, not by number.

  21. Scott Cheloha says:


    History doesn't repeat itself, but it sure does rhyme ;)

  22. vince says:

    I am happy/disappointed that you managed to use a version of Raspbian old enough to not involve systemd. I fear there might have been few survivors otherwise.

  23. jwz says:

    Of course, Limor did it better ages ago. Hers is red-boxable!

  24. jwz says:

    Maybe I should implement T9. Though without a display, that might be tricky.

    Now I'm regretting that I didn't get a payphone with a rotary dial instead.

    And implemented T9 on that.

    • Louis says:

      You could have audio responses to the button presses. After each quick button press the letter of the alphabet would be pronounced (Pressing 222 would make the phone say "abc", and if the user waits, there would be a beep to signal that the system is ready for the next character. You'd need a backspace, and "read input until now" button though.

  25. James says:

    The Link says the 29th, not the 22nd.

  26. Russ says:

    Rather than spending all the time making a connector, I would have just exopied some 0.1" header to the USB board, and then used wires to connect it up directly to the SOIC. That chip has quite a bit wider pitch than the header and would be pretty easy to solder up. Either that or desolder the connector and solder directly to the lands.

    • jwz says:

      I think you're saying, "the pin spacing on the chip might have been the same as the spacing of the pins on a header"? I don't have it in front of me, but from looking at the photo, I think the chip's spacing was tighter than that. Almost half, maybe.

      Trying to solder directly onto the round contacts on the board next to the socket was not possible, certainly not with the equipment I have. I would have gotten the solder on more than one contact and probably ended up delaminating the board trying to fix it.

  27. Ted says:

    All you had to do is use BOARD rather then BCM,
    now it matches with the Pin Number as a Pin Number!

  28. void says:

    In the python code you forgot to initialize the variable 'last'

    while True:
    state = GPIO.input (pin)
    if state != last:
    if state == True:
    print ('CLOSED')
    print ('OPEN')
    last = state

    In the perl code you swapped the two variables:,
    $state = $last; should be $last = $state;

    my $last = -1;
    while (1) {
    if ($state != $last) {
    $state = $last;

  29. Steve says:

    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.

    I'm totally with you.

    The only thing that's tempting me is that I have to worry about my whitespace in perl anyway, just purely for aesthetic reasons. I'm always indented, reindenting, etc. So, I figure I can cope with python deriving some meaning from beautification. I haven't taken the python plunge yet but this is the strategy I'm planning to make my brain use.