@ -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. |
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`**.
@ -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.
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`.
@ -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 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.
@ -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).
@ -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.
## 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`**.
@ -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.
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`.
@ -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).