Receiving and storing pager messages

Pager

I was reading on a forum recently about a guy that was boasting he had a private database containing pager messages dating back decades. A lot of people were asking him about his setup and why he bothered getting into this. Unfortunately, he was being quite secretive and not giving much away. I hoard lots of data but hoarding pager messages is something that never really interested me. Why would you care to save messages that were nothing to do with you? Regardless, I read into the subject a little and decided to see what it would take to put a similar system together.

I’m going to go to great pains to make sure I don’t accidentally receive any private message not intended for me. Depending on where you live, you could get in legal trouble for intercepting a radio transmission not intended for you. If you’re in the UK, for example, have a good read of this before even setting up your radio equipment: https://www.legislation.gov.uk/ukpga/2006/36/section/48

What are pagers?

For the benefit of my younger readers, I’m going to go back to basics and explain what pagers are. If you find this condescending then I apologise, please skip ahead. I honestly just have no idea if people still know what pagers are.

Pagers are small battery-operated devices, capable of receiving a phone number or short message and displaying it on a small LCD display. They were the precursor in some regards to the mobile phone and they were insanely popular in the 80’s and 90’s. Usually, the person sending the message would dial the phone number associated with the pager. The phone call wouldn’t be answered by the pager, but would instead be picked up by an operator working in a call centre. The caller would dictate their message to the operator and hang up. The operator would then type the message out and click send.

From there the message would be transmitted out into the ether from broadcasting towers scattered across the land. The receiving pager would be constantly monitoring the airwaves, receiving thousands of messages, waiting for one of the messages to be addressed to it. On receiving a message with its own address/number the pager would beep (hence why pagers are sometimes called beepers or bleepers) and display the message on its screen. Earlier iterations of the pager didn’t allow the caller to leave a message, only a number they wished to be reached on. On receiving the caller’s number on their pager, the pager owner would then need to find a phone to call them back.

Are pagers still used?

This is a good question, and I wasn’t sure myself at first and had to read into the matter a little. You would imaging that with the explosion of mobile phones over recent decades that the pager would have died out. To be fair, it largely has and in the UK, the majority of the larger network operators (e.g. Vodafone) have now retired their pager infrastructure.

There are still some users, however. Because pagers only receive and not transmit, they are still popular in certain environments. For example, in certain areas of hospitals where mobile phones are not allowed, due to their radio transmissions affecting medical equipment, doctors often still use pagers to receive urgent messages. Privacy-focused billionaires are also said to rely on pagers due to their, receive-only nature. When a message is sent to a pager, the message is broadcast across the whole country, because nobody knows whereabouts the pager is or even if it’s switched on. Similarly, there’s no way to be sure whether the message was even received. Unlike mobile phone communications, pager communications are strictly one-way.

What is POCSAG and can it be decoded?

POCSAG is the main protocol used to transmit messages from the network operators to pagers over the airways. It’s an acronym that stands for Post Office Code Standardisation Advisory Group, referring to the group that designed the protocol way back in the early 1980’s. In case you’re wondering, “Post Office” refers to the British post office or “GPO”. They had responsibility for all telecommunications before matters were privitised/before BT came along.

The POCSAG protocol is fairly simple to understand, especially if you’re used to more modern communication protocols used today with radio and the Internet. There’s a Wikipedia article about POCSAG here, although, for the purposes of this post, we don’t need to worry about the intricacies too much.

As for whether or not POCSAG can be decoded, I’m sure you’ve guessed that the answer is yes. Not only is the protocol easy to understand, but it also dates back to a period where privacy and security weren’t at the forefront of everyone’s minds. POCSAG is not encrypted, perhaps this was due to the overhead involved in the encryption/decryption process on relatively low-powered devices but I suspect it was just not deemed necessary. Who would be mad enough to try to intercept some mundane messages intended for someone else, right?

How to pick up POCSAG pager signals?

Before we can use a computer to decode POCSAG, we first need to be able to receive the signal over the air and pass it to the computer. There are a couple of ways to achieve this. Firstly, you could use a standard radio scanner, and pass the audio from the scanner to the computer’s sound card. This can be a bit tricky and really, you would want to use a radio scanner capable of outputting the “discriminator” signal (i.e. the radio signal before it’s processed by the audio circuitry).

The second option would be to use an “RTL-SDR” USB dongle device. This is the option I am going with.

What is an RTL-SDR dongle?

When talking about RTL-SDR dongles, we’re usually referring to USB sticks that were originally designed to pick up DVB-T TV signals (e.g. Freeview in the UK). The “RTL” part refers to the chipset that these devices use (Realtek RTL2832) and the “SDR” is an acronym for Software Defined Radio.

Basically, these devices were intended to allow you to watch/record TV on your computer. Some clever people however realised early on that you could replace the software driver on the computer and it would allow these devices to pick up a lot more than just digital TV. In fact, the devices can pick up a huge portion of the RF spectrum, allowing you to receive FM broadcasts, amateur/ham radio. aircraft and of course pager signals!

I won’t get into the specifics but this is possible because we can use the computer to replace many of the components that would typically need to exist in a traditional radio. They are “Software-defined” because the software on our computers is doing the heavy lifting, processing the signals passed to it by the dongle.

In case I didn’t mention it, these devices are extremely cheap to buy. They cost much less than a decent radio or scanner.

Receiving and decoding POCSAG pager messages using the RTL-SDR

This is going to be a two-step process. Before we can decode the POCSAG signal, we of course first need to receive it. Don’t worry, this is very straightforward as some clever people have kindly developed all the software we need.

Step 1 – Receving the POCSAG signal with SDRSharp

I’m not going to write a whole tutorial on setting up the RTL SDR dongle and installing SDRSharp, etc. There are plenty of well-written guides out there. Instead, I’m just going to go over the high-level steps and leave you to research each one if necessary.

Connect your RTL-SDR Dongle and install the “Zadig” driver.

This will allow your RTL-SDR to receive signals other than just digital TV (DVB-T).

Install SDR Sharp

SDR Sharp is the software that lets you use the dongle as a radio. It’s the “brains of the operation” if you will. The software takes the raw signals from the SDR dongle, and interprets them in software rather than requiring traditional radio hardware.

Step 2 – Decoding the received POCSAG audio with PDW

Install PDW software

PDW is a piece of software that listens to the POCSAG audio tones and decodes them to text. At the time of writing, the latest version of PDW is v3.12. PDW is free to use and as well and POCSAG, it can also decode another pager protocol known as “Flex”

Install VB Virtual Cable software

Back in the day, when the likes of PDW were first released, you would connect the output from your scanner (e.g. the headphone jack) into your computer’s sound card (e.g. into the “Line In” or “Microphone” socket). The software would then wait for audio to be passed from the radio to the soundcard and attempt to decode it.

As you’re aware, we’re going to be using a software-defined radio rather than a traditional radio scanner, so we don’t have a physical audio output as such. Instead, we’re going to “route” the virtual audio output from SDR Sharp to PDW. We’ll do this by using the free “VB” software. We’ll set the audio output in SDR Sharp as the virtual cable and select the audio input in PDW to the same virtual cable.

It may sound a bit confusing but it’s actually fairly simple.

Tune SDR Sharp to a pager/POCSAG frequency

At this point, I need to remind you to check your local laws to make sure you’re not about to break any of them. To be safe, you should only be listening/decoding signals intended for you.

That said, tune the software to a frequency that’s currently broadcasting POCSAG signals. Make sure:

  • Your audio output is set to VB-Cable Input
  • Radio bandwidth is set to 25KHz
  • The audio output level is set to around 50dB (you can fine-tune this later to get the best decoding)
  • Finally, hit the “Play” button

At this point, after a few seconds, you should see in the waterfall display that some signals are being received. If you’ve set everything up correctly then you won’t be able to hear them over your speakers.

I’ve highlighted the important bits in the image below:

SDR Sharp receiving POCSAG pager signals using an RTL-SDR v3 device
SDR Sharp receiving POCSAG pager signals using an RTL-SDR v3 device

Now, you can launch the PDW software. This time, you want to go to “Options”, “Setup”, and set the soundcard to “Cable Output”. This means that SDR Sharp is passing its audio to PDW over the virtual cable:

The soundcard options in PDW
The soundcard options in PDW

At this point, if everything has gone to plan, you should find that the signal quality meter in the top right-hand corner of PDW is at or close to 100%. As SDR Sharp receives a POCSAG message, PDW will decode it and display its contents. The received messages will begin to fill the PDW window from the top down:

Decoded pager messages being displayed in PDW
Decoded pager messages being displayed in PDW

Storing the decoded pager messages

So far, we’ve covered receiving and decoding the messages. This proves that the pager message hoarding guy on the forum could well be telling the truth about having a private collection of historic messages. He stated however that he had them all stored in an easily searchable database.

This sounds like it would be fairly trivial to achieve for anyone with some programming/database knowledge, so let’s put together a simple proof of concept.

Extracting the pager messages from PDW

First things first. Before we can store the messages in a database, we need a way to extract them from PDW. If you were looking for a truly professional POCSAG-hoarding set up then you would probably want to code a system from the ground up. You would design something that would take the POCSAG signal, decode it internally and then commit it to a database.

As I said, this is just a proof of concept so we’re not going to all that trouble, hence why we’re using PDW to do the hard work.

Fortunately, if we go to “Options”, “General” from within PDW, we’ll find that the developer has kindly included a system to log received messages to text file:

Log file options within the PDW software
Log file options within the PDW software

So, in theory, all we would need to do to store the messages is parse the log files, and import their contents into a SQL database.

The format of the logfiles does seem a little odd. It appears the actual message always starts at character column 50, yet the preceding data doesn’t seem to have a consistent character offset. Instead, each field appears to be delimited by a varying number of spaces.

This isn’t really an issue, we can tweak these values easily enough in code. For this proof of concept, I’ve quickly thrown together some PHP code to read the log files, import them into a SQL database, and then move the processed log files to another folder. In theory, you would just need to periodically run the script to keep the database up to date with all your received pager messages.

This is just a proof of concept. In production use, you would want to tidy up this code, introduce error handling, and some sanity checking. If you do decide to use this yourself, please bear this in mind.

You would likely want to store values such as “msgEnc” and “msgType” in your database as integer, with a lookup-table, rather than just text:

<?php
include './db.php';
$logsDir = 'c:\temp\pdwlogs';
$logFiles = scandir($logsDir);

$db = new db();

# Process each file found by scandir
foreach ($logFiles as $logFile) {
    # Only work on files with the .log extension. This stops us trying to accidently work on ".", "..", "processed", etc.
    if (substr($logFile, - 4) == '.log') {
        print "Processing $logFile";
        $handle = @fopen($logsDir . '\\' . $logFile, "r");
        if ($handle) {
            while (($buffer = fgets($handle, 4096)) !== false) {
                $buffer = trim($buffer);
                if (strlen($buffer) > 0) {
                    $metaData = substr($buffer, 0, 49);
                    $msgText = substr($buffer, 49);

                    # Replace all consecutive spaces within the header/meta data with a single space.
                    $count = - 1;
                    while ($count != 0) {
                        $metaData = str_replace('  ', ' ', $metaData, $count);
                    }

                    # Create an array containing the metadata, delimited with a space
                    $metaData = explode(' ', $metaData);

                    $pagerID = $metaData[0];
                    $msgTime = $metaData[1];
                    $msgDate = $metaData[2];
                    $msgEnc = $metaData[3];
                    $msgType = $metaData[4];
                    $msgBaud = $metaData[5];

                    print "Pager ID: $pagerID" . PHP_EOL;
                    print "Time: $msgTime" . PHP_EOL;
                    print "Date: $msgDate" . PHP_EOL;
                    print "Encoding: $msgEnc" . PHP_EOL;
                    print "Type: $msgType" . PHP_EOL;
                    print "Baud Rate: $msgBaud" . PHP_EOL;
                    print "Message: $msgText" . PHP_EOL . PHP_EOL;

                    # Convert the date into international format ready for MySQL
                    $msgDate = explode('-', $msgDate);
                    $msgDate[2] = $msgDate[2] + 2000;
                    $msgDate = $msgDate[2] . '/' . $msgDate[1] . '/' . $msgDate[0];

                    # Replace single quotes in the pager message with an escaped single quote. It would be a good idea to do some other cleanup here in case of a SQL injection attempt.
                    $msgText = str_replace('\'', '\\\'', $msgText);
                    $sql = "INSERT INTO `pocsag`.`2021` (`pagerID`, `msgTime`, `msgDate`, `msgEnc`, `msgType`, `msgBaud`, `msgText`) VALUES (" . $pagerID . ",'" . $msgTime . "','" . $msgDate . "','" . $msgEnc . "','" . $msgType . "','" . $msgBaud . "','" . $msgText . "')";
                    $db->query($sql);
                }
            }
            if (! feof($handle)) {
                echo "Error whilst reading log file $logFile\r\n";
            }
            fclose($handle);
            # Move the log file to the "processed" sub-directory
            rename($logsDir . '\\' . $logFile, $logsDir . '\processed\\' . $logFile);
        }
    }
}
?>

After running the above code, I can see that my MySQL database is now populated as expected:

Decoded POCSAG pager messages commited to the MySQL database
Decoded POCSAG pager messages commited to the MySQL database

From here, it is trivial to put together a front end interface with a bit of backend code to allow you to perform queries on historic data. Please excuse my 1990’s web design habits:

The final Proof of Concept. Historic pager messages could be stored and easily searched.
The final Proof of Concept. Historic pager messages could be stored and easily searched.

Summary

We’ve shown that it’s fairly easy to receive pager signals using a cheap off-the-shelf SDR dongle. We’ve then piped these signals to a POCSAG decoder (PDW), using a free “virtual sound cable” piece of software (VB-Cable).

From there we’ve shown that it would be trivial to transfer the decoded pager messages to an easily searchable database for long-term storage. Why anyone would want to do this is beyond me, but clearly, some people are interested in the topic.

Who knows, perhaps in years to come, terabytes of pager messages spanning decades might hold some historic significance and provide a snapshot of the past. If you’ve got some old pager messages stored away from the 80’s, 90’s or 2000’s then please get in touch. I’d love to hear your story.

One thing’s for sure, I won’t be sending any sensitive information over the pager networks again and I advise that you shouldn’t do either.

Leave a Comment