From 9bfc6f962d006ce226ee8e46983de3bcbbed0a25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20P=C3=A9rez?= Date: Thu, 16 Apr 2026 06:40:20 +0000 Subject: [PATCH] docs: sync EN/ES docs with current runtime behavior --- .gitignore | 10 ++++-- docs/en/README.md | 2 +- .../development/behaviour-and-timers.md | 31 +++++++++++++++++++ docs/en/server/protocols/openbridge.md | 4 +-- .../user-guide/bridges-and-talkgroups.md | 6 ++++ docs/en/server/user-guide/introduction.md | 2 +- docs/en/server/user-guide/special-numbers.md | 18 +++++++++++ docs/es/README.md | 2 +- .../development/behaviour-and-timers.md | 31 +++++++++++++++++++ docs/es/server/protocols/openbridge.md | 6 ++-- .../user-guide/bridges-and-talkgroups.md | 6 ++++ docs/es/server/user-guide/introduction.md | 2 +- docs/es/server/user-guide/special-numbers.md | 18 +++++++++++ 13 files changed, 126 insertions(+), 12 deletions(-) diff --git a/.gitignore b/.gitignore index 047bf97..59d2713 100644 --- a/.gitignore +++ b/.gitignore @@ -9,8 +9,8 @@ adn-voice.yaml *.local.yaml *.local.yml -# Local/helper scripts (not for prod repo; users use their own run method) -scripts/run.sh +# Local/helper scripts (keep scripts out of git) +scripts/ # Env and secrets .env @@ -33,9 +33,13 @@ data/*.bak json/* !json/.gitkeep -# Internal +# Internal docs-priv/ +# Docs policy: keep source markdown + mkdocs configs in git; ignore generated assets +docs/build-assets/ +requirements-docs.txt + # MkDocs build output (site/en, site/es) site/ diff --git a/docs/en/README.md b/docs/en/README.md index 2a30308..3d352d8 100644 --- a/docs/en/README.md +++ b/docs/en/README.md @@ -12,7 +12,7 @@ The **ADN DMR Peer Server** is a [GPL-3.0](https://www.gnu.org/licenses/gpl-3.0. ### What the server does - Terminates **HBP** (HomeBrew Protocol) links to **MASTER** and **PEER** systems (hotspots, repeaters). -- Terminates **OpenBridge** links to other servers over UDP — **DMRE v5** (recommended on ADN) or legacy **DMRD** v1. +- Terminates **OpenBridge** links to other servers over UDP — **DMRE v5** (recommended on ADN) or **DMRD** v1 compatibility mode. - Runs **bridge routing** (`BRIDGES`): forwards group voice, loop control, ACLs, optional **BCSQ** / **BCKA**. - Supports **private calls** (`SUB_MAP`), **voice**, **TTS**, **recording**, and **TCP reporting** to the monitor. diff --git a/docs/en/server/development/behaviour-and-timers.md b/docs/en/server/development/behaviour-and-timers.md index 6b679a0..2e3775b 100644 --- a/docs/en/server/development/behaviour-and-timers.md +++ b/docs/en/server/development/behaviour-and-timers.md @@ -9,3 +9,34 @@ Intervals are part of the **observable behaviour** of the product (operators and ## Configuration visibility Runtime state lives in a shared **`config`** dict: options from peers, `SUB_MAP`, OpenBridge control-plane fields (`_bcsq`, `_bcka`), and similar. Adapters update this structure; use cases read it. This matches how the running process is inspected in logs and support scenarios. + +## Core timer intervals (operational contract) + +The following intervals are part of the current runtime behavior: + +| Loop | Interval | Role | +|------|----------|------| +| `rule_timer` | **52s** | Bridge timeout/on-off state progression. | +| `stream_trimmer` | **5s** | Stream cleanup, timeout handling, end-of-call state trimming. | +| `bridge_reset` | **6s** | Bridge reset flag cleanup and pending reset completion. | +| `options_config_loop` | **26s** | Refresh static TG / reflector options from peer OPTIONS payloads. | +| `statTrimmer` | **303s** | Trim stale STAT bridges and transient status entries. | + +If you change one of these intervals, document the operational impact for monitoring, loop behavior, and troubleshooting. + +## In-band VTERM scope + +In-band bridge signalling on voice terminator (VTERM) is intentionally scoped to: + +- call type **`group`** +- call type **`vcsbk`** + +It is not applied on **unit/private** VTERM paths. + +## Packet-control behavior notes + +Current packet-control behavior for stream dedup and ordering: + +- OBP hash duplicate-drop checks are evaluated with **`seq > 0`** guard. +- HBP still computes/stores CRC for `seq == 0`, while duplicate-drop by CRC remains guarded by **`seq > 0`**. +- This avoids over-dropping first-packet edge cases while preserving stream duplicate protection. diff --git a/docs/en/server/protocols/openbridge.md b/docs/en/server/protocols/openbridge.md index 9899d72..1251ca0 100644 --- a/docs/en/server/protocols/openbridge.md +++ b/docs/en/server/protocols/openbridge.md @@ -4,13 +4,13 @@ On the wire, extended OpenBridge uses the **`DMRE`** opcode. The **embedded protocol version** byte inside the frame (see [DMRE v5 layout](dmre-v5.md)) selects the layout: **version > 4** is the **89-byte v5** format (hops, source repeater field, BLAKE2b MAC). In documentation and operator discussions, **“DMRE v5”** and **“OpenBridge v5”** refer to the same thing: **DMRE frames with embedded version 5** (not the older short DMRD-only path). -**Recommendation (ADN Systems network):** All inter-server links that participate in the **ADN Systems** mesh should use **DMRE v5** (`PROTO_VER: 5` in YAML, which sets the negotiated **VER** / embedded version) and **`ENHANCED_OBP: true`** so **BCSQ**, **BCKA**, and multi-path loop control behave consistently. **Peers** (other servers) should be configured the same way. **DMRD v1** (HMAC-only) remains supported for interoperability with older stacks, but it is **not** the preferred mode for new ADN deployments. +**Recommendation (ADN Systems network):** All inter-server links that participate in the **ADN Systems** mesh should use **DMRE v5** (`PROTO_VER: 5` in YAML, which sets the negotiated **VER** / embedded version) and **`ENHANCED_OBP: true`** so **BCSQ**, **BCKA**, and multi-path loop control behave consistently. **Peers** (other servers) should be configured the same way. **DMRD v1** (HMAC-only) remains available as a compatibility mode, but it is **not** the preferred mode for new ADN deployments. ## What OpenBridge is **OpenBridge** is a UDP protocol between **servers** (and some gateways). It carries DMR voice using: -- **`DMRD`** version 1 — HMAC-SHA1 authenticated payload (legacy interop); or +- **`DMRD`** version 1 — HMAC-SHA1 authenticated payload (compatibility mode); or - **`DMRE`** — extended frame with **BLAKE2b** MAC, embedded version, timestamps, **hops**, source server/repeater IDs, etc. (**DMRE v5** = embedded version 5, recommended above). This stack implements the **OPENBRIDGE** peer mode in **`udp_hbp.py`** and bridge routing in **`BridgeUseCases`**. diff --git a/docs/en/server/user-guide/bridges-and-talkgroups.md b/docs/en/server/user-guide/bridges-and-talkgroups.md index 48479ab..cfbc2bb 100644 --- a/docs/en/server/user-guide/bridges-and-talkgroups.md +++ b/docs/en/server/user-guide/bridges-and-talkgroups.md @@ -17,6 +17,12 @@ The router scans `BRIDGES` for an **ACTIVE** row matching the **current source s - **User-activated** bridges are created when a user keys a TG without a pre-built row (subject to `DEFAULT_UA_TIMER` and options). - **Static** TGs and **STAT** bridges are created from **OPTIONS** / `make_static_tg` / `GEN_STAT_BRIDGES` flows. +## Source-row guard and safe iteration + +Forwarding is allowed only when the current system has a matching **ACTIVE source row** for that TG/slot context. This prevents accidental forwarding from rows that are present but not currently eligible as source legs. + +`BRIDGES` scans and updates are also protected against concurrent row mutations during runtime loops, so timer/debug passes do not corrupt active iteration state. + ## OpenBridge and TG display For OpenBridge, the **DMR destination** in the packet may differ from the **TGID** in a bridge row (remap). Monitoring may show **RX TG** (as received) vs **TX TG** (as rewritten for a destination); correlate by **`stream_id`**, not TG alone. diff --git a/docs/en/server/user-guide/introduction.md b/docs/en/server/user-guide/introduction.md index f412882..8e54c84 100644 --- a/docs/en/server/user-guide/introduction.md +++ b/docs/en/server/user-guide/introduction.md @@ -5,7 +5,7 @@ This service is a **DMR peer and bridge**. It implements: - **HBP** over UDP to **MASTER** and **PEER** systems (DMRD frames, authentication, pings). -- **OpenBridge** over UDP to other networks — **DMRE v5** (embedded version 5, BLAKE2b, hops) is the **recommended** inter-server mode on ADN; **DMRD** v1 remains for legacy interop (see [OpenBridge](../protocols/openbridge.md#dmre-and-openbridge-v5)). +- **OpenBridge** over UDP to other networks — **DMRE v5** (embedded version 5, BLAKE2b, hops) is the **recommended** inter-server mode on ADN; **DMRD** v1 remains available for compatibility (see [OpenBridge](../protocols/openbridge.md#dmre-and-openbridge-v5)). Configuration is **YAML** (`adn-server.yaml`), merged at runtime with optional voice settings (`adn-voice.yaml`). The shipped template is `adn-server.example.yaml`. diff --git a/docs/en/server/user-guide/special-numbers.md b/docs/en/server/user-guide/special-numbers.md index 8c538ed..953a828 100644 --- a/docs/en/server/user-guide/special-numbers.md +++ b/docs/en/server/user-guide/special-numbers.md @@ -48,6 +48,14 @@ That follows a common **HomeBrew / conference** convention: keep short **local s Many **reflector / dial** rows store **`TGID` = 9** on **TS2** as the **leg destination** used internally to attach the dynamic path to the real talkgroup — that is wiring inside `BRIDGES`, not something you “call” like a normal national TG. +### In-band VTERM rules that affect TG 9 / reflector behavior + +In-band bridge activation/deactivation is applied on **voice terminator (VTERM)** with this scope: + +- It runs only for call types **`group`** and **`vcsbk`** (not for **unit/private** VTERM). +- For reflector bridges (`#...`), in-band handling is evaluated only when the destination is **TG 9**. +- This is why reflector prompts and dial wiring are tied to TG 9 while private calls do not trigger that bridge-timer logic. + ## TG / ID 4000 — deactivate dynamic bridges **Purpose:** Clear **user-activated (dynamic) bridges** for the system that receives the call. @@ -60,6 +68,15 @@ Many **reflector / dial** rows store **`TGID` = 9** on **TS2** as the **leg dest Use this when operators need to **reset** dynamic routing without restarting the server. +### `SINGLE_MODE` impact on deactivation logic + +When in-band rules evaluate deactivation on a MASTER slot: + +- **`SINGLE_MODE: true`**: deactivation is aggressive. A bridge leg can be turned off by OFF/RESET triggers, **TG 4000**, or traffic that does not match the leg TG. +- **`SINGLE_MODE: false`**: deactivation is conservative. **TG 4000** is the primary forced-deactivate trigger; static TG rows and reflector rows are preserved according to current bridge checks. + +Operationally: if users report “bridges drop too easily” after OPTIONS updates, verify the current `SINGLE_MODE` value and hotspot OPTIONS payload. + ## TG 9991–9999 — information / on-demand audio **Purpose:** **Play back** pre-generated AMBE (“ondemand”) files (e.g. station info, help). @@ -67,6 +84,7 @@ Use this when operators need to **reset** dynamic routing without restarting the **Behaviour:** - Triggers **`playFileOnRequest`**-style handling: maps the last digits to a file name under the configured audio tree. +- Trigger path is **private VTERM** for destination **9991–9999**, then async playback generation. - Works from **MASTER** and **PEER** paths. The **audio** is sent with **source ID 5000** and **destination TG 9** in the generated stream. File layout: [Voice, announcements, and TTS](voice-and-tts.md). diff --git a/docs/es/README.md b/docs/es/README.md index 977af58..65e8de0 100644 --- a/docs/es/README.md +++ b/docs/es/README.md @@ -11,7 +11,7 @@ El **ADN DMR Peer Server** es un puente de conferencia [GPL-3.0](https://www.gnu ### Qué hace el servidor - Termina enlaces **HBP** (HomeBrew Protocol) hacia sistemas **MASTER** y **PEER** (hotspots, repetidores). -- Termina enlaces **OpenBridge** hacia otros servidores por UDP — **DMRE v5** (recomendado en ADN) o **DMRD** v1 heredado. +- Termina enlaces **OpenBridge** hacia otros servidores por UDP — **DMRE v5** (recomendado en ADN) o **DMRD** v1 en modo de compatibilidad. - Ejecuta **enrutado de bridges** (`BRIDGES`): voz de grupo, control de bucle, ACL, **BCSQ** / **BCKA** opcionales. - Soporta **llamadas privadas** (`SUB_MAP`), **voz**, **TTS**, **grabación** e **informes TCP** al monitor. diff --git a/docs/es/server/development/behaviour-and-timers.md b/docs/es/server/development/behaviour-and-timers.md index dda843f..03b5c69 100644 --- a/docs/es/server/development/behaviour-and-timers.md +++ b/docs/es/server/development/behaviour-and-timers.md @@ -9,3 +9,34 @@ Los intervalos forman parte del **comportamiento observable** del producto (oper ## Visibilidad de la configuración El estado en tiempo de ejecución vive en un **`config` dict** compartido: opciones de peers, `SUB_MAP`, campos de plano de control OpenBridge (`_bcsq`, `_bcka`), y similares. Los adaptadores actualizan esta estructura; los casos de uso la leen. Así coincide con cómo se inspecciona el proceso en ejecución en logs y escenarios de soporte. + +## Intervalos clave de temporizadores (contrato operativo) + +Los siguientes intervalos forman parte del comportamiento actual en ejecución: + +| Bucle | Intervalo | Rol | +|------|-----------|-----| +| `rule_timer` | **52s** | Progresión de timeout y estado on/off de bridges. | +| `stream_trimmer` | **5s** | Limpieza de streams, manejo de timeout y cierre de estado de llamada. | +| `bridge_reset` | **6s** | Limpieza de flags de reset y cierre de resets pendientes. | +| `options_config_loop` | **26s** | Refresco de TG estáticas / reflector desde payload OPTIONS de peers. | +| `statTrimmer` | **303s** | Limpieza de bridges STAT obsoletos y estados transitorios. | + +Si cambias uno de estos intervalos, documenta el impacto operativo en monitorización, comportamiento de bucles y troubleshooting. + +## Alcance de VTERM in-band + +La señalización in-band en voice terminator (VTERM) está acotada a: + +- tipo de llamada **`group`** +- tipo de llamada **`vcsbk`** + +No se aplica en rutas VTERM **unit/private**. + +## Notas de comportamiento de packet-control + +Comportamiento actual para deduplicación y orden de streams: + +- La deduplicación por hash en OBP se evalúa con guardia **`seq > 0`**. +- En HBP se calcula/guarda CRC también para `seq == 0`, pero la caída por duplicado por CRC sigue guardada por **`seq > 0`**. +- Esto evita sobre-descartar casos de primer paquete y mantiene protección de duplicados de stream. diff --git a/docs/es/server/protocols/openbridge.md b/docs/es/server/protocols/openbridge.md index 7906493..5ee7c12 100644 --- a/docs/es/server/protocols/openbridge.md +++ b/docs/es/server/protocols/openbridge.md @@ -2,15 +2,15 @@ ## DMRE y «OpenBridge v5» {#dmre-and-openbridge-v5} -En cable, OpenBridge extendido usa el opcode **`DMRE`**. El **byte de versión de protocolo embebido** dentro de la trama (ver [disposición DMRE v5](dmre-v5.md)) selecciona el diseño: **versión > 4** es el formato **v5 de 89 bytes** (saltos, campo repetidor fuente, MAC BLAKE2b). En documentación y conversaciones de operadores, **«DMRE v5»** y **«OpenBridge v5»** son lo mismo: **tramas DMRE con versión embebida 5** (no el camino corto solo DMRD antiguo). +En cable, OpenBridge extendido usa el opcode **`DMRE`**. El **byte de versión de protocolo embebido** dentro de la trama (ver [disposición DMRE v5](dmre-v5.md)) selecciona el diseño: **versión > 4** es el formato **v5 de 89 bytes** (saltos, campo repetidor fuente, MAC BLAKE2b). En documentación y conversaciones de operadores, **«DMRE v5»** y **«OpenBridge v5»** son lo mismo: **tramas DMRE con versión embebida 5** (no el camino corto solo DMRD). -**Recomendación (red ADN Systems):** todos los enlaces inter-servidor que participen en la malla **ADN Systems** deberían usar **DMRE v5** (`PROTO_VER: 5` en YAML, que fija **VER** / versión embebida negociada) y **`ENHANCED_OBP: true`** para que **BCSQ**, **BCKA** y el control de bucle multipath se comporten igual. Los **pares** (otros servidores) deben configurarse igual. **DMRD v1** (solo HMAC) sigue soportado para interoperar con pilas antiguas, pero **no** es el modo preferido para nuevos despliegues ADN. +**Recomendación (red ADN Systems):** todos los enlaces inter-servidor que participen en la malla **ADN Systems** deberían usar **DMRE v5** (`PROTO_VER: 5` en YAML, que fija **VER** / versión embebida negociada) y **`ENHANCED_OBP: true`** para que **BCSQ**, **BCKA** y el control de bucle multipath se comporten igual. Los **pares** (otros servidores) deben configurarse igual. **DMRD v1** (solo HMAC) permanece como modo de compatibilidad, pero **no** es el modo preferido para nuevos despliegues ADN. ## Qué es OpenBridge **OpenBridge** es un protocolo UDP entre **servidores** (y algunos gateways). Transporta voz DMR usando: -- **`DMRD`** versión 1 — carga autenticada HMAC-SHA1 (interop heredada); o +- **`DMRD`** versión 1 — carga autenticada HMAC-SHA1 (modo de compatibilidad); o - **`DMRE`** — trama extendida con MAC **BLAKE2b**, versión embebida, marcas de tiempo, **saltos**, IDs servidor/repetidor de origen, etc. (**DMRE v5** = versión embebida 5, recomendada arriba). Esta pila implementa el modo par **OPENBRIDGE** en **`udp_hbp.py`** y el enrutado de bridges en **`BridgeUseCases`**. diff --git a/docs/es/server/user-guide/bridges-and-talkgroups.md b/docs/es/server/user-guide/bridges-and-talkgroups.md index 50bc074..afda545 100644 --- a/docs/es/server/user-guide/bridges-and-talkgroups.md +++ b/docs/es/server/user-guide/bridges-and-talkgroups.md @@ -17,6 +17,12 @@ El router recorre `BRIDGES` buscando una fila **ACTIVE** que coincida con el **s - Los bridges **activados por usuario** se crean cuando alguien pulsa una TG sin fila previa (sujeto a `DEFAULT_UA_TIMER` y opciones). - Las TG **estáticas** y bridges **STAT** se crean desde flujos **OPTIONS** / `make_static_tg` / `GEN_STAT_BRIDGES`. +## Guardia de fila de origen e iteración segura + +El reenvío solo se permite cuando el sistema actual tiene una **fila de origen ACTIVE** que coincide con ese contexto TG/slot. Esto evita reenviar desde filas presentes pero no elegibles como patas de origen. + +Los recorridos y actualizaciones de `BRIDGES` también están protegidos frente a mutaciones concurrentes de filas durante bucles en ejecución, de forma que los pases de temporizador/debug no corrompan el estado de iteración activa. + ## OpenBridge y visualización de TG En OpenBridge, el **destino DMR** en el paquete puede diferir del **TGID** en una fila de bridge (remap). El monitor puede mostrar **TG RX** (recibida) frente a **TG TX** (reescrita para un destino); correlaciona por **`stream_id`**, no solo por TG. diff --git a/docs/es/server/user-guide/introduction.md b/docs/es/server/user-guide/introduction.md index ddc708f..c03a4a9 100644 --- a/docs/es/server/user-guide/introduction.md +++ b/docs/es/server/user-guide/introduction.md @@ -5,7 +5,7 @@ Este servicio es un **peer y bridge DMR**. Implementa: - **HBP** por UDP hacia sistemas **MASTER** y **PEER** (tramas DMRD, autenticación, pings). -- **OpenBridge** por UDP hacia otras redes — **DMRE v5** (versión embebida 5, BLAKE2b, saltos) es el modo **recomendado** entre servidores en ADN; **DMRD** v1 sigue para interoperabilidad heredada (ver [OpenBridge](../protocols/openbridge.md#dmre-and-openbridge-v5)). +- **OpenBridge** por UDP hacia otras redes — **DMRE v5** (versión embebida 5, BLAKE2b, saltos) es el modo **recomendado** entre servidores en ADN; **DMRD** v1 sigue disponible para compatibilidad (ver [OpenBridge](../protocols/openbridge.md#dmre-and-openbridge-v5)). La configuración es **YAML** (`adn-server.yaml`), fusionada en tiempo de ejecución con ajustes de voz opcionales (`adn-voice.yaml`). La plantilla incluida es `adn-server.example.yaml`. diff --git a/docs/es/server/user-guide/special-numbers.md b/docs/es/server/user-guide/special-numbers.md index 71310c9..d3f7294 100644 --- a/docs/es/server/user-guide/special-numbers.md +++ b/docs/es/server/user-guide/special-numbers.md @@ -48,6 +48,14 @@ Los **anuncios programados** y **TTS** usan el **`TG`** que configures en `adn-v Muchas filas **reflector / marcado** guardan **`TGID` = 9** en **TS2** como **destino de pata** interno para enganchar el camino dinámico al TG real — es cableado dentro de `BRIDGES`, no un «número al que llamar» como un TG nacional normal. +### Reglas in-band de VTERM que afectan TG 9 / reflectores + +La activación/desactivación in-band de bridges se aplica sobre **voice terminator (VTERM)** con este alcance: + +- Solo corre para tipos de llamada **`group`** y **`vcsbk`** (no para VTERM **unit/private**). +- En bridges reflector (`#...`), el manejo in-band solo se evalúa cuando el destino es **TG 9**. +- Por eso los mensajes de reflector y el cableado de marcado usan TG 9, mientras que llamadas privadas no disparan esa lógica de temporizadores de bridge. + ## TG / ID 4000 — desactivar bridges dinámicos **Propósito:** borrar **bridges dinámicos activados por usuario** para el sistema que recibe la llamada. @@ -60,6 +68,15 @@ Muchas filas **reflector / marcado** guardan **`TGID` = 9** en **TS2** como **de Úsalo cuando los operadores necesiten **reiniciar** el enrutado dinámico sin reiniciar el servidor. +### Impacto de `SINGLE_MODE` en la lógica de desactivación + +Cuando las reglas in-band evalúan desactivación en un slot MASTER: + +- **`SINGLE_MODE: true`**: la desactivación es agresiva. Una pata puede apagarse por triggers OFF/RESET, por **TG 4000** o por tráfico que no coincide con el TG de la pata. +- **`SINGLE_MODE: false`**: la desactivación es conservadora. **TG 4000** es el trigger principal de apagado forzado; filas de TG estática y filas reflector se preservan según los chequeos actuales del bridge. + +A nivel operativo: si usuarios reportan «bridges que se caen demasiado fácil» tras cambios de OPTIONS, verifica el valor actual de `SINGLE_MODE` y el payload OPTIONS del hotspot. + ## TG 9991–9999 — audio informativo / bajo demanda **Propósito:** **reproducir** ficheros AMBE pregenerados («ondemand») (p. ej. información de la estación, ayuda). @@ -67,6 +84,7 @@ Muchas filas **reflector / marcado** guardan **`TGID` = 9** en **TS2** como **de **Comportamiento:** - Dispara manejo tipo **`playFileOnRequest`**: mapea los últimos dígitos al nombre de fichero bajo el árbol de audio configurado. +- La ruta de disparo es **private VTERM** para destino **9991–9999**, seguida de generación/reproducción asíncrona. - Funciona desde rutas **MASTER** y **PEER**. El **audio** se envía con **ID de fuente 5000** y **TG de destino 9** en el flujo generado. Estructura de ficheros: [Voz, anuncios y TTS](voice-and-tts.md).