Clone
4
POCSAG
ua1zbe edited this page 2026-04-12 01:15:14 +03:00
This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

POCSAG декодер

Обзор

POCSAG (Post Office Code Standardization Advisory Group) — стандарт пейджинговой связи. Данный декодер реализует приём и декодирование POCSAG сигналов с частотами 512 и 1200 бод.

Протокол POCSAG

Структура передачи

┌─────────────────┬──────────────┬──────────────────────────┐
│   Преамбула     │  Sync word   │   Batch 1 (32 слова)     │
│  0xAAAAAAAB...  │  0x7CD21538  │   [Address/Data] × 32    │
│  (≥576 бит)     │              │                          │
└─────────────────┴──────────────┴──────────────────────────┘
                                                         │
                    ┌────────────────────────────────────┘
                    ▼
              ┌──────────────────────────┐
              │   Batch 2 (32 слова)     │
              │   + sync word            │
              └──────────────────────────┘

Параметры

Параметр Значение
Скорость 512 или 1200 бод
Модуляция FSK (FM)
Кодирование BCH(31,21)
Исправление ошибок До 2 бит на слово
Длина слова 32 бита (21 данные + 10 BCH + 1 чётность)
Преамбула 0x55555555... ≥ 576 бит, заканчивается на 1
Sync word 0x7CD21538
Idle word 0x7A89C197

Типы сообщений

Function bits Тип Описание
00 Numeric Числовой пейджер (BCD цифры)
01 Reserved Зарезервировано
10 Alpha Алфавитный пейджер (7-bit ASCII)
11 Reserved Зарезервировано

Архитектура декодера

Файлы

Файл Описание
app/pocsag/pocsag.c Основной декодер
app/pocsag/pocsag.h Заголовочный файл, API
app/pocsag/bch31.c BCH(31,21) коррекция ошибок
app/pocsag/bch31.h Заголовочный файл BCH

Цепочка обработки

┌──────────┐    ┌──────────────┐    ┌──────────────┐    ┌───────────────┐
│ BK4819   │───▶│ Zero-crossing│───▶│ Bit slicing  │───▶│ POCSAG decode │
│ FM demod │    │ detection    │    │ (averaging)  │    │ (state machine)│
└──────────┘    └──────────────┘    └──────────────┘    └───────────────┘
                                                              │
                    ┌─────────────────────────────────────────┘
                    ▼
              ┌──────────────┐
              │ BCH correct  │
              │ (up to 2 err)│
              └──────────────┘
                    │
                    ▼
              ┌──────────────┐
              │ Ring buffer  │
              │ (8 messages) │
              └──────────────┘

Машина состояний

                    ┌─────────┐
                    │  IDLE   │
                    └────┬────┘
                         │ 576 alternating bits
                         ▼
                  ┌──────────────┐
         ┌───────▶│  PREAMBLE    │
         │        └──────┬───────┘
timeout  │               │ sync word found (0x7CD21538)
         │               ▼
         │        ┌──────────────┐
         │        │    SYNC      │
         │        └──────┬───────┘
         │               │ 32-bit word valid
         │               ▼
         │        ┌──────────────┐
         └────────│    DATA      │
   sync lost      └──────────────┘

Алгоритм BCH(31,21)

Параметры кода

Параметр Значение
Длина кода (n) 31 бит
Информационные биты (k) 21 бит
Проверочные биты 10 бит
Мин. расстояние (d_min) 5
Исправление ошибок До 2 бит

Генераторный полином

g(x) = x^10 + x^9 + x^8 + x^6 + x^5 + x^3 + 1
     = 0x72D (binary: 111 0010 1101)

Процесс коррекции

1. Проверка чётности (even parity)
   └─ Если OK и синдром = 0 → нет ошибок

2. Вычисление синдрома S(x) = R(x) mod g(x)
   └─ Если S(x) = 0 → нет ошибок

3. Поиск одиночной ошибки
   └─ S(x) = x^i mod g(x) для позиции i
   └─ Если найдено → исправить бит i

4. Поиск двойной ошибки (перебор пар)
   └─ S(x) = x^i + x^j mod g(x) для пар (i, j)
   └─ 465 комбинаций для 31 бита
   └─ Если найдено → исправить биты i и j

5. Если не найдено → слово отбрасывается

Оптимизация для Cortex-M0

Cortex-M0 не имеет аппаратного деления. Все операции в GF(2) реализованы через сдвиги и XOR:

// Умножение на x в GF(2^10 / g(x))
test_syn <<= 1;
if (test_syn & 0x0400U) {      // Если бит 10 установлен
    test_syn ^= BCH31_GEN_POLY; // XOR с генератором
}
test_syn &= 0x03FFU;           // Оставляем 10 бит

Конфигурация BK4819

Для приёма POCSAG радиочип настраивается следующим образом:

// Узкая полоса (POCSAG обычно narrow FM)
BK4819_SetFilterBandwidth(BK4819_FILTER_BW_NARROW, true);

// Отключение шумоподавления (непрерывный приём аудио)
BK4819_SetupSquelch(0, 0, 0, 0, 255, 0);

// Включение RX链路
BK4819_WriteRegister(BK4819_REG_30,
    BK4819_REG_30_ENABLE_VCO_CALIB |
    BK4819_REG_30_ENABLE_RX_LINK |
    BK4819_REG_30_ENABLE_AF_DAC |
    BK4819_REG_30_ENABLE_DISC_MODE |
    BK4819_REG_30_ENABLE_PLL_VCO |
    BK4819_REG_30_ENABLE_RX_DSP);

// AF output — демодулированный FM сигнал
BK4819_SetAF(BK4819_AF_FM);

Известные ограничения

Сэмплинг (критично)

Проблема: POCSAG_FeedSample() вызывается ~1 раз в 10 мс из timeslice. Для корректного декодирования POCSAG 1200 бод требуется ~1 раз в 125 мкс (8000 сэмплов/сек).

Текущее состояние: Преамбула НЕ будет обнаружена при текущей частоте сэмплирования. BCH коррекция работает правильно, но до неё дело не доходит.

Планируемое исправление:

// В MODE_TimeSlice10ms(), case MODE_POCSAG:
for (int i = 0; i < 80; i++) {
    uint16_t audio = BK4819_GetVoiceAmplitudeOut();
    POCSAG_FeedSample(audio);
    SYSTEM_DelayUs(125);  // 8 kHz sampling rate
}

Ограничения памяти

Ресурс Использование
Кольцевой буфер сообщений 8 сообщений × ~80 байт = 640 байт
Статические буферы декодера ~200 байт
BCH таблица синдромов 0 байт (вычисляется на лету)

API декодера

Инициализация

// Инициализация с baud rate 1200
POCSAG_Init(POCSAG_BAUD_1200);

// Настройка радиочасти на частоту 145.525 MHz
POCSAG_ConfigureRadio(145525000);

Переключение скорости

// Переключение 1200 -> 512 бод
POCSAG_SwitchBaud(POCSAG_BAUD_512);

// Текущая скорость
uint32_t baud = POCSAG_GetBaud();

Проверка сообщений

// Проверка наличия декодированных сообщений
if (POCSAG_MessageAvailable()) {
    pocsag_msg_t msg;
    if (POCSAG_GetMessage(&msg)) {
        // msg.address  — адрес (21 бит)
        // msg.func     — function code (2 бита)
        // msg.text     — текст сообщения
        // msg.is_alpha — true = алфавитный, false = числовой
    }
}

Состояние декодера

pocsag_state_t state = POCSAG_GetState();
// POCSAG_STATE_IDLE      — ожидание
// POCSAG_STATE_PREAMBLE  — обнаружение преамбулы
// POCSAG_STATE_SYNC      — поиск sync слова
// POCSAG_STATE_DATA      — приём данных

bool signal = POCSAG_SignalDetected();  // true если sync найден