CEDNAV · Armada Nacional de Colombia · Ingeniería de Software

BARRACUDA SVELT
Diagrama de Componentes UML

Descomposición modular del ecosistema: interfaces proporcionadas/requeridas, dependencias entre componentes y mecanismos de comunicación inter-componente

1. Diagrama de Componentes UML — Visión General § Component Diagram
graph TB subgraph BACKEND[" PAQUETE: BACKEND NODE.JS (server.js)"] direction TB subgraph INFRA["CAPA INFRAESTRUCTURA — Drivers de Red"] TCP["«componente»\nTCPService\n──────────\nnet.Socket :6001\nReconexión automática\nWatchdog 1200ms"] UDP_JOY["«componente»\nJoystickDriver\n──────────\ndgram :4531\n$BPJ frame parser"] UDP_KBD["«componente»\nKeyboardDriver\n──────────\ndgram :5501\nBidireccional"] UDP_NMEA["«componente»\nNMEADriver\n──────────\ndgram :70xx\nGPS/Gyro/DDU"] UDP_CMS["«componente»\nCMSDriver\n──────────\ndgram :8000\n42-byte tracks"] VIDEO["«componente»\nVideoService\n──────────\nchild_process.spawn\nFFmpeg H.264"] end subgraph DOMAIN["CAPA DOMINIO — Lógica Naval"] BPS["«componente»\nBinaryProtocolService\n──────────\ngenerateFrame() 29B TX\nparseFrame() 31B RX\ncalculateChecksum() XOR"] FSM["«componente»\nFSM WorkMode\n──────────\nRWS ↔ EOT ↔ CMS\nGuard Clauses\nTransición segura"] JOY_DEC["«componente»\nJoystickDecoder\n──────────\nDeadzone ±5\nEjes X/Y/Z signed\n12 botones map"] NMEA_SVC["«componente»\nNMEAService\n──────────\n$GPGGA → Lat/Lon\n$HEHDT → Heading\nPitch/Roll BigEndian"] CMS_SVC["«componente»\nCMSService\n──────────\nParseo pistas 42B\nBearing/Range/Class\ncmsEnabled flag"] FEED["«componente»\nFeedbackService\n──────────\nLED state → 5 bytes\nHardware-confirmed UI\nPanel sync"] end subgraph APP["CAPA APLICACIÓN — Orquestador"] SRV["«componente»\nserver.js\n──────────\nEventEmitter Hub\nHeartbeat Loop 100ms\nPipeline coordinador"] SM["«componente»\nStationManager\n──────────\nExclusividad mando\nC1/C2/C3 assignment\nvalidateExclusivity()"] WS["«componente»\nWebSocketServer\n──────────\nws :8001\nJSON Full-Duplex\nBroadcast a Renderer"] end end subgraph FRONTEND[" PAQUETE: FRONTEND SVELTE (Chromium Renderer)"] direction TB subgraph STORES["CAPA ESTADO — Svelte Stores"] ST_IC["«store»\nicData\nTelemetría IC"] ST_STA["«store»\nstationStatus\nEstado estación"] ST_GYRO["«store»\ngyroData\nHeading buque"] ST_CMS["«store»\ncmsTracks\nPistas tácticas"] end subgraph VIEWS["CAPA PRESENTACIÓN — Componentes UI"] RADAR["«componente»\nRadar.svelte\n──────────\nPPI SVG vectorial\nBearing RWS/EOT\nCMS tracks overlay"] GAUGE["«componente»\nGaugePanel.svelte\n──────────\nRonza / Elevación\nEstado IC realtime"] VID_C["«componente»\nVideoEOT.svelte\n──────────\nCanvas H.264\nStream segregado"] HACK["«componente»\nHackingView.svelte\n──────────\nAuditoría HEX live\nTX/RX frames raw"] SET["«componente»\nSettings.svelte\n──────────\nSelección estación\nConfiguración IP"] end end subgraph EXTERNAL["🔌 COMPONENTES EXTERNOS"] IC_EXT["«externo»\nIC Gabinete\nFFS-RWS Controller"] HW["«externo»\nHardware Arma\nServomotores/Sensores"] JOY_HW["«externo»\nJoystick Táctico"] KBD_HW["«externo»\nTeclado Naval"] NMEA_HW["«externo»\nGPS / Gyro / DDU"] CMS_HW["«externo»\nSistema CMS"] CAM_HW["«externo»\nCámaras EOT"] end %% Infraestructura → Dominio (Dependencias de Interfaz) TCP -.->|"«use»"| I_BPS(("I_Protocol")) I_BPS --- BPS UDP_JOY -.->|"«use»"| I_JOY(("I_Joystick")) I_JOY --- JOY_DEC UDP_NMEA -.->|"«use»"| I_NMEA(("I_NMEA")) I_NMEA --- NMEA_SVC UDP_CMS -.->|"«use»"| I_CMS(("I_CMS")) I_CMS --- CMS_SVC UDP_KBD -.->|"«use»"| I_FEED(("I_Feedback")) I_FEED --- FEED %% Dominio → Aplicación (Consumo de Interfaz) BPS -.->|"«event»"| I_SRV(("I_Control")) FSM -.->|"«event»"| I_SRV JOY_DEC -.->|"«event»"| I_SRV NMEA_SVC -.->|"«event»"| I_SRV CMS_SVC -.->|"«event»"| I_SRV FEED -.->|"«event»"| I_SRV I_SRV --- SRV SM -.->|"«call»"| I_SRV SRV -.->|"«call»"| I_BPS SRV -.->|"«call»"| I_FSM(("I_WorkMode")) I_FSM --- FSM %% Aplicación → Frontend (Broadcasting / WebSockets) WS -.->|"«transmit»"| I_ST_IC(("I_Store_IC")) WS -.->|"«transmit»"| I_ST_STA(("I_Store_STA")) WS -.->|"«transmit»"| I_ST_GYRO(("I_Store_GYRO")) WS -.->|"«transmit»"| I_ST_CMS(("I_Store_CMS")) I_ST_IC --- ST_IC I_ST_STA --- ST_STA I_ST_GYRO --- ST_GYRO I_ST_CMS --- ST_CMS %% Stores → Views (Suscripción e Interfaces Web) ST_IC -.->|"«bind»"| I_RADAR(("I_Radar_View")) ST_GYRO -.->|"«bind»"| I_RADAR ST_CMS -.->|"«bind»"| I_RADAR I_RADAR --- RADAR ST_IC -.->|"«bind»"| I_GAUGE(("I_Gauge_View")) I_GAUGE --- GAUGE ST_IC -.->|"«bind»"| I_HACK(("I_Hacking_View")) I_HACK --- HACK ST_STA -.->|"«bind»"| I_SET(("I_Settings_View")) I_SET --- SET %% Externos (Interfaces Físicas) IC_EXT <-->|"«protocol» TCP :6001"| TCP JOY_HW -.->|"«interface» UDP :4531"| UDP_JOY KBD_HW <-->|"«interface» UDP :5501"| UDP_KBD NMEA_HW -.->|"«interface» UDP :70xx"| UDP_NMEA CMS_HW -.->|"«interface» UDP :8000"| UDP_CMS CAM_HW -.->|"«interface» UDP :3751x"| VIDEO IC_EXT -.->|"«hardware»"| HW style TCP fill:#052e16,stroke:#34d399,color:#fff style UDP_JOY fill:#052e16,stroke:#34d399,color:#fff style UDP_KBD fill:#052e16,stroke:#34d399,color:#fff style UDP_NMEA fill:#052e16,stroke:#34d399,color:#fff style UDP_CMS fill:#052e16,stroke:#34d399,color:#fff style VIDEO fill:#052e16,stroke:#34d399,color:#fff style BPS fill:#1e3a5f,stroke:#38bdf8,color:#fff style FSM fill:#1e3a5f,stroke:#38bdf8,color:#fff style JOY_DEC fill:#1e3a5f,stroke:#38bdf8,color:#fff style NMEA_SVC fill:#1e3a5f,stroke:#38bdf8,color:#fff style CMS_SVC fill:#1e3a5f,stroke:#38bdf8,color:#fff style FEED fill:#1e3a5f,stroke:#38bdf8,color:#fff style SRV fill:#7c2d12,stroke:#fb923c,color:#fff style SM fill:#7c2d12,stroke:#fb923c,color:#fff style WS fill:#7c2d12,stroke:#fb923c,color:#fff style ST_IC fill:#4a044e,stroke:#c084fc,color:#fff style ST_STA fill:#4a044e,stroke:#c084fc,color:#fff style ST_GYRO fill:#4a044e,stroke:#c084fc,color:#fff style ST_CMS fill:#4a044e,stroke:#c084fc,color:#fff style RADAR fill:#4a044e,stroke:#a78bfa,color:#fff style GAUGE fill:#4a044e,stroke:#a78bfa,color:#fff style VID_C fill:#4a044e,stroke:#a78bfa,color:#fff style HACK fill:#4a044e,stroke:#a78bfa,color:#fff style SET fill:#4a044e,stroke:#a78bfa,color:#fff style IC_EXT fill:#1a1a2e,stroke:#64748b,color:#94a3b8 style HW fill:#1a1a2e,stroke:#64748b,color:#94a3b8 style JOY_HW fill:#1a1a2e,stroke:#64748b,color:#94a3b8 style KBD_HW fill:#1a1a2e,stroke:#64748b,color:#94a3b8 style NMEA_HW fill:#1a1a2e,stroke:#64748b,color:#94a3b8 style CMS_HW fill:#1a1a2e,stroke:#64748b,color:#94a3b8 style CAM_HW fill:#1a1a2e,stroke:#64748b,color:#94a3b8
🔌
2. Componentes Backend — Capa de Infraestructura (Drivers de Red) § Infrastructure Layer
DRIVER · TCP

TCPService

Archivo: backend/src/services/tcp.service.js
Responsabilidad: Gestiona la conexión TCP persistente con el IC en el puerto 6001. Implementa reconexión automática con backoff exponencial y el Watchdog de 1200ms que detecta la pérdida del enlace.
Patrón: Singleton — una única instancia activa en el proceso.

▸ Proporciona: onData(buffer) ▸ Proporciona: sendFrame(buffer) ◂ Requiere: IC_HOST, IC_PORT
DRIVER · UDP

JoystickDriver

Puerto: UDP 4531
Responsabilidad: Recibe frames $BPJ del Joystick táctico a ~100 Hz. Deserializa los 3 ejes (signed int8) y mapea los 12 botones.
Dirección: Unidireccional (solo recepción).

▸ Proporciona: onJoystickFrame(axes, buttons) ◂ Requiere: dgram.createSocket('udp4')
DRIVER · UDP BIDIRECCIONAL

KeyboardDriver

Puerto: UDP 5501
Responsabilidad: Recibe comandos ASCII del Teclado Naval y envía tramas de feedback (5 bytes) para actualizar los LEDs físicos del panel.
Dirección: Bidireccional (RX comandos + TX LEDs).

▸ Proporciona: onKeyCommand(cmd) ▸ Proporciona: sendLedFeedback(state)
DRIVER · UDP

NMEADriver

Puerto: UDP 70xx (múltiples)
Responsabilidad: Recibe sentencias NMEA 0183 de GPS ($GPGGA), Girocompás ($HEHDT) e Inclinómetro (Pitch/Roll). Parsea según los estándares IEC 61162-1.
Corrección DEF-02: Lectura Big-Endian del inclinómetro.

▸ Proporciona: onNMEASentence(type, data)
DRIVER · UDP

CMSDriver

Puerto: UDP 8000 (Multicast)
Responsabilidad: Recibe tramas de 42 bytes del CMS con pistas tácticas. Cada pista contiene bearing, range, clasificación NATO y el flag cmsEnabled.
Frecuencia: ~5 Hz por pista activa.

▸ Proporciona: onTrackUpdate(tracks[]) ▸ Proporciona: cmsEnabled: boolean
DRIVER · PROCESO HIJO

VideoService

Puerto: UDP 37511 + (consoleNum - 1)
Responsabilidad: Lanza FFmpeg como proceso hijo aislado (child_process.spawn) para decodificar el stream H.264 de la cámara EOT. Genera un proceso independiente por consola.
Aislamiento: No compite con el Event Loop del backend.

▸ Proporciona: onVideoFrame(buffer) ◂ Requiere: ffmpeg binary (asarUnpack)
🧠
3. Componentes Backend — Capa de Dominio (Lógica Naval) § Domain Layer
SERVICIO · CRÍTICO

BinaryProtocolService

Archivo: backend/src/services/binary-protocol.service.js
Responsabilidad: Núcleo del protocolo binario ICD. Serializa tramas TX (29 bytes) con campos de mando y checksum XOR, y deserializa tramas RX (31-33 bytes) con telemetría del IC.
Patrón: Singleton — único punto de mutación del estado de protocolo.

▸ generateFrame(): Buffer[29] ▸ parseFrame(buf): Object ▸ updateField(name, value): void ▸ calculateChecksum(buf): uint8
SERVICIO · ESTADOS

FSM WorkMode

Responsabilidad: Máquina de Estados Finita que gobierna las transiciones entre modos de trabajo: RWS (Remote Weapon Station), EOT (Electro-Optical Tracker) y CMS Pista (asignación de blanco).
Guard Clauses: No permite transición a CMS sin cmsEnabled=1.

▸ transition(targetMode): boolean ▸ getCurrentMode(): string ◂ Requiere: cmsEnabled (CMSService)
SERVICIO · PROCESAMIENTO

JoystickDecoder

Responsabilidad: Aplica el algoritmo de Deadzone (±5) a los ejes X/Y/Z del Joystick para filtrar ruido mecánico. Mapea los 12 botones a acciones tácticas (energizar EOT, seleccionar modo, zoom).
Salida: Valores normalizados listos para inyectar en la trama TX.

▸ decode(rawAxes, rawButtons): JoystickState ▸ applyDeadzone(value, threshold): int
SERVICIO · NAVEGACIÓN

NMEAService

Responsabilidad: Parsea sentencias NMEA 0183 estandarizadas. Extrae posición GPS (Lat/Lon), heading verdadero del buque (girocompás) y datos de estabilidad (pitch/roll).
Corrección: Lectura Big-Endian para inclinómetro (DEF-02).

▸ parseGPGGA(sentence): Position ▸ parseHEHDT(sentence): Heading ▸ parseDDU(buffer): PitchRoll
SERVICIO · COMBATE

CMSService

Responsabilidad: Procesa tramas de pistas tácticas del CMS (42 bytes cada una). Extrae bearing, range, clasificación NATO, y el flag crítico de habilitación de mando.
Impacto: cmsEnabled controla si el operador puede asignar mando de disparo.

▸ parseTrack(buf): CMSTrack ▸ getTracks(): CMSTrack[] ▸ isEnabled(): boolean
SERVICIO · FEEDBACK

FeedbackService

Responsabilidad: Genera tramas de 5 bytes para actualizar los LEDs físicos del Teclado Naval. Solo refleja estados confirmados por el IC (Hardware-Driven UI), nunca estado optimista local.
Principio: Zero trust — LED encendido SOLO cuando el hardware confirma.

▸ buildFeedbackFrame(confirmedState): Buffer[5] ◂ Requiere: parseFrame() confirmación
🎛️
4. Componentes Backend — Capa de Aplicación (Orquestador) § Application Layer
ORQUESTADOR · CENTRAL

server.js — EventEmitter Hub

Archivo: backend/src/server.js
Responsabilidad: Punto de entrada del backend. Instancia todos los servicios, configura los listeners de eventos, ejecuta el Heartbeat Loop (100ms con compensación de drift) y coordina el pipeline de datos: Drivers → Dominio → WebSocket → Frontend.
Rol: Actúa como bus de eventos central (EventEmitter) del ecosistema.

▸ Proporciona: heartbeat() loop ▸ Proporciona: emit('event', data) ◂ Requiere: Todos los servicios
SERVICIO · GESTIÓN

StationManager

Archivo: backend/src/services/station-manager.service.js
Responsabilidad: Gestiona la asignación de hasta 3 consolas (C1 Estribor, C2 Babor, C3 Popa). Implementa el patrón de exclusividad de mando: solo una consola puede tener el mando activo a la vez.
Patrón: Singleton — garantiza consistencia global.

▸ assignStation(consoleId): boolean ▸ validateExclusivity(): boolean ▸ getActiveStation(): string
COMUNICACIÓN · WS

WebSocketServer

Puerto: ws://localhost:8001
Responsabilidad: Servidor WebSocket Full-Duplex que distribuye actualizaciones JSON al frontend (broadcast) y recibe comandos del operador (SELECT_STATION, MODE_CHANGE, SETTINGS).
Frecuencia: ~10 Hz de broadcast (sincronizado con Heartbeat).

▸ broadcast(type, payload): void ▸ onMessage(ws, data): void ◂ Requiere: ws npm package
🎨
5. Componentes Frontend — Svelte 4 (Chromium Renderer) § Frontend Components
STORE · REACTIVO

Svelte Stores (Estado Global)

Archivo: app/src/lib/stores.js
Stores:
icData — Telemetría del IC (ronza, elevación, estado)
stationStatus — Consola activa, modo trabajo, conexión
gyroData — Heading del buque (girocompás)
cmsTracks — Array de pistas tácticas activas
Reactividad: writable() → suscripción automática en componentes.

COMPONENTE · RADAR

Radar.svelte — PPI Display

Responsabilidad: Renderiza el Plan Position Indicator (PPI) usando SVG vectorial puro. Calcula transformaciones polares a cartesianas para posicionar los indicadores de bearing (RWS/EOT) y las pistas CMS. Rota el displayen modo "Course Up" según el heading del girocompás.
Renderizado: requestAnimationFrame → ≥30 FPS.

COMPONENTE · GAUGES

GaugePanel.svelte — Telemetría

Responsabilidad: Muestra en tiempo real los valores de ronza (bearing), elevación, estado del IC (encendido/apagado), modo de trabajo activo y nivel de señal TCP.
Actualización: Reactiva via $icData store (~10 Hz).

COMPONENTE · VIDEO

VideoEOT.svelte — Stream Óptico

Responsabilidad: Renderiza el video H.264 decodificado de la cámara EOT sobre un Canvas HTML5. El stream es segregado por estación (C1→:37511, C2→:37512, C3→:37513).

COMPONENTE · DEBUG

HackingView.svelte — Auditoría HEX

Responsabilidad: Vista de depuración que muestra las tramas TX/RX en formato hexadecimal crudo en tiempo real. Permite auditar cada byte del protocolo binario para validación de integridad.
Uso: Pruebas, diagnóstico y auditoría operativa.

COMPONENTE · CONFIG

Settings.svelte — Configuración

Responsabilidad: Panel de selección de estación (C1/C2/C3), configuración de IP del IC, y parámetros operativos. Envía comandos SELECT_STATION al backend via WebSocket.

🔌
6. Componentes Externos (Fuera del Ecosistema de Software) § External Components
EXTERNO · HARDWARE

🔋 IC — Gabinete de Interfaz

Controlador hardware del FFS-RWS. Traduce los comandos digitales de BARRACUDA SVELT en señales de control para servomotores, relés e instrumentación óptica. Protocolo binario propietario ICD sobre TCP :6001.

EXTERNO · PERIFÉRICO

🕹️ Joystick Táctico + ⌨️ Teclado Naval

Dispositivos de entrada del operador. El Joystick provee 3 ejes de mando y 12 botones tácticos (UDP :4531). El Teclado Naval provee 36 teclas con LEDs de feedback (UDP :5501 bidireccional).

EXTERNO · SENSORES

🛰️ GPS / 🧭 Girocompás / 📐 Inclinómetro

Sensores de navegación del buque que emiten sentencias NMEA 0183 por UDP :70xx. Proveen posición, heading y estabilidad para el PPI y la compensación de horizontes.

EXTERNO · COMBATE

⚔️ CMS — Sistema de Gestión de Combate

Provee pistas tácticas (42 bytes/pista) y el flag de habilitación de asignación de mando. Sin cmsEnabled=1, el operador no puede asumir el control de disparo. UDP :8000 multicast.

EXTERNO · VIDEO

📷 Cámaras EOT

3 cámaras del sistema Electro-Optical Tracker que emiten streams H.264/AVC por UDP RTP, segregados por estación (:37511/:37512/:37513). Decodificado por FFmpeg en cada PC consola.

📋
7. Matriz de Dependencias Inter-Componente § Dependency Matrix
Componente Origen Relación Componente Destino Mecanismo Datos Intercambiados
TCPService emite BinaryProtocolService EventEmitter ('tcp:data') Buffer binario RX 31-33 bytes
BinaryProtocolService usa TCPService sendFrame(buffer) Buffer binario TX 29 bytes + XOR
JoystickDriver emite JoystickDecoder EventEmitter ('joy:frame') Ejes X/Y/Z raw + 12 botones
JoystickDecoder usa BinaryProtocolService updateField() Valores con deadzone aplicada
NMEADriver emite NMEAService EventEmitter ('nmea:sentence') Sentencias NMEA 0183 crudas
CMSDriver emite CMSService EventEmitter ('cms:track') Buffer 42 bytes por pista
CMSService usa FSM WorkMode cmsEnabled flag Habilitación de mando de disparo
FSM WorkMode usa BinaryProtocolService updateField('workMode') RWS=0x01, EOT=0x02, CMS=0x03
server.js usa Todos los servicios Instanciación directa Configuración desde console.config.json
StationManager usa server.js validateExclusivity() ConsoleId de la estación activa
server.js spawn VideoService child_process.spawn() Puerto UDP dinámico por consola
WebSocketServer ws Svelte Stores JSON broadcast ws://localhost:8001 IC_DATA, STATION_STATUS, NAV_DATA, CMS_TRACKS
Svelte Stores ws WebSocketServer JSON command ws://localhost:8001 SELECT_STATION, MODE_CHANGE, SETTINGS
icData Store suscribe Radar.svelte Svelte reactive $icData Bearing RWS/EOT, telemetría
icData Store suscribe GaugePanel.svelte Svelte reactive $icData Ronza, elevación, estado IC
gyroData Store suscribe Radar.svelte Svelte reactive $gyroData Heading del buque (Course Up)
cmsTracks Store suscribe Radar.svelte Svelte reactive $cmsTracks Array de pistas tácticas CMS
FeedbackService usa KeyboardDriver sendLedFeedback(state) 5 bytes de estado LED confirmado