Build your own PABX and Modem emulator


Okay, I'll admit it, I have a thing for Viewdata terminals - be they Prestel, Minitel or even Bildschirmtext! But these little machines are only fun if they have something to dial into. There are some online Viewdata services accesible via Telnet (more of these later), so what I needed was something that could be dialled into and redirect this call over the internet. I wanted to avoid real modems (fun as they are) and real phone lines (I don't even have one!) and build something simple I could take to events and not be hunting for a landline.

So this is my solution to that problem. There may be easier ways of doing some of this. My Linux skills are a bit old school (I haven't really moved on from BSD4.3), so if there's more modern ways of doing things, let me know. Enough preamble, on with the show ...

The Hardware

The Server

I'm using a Raspberry Pi 3+. I guess this would work with any Linux system. I just wanted something small and inexpensive I could dedicate to the task. It's running Raspbian 10.

The Analogue Telephone Adaptor (ATA)

Probably the most common ATA out there is the Linksys PAP2T, designed for VOIP applications. They seem to sell for around £20 on eBay. It works perfectly but only supports tone dialling (DTMF). Some of my terminals require the older pulse dialling, and ATAs that support that are rarer. I'm using a Grandstream HT502, which offers me both types of dialling. These instructions will cover the HT502, but I'll try and remember to point out what to do on a Linksys as well.

You can find a lot more info on pulse dialling ATAs here at the Classic Rotary Phones Forum and info about the Vonage issues.

Bits and Bobs

A real telephone can come in handy for debugging things and talking to the ATA when you can't access it from the computer.

An RJ11 to BT phone socket convertor. Always useful!

Putting it all together

the kit

Connecting up the ATA

Both the Grandstream and the Linksys have an ethernet port and support DHCP. This means you could just plug them into your nearby hub. But you might not have a nearby hub. Or, like me, you might be trying to build a simple, portable solution for shows. For this reason, I'm using the ethernet port on the Pi itself to connect to, and installing a DHCP server on the Pi.

If you're not using a Pi, or have a nearby hub, you can skip this stage. I guess you don't need to run DHCP on the Pi - you could just give the ATA a fixed address. I chose this route because it meant I could plug in different ATAs (and, potentially, multiple ATAs) and not worry about their IP addresses. It also meant I could assign a fixed address to the Pi's ethernet port (making ATA configuration easier), rather than try and work out the address if it's on someone else's network. Finally, it means that at a show I just need to connect the Pi to their WiFi and it should all work. Hopefully.

The Software

Installing DNSMASQ on the PI

Install Lynx. You don't have to, but having a web browser you can run over an xterm/ssh/dumb terminal will save you one day, I promise you.

$ sudo apt-get install lynx

Install DNSMASQ. This will control your DHCP. It can do a zillion other things too, but you can explore that at your leisure, it's not needed for this.

$ sudo apt-get install dnsmasq

Uncomment line 44 of dhcpcd.conf. This sets the IP address of the Pi's ethernet port.

$ sudo vi /etc/dhcpcd.conf

Set up a DHCP range for the rack of ATAs you might be connecting in the future :)

$ sudo vi /etc/dnsmasq.conf

Uncomment line 157:

Uncomment line 180 and add wlan0 - this stops the Pi from trying to answer DHCP requests it sees on the WiFi network

And now start it all up

$ sudo service dhcpcd restart
$ sudo systemctl start dnsmasq

Configuring the ATA

These instructions are for the Grandstream. I'll talk about the Linksys later. First off, power up the Grandstream, not plugged into anything (but power!). Now find your telephone, plug it into the first socket and ring this number *** 01. Hopefully a disembodied voice will say "dynamic IP mode", meaning you're all set for DHCP. If it's "static IP mode" use 9 to toggle it.

Okay, now we can plug the Grandstream into the Pi. Count to twenty while they talk to each other and hopefully the Grandstream now has an IP address - ring *** 02 to find it out. Hopefully it will be an IP in the range we set up earlier. Currently I have

Now we need to switch on the web interface. Ring *** 12 9 to turn it on. Now point your web browser (or Lynx if you're feeling brave) at (or whatever IP address you got). I note that Lynx works fine on the Grandstream pages.

At the login page, the password is admin.

the kit

Select FXS PORT1 - this is the menu for the first phone socket config. Make sure the account is active. Enter the IP address of the PI ( if you've been following these instructions verbatim) into Primary SIP Server. Enter anything you want into SIP User ID. I'm only using pap2t-client because that's what was in an example Linksys config. Keep a note of what you've entered here.

Finally, enter the password in 'Authenticate Password' - the password is the rather secure password. If this truly offends you, you can change it later when you edit sip.conf. Note that after you've entered this, it doesn't show you that you've entered a password. It took me a long time to realise I had previously entered a password in here.

Now scroll to the very end and Update, Apply and Reboot.

Setting up Asterisk

We're going to use v13 of Asterisk here. I think it's currently up to version 18, but this is the latest version that I can make run the modem simulator. You'll also need the Spandsp library and the soft modem. And possibly a whole bunch of other stuff I'm getting just to be on the safe side

$ sudo apt-get install build-essential libsqlite3-dev libxml2-dev libncurses5-dev libncursesw5-dev libmariadb-dev-compat libmariadb-dev libiksemel-dev libssl-dev libnewt-dev libusb-dev libeditline-dev libedit-dev curl libcurl4-gnutls-dev libjansson-dev uuid-dev
$ sudo apt-get install libspandsp-dev
$ git clone -b 13 asterisk-13
$ git clone

Now you're ready to build Asterisk:

$ cd asterisk-13
$ ./configure

checking build system type... armv7l-unknown-linux-gnueabihf
checking host system type... armv7l-unknown-linux-gnueabihf

$ make

make[1]: Entering directory '/home/pi/asterisk-13'
rm -f defaults.h

$ sudo make install

CC="cc" CXX="g++" LD="" AR="" RANLIB="" CFLAGS="" LDFLAGS="" make -C menuselect CONFIGURE_SILENT="--silent" makeopts
make[1]: Entering directory '/home/pi/asterisk-13/menuselect'

$ sudo make samples

Installing adsi config files...
/usr/bin/install -c -d "/etc/asterisk"

Hopefully it's all built correctly, and you're not swearing at me because I've missed out a dependancy somewhere. Now we need to configure Asterisk to listen out for a SIP connection from the Grandstream. SIP stands for "Session Initiation Protocol" and is used to set up the communiction with the ATA.

$ sudo vi /etc/asterisk/sip.conf

I've dropped this code in at the end:

The name in brackets must be the same as the name used in the Grandstream configuration.

Now for the fun bit, let's get it to actually answer the phone and do something. This slots into the [default] section of the extensions.conf file.

$ sudo vi /etc/asterisk/extensions.conf

Find the section for [default] on line 665 and comment out the include => demo and append with this:

So now the modem will answer on phone numbers 618 and 918, the numbers originally used by Prestel back in the 80s - but you won't be charged 50p a minute!

Now, you must be itching to see if it's all worked. Startup asterisk and connect to it with the asterisk client in debug mode.

$ sudo /usr/sbin/safe_asterisk
$ sudo asterisk -rvvvvv

Connected to Asterisk GIT-13-13.15.0-rc1-2819-g34ca632b1a currently running on newpi (pid = 7024)
-- Registered SIP 'pap2t-client' at
> Saved useragent "Grandstream HT-502 V1.2A chip V2.2" for peer pap2t-client
[Feb 8 17:23:54] NOTICE[7055]: chan_sip.c:24779 handle_response_peerpoke: Peer 'pap2t-client' is now Reachable. (12ms / 200ms)

If the gods are smiling on you, you should get a message that looks like the above. You can double check its working like this:

newpi*CLI> sip show peers
Name/username Host Dyn Forcerport Comedia ACL Port Status Description
pap2t-client/pap2t-client D No No 5060 OK (12 ms)
1 sip peers [Monitored: 1 online, 0 offline Unmonitored: 0 online, 0 offline]

Okay, now it's time to test it. Plug the phone in and dial 618 and you should hear the tone of a V23 modem pick up. It works!

Now, find your nearest Prestel terminal, plug it in, ring the same number and hopefully you'll connect with some debug info that looks like this:

== Using SIP RTP CoS mark 5
> 0x7400d608 -- Strict RTP learning after remote address set to:
-- Executing [618@default:1] Answer("SIP/pap2t-client-00000001", "") in new stack
> 0x7400d608 -- Strict RTP switching to RTP target address as source
-- Executing [618@default:2] Softmodem("SIP/pap2t-client-00000001", ", 6502, v(V23)ld(8)s(1)") in new stack
> 0x7400d608 -- Strict RTP learning complete - Locking on source address

If you've successfully connected to Telstar, hit any key and you should be presented with the Telstar welcome screen.

the kit

Tidying up and other notes

Getting Asterisk to start on a reboot

I've discovered that things have moved on from my BSD days. This method appears to work. Other methods may work too!

Copy the example config file to init.d:

$ sudo cp asterisk-13/contrib/init.d/rc.debian.asterisk /etc/init.d/asterisk

Now change the config settings to match how we've installed it.

$ sudo vi /etc/init.d/asterisk

Change line 23 onwards:

And finally make the system aware of the changes:

$ update-rc.d asterisk defaults

Configuring other dial-in services

Let's look again at an example config:

618 is the phone number - of course, it can be any phone number you want. Do you have something with a hardwired phone number? Then simply set it to that. Not sure what that phone number is? Then just let it dial and watch the Asterisk logs. You'll get something like this:

[Feb 8 21:37:49] NOTICE[840][C-00000000]: chan_sip.c:26602 handle_request_invite: Call from 'pap2t-client' ( to extension '018118055' rejected because extension not found in context 'default'.

Now you can set up something to answer on 01 811 8055.

The important function is Softmodem(, 6502, v(V23)ld(8)s(1)). is the name of the server running the service and the port number is 6502. There are a number of other fun services out there:, 6502: This is Teefax, a service similar to Telstar but feels more like the old teletext systems like Ceefax. The page cycling can upset some Viewdata terminals., 23: This a strange and mysterious service. You'll need to register. See for more (or less) details.

(Not very) frequently asked questions

Will the soft modem support other speeds?

Well, the README says. We're using v23 (1200/75) here, but it should do everything from 300 (V21) to 2400 baud (V22bis). But so far, I've not tried. If you try and it works (or doesn't work), let me know!

Will this work with other services, or just Viewdata?

I've had it working with Minitel, kinda (hard to find Minitel services to telnet into). But it should work with any online service you can telnet into - although watch out for my hack to make it use 7 bit even parity.

Can you run two connections at once?

Well, in theory, the Pi should be up to this, but I'm having problems. I've set up the FXS PORT2 on the Grandstream with both the same username and a different username, and I get the same problem. I can dial in from either port, or both ports simultaneously. But if both machines are receiving data at the same time, the data is corrupt. This will take some digging.

I'd like to fix this, because I'd like to have multiple machines running at shows and I don't want to have to dedicate a Pi and an ATA to each. I haven't tried using multiple ATAs on one machine. Again, I can't see why it won't work, but I do wonder if the corruption is happening inside the soft modem - perhaps two running instances interfere with each other. Watch this space for updates.