Hace mucho tiempo, cuando un teléfono móvil costaba alrededor de 2000 $ y un minuto de llamada de voz costaba 50 centavos, los buscapersonas eran muy populares. Más tarde, los teléfonos celulares se volvieron más baratos, las llamadas y los precios de los SMS disminuyeron, y finalmente los buscapersonas desaparecieron en su mayoría.
Para las personas que antes tenían un localizador y quieren saber cómo funciona, este artículo será útil.
Información principal
Para las personas que olvidaron los principios o nacieron después de 2000x, les recordaré las ideas principales en breve.
La red de comunicaciones de paginación tiene algunas ventajas, que a veces son importantes incluso ahora:
- Es una comunicación unidireccional, sin ningún tipo de confirmación, por lo que la red no se puede sobrecargar, simplemente no depende de varios usuarios. Los mensajes se transmiten continuamente "tal cual", uno tras otro, y el localizador recibe el mensaje si su número (llamado Capcode) es igual al número interno del dispositivo.
- El receptor es muy liviano (tanto literal como electrónicamente) y puede funcionar hasta un mes con 2 baterías AA.
Hay dos estándares básicos de transmisión de mensajes:
POCSAG (Grupo Asesor de Normalización del Código de la Oficina de Correos) y
FLEX . Ambos estándares son bastante antiguos, POCSAG se fabricó en 1982, puede admitir velocidades de 512, 1200 y 2400 bit / s. Para transmitir, el método FSK (modulación por desplazamiento de frecuencia) se utiliza con una separación de frecuencia de 4.5KHz. FLEX es un poco más nuevo (fue hecho por Motorola en el 90), puede funcionar con una velocidad de hasta 6400 bit / sy puede usar tanto FSK2 como FSK4.
En general, ambos protocolos son muy fáciles, y hace unos 20 años se crearon decodificadores de PC que pueden decodificar mensajes desde un puerto serie de tarjeta de sonido (no hay cifrado compatible, por lo que todos pueden leer todos los mensajes).
Veamos cómo funciona.
Recibiendo una señal
Primero, necesitamos una señal para decodificar. Tomemos una computadora portátil, un receptor rtl-sdr y consigámosla.

Se utiliza la modulación por desplazamiento de frecuencia, por lo que configuraremos FM. Con HDSDR guardaremos una señal en formato WAV.
Vamos a ver qué tenemos. Carga del archivo wav como una matriz de datos de Python:
from scipy.io import wavfile import matplotlib.pyplot as plt fs, data = wavfile.read("pocsag.wav") plt.plot(data) plt.show()
Salida (bits añadidos manualmente):

Como podemos ver, es fácil, e incluso "a simple vista" podemos dibujar bits en Paint, es fácil distinguir dónde está "0" y dónde está "1". Pero será demasiado largo para hacerlo manualmente, es hora de automatizar el proceso.
Después de ampliar el gráfico, podemos ver que cada bit tiene un ancho de 20 muestras. Tenemos 24000 muestras por segundo archivo wav de velocidad de bits, por lo que la velocidad de codificación es de 1200 bits / s. Vamos a encontrar una posición de cruce por cero: es el comienzo de la secuencia de bits. También agreguemos marcadores para verificar que todos los bits estén en los lugares adecuados.
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
Como podemos ver, no coincide perfectamente (el transmisor y el receptor tienen frecuencias ligeramente diferentes), pero definitivamente es suficiente para la decodificación.

Para señales largas probablemente necesitaremos un algoritmo de corrección automática de frecuencia, pero para este tipo de señales no es crítico.
El último paso: necesitamos traducir el archivo wav a la secuencia de bits. También es fácil, sabemos la longitud de cada bit, si la suma de datos es positiva, agregaremos "1", de lo contrario, "0" (finalmente se encontró que una señal debe revertirse, por lo que se reemplazaron 0 y 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)
Salida: secuencia de bits adecuada (en formato de cadena) que contiene nuestro mensaje.
101010101010101010101010101010101010101010101010101010101010101010101010101
010101010101010101010101010101010101010101010100111110011010010000101001101
100001111010100010011100000110010111011110101000100111000001100101110111101
010001001110000011001011101111010100010011100000110010111011110101000100111
000001100101110111101010001001110000011001011101111010100010011100000110010
011011110101000100111000001100101110111101010001001110000011001011101111010
100010011100000110010111011110101000100111000001100101110111101010001001110
...
111101111
Decodificar mensajes solo numéricos
Una secuencia de bits es mucho más conveniente que un archivo wav, podemos extraer datos de ella. Primero, dividamos los datos en bloques de 4 bytes.
10101010101010101010101010101010
10101010101010101010101010101010
10101010101010101010101010101010
10101010101010101010101010101010
01111100110100100001010011011000
01111010100010011100000110010111
01111010100010011100000110010111
01111010100010011100000110010111
01111010100010011100000110010111
00001000011011110100010001101000
10000011010000010101010011010100
01111100110100100001010111011000
11110101010001000001000000111000
01111010100010011100000110010111
01111010100010011100000110010111
01111010100010011100000110010111
00100101101001011010010100101111
Definitivamente podemos ver un patrón. Ahora necesitamos encontrar qué significa cada parte. El manual POCSAG está disponible
en formato PDF , permite verificar la descripción de las estructuras de datos.

Ahora es mucho más claro. El encabezado contiene un bloque largo "10101010101", se utiliza para "despertar" el buscapersonas desde un modo de suspensión. El mensaje en sí contiene los bloques Batch-1 ... Batch-N, cada bloque comienza a partir de la secuencia única FSC. Luego, como podemos ver en el manual, si la cadena comienza desde "0", contiene la dirección del destinatario. La dirección en sí (código de cap) se almacena es el localizador, y si no coincide, el localizador ignorará el mensaje. Si una cadena comienza desde "1", contiene el cuerpo del mensaje. En nuestro ejemplo tenemos 2 cadenas de este tipo.
No revisemos cada bloque. También podemos ver códigos inactivos: bloques vacíos 01111 ... 0111, no tienen ninguna información útil. Después de eliminarlos, obtenemos solo esto:
01111100110100100001010011011000 - Frame Sync
00001000011011110100010001101000 - Address
10000011010000010101010011010100 - Message
01111100110100100001010111011000 - Frame Sync
11110101010001000001000000111000 - Message
00100101101001011010010100101111 - Address
Necesitamos encontrar, qué hay dentro.
Después de revisar el manual, queda claro que hay dos tipos de mensajes:
solo numéricos y alfanuméricos . Los mensajes solo numéricos se guardan como códigos BCD de 4 bits, por lo que 20 bits pueden contener 5 símbolos (también hay bits CRC, no los estamos usando por ahora). Si el mensaje es alfanumérico, se utiliza la codificación ASCII de 7 bits. Este mensaje es demasiado corto, por lo que solo puede ser un mensaje numérico.
De las cadenas 10000011010000010101010011010100 y 11110101010001000001000000111000 podemos obtener estas secuencias de 4 bits:
1 0000 0110 1000 0010 10101 0011010100 - 0h 6h 8h 2h Ah
1 1110 1010 1000 1000 00100 0000111000 - Eh Ah 8h 8h 2h
El siguiente paso es obtener la tabla de decodificación del manual:

Es obvio que un mensaje solo numérico puede contener dígitos 0-9, letra U ("ugrent"), espacio y dos paréntesis. Vamos a escribir un pequeño método para decodificarlo:
def parse_msg(block):
Finalmente, recibimos un mensaje "0682 *) * 882".
Es difícil saber qué significa, pero si se usan los mensajes solo numéricos, probablemente alguien lo necesite.
Decodificar mensajes alfanuméricos
El siguiente paso, y más interesante, es decodificar mensajes alfanuméricos. Es más interesante, porque como salida, deberíamos obtener el texto legible por humanos.
Primero, necesitamos grabar un mensaje nuevamente, usaremos HDSDR. No conocemos un tipo de mensaje antes de la decodificación, por lo que solo registraremos un mensaje más largo que podamos obtener y esperamos que contenga algo de texto.

Después de convertir de wav a una secuencia de bits (ver un código de Python arriba), estamos obteniendo esto:

Algunas cosas interesantes que podemos ver de inmediato, a simple vista, como por ejemplo, la secuencia de inicio 01010101010101 se repite dos veces. Por lo tanto, este mensaje no solo es más largo, sino que literalmente contiene dos mensajes, combinados (un estándar no lo niega, por cierto).
Como hemos encontrado antes, cada bloque de datos comienza a partir de una secuencia, llamada Código de sincronización de trama (01111100 ...), después de que se envían bloques de 32 bits. Cada bloque puede almacenar la dirección o el cuerpo del mensaje.
Anteriormente recibimos los mensajes solo numéricos, ahora queremos leer los mensajes ASCII. Primero, necesitamos distinguirlos. Estos datos se guardan en un campo "Bits de función" (bits 20-21): si ambos bits son 00, es un mensaje solo numérico, si los bits son 11, es un mensaje de texto.
Es interesante mencionar que ese campo de mensaje tiene una longitud de 20 bits, por lo que es ideal colocar cinco bloques de 4 bits en el caso de un mensaje solo numérico. Pero si tenemos un mensaje ASCII de 7 bits, no podemos dividir 20 a 7. Es posible predecir que la primera versión del protocolo
admitía solo mensajes numéricos (no olvide que se hizo en 1982
y probablemente los primeros buscapersonas de tubo nixie) no pudieron mostrar más ), y solo más tarde se agregó compatibilidad con mensajes ASCII. Debido a las razones heredadas, el estándar de encuadre no se modificó, y los desarrolladores utilizaron el enfoque fácil: simplemente combinaron bits "tal cual", uno tras otro. De cada mensaje necesitamos tomar 20 bits y fusionarlo con el siguiente, finalmente podemos decodificar el cuerpo del mensaje.
Veamos un bloque de nuestro mensaje (los espacios se sumaron para leer más fácilmente):
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
El bit "0" en la primera cadena nos muestra que es el campo de dirección, y el "11" en 20-21 bits nos muestra que el mensaje es realmente alfanumérico. Luego solo tomamos 20 bits de cada cadena y los fusionamos.
Esta es nuestra secuencia de bits:
00010100000110110011010110100110011101001101000111011010010011000001101000
11010011100000010100011011001100101110110011010001100101110001011010101100
000010010101000101101110110011011010010100000010100000111101010101101
En POCSAG se usa el código ASCII de 7 bits, por lo que dividiremos una cadena en 7 bloques de caracteres:
0001010 0000110 1100110 1011010 0110011 1010011 ...
Después de intentar decodificarlo (la tabla ASCII se puede encontrar fácilmente en Internet), obtenemos ... simplemente nada. Revisando el manual nuevamente, y aquí está la pequeña frase "Los caracteres ASCII se colocan de izquierda a derecha (MSB a LSB). El LSB está transmitiendo primero ". Entonces, el bit bajo se transmite primero: para una decodificación correcta, necesitamos invertir todas las cadenas.
Es demasiado aburrido hacerlo manualmente, así que escribamos un código Python:
def parse_msg(block): msgs = "" for cw in range(16): cws = block[32 * cw:32 * (cw + 1)]
Finalmente, estamos obteniendo esta secuencia (bits, códigos de símbolos y símbolos ASCII):
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
Después de la fusión, obtenemos la cadena: "(03-feb-2019 13:31:45 * 476) AWZ". Como se prometió, es bastante legible para los humanos.
Por cierto, es interesante mencionar que se utilizan códigos ASCII de 7 bits. Los símbolos de algunos alfabetos (alemán, cirílico, etc.) no se pueden codificar correctamente en 7 bits. ¿Por qué 7 bits? Probablemente los ingenieros habían decidido que "7 bits serán suficientes para todos", quién sabe ...
Conclusión
Fue realmente interesante investigar cómo funciona POCSAG. Es uno de los protocolos raros, que están en uso hasta ahora, que literalmente se puede decodificar en la hoja de papel (y definitivamente no lo intentaré con TETRA o GSM).
Por supuesto, el protocolo POCSAG no se describe completamente aquí. La parte más importante e interesante está hecha, otras cosas no son tan emocionantes. Al menos, no hay decodificación de capcodes y no hay código de corrección de errores (BCH Check Bits): puede permitir corregir hasta 2 bits incorrectos en el mensaje. Pero no había objetivo para escribir otro decodificador POCSAG aquí, ya hay suficientes.
Para aquellos que quieran probar la decodificación real con rtl-sdr, se puede usar la
aplicación gratuita
PDW . No requiere instalación, solo es suficiente para reenviar el sonido de HDSDR a PDW a través de la aplicación Virtual Audio Cable.
Los resultados se ven así:

(tenga en cuenta que la decodificación de mensajes de servicio público puede ser ilegal en algunos países y, de todos modos, respetar la privacidad de los destinatarios)
Si alguien quiere obtener más información sobre este tema, las fuentes del decodificador
multimon-ng están disponibles, puede decodificar muchos protocolos, también POCSAG y FLEX.
Gracias por leer