Хабрахабр

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

Привет habr,

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

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

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

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

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

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

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

Стандарты совсем не новые, POCSAG был утвержден еще в 1982г, поддерживаемые скорости 512, 1200 и 2400 бит/с. Для передачи сообщений существуют два основных стандарта — POCSAG (Post Office Code Standardization Advisory Group) и FLEX. 5КГц. Для передачи используется частотная манипуляция (FSK — frequency shift keying) с разносом частот 4. Более новый стандарт 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)

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

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

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

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

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

Пишем несложную функцию вывода, чтобы не считать их вручную:

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 весьма простой, и по сути, может быть декодирован даже в школьной тетради. И хотя сейчас это имеет скорее исторический интерес, анализ таких протоколов весьма полезен с познавательной точки зрения.

Если у аудитории будет интерес, в следующей части можно продолжить и рассказать про декодирование текстовых сообщений.

Показать больше

Похожие публикации

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»