Sync docs to Wiki / wiki (push) Has been cancelled
Signed-off-by: Stan Grams <sjg@haxx.space>
185 lines
4.5 KiB
Rust
185 lines
4.5 KiB
Rust
// SPDX-FileCopyrightText: 2026 Stan Grams <sjg@haxx.space>
|
|
//
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
/// FTx protocol variants.
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
pub enum FtxProtocol {
|
|
Ft4,
|
|
Ft8,
|
|
#[cfg(feature = "ft2")]
|
|
Ft2,
|
|
}
|
|
|
|
impl FtxProtocol {
|
|
/// Symbol period in seconds.
|
|
pub fn symbol_period(self) -> f32 {
|
|
match self {
|
|
Self::Ft8 => FT8_SYMBOL_PERIOD,
|
|
Self::Ft4 => FT4_SYMBOL_PERIOD,
|
|
#[cfg(feature = "ft2")]
|
|
Self::Ft2 => FT2_SYMBOL_PERIOD,
|
|
}
|
|
}
|
|
|
|
/// Slot time in seconds.
|
|
pub fn slot_time(self) -> f32 {
|
|
match self {
|
|
Self::Ft8 => FT8_SLOT_TIME,
|
|
Self::Ft4 => FT4_SLOT_TIME,
|
|
#[cfg(feature = "ft2")]
|
|
Self::Ft2 => FT2_SLOT_TIME,
|
|
}
|
|
}
|
|
|
|
/// Whether this protocol uses FT4-style channel layout (FT4 and FT2).
|
|
pub fn uses_ft4_layout(self) -> bool {
|
|
#[cfg(feature = "ft2")]
|
|
if matches!(self, Self::Ft2) {
|
|
return true;
|
|
}
|
|
matches!(self, Self::Ft4)
|
|
}
|
|
|
|
/// Number of data symbols.
|
|
pub fn nd(self) -> usize {
|
|
if self.uses_ft4_layout() {
|
|
FT4_ND
|
|
} else {
|
|
FT8_ND
|
|
}
|
|
}
|
|
|
|
/// Total channel symbols.
|
|
pub fn nn(self) -> usize {
|
|
if self.uses_ft4_layout() {
|
|
FT4_NN
|
|
} else {
|
|
FT8_NN
|
|
}
|
|
}
|
|
|
|
/// Length of each sync group.
|
|
pub fn sync_length(self) -> usize {
|
|
if self.uses_ft4_layout() {
|
|
FT4_LENGTH_SYNC
|
|
} else {
|
|
FT8_LENGTH_SYNC
|
|
}
|
|
}
|
|
|
|
/// Number of sync groups.
|
|
pub fn num_sync(self) -> usize {
|
|
if self.uses_ft4_layout() {
|
|
FT4_NUM_SYNC
|
|
} else {
|
|
FT8_NUM_SYNC
|
|
}
|
|
}
|
|
|
|
/// Offset between sync groups.
|
|
pub fn sync_offset(self) -> usize {
|
|
if self.uses_ft4_layout() {
|
|
FT4_SYNC_OFFSET
|
|
} else {
|
|
FT8_SYNC_OFFSET
|
|
}
|
|
}
|
|
|
|
/// Number of FSK tones.
|
|
pub fn num_tones(self) -> usize {
|
|
if self.uses_ft4_layout() {
|
|
4
|
|
} else {
|
|
8
|
|
}
|
|
}
|
|
}
|
|
|
|
// FT8 timing
|
|
pub const FT8_SYMBOL_PERIOD: f32 = 0.160;
|
|
pub const FT8_SLOT_TIME: f32 = 15.0;
|
|
|
|
// FT4 timing
|
|
pub const FT4_SYMBOL_PERIOD: f32 = 0.048;
|
|
pub const FT4_SLOT_TIME: f32 = 7.5;
|
|
|
|
// FT2 timing
|
|
#[cfg(feature = "ft2")]
|
|
pub const FT2_SYMBOL_PERIOD: f32 = 0.024;
|
|
#[cfg(feature = "ft2")]
|
|
pub const FT2_SLOT_TIME: f32 = 3.75;
|
|
|
|
// FT8 symbol counts
|
|
pub const FT8_ND: usize = 58;
|
|
pub const FT8_NN: usize = 79;
|
|
pub const FT8_LENGTH_SYNC: usize = 7;
|
|
pub const FT8_NUM_SYNC: usize = 3;
|
|
pub const FT8_SYNC_OFFSET: usize = 36;
|
|
|
|
// FT4 symbol counts
|
|
pub const FT4_ND: usize = 87;
|
|
pub const FT4_NR: usize = 2;
|
|
pub const FT4_NN: usize = 105;
|
|
pub const FT4_LENGTH_SYNC: usize = 4;
|
|
pub const FT4_NUM_SYNC: usize = 4;
|
|
pub const FT4_SYNC_OFFSET: usize = 33;
|
|
|
|
// FT2 reuses FT4 layout
|
|
#[cfg(feature = "ft2")]
|
|
pub const FT2_ND: usize = FT4_ND;
|
|
#[cfg(feature = "ft2")]
|
|
pub const FT2_NR: usize = FT4_NR;
|
|
#[cfg(feature = "ft2")]
|
|
pub const FT2_NN: usize = FT4_NN;
|
|
#[cfg(feature = "ft2")]
|
|
pub const FT2_LENGTH_SYNC: usize = FT4_LENGTH_SYNC;
|
|
#[cfg(feature = "ft2")]
|
|
pub const FT2_NUM_SYNC: usize = FT4_NUM_SYNC;
|
|
#[cfg(feature = "ft2")]
|
|
pub const FT2_SYNC_OFFSET: usize = FT4_SYNC_OFFSET;
|
|
|
|
// LDPC parameters
|
|
pub const FTX_LDPC_N: usize = 174;
|
|
pub const FTX_LDPC_K: usize = 91;
|
|
pub const FTX_LDPC_M: usize = 83;
|
|
pub const FTX_LDPC_N_BYTES: usize = FTX_LDPC_N.div_ceil(8);
|
|
pub const FTX_LDPC_K_BYTES: usize = FTX_LDPC_K.div_ceil(8);
|
|
|
|
// CRC parameters
|
|
pub const FT8_CRC_POLYNOMIAL: u16 = 0x2757;
|
|
pub const FT8_CRC_WIDTH: u32 = 14;
|
|
|
|
// Message parameters
|
|
pub const FTX_PAYLOAD_LENGTH_BYTES: usize = 10;
|
|
pub const FTX_MAX_MESSAGE_LENGTH: usize = 35;
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn protocol_timing() {
|
|
assert!((FtxProtocol::Ft8.symbol_period() - 0.160).abs() < 1e-6);
|
|
assert!((FtxProtocol::Ft4.symbol_period() - 0.048).abs() < 1e-6);
|
|
#[cfg(feature = "ft2")]
|
|
assert!((FtxProtocol::Ft2.symbol_period() - 0.024).abs() < 1e-6);
|
|
}
|
|
|
|
#[test]
|
|
fn ft4_layout() {
|
|
assert!(FtxProtocol::Ft4.uses_ft4_layout());
|
|
#[cfg(feature = "ft2")]
|
|
assert!(FtxProtocol::Ft2.uses_ft4_layout());
|
|
assert!(!FtxProtocol::Ft8.uses_ft4_layout());
|
|
}
|
|
|
|
#[test]
|
|
fn symbol_counts() {
|
|
assert_eq!(FtxProtocol::Ft8.nn(), 79);
|
|
assert_eq!(FtxProtocol::Ft4.nn(), 105);
|
|
#[cfg(feature = "ft2")]
|
|
assert_eq!(FtxProtocol::Ft2.nn(), 105);
|
|
}
|
|
}
|