Grundlegendes zum POCSAG-Paging-Protokoll

Vor langer Zeit, als ein Mobiltelefon etwa 2000 US-Dollar kostete und eine Minute Sprachanruf 50 Cent kostete, waren Pager sehr beliebt. Später wurden Mobiltelefone billiger, Anrufe und SMS-Preise wurden niedriger und schließlich verschwanden die Pager größtenteils.


Für Personen, die zuvor einen Pager besessen haben und wissen möchten, wie er funktioniert, ist dieser Artikel hilfreich.

Hauptinfo


Für Leute, die die Prinzipien vergessen haben oder nach 2000x geboren wurden, werde ich kurz an die Hauptideen erinnern.

Das Paging-Kommunikationsnetz hat einige Vorteile, die manchmal schon jetzt wichtig sind:

- Es handelt sich um eine einseitige Kommunikation ohne jegliche Bestätigung, sodass das Netzwerk nicht überlastet werden kann. Es hängt nur nicht von einer Reihe von Benutzern ab. Nachrichten werden kontinuierlich "wie sie sind" nacheinander übertragen, und der Pager erhält die Nachricht, wenn seine Nummer (sogenannter Capcode) der internen Nummer des Geräts entspricht.

- Der Empfänger ist sehr leicht (sowohl wörtlich als auch elektronisch) und kann mit 2 AA-Batterien bis zu einem Monat arbeiten.

Es gibt zwei grundlegende Standards für die Nachrichtenübertragung: POCSAG (Post Office Code Standardization Advisory Group) und FLEX . Beide Standards sind ziemlich alt, POCSAG wurde 1982 hergestellt und unterstützt Geschwindigkeiten von 512, 1200 und 2400 Bit / s. Zur Übertragung wird das FSK-Verfahren (Frequency Shift Keying) mit einer Frequenztrennung von 4,5 kHz verwendet. FLEX ist etwas neuer (wurde von Motorola im Jahr 90 hergestellt), kann mit einer Geschwindigkeit von bis zu 6400 Bit / s arbeiten und sowohl FSK2 als auch FSK4 verwenden.

Beide Protokolle sind im Allgemeinen sehr einfach, und vor etwa 20 Jahren wurden PC-Decoder hergestellt, die Nachrichten von einer seriellen Schnittstelle einer Soundkarte decodieren können (es wird keine Verschlüsselung unterstützt, sodass alle Nachrichten von jedem gelesen werden können).

Schauen wir uns an, wie es funktioniert.

Ein Signal empfangen


Zunächst benötigen wir ein Signal zum Decodieren. Nehmen wir einen Laptop, einen RTL-SDR-Empfänger und holen ihn uns.



Die Frequenzumtastung wird verwendet, daher stellen wir FM ein. Mit HDSDR speichern wir ein Signal im WAV-Format.

Überprüfen wir, was wir bekommen. Laden der WAV-Datei als Python-Datenarray:

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

Ausgabe (manuell hinzugefügte Bits):



Wie wir sehen können, ist es einfach und sogar "mit bloßem Auge" können wir Bits in Paint zeichnen. Es ist leicht zu unterscheiden, wo "0" und wo "1" ist. Es wird jedoch zu lange dauern, dies manuell zu tun. Es ist an der Zeit, den Prozess zu automatisieren.

Nach dem Vergrößern des Diagramms können wir sehen, dass jedes Bit eine Breite von 20 Abtastwerten hat. Wir haben 24000 Samples pro Sekunde Bitrate-WAV-Datei, daher beträgt die Schlüsselgeschwindigkeit 1200 Bit / s. Finden wir eine Nulldurchgangsposition - dies ist der Beginn der Bitsequenz. Fügen Sie auch Markierungen hinzu, um zu überprüfen, ob sich alle Bits an den richtigen Stellen befinden.

 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) 

Wie wir sehen können, stimmt es nicht perfekt überein (Sender und Empfänger haben leicht unterschiedliche Frequenzen), aber es reicht definitiv zum Decodieren aus.



Für lange Signale benötigen wir wahrscheinlich einen automatischen Frequenzkorrekturalgorithmus, aber für diese Art von Signalen ist dies nicht kritisch.

Der letzte Schritt - wir müssen die WAV-Datei in die Bitfolge übersetzen. Es ist auch einfach, wir kennen die Länge jedes Bits. Wenn die Datensumme positiv ist, addieren wir "1", andernfalls "0" (schließlich wurde festgestellt, dass ein Signal zurückgesetzt werden muss, sodass 0 und 1 ersetzt wurden). .

 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) 

Ausgabe - richtige Bitfolge (in einem Zeichenfolgenformat), die unsere Nachricht enthält.

101010101010101010101010101010101010101010101010101010101010101010101010101
010101010101010101010101010101010101010101010100111110011010010000101001101
100001111010100010011100000110010111011110101000100111000001100101110111101
010001001110000011001011101111010100010011100000110010111011110101000100111
000001100101110111101010001001110000011001011101111010100010011100000110010
011011110101000100111000001100101110111101010001001110000011001011101111010
100010011100000110010111011110101000100111000001100101110111101010001001110
...
111101111


Nur numerische Nachrichten dekodieren


Eine Bitfolge ist viel praktischer als eine WAV-Datei, wir können Daten daraus extrahieren. Lassen Sie uns zunächst die Daten in 4-Byte-Blöcke aufteilen.

10101010101010101010101010101010
10101010101010101010101010101010
10101010101010101010101010101010
10101010101010101010101010101010

01111100110100100001010011011000
01111010100010011100000110010111
01111010100010011100000110010111
01111010100010011100000110010111
01111010100010011100000110010111
00001000011011110100010001101000
10000011010000010101010011010100

01111100110100100001010111011000
11110101010001000001000000111000
01111010100010011100000110010111
01111010100010011100000110010111
01111010100010011100000110010111
00100101101001011010010100101111


Wir können definitiv ein Muster sehen. Jetzt müssen wir herausfinden, was jeder Teil bedeutet. Das POCSAG-Handbuch ist im PDF-Format verfügbar. Hier können Sie die Beschreibung der Datenstrukturen überprüfen.



Es ist jetzt viel klarer. Der Header enthält einen langen Block "10101010101", mit dem der Pager aus dem Ruhemodus "geweckt" wird. Die Nachricht selbst enthält die Blöcke Batch-1 ... Batch-N, jeder Block beginnt mit der eindeutigen Sequenz FSC. Wie wir im Handbuch sehen können, enthält die Zeichenfolge, wenn sie bei "0" beginnt, die Empfängeradresse. Die gespeicherte Adresse selbst (Capcode) ist der Pager. Wenn sie nicht übereinstimmt, ignoriert der Pager die Nachricht. Wenn eine Zeichenfolge bei "1" beginnt, enthält sie den Nachrichtentext. In unserem Beispiel haben wir 2 Zeichenfolgen dieses Typs.

Überprüfen wir nicht jeden Block. Wir können auch Leerlaufcodes sehen - leere Blöcke 01111 ... 0111, sie haben keine nützlichen Informationen. Nachdem wir sie entfernt haben, erhalten wir nur Folgendes:

01111100110100100001010011011000 - Frame Sync
00001000011011110100010001101000 - Address
10000011010000010101010011010100 - Message

01111100110100100001010111011000 - Frame Sync
11110101010001000001000000111000 - Message
00100101101001011010010100101111 - Address


Wir müssen herausfinden, was drin ist.

Nach Durchsicht des Handbuchs ist klar, dass es zwei Arten von Nachrichten gibt - nur numerische und alphanumerische . Nur numerische Nachrichten werden als 4-Bit-BCD-Codes gespeichert, sodass 20 Bit 5 Symbole enthalten können (es gibt auch CRC-Bits, die wir derzeit nicht verwenden). Wenn die Nachricht alphanumerisch ist, wird eine 7-Bit-ASCII-Codierung verwendet. Diese Nachricht ist zu kurz, daher kann es sich nur um eine reine numerische Nachricht handeln.

Aus den Zeichenfolgen 10000011010000010101010011010100 und 11110101010001000001000000111000 können wir diese 4-Bit-Sequenzen erhalten:
1 0000 0110 1000 0010 10101 0011010100 - 0h 6h 8h 2h Ah
1 1110 1010 1000 1000 00100 0000111000 - Eh Ah 8h 8h 2h

Der nächste Schritt besteht darin, die Dekodierungstabelle aus dem Handbuch abzurufen:



Es ist offensichtlich, dass eine nur numerische Nachricht die Ziffern 0-9, den Buchstaben U ("ugrent"), ein Leerzeichen und zwei Klammern enthalten kann. Schreiben wir eine kleine Methode, um sie zu dekodieren:

 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() 

Schließlich erhalten wir eine Nachricht "0682 *) * 882".

Es ist schwer zu sagen, was es bedeutet, aber wenn die nur numerischen Nachrichten verwendet werden, braucht es wahrscheinlich jemand.

Dekodieren von alphanumerischen Nachrichten


Der nächste und interessantere Schritt besteht darin, alphanumerische Nachrichten zu dekodieren. Es ist interessanter, weil wir als Ausgabe den vom Menschen lesbaren Text erhalten sollten.

Zuerst müssen wir eine Nachricht erneut aufzeichnen, wir werden HDSDR verwenden. Wir kennen keinen Nachrichtentyp vor dem Dekodieren, daher zeichnen wir nur eine längste Nachricht auf, die wir erhalten können, und hoffen, dass sie Text enthält.



Nach der Konvertierung von WAV in eine Bitsequenz (siehe Python-Code oben) erhalten wir Folgendes:



Einige interessante Dinge, die wir sofort mit bloßem Auge sehen können - zum Beispiel wiederholt sich die Startsequenz 01010101010101 zweimal. Somit ist diese Nachricht nicht nur länger, sie enthält buchstäblich zwei Nachrichten, die zusammengeführt werden (ein Standard leugnet dies übrigens nicht).

Wie wir zuvor festgestellt haben, beginnt jeder Datenblock mit einer Sequenz namens Frame Sync Code (01111100 ...), nachdem 32-Bit-Blöcke gesendet wurden. Jeder Block kann entweder die Adresse oder den Nachrichtentext speichern.

Früher haben wir nur numerische Nachrichten erhalten, jetzt möchten wir ASCII-Nachrichten lesen. Zuerst müssen wir sie unterscheiden. Diese Daten werden in einem Feld "Funktionsbits" (Bits 20-21) gespeichert. Wenn beide Bits 00 sind, handelt es sich um eine rein numerische Nachricht. Wenn die Bits 11 sind, handelt es sich um eine Textnachricht.

Interessanterweise ist dieses Nachrichtenfeld 20 Bit lang, daher ist es ideal, dort bei einer nur numerischen Nachricht fünf 4-Bit-Blöcke zu platzieren. Wenn wir jedoch eine 7-Bit-ASCII-Nachricht haben, können wir 20 nicht auf 7 teilen. Es ist möglich vorherzusagen, dass die erste Protokollversion nur numerische Nachrichten unterstützt (vergessen Sie nicht, dass sie 1982 erstellt wurde und wahrscheinlich die ersten Nixie-Tube-Pager konnten nicht mehr anzeigen ), und erst später wurde die Unterstützung für ASCII-Nachrichten hinzugefügt. Aus den alten Gründen wurde der Framing-Standard nicht geändert, und die Entwickler verwendeten den einfachen Ansatz - sie kombinierten die Bits einfach "wie sie sind" nacheinander. Von jeder Nachricht müssen wir 20 Bits nehmen und zur nächsten zusammenführen, schließlich können wir den Nachrichtentext dekodieren.

Sehen wir uns einen Block unserer Nachricht an (Leerzeichen waren Addierer, um das Lesen zu erleichtern):

0 0001010011100010111111110010010
1 00010100000110110011 11100111001
1 01011010011001110100 01111011100
1 11010001110110100100 11011000100
1 11000001101000110100 10011110111
1 11100000010100011011 11101110000
1 00110010111011001101 10011011010
1 00011001011100010110 10011000010
1 10101100000010010101 10110000101
1 00010110111011001101 00000011011
1 10100101000000101000 11001010100
1 00111101010101101100 11011111010


"0" -Bit In der ersten Zeichenfolge wird angezeigt, dass es sich um das Adressfeld handelt, und "11" in 20 bis 21 Bit zeigt an, dass die Nachricht wirklich alphanumerisch ist. Dann nehmen wir einfach 20 Bit von jedem String und führen ihn zusammen.

Dies ist unsere Bitfolge:

00010100000110110011010110100110011101001101000111011010010011000001101000
11010011100000010100011011001100101110110011010001100101110001011010101100
000010010101000101101110110011011010010100000010100000111101010101101


In POCSAG wird 7-Bit-ASCII-Code verwendet, daher wird eine Zeichenfolge in 7 Zeichenblöcke aufgeteilt:

0001010 0000110 1100110 1011010 0110011 1010011 ...

Nachdem wir versucht haben, es zu dekodieren (ASCII-Tabelle kann leicht im Internet gefunden werden), bekommen wir ... einfach nichts. Überprüfen Sie das Handbuch erneut, und hier ist der kleine Satz "ASCII-Zeichen werden von links nach rechts platziert (MSB zu LSB). Das LSB sendet zuerst. " Das niedrige Bit sendet also zuerst - für eine korrekte Decodierung müssen alle Zeichenfolgen umgekehrt werden.

Es ist zu langweilig, um es manuell zu machen, also schreiben wir einen Python-Code:

 def parse_msg(block): msgs = "" for cw in range(16): cws = block[32 * cw:32 * (cw + 1)] # Skip the idle word if cws.startswith("0111101010"): continue if cws[0] == "0": addr, type = cws[1:19], cws[19:21] print(" Addr:" + addr, type) else: msg = cws[1:21] print(" Msg: " + msg) msgs += msg # Split long string to 7 chars blocks bits = [msgs[i:i+7] for i in range(0, len(msgs), 7)] # Get the message msg = "" for b in bits: b1 = b[::-1] # Revert string value = int(b1, 2) msg += chr(value) print("Msg:", msg) print() 

Schließlich erhalten wir diese Sequenz (Bits, Symbolcodes und ASCII-Symbole):

 0101000 40 ( 0110000 48 0 0110011 51 3 0101101 45 - 1100110 102 f 1100101 101 e 1100010 98 b 0101101 45 - 0110010 50 2 0110000 48 0 0110001 49 1 0111001 57 9 0100000 32 0110001 49 1 0110011 51 3 0111010 58 : 0110011 51 3 0110001 49 1 0111010 58 : 0110100 52 4 0110101 53 5 0100000 32 0101010 42 * 0110100 52 4 0110111 55 7 0110110 54 6 0101001 41 ) 0100000 32 1000001 65 A 1010111 87 W 1011010 90 Z 

Nach dem Zusammenführen erhalten wir die Zeichenfolge: "(03-feb-2019 13:31:45 * 476) AWZ". Wie versprochen, ist es ziemlich menschlich lesbar.

Es ist übrigens interessant zu erwähnen, dass 7-Bit-ASCII-Codes verwendet werden. Symbole einiger Alphabete (Deutsch, Kyrillisch usw.) können nicht richtig in 7 Bit codiert werden. Warum 7 Bits? Wahrscheinlich hatten die Ingenieure entschieden, dass "7 Bits für alle ausreichen", wer weiß ...

Fazit


Es war wirklich interessant zu untersuchen, wie POCSAG funktioniert. Es ist eines der seltenen Protokolle, die bisher verwendet werden und die buchstäblich auf dem Blatt Papier dekodiert werden können (und ich werde dies definitiv nicht mit TETRA oder GSM versuchen).

Natürlich wird das POCSAG-Protokoll hier nicht vollständig beschrieben. Der wichtigste und interessanteste Teil ist erledigt, andere Sachen sind nicht so aufregend. Zumindest gibt es keine Capcode-Decodierung und keinen Fehlerkorrekturcode (BCH Check Bits) - es können bis zu 2 falsche Bits in der Nachricht behoben werden. Aber es gab kein Ziel, hier einen anderen POCSAG-Decoder zu schreiben, es gibt bereits genug davon.

Für diejenigen, die echte Dekodierung mit rtl-sdr testen möchten, kann eine Freeware- PDW-Anwendung verwendet werden. Es ist keine Installation erforderlich, es reicht nur aus, um den Ton von HDSDR über die Virtual Audio Cable-Anwendung an PDW weiterzuleiten.

Das Ergebnis sieht folgendermaßen aus:



(Bitte beachten Sie, dass das Dekodieren von öffentlich-rechtlichen Nachrichten in einigen Ländern illegal sein kann und trotzdem die Privatsphäre der Empfänger respektiert.)

Wenn jemand mehr Informationen zu diesem Thema erhalten möchte, stehen Quellen des Multimon-ng- Decoders zur Verfügung, der viele Protokolle dekodieren kann, auch POCSAG und FLEX.

Danke fürs Lesen.

Source: https://habr.com/ru/post/de438906/


All Articles