Click here to Skip to main content
15,881,844 members
Articles / Programming Languages / C++
Article

POCSAG Encoder

Rate me:
Please Sign up or sign in to vote.
4.65/5 (10 votes)
23 Feb 20068 min read 121.5K   4.7K   19   18
The article is about encoding a text message for pagers using POCSAG encoder.

Sample Image - POCSAG1.jpg

Introduction

We have available many communication technologies to communicate with each other. Every technology has its advantages and disadvantages. One of the popular technologies that has been used for many years, in many industries, is the pager. The pager uses a protocol named POCSAG or Post Office Code Standardization Advisory Group code. If you search Google for POCSAG Encoder/Decoder, you will find many devices from various companies. This article is an effort for doing the same task using only software code. For this purpose, I used my previous article, BCH 21,31, for implementing a BCH Error Correction Code that is part of the POCSAG protocol that we are going to see in the following sections.

I grabbed most of the information about the POCSAG protocol from Brad Dye's Paging Information Resource website. The website has many useful information for various wireless technologies including pager.

I also wrote the code for sending the encoded message to the end user using a special modem. The modem connects to the serial port of a computer and sends the message on the air through a transmitter.

POCSAG Protocol

A. General

The basic signaling pattern used in many pagers is a sequence of coded binary data using the Post Office Code Standardization Advisory Group (POCSAG) code. The POCSAG code is a synchronous paging format that allows pages to be transmitted in a single-batch structure. The POCSAG code provides improved battery-saving capability and an increased code capacity.

The POCSAG code format consists of a preamble and one or more batches of codewords. Each batch comprises a 32-bit frame synchronization code, and eight 64-bit address frames of two 32-bit addresses or idle codewords each. The frame synchronization code marks the start of the batch of codewords.

B. Preamble Structure

Figure 2 shows the signal format. As you see, the signal contains several codewords (Synchronization, Preamble, Address, Message, and Idle).

Signal Format

The preamble shown in Figure 2, consists of 576 bits of an alternating 101010 pattern transmitted at a bit rate of 512, 1200, or 2400 bps. The decoder uses the preamble both to determine if the data received is a POCSAG signal, and for synchronization with the stream of data. Every codeword has 32 bits, and contains several fields. The bits are a type of codeword (Address or Message), Address/Message body, Function bits, Parity check bits, and Even Parity bit. Figure 3 shows the concept. In following sections, we learn how to create the codewords.

Codeword Format

C. Batch Structure

A batch consists of a frame synchronization code followed by 8 frames of two address codewords per frames (16 address codewords per batch). In order to maintain the proper batch structure, each frame is filled with two address codewords, or two idle codewords, or two message codewords, or any appropriate combination of the three codeword types.

D. Frame Synchronization Code Structure

The frame synchronization (FS) code is a unique reserved word that is used to identify the beginning of each batch. The FS code comprises the 32 bits: 01111100110100100001010111011000 or simply 0x7CD215D8.

E. Address Codeword Structure

The structure of an address codeword is shown in Figure 4. An address codeword's first bit (bit 1) is always a zero. Bits 2 through 19 are the address bits. The pager looks at these bits to find its own unique address. Each POCSAG codeword is capable of providing address information for four different paging sources (address 1 through address 4). These addresses are determined by combinations of the values of bits 20 and 21 (the source identifier bits); these combinations are shown in Figure 4. Bits 22 through 31 are the parity check bits, and bit 32 is the even parity bit.

Address Codeword

The combination of the code plug's three pre-coded frame location bits and the address codeword's 18 address bits provides over two million different assignable codes. In this combination, the frame location bits are the least-significant bits, and the address bits are the most-significant bits.

F. Message Codeword Structure

The structure of a message codeword is shown in Figure 3. A message codeword always starts with a 1 in bit 1, and always follows directly after the address. Each message codeword replaces an address codeword in the batch.

G. Idle Codeword Structure

The idle codeword is a unique, reserved codeword used to take the place of an address in any frame that would not otherwise be filled with 64 bits. Thus, if a frame contains only an address, an idle codeword will be added to complete the 64-bit frame. The idle codeword comprises the 32 bits: 01111010100010011100000110010111, or simply 0x7A89C197.

POCSAG protocol in detail

POCSAG as defined in the standard (original POCSAG), is 512 bits per second direct FSK (not AFSK) of the carrier wave with +- 4.5 KHz shift (less deviation than that is used in some US systems). Data is NRZ coded, with the higher frequency representing 0 (space) and the lower one representing 1 (mark).

The basic unit of data in a POCSAG message is the codeword which is always a 32 bit long entity. The most significant bit of a codeword is transmitted first, followed immediately by the next most significant bit, and so forth. The data is NRZ, so that mark and space values (plus and minus voltages) as sampled on the output of the receiver discriminator at a 512 Hz rate correspond directly to bits in the codeword starting with the MSB.

The first (MSB) bit of every POCSAG codeword (bit 31) indicates whether the codeword is an address codeword (pager address) (bit 31 = 0) or a message codeword (bit 31 = 1). The two codeword types have different internal structures.

Message codewords (bit 31 = 1) use the 20 bits starting at bit 30 (bit 30-11) as message data. Address codewords (bit 31 = 0) use 18 bits starting at bit 30 as address (bits 30-13) and bits 12 and 11 as function bits which indicate the type and format of the page. Bits 10 through 1 of both types of codewords are the bits of a BCH (31,21) block ECC code computed over the first 31 bits of the codeword, and bit 0 of both codeword types is an even parity bit.

The BCH ECC code used provides a 6 bit hamming distance between all valid codewords in the possible set (that is, every valid 32 bit codeword differs from every other one in at least 6 bits). This makes one or two bit error correction of codewords possible, and provides a robust error detection capability (very low chance of false pages). The generating polynomial for the (31,21) BCH code is x**10 + x**9 + x**8 + x**6 + x**5 + x**3 + 1. I suggest you to take a look at my other article BCH 21, 31 for detailed information.

Codewords are transmitted in groups of 16 (called batches), and each batch is preceded by a special 17th codeword which contains a fixed frame synchronization pattern. The magic word is 0x7CD215D8.

Batches of codewords in a transmission are preceded by a start of transmission preamble of reversals (10101010101 pattern) which must be at least 576 bits long. Thus, a transmission (paging burst) consists of a carrier turnon during which it is modulated with 512 baud reversals (the preamble pattern), followed by at least 576/512 seconds worth of actual preamble, and then a sync codeword (0x7CD215D8), followed by 16 data/address codewords, another sync codeword, 16 more data/address codewords, and so forth until the traffic is completely transmitted. All 16 of the last codewords of a transmission are always sent before the carrier is shut off, and if there is no message to be sent in them, the idle codeword (0x7A89C197) is sent.

A message to a pager consists of an address codeword in the proper two codeword frame within the batch to match the recipient's frame assignment (based on the low three bits of the recipient's 21 bit effective address), and between 0 and n of the immediately following codewords which contain the message text. A message is terminated by either another address codeword or an idle codeword. Idle codewords have the special hex value of 0x7A89C197. A message with a long text may potentially spill over between two or more 17 codeword batches.

Alphanumeric messages are encoded in 7 bit ASCII characters packed into the 20 bit data area of a message codeword (bits 30-11). Since four seven bit characters are 21 rather than 20 bits, and the designers of the standard did not want to waste transmission time, they chose to pack the first 20 bits of an ASCII message into the first codeword, the next 20 bits of a message into the next codeword, and so forth. This means that a 7 bit ASCII character of a message that falls on a boundary can and will be split between two codewords, and that the alignment of character boundaries in a particular alpha message codeword depends on which codeword it is of a message. Within a codeword, 7 bit characters are packed from left to right (MSB to LSB). The LSB of an ASCII character is sent first (is the MSB in the codeword) as per standard ASCII transmission conventions; so viewed as bits inside a codeword, the characters are bit reversed.

Code

The code uses the above technique to calculate the encoded message as well as uses BCH 21,31.

#include "7BitASCII.h"

#define POCSAG_PREAMBLE_CODEWORD    0xAAAAAAAA
#define POCSAG_IDLE_CODEWORD        0x7A89C197
#define POCSAG_SYNCH_CODEWORD        0x7CD215D8

union  Packet
{
    int  iPacket;
    char cPacket[4];
};

typedef struct tagASCII7Bit
{
    char Letter;
    char Bits[8];
} ASCII7Bit;

extern ASCII7Bit ASCII7BitTable[128];

void CPOCSAGDlg::OnCalculate() 
{
    UpdateData(TRUE);

    int i;
    int iPOCSAGMsg[68];
    CBCHEncoder m_bch;
    
    int iReciever=atoi(m_Reciever.GetBuffer(0));

    //Reset the codewords
    for (i=0; i<68; i++)
        iPOCSAGMsg[i]=POCSAG_IDLE_CODEWORD;

    //Initilizing Synch Codewords
    for (i=0; i<68; i+=17)
        iPOCSAGMsg[i]=POCSAG_SYNCH_CODEWORD;

    //compute address codeword
    int iStartFrame=iReciever%8;

    int iAddress=iReciever >> 3;
    iAddress=iAddress<<2;
    iAddress|=0x3;
    iAddress=iAddress<<11;

    m_bch.SetData(iAddress);
    m_bch.Encode();
    int iAddressEnc=m_bch.GetEncodedData();

    iPOCSAGMsg[iStartFrame*2+1]=iAddressEnc;

    //computer message codeword
    CString TempBits;
    int iLen=m_Message.GetLength();
    char cMessage[2048];
    ZeroMemory(cMessage, 2048);
    strcpy(cMessage, m_Message.GetBuffer(0));

    for (i=0; i<iLen; i++)
    {
        char c=cMessage[i];

        for (int j=0; j<128; j++)
            if (ASCII7BitTable[j].Letter==c)
            {
                CString TempStr=ASCII7BitTable[j].Bits;
                TempStr.MakeReverse();
                TempBits+=TempStr;
                break;
            }
    }

    //EOT = End of Transmission
    CString TempStr=ASCII7BitTable[4].Bits;
    TempStr.MakeReverse();
    TempBits+=TempStr;

    //now we have bits of message!
    int iMessageCodewords=(iLen+1)*7/20;

    if (iMessageCodewords*20!=(iLen+1)*7)
        iMessageCodewords++;

    int iRemainBit=iMessageCodewords*20-7*(iLen+1);
    float fRemain=ceil((float) iRemainBit/7);
    iRemainBit=(int) fRemain;

    for (i=0; i<iRemainBit; i++)
    {
        TempStr=ASCII7BitTable[4].Bits;
        TempStr.MakeReverse();
        TempBits+=TempStr;
    }
    
    iRemainBit=TempBits.GetLength()%20;

    //must remove iRemainBits from right of string
    TempBits=TempBits.Left(TempBits.GetLength()-iRemainBit);

    std::bitset<2100> MsgBits(TempBits.GetBuffer(0));
    
    int k=TempBits.GetLength()-1;
    
    int iCodeword=1;

    for (i=k; i>=0; i-=20)
    {
        int iMsgCode=1<<31;
        //0x80000000
        
        for (int j=0; j<20; j++)
        {
            if (i-j>=0)
                iMsgCode|=MsgBits[i-j]<<(30-j);
        }
        
        m_bch.SetData(iMsgCode);
        m_bch.Encode();

        iMsgCode=m_bch.GetEncodedData();    

        if ((iStartFrame*2+1+iCodeword)%17==0)
            iCodeword++;

        iPOCSAGMsg[iStartFrame*2+1+iCodeword]=iMsgCode;

        iCodeword++;
    }    

    //now update display
    CString szRes;
    CString szTemp;
    for (i=0; i<68; i++)
    {
        szTemp.Format("%X   ", iPOCSAGMsg[i]);
        szRes+=szTemp;

        if (i%17==0)
            szRes+=CString("\r\n");

        if (i%17==8 || i%17==16)
            szRes+=CString("\r\n");            
    }

    m_EncodedMessage=szRes;

    UpdateData(FALSE);
}

Enjoy!

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
CEO Solaris Electronics LLC
United Arab Emirates United Arab Emirates
I was born in Shiraz, a very beautiful famous city in Iran. I started programming when I was 12 years old with GWBASIC. Since now, I worked with various programming languages from Basic, Foxpro, C/C++, Visual Basic, Pascal to MATLAB and now Visual C++.
I graduated from Iran University of Science & Technology in Communication Eng., and now work as a system programmer for a telecommunication industry.
I wrote several programs and drivers for Synthesizers, Power Amplifiers, GPIB, GPS devices, Radio cards, Data Acquisition cards and so many related devices.
I'm author of several books like Learning C (primary and advanced), Learning Visual Basic, API application for VB, Teach Yourself Object Oriented Programming (OOP) and etc.
I'm winner of January, May, August 2003 and April 2005 best article of month competition, my articles are:


You can see list of my articles, by clicking here


Comments and Discussions

 
QuestionSoundcard sending? Pin
Videogamer5554-Feb-15 12:40
Videogamer5554-Feb-15 12:40 
QuestionCan numeric POCSAG pages be encoded? Pin
Member 111542603-Nov-14 20:13
Member 111542603-Nov-14 20:13 
QuestionIS IT NORMAL CODEWORD WITH ONLY 16 BITS? Pin
Member 1040856818-Nov-13 0:42
Member 1040856818-Nov-13 0:42 
AnswerRe: IS IT NORMAL CODEWORD WITH ONLY 16 BITS? Pin
Member 1040856818-Nov-13 0:48
Member 1040856818-Nov-13 0:48 
GeneralMy vote of 5 Pin
Amir Mohammad Nasrollahi9-Aug-13 20:43
professionalAmir Mohammad Nasrollahi9-Aug-13 20:43 
QuestionPOCSAG Encoder Pin
tgahner18-Dec-12 21:15
tgahner18-Dec-12 21:15 
GeneralMy vote of 5 Pin
Manoj Kumar Choubey26-Feb-12 19:57
professionalManoj Kumar Choubey26-Feb-12 19:57 
GeneralPOCSAG Encoder Circuit Pin
Member 54067792-Dec-09 1:43
Member 54067792-Dec-09 1:43 
QuestionNot working??? Pin
Member 300148520-Oct-09 2:21
Member 300148520-Oct-09 2:21 
QuestionSoftware Encoder code not working Pin
SAK_20003-May-07 4:51
SAK_20003-May-07 4:51 
AnswerRe: Software Encoder code not working Pin
Abbas_Riazi6-May-07 2:17
professionalAbbas_Riazi6-May-07 2:17 
GeneralRe: Software Encoder code not working Pin
SAK_20006-May-07 20:32
SAK_20006-May-07 20:32 
GeneralRe: Software Encoder code not working Pin
satfrx12-Jul-11 3:52
satfrx12-Jul-11 3:52 
AnswerRe: Software Encoder code not working Pin
Amir Mohammad Nasrollahi9-Aug-13 20:44
professionalAmir Mohammad Nasrollahi9-Aug-13 20:44 
GeneralPOCSAG Encoders Pin
stephenvs8-Apr-07 22:44
stephenvs8-Apr-07 22:44 
GeneralReplace Glenyare Paging Terminal by Software Pin
stephenvs8-Apr-07 21:40
stephenvs8-Apr-07 21:40 
GeneralApplication Pin
unitrunker23-Feb-06 18:10
unitrunker23-Feb-06 18:10 
GeneralRe: Application Pin
Abbas_Riazi23-Feb-06 22:43
professionalAbbas_Riazi23-Feb-06 22:43 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.