Files
trx-rs/src/trx-core/src/decode.rs
T
sjg 92423f1e02 [feat](trx-rs): add VDES decoder mode support
Add a new trx-vdes decoder path alongside AIS, wire VDES through the server/frontend decode pipeline, and fix the web map so AIS vessel symbols load correctly and the TRX receiver marker appears when location data arrives.

Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
2026-03-03 00:05:16 +01:00

149 lines
4.5 KiB
Rust

// SPDX-FileCopyrightText: 2025 Stanislaw Grams <stanislawgrams@gmail.com>
//
// SPDX-License-Identifier: BSD-2-Clause
//! Shared types for server-side decoded messages (APRS, AIS, CW).
use serde::{Deserialize, Serialize};
/// A decoded message from the server-side decoders.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type")]
pub enum DecodedMessage {
#[serde(rename = "ais")]
Ais(AisMessage),
#[serde(rename = "vdes")]
Vdes(VdesMessage),
#[serde(rename = "aprs")]
Aprs(AprsPacket),
#[serde(rename = "cw")]
Cw(CwEvent),
#[serde(rename = "ft8")]
Ft8(Ft8Message),
#[serde(rename = "wspr")]
Wspr(WsprMessage),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AisMessage {
#[serde(skip_serializing_if = "Option::is_none")]
pub ts_ms: Option<i64>,
pub channel: String,
pub message_type: u8,
pub repeat: u8,
pub mmsi: u32,
pub crc_ok: bool,
pub bit_len: usize,
pub raw_bytes: Vec<u8>,
#[serde(skip_serializing_if = "Option::is_none")]
pub lat: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub lon: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub sog_knots: Option<f32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub cog_deg: Option<f32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub heading_deg: Option<u16>,
#[serde(skip_serializing_if = "Option::is_none")]
pub nav_status: Option<u8>,
#[serde(skip_serializing_if = "Option::is_none")]
pub vessel_name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub callsign: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub destination: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct VdesMessage {
#[serde(skip_serializing_if = "Option::is_none")]
pub ts_ms: Option<i64>,
pub channel: String,
pub message_type: u8,
pub repeat: u8,
pub mmsi: u32,
pub crc_ok: bool,
pub bit_len: usize,
pub raw_bytes: Vec<u8>,
#[serde(skip_serializing_if = "Option::is_none")]
pub lat: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub lon: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub sog_knots: Option<f32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub cog_deg: Option<f32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub heading_deg: Option<u16>,
#[serde(skip_serializing_if = "Option::is_none")]
pub nav_status: Option<u8>,
#[serde(skip_serializing_if = "Option::is_none")]
pub vessel_name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub callsign: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub destination: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AprsPacket {
#[serde(skip_serializing_if = "Option::is_none")]
pub ts_ms: Option<i64>,
pub src_call: String,
pub dest_call: String,
pub path: String,
pub info: String,
pub info_bytes: Vec<u8>,
pub packet_type: String,
pub crc_ok: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub lat: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub lon: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub symbol_table: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub symbol_code: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CwEvent {
/// Decoded text fragment (one or more characters)
pub text: String,
/// Current detected WPM
pub wpm: u32,
/// Current detected tone frequency (Hz)
pub tone_hz: u32,
/// Whether a CW tone is currently detected
pub signal_on: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Ft8Message {
/// UTC timestamp (milliseconds since epoch)
pub ts_ms: i64,
/// Approximate SNR (dB)
pub snr_db: f32,
/// Time offset within slot (seconds)
pub dt_s: f32,
/// Audio frequency (Hz)
pub freq_hz: f32,
/// Decoded message text
pub message: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WsprMessage {
/// UTC timestamp (milliseconds since epoch)
pub ts_ms: i64,
/// Approximate SNR (dB)
pub snr_db: f32,
/// Time offset within slot (seconds)
pub dt_s: f32,
/// Audio frequency (Hz)
pub freq_hz: f32,
/// Decoded message text
pub message: String,
}