Разбираем протокол пейджерных сообщений POCSAG, ч1

    Привет, Habr!

    Давным-давно, когда мобильный телефон стоил 2000$ и минута звонка стоила 50 центов, была такая популярная штука как пейджинговая связь. Затем связь стала дешевле, и пейджер сначала превратился из престижного атрибута делового человека в непрестижный атрибут курьера или секретаря, а затем эта технология практически и вовсе сошла на нет.


    Для тех, кто помнит шутку «читал пейджер, много думал», и хочет разобраться, как это работает, продолжение под катом. Для тех, кто хочет разобраться еще более подробно, доступна вторая часть.

    Общая информация


    Для тех, кто забыл или родился после 2000х, кратко напомню основные идеи.

    С точки зрения пользователя, пейджинговая связь обладает двумя большими плюсами, которые в некоторых случаях актуальны и до сих пор:

    — Связь односторонняя, без каких-либо подтверждений, поэтому пейджинговую сеть невозможно перегрузить, ее работоспособность не зависит от числа абонентов. Сообщения просто последовательно передаются в эфир «как есть», а пейджер принимает их если номер получателя совпадает с номером пейджера.

    — Приемное устройство очень простое, так что пейджер может работать без подзарядки до месяца от 2х обычных батареек АА.

    Для передачи сообщений существуют два основных стандарта — POCSAG (Post Office Code Standardization Advisory Group) и FLEX. Стандарты совсем не новые, POCSAG был утвержден еще в 1982г, поддерживаемые скорости 512, 1200 и 2400 бит/с. Для передачи используется частотная манипуляция (FSK — frequency shift keying) с разносом частот 4.5КГц. Более новый стандарт FLEX (был предложен Motorola в 90х) поддерживает скорости до 6400 бит/с и может использовать не только FSK2, но и FSK4.

    Протоколы по своей сути достаточно просты, и еще лет 20 назад для них были написаны декодеры, способные дешифровывать сигнал со входа звуковой карты (шифрования сообщений не предусмотрено, так что читать их с такой программой в принципе может любой).

    Посмотрим, как это работает.

    Прием сигналов


    Для начала, нам нужен образец для декодирования. Берем ноутбук, rtl-sdr приемник, машину времени, и принимаем нужный нам сигнал.



    Т.к. модуляция частотная, режим приема также ставим FM. С помощью HDSDR записываем сигнал в формате WAV.

    Посмотрим, что у нас получилось. Загружаем wav-файл в виде массива с помощью Python:

    from scipy.io import wavfile
    import matplotlib.pyplot as plt
    
    fs, data = wavfile.read("pocsag.wav")
    plt.plot(data)
    
    plt.show()

    Результат (биты подписаны вручную):



    Как можно видеть, все просто, и даже «на глаз» в Paint можно дорисовать биты, где «0» а где «1». Но делать это для всего файла было бы слишком долго, процесс надо автоматизировать.

    Если увеличить график, то можно видеть что ширина каждого «бита» равна 20 отсчетам, что при частоте дискретизации wav-файла 24000 семпла/c, соответствует скорости 1200 бит/с. Найдем в сигнале место перехода через ноль — это будет начало битовой последовательности. Выведем на экран маркеры, чтобы проверить что биты совпадают.

    speed = 1200
    fs = 24000
    cnt = int(fs/speed)
    
    start = 0
    for p in range(2*cnt):
        if data[p] < - 50 and data[p+1] > 50:
            start = p
            break
    
    # Bits frame
    bits = np.zeros(data.size)
    for p in range(0, data.size - cnt, cnt):
        bits[start + p] = 500
    
    plt.plot(bits)
    

    Как можно видеть, совпадение не идеально (частоты передатчика и приемника все же чуть различны), но для декодирования вполне достаточно.



    Для длинных сигналов пришлось бы вводить алгоритм подстройки частоты, но в данном случае этого не требуется.

    И последний шаг — переведем массив из wav в битовую последовательность. Тут все тоже просто, длину одного бита мы уже знаем, если данные за этот период положительны, то добавляем «1», иначе «0» (правка — как оказалось, сигнал нужно было реверсировать, так что 0 и 1 поменяны местами).

    bits_str = ""
    for p in range(0, data.size - cnt, cnt):
        s = 0
        for p1 in range(p, p+cnt):
            s += data[p]
        bits_str += "1" if s < 0 else "0"
    
    print("Bits")
    print(bits_str)
    

    Возможно, код можно оптимизировать, отказавшись от цикла, хотя в данном случае это некритично.

    Результат — готовая последовательность бит (в виде строки), сохраняющая наше сообщение.

    101010101010101010101010101010101010101010101010101010101010101010101010101
    010101010101010101010101010101010101010101010100111110011010010000101001101
    100001111010100010011100000110010111011110101000100111000001100101110111101
    010001001110000011001011101111010100010011100000110010111011110101000100111
    000001100101110111101010001001110000011001011101111010100010011100000110010
    011011110101000100111000001100101110111101010001001110000011001011101111010
    100010011100000110010111011110101000100111000001100101110111101010001001110

    111101111


    Декодирование


    Последовательность бит — это уже гораздо удобнее, чем просто wav-файл, из нее уже можно извлечь какие-либо данные. Разобьем файл на блоки по 4 байта, и получим более понятную последовательность:

    10101010101010101010101010101010
    10101010101010101010101010101010
    10101010101010101010101010101010
    10101010101010101010101010101010
    01111100110100100001010011011000
    01111010100010011100000110010111
    01111010100010011100000110010111
    01111010100010011100000110010111
    01111010100010011100000110010111
    00001000011011110100010001101000
    10000011010000010101010011010100
    01111100110100100001010111011000
    11110101010001000001000000111000
    01111010100010011100000110010111
    01111010100010011100000110010111
    01111010100010011100000110010111
    00100101101001011010010100101111


    Это все, что мы можем извлечь из файла, осталось понять что эти строки значат. Открываем документацию на формат, которая доступна в виде PDF.



    Все более-менее понятно. Заголовок сообщения состоит из длинного блока «10101010101» который нужен, чтобы пейджер вышел из «спящего режима». Само сообщение состоит из блоков Batch-1… Batch-N, каждый из которых начинается с уникальной последовательности FSC (в тексте выделено жирным). Далее, как видно из мануала, если строка начинается с «0», то это адрес получателя. Адрес зашит в самом пейджере, и если он не совпадет, пейджер сообщение просто проигнорирует. Если строка начинается с «1», то это собственно, сообщение. Таких строк у нас две.

    Теперь посмотрим на каждый блок. Мы видим коды Idle — пустые блоки 01111...0111, не несущие полезной информации. Удаляем их, информации остается весьма мало, все что остается:

    01111100110100100001010011011000 — Frame Sync
    00001000011011110100010001101000 — Address
    10000011010000010101010011010100 — Message

    01111100110100100001010111011000 — Frame Sync
    11110101010001000001000000111000 — Message
    00100101101001011010010100101111 — Address


    Осталось понять, что внутри.

    Ищем дальше в мануале, и выясняем, что сообщения могут быть цифровые или текстовые. Цифровые сообщения хранятся в виде 4-битных BCD-кодов, значит в 20 битах может поместиться 5 символов (еще остаются биты для контроля, мы их рассматривать не будем). Сообщение также может быть текстовым, в этом случае используется 7-битная кодировка, но для текстового наше сообщение слишком мало — суммарное количество бит сообщения не кратно 7.

    Из строк 10000011010000010101010011010100 и 11110101010001000001000000111000 получаем следующие 4х битные последовательности:
    1 0000 0110 1000 0010 10101 0011010100 — 0h 6h 8h 2h Ah
    1 1110 1010 1000 1000 00100 0000111000 — Eh Ah 8h 8h 2h

    И наконец, последний шаг — смотрим в документации таблицу соответствия символов.



    Как можно видеть, цифровое сообщение может содержать только цифры 0-9, букву U («ugrent»), пробел и пару скобок. Пишем несложную функцию вывода, чтобы не считать их вручную:

    def parse_msg(block):
        # 16 lines in a batch, each block has a length 32 bits
        for cw in range(16):  
            cws = block[32 * cw:32 * (cw + 1)]
            if cws[0] == "0":
                addr = cws[1:19]
                print("  Addr:" + addr)
            else:
                msg = cws[1:21]
                print("  Msg: " + msg)
                size = 4
                s = ""
                for ind in range(0, len(msg), size):
                    bcd_s = msg[ind:ind + size]
                    value = int(bcd_s, 2)
                    symbols = "0123456789*U -)("
                    s += symbols[value]
                print("    ", s)
        print()
    

    В итоге получаем переданное сообщение «0682*)*882». Что оно значит, сказать сложно, но раз формат поддерживает цифровые сообщения, значит наверно оно кому-то нужно.

    Выводы


    Как можно видеть, формат POCSAG весьма простой, и по сути, может быть декодирован даже в школьной тетради. И хотя сейчас это имеет скорее исторический интерес, анализ таких протоколов весьма полезен с познавательной точки зрения.

    В следующей части рассказано про декодирование ASCII-сообщений.
    Поделиться публикацией

    Комментарии 18

      +8
      Если есть машина времени, то правильно использовать не rtl-sdr, а плату ТВ-тюнера AverMedia. Те, у кого во времена пейджеров не было денег, например, на WinRadio, использовали для экспериментов именно их.
        0
        О да, был такой когда-то.
          0
          Название софта вот не могу вспомнить из конца девяностых, а позже уже был PDW.
        +1
        Была такая забава. Выбрать случайного абонента (нетрудно сопоставить абонентский номер у оператора и идентификатор в принимаемой из эфира посылке) и слать сообщения на его пейджер, предварительно договорившись о кодовом слове в начале сообщения, чтобы было понятно, что сообщение тому, кто мониторит, а не самому абоненту, который вообще ни о чем не подозревает и смысла адресованных не ему сообщений, конечно, понять не может. Для приема использовались любые имевшиеся в хозяйстве портативные р/ст, без заморочек с гальванической развязкой и согласованием уровней подключенные к звуковухе. На передачу тоже можно было, но незаконно и бессмысленно, поэтому на передачу не работали. Что за софт был — не помню за давностью, но и не важно, т.к. сейчас вариантов еще больше. Практической ценности это не имело и наскучило за пару дней, но сама возможность «хакнуть» радовала начинающих радиолюбителей.
          0
          Жду статью про приём текста!

          Хорошая была технология. У пейджеров только один недостаток — связь в одну сторону.

          А если говорить про «двусторонний пейджинг», то нужно, либо централизованную сеть через TDMA и FDMA строить как у сотовых, либо делать децентрализованную mesh-сеть — что предпочтительнее в свете надвигающегося Оруэлла.
            +3
            связь в одну сторону.


            Справедливости ради, были и твейджеры. В них вполне себе была реализована связь в обе стороны. Но не прижились, не успели — мобилы и sms уже пошли в массы.

            В конце нулевых один очень жадный клиент просил сделать вызывную связь на складе почти 100 тысяч квм и под тысячу сотрудников. Громкая связь забивалась производственными шумами. Купили ему целый контейнер нулёвых запечатанных пейджеров «свинг» по доллару за штуку(хотели мотороллу но они стоили по два бакса) и на компе реализовали связку jabber и передатчика.
            Так что управляющий или любой подключенный к жабе мог в любое время вызвать любого сотрудника, а поскольку покрытие было гарантированным, то и проблем не было.
            Два года назад там был — до сих пор работает.
          +1
          Выход статьи совпал со смертью одного из ярких представителей той эпохи.
            +2
            И то правда :(

            Слушать — не слушал, поклонником никогда не был, но уважение за то, что человек не превратился в фекальную массу, став известным в детстве, испытывал. Ведь в те времена не слышал его разве что глухой.

            Да и по сути, всё, что большинство россиян помнит о пейджерах — это «Коля, не стреляй в гулю!» и
            Пепси, пейджер, MTV
            Пепси, пейджер, МТВ - Децл
              0
              Может хватит уже?
              Похоже в веб в ближайшее время вообще не выйти, чтобы не наткнуться.
              0
              До сих пор на полочке лежит Motorola Scriptor LX4 в котором регулярно меняю батарейку! Если расскажете как можно оживить технологию в нынешних реалиах, это будет прекрасная статья, а я оживлю свой пейджер и научу свой «умный дом» присылать мне сообщения.
                0
                Например, так:

                1) выяснить, на каких частотах работает этот пейджер (частот много).
                2) прилепить маломощный FM передатчик к R-Pi (зачастую и паять не надо)
                3) профит!
                  0
                  как можно оживить технологию в нынешних реалиах

                  Почитайте ветку на этом форуме, там разбирались разные решения: www.radioscanner.ru/forum/topic39329.html
                    +1
                    Я лично юзал для приёма сообщений пейджер через HackRF, генерируя посылку при помощи форка pocsag2sdr, собирающегося под мак и линух, а затем закидывая её в hackrf_transfer. Вся эта связка вызывается из простейшей обёртки-плагина для AKLongpollSvr (настроенного в silent режим) при приходе сообщения в ВК.

                    Частоту пейджера нашёл как посчитать на форуме, так как у меня был NEC с гетеродином и двумя кристаллами, капкоды пришлось искать перебором, нашёл что-то около 4 из 10, но вот оно даже и работает:

                    Спрятал фотку под кат, а то огромная
                    image
                      0
                      PWM (Шим) контроллеры, достаточно неплохая альтернатива в определенной нише различной автоматики.
                      0
                      Лично я пейджинговую связь рассматриваю как удобнейшую штуку для всяких оповещений на даче — покупаем примитивную радиостанцию подключаем к компьютеру/ардуинке и вуаля. с MQTT ретранслируем на нужные номера пейджеров. очень удобно на самом деле когда дом большой и есть огород в километр длиной. мобилки какими бы они ни были — неудобны т.к. когда копаешся в земле руки грязные а пейджерок — самое оно чтоб узнать что ктото в звонок позвонил или в котельной протечка воды или ещё что — пейджеров сичас на 100 руб горсть можно купить
                        0
                        Кстати да, интересный момент — рост популярности IoT и «умных домов» возрастает, так что не удивлюсь если пейджинговые сервисы снова появятся. Тем более что их выпуск-то в мире и не прекращался, для врачей и пожарных до сих пор актуально.
                          0
                          Вот как раз хотел сказать, что еще относительно недавно видел пейджеры у врачей в госпитале.

                      Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                      Самое читаемое