mirror of
https://github.com/MidnightBlueLabs/tetra-bluestation.git
synced 2026-03-29 05:09:51 +00:00
Version 0.5.6, final tweaks to new soapy config
Config file should now be version 0.6 Slight tweaks to example config Program now prints version number on startup Formatting changes
This commit is contained in:
18
Cargo.lock
generated
18
Cargo.lock
generated
@@ -150,7 +150,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bluestation-bs"
|
name = "bluestation-bs"
|
||||||
version = "0.5.5"
|
version = "0.5.6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap",
|
"clap",
|
||||||
"ctrlc",
|
"ctrlc",
|
||||||
@@ -719,7 +719,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "net-tnmm-test"
|
name = "net-tnmm-test"
|
||||||
version = "0.5.5"
|
version = "0.5.6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap",
|
"clap",
|
||||||
"tetra-config",
|
"tetra-config",
|
||||||
@@ -734,7 +734,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "net-tnmm-test-quic"
|
name = "net-tnmm-test-quic"
|
||||||
version = "0.5.5"
|
version = "0.5.6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"quinn",
|
"quinn",
|
||||||
"rcgen",
|
"rcgen",
|
||||||
@@ -886,7 +886,7 @@ checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pdu-tool"
|
name = "pdu-tool"
|
||||||
version = "0.5.5"
|
version = "0.5.6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap",
|
"clap",
|
||||||
"tetra-config",
|
"tetra-config",
|
||||||
@@ -1501,7 +1501,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tetra-config"
|
name = "tetra-config"
|
||||||
version = "0.5.5"
|
version = "0.5.6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono-tz",
|
"chrono-tz",
|
||||||
"serde",
|
"serde",
|
||||||
@@ -1511,7 +1511,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tetra-core"
|
name = "tetra-core"
|
||||||
version = "0.5.5"
|
version = "0.5.6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"const_format",
|
"const_format",
|
||||||
"git-version",
|
"git-version",
|
||||||
@@ -1523,7 +1523,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tetra-entities"
|
name = "tetra-entities"
|
||||||
version = "0.5.5"
|
version = "0.5.6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"as-any",
|
"as-any",
|
||||||
"bitcode",
|
"bitcode",
|
||||||
@@ -1553,7 +1553,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tetra-pdus"
|
name = "tetra-pdus"
|
||||||
version = "0.5.5"
|
version = "0.5.6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"tetra-config",
|
"tetra-config",
|
||||||
"tetra-core",
|
"tetra-core",
|
||||||
@@ -1563,7 +1563,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tetra-saps"
|
name = "tetra-saps"
|
||||||
version = "0.5.5"
|
version = "0.5.6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"tetra-core",
|
"tetra-core",
|
||||||
"tracing",
|
"tracing",
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ members = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
version = "0.5.5"
|
version = "0.5.6"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
authors = ["Wouter Bokslag / Midnight Blue"]
|
authors = ["Wouter Bokslag / Midnight Blue"]
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
|||||||
@@ -92,9 +92,9 @@ fn main() {
|
|||||||
eprintln!("░▀█▀░█▀▀░▀█▀░█▀▄░█▀█░░░░░█▀▄░█░░░█░█░█▀▀░█▀▀░▀█▀░█▀█░▀█▀░▀█▀░█▀█░█▀█");
|
eprintln!("░▀█▀░█▀▀░▀█▀░█▀▄░█▀█░░░░░█▀▄░█░░░█░█░█▀▀░█▀▀░▀█▀░█▀█░▀█▀░▀█▀░█▀█░█▀█");
|
||||||
eprintln!("░░█░░█▀▀░░█░░█▀▄░█▀█░▄▄▄░█▀▄░█░░░█░█░█▀▀░▀▀█░░█░░█▀█░░█░░░█░░█░█░█░█");
|
eprintln!("░░█░░█▀▀░░█░░█▀▄░█▀█░▄▄▄░█▀▄░█░░░█░█░█▀▀░▀▀█░░█░░█▀█░░█░░░█░░█░█░█░█");
|
||||||
eprintln!("░░▀░░▀▀▀░░▀░░▀░▀░▀░▀░░░░░▀▀░░▀▀▀░▀▀▀░▀▀▀░▀▀▀░░▀░░▀░▀░░▀░░▀▀▀░▀▀▀░▀░▀\n");
|
eprintln!("░░▀░░▀▀▀░░▀░░▀░▀░▀░▀░░░░░▀▀░░▀▀▀░▀▀▀░▀▀▀░▀▀▀░░▀░░▀░▀░░▀░░▀▀▀░▀▀▀░▀░▀\n");
|
||||||
eprintln!(" Wouter Bokslag / Midnight Blue");
|
eprintln!(" Wouter Bokslag / Midnight Blue");
|
||||||
eprintln!(" -> https://github.com/MidnightBlueLabs/tetra-bluestation");
|
eprintln!(" https://github.com/MidnightBlueLabs/tetra-bluestation");
|
||||||
eprintln!(" -> https://midnightblue.nl\n");
|
eprintln!(" Version: {}", tetra_core::STACK_VERSION);
|
||||||
|
|
||||||
let args = Args::parse();
|
let args = Args::parse();
|
||||||
let mut cfg = load_config_from_toml(&args.config);
|
let mut cfg = load_config_from_toml(&args.config);
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ pub fn from_toml_str(toml_str: &str) -> Result<SharedConfig, Box<dyn std::error:
|
|||||||
let root: TomlConfigRoot = toml::from_str(toml_str)?;
|
let root: TomlConfigRoot = toml::from_str(toml_str)?;
|
||||||
|
|
||||||
// Various sanity checks
|
// Various sanity checks
|
||||||
let expected_config_version = "0.5";
|
let expected_config_version = "0.6";
|
||||||
if !root.config_version.eq(expected_config_version) {
|
if !root.config_version.eq(expected_config_version) {
|
||||||
return Err(format!(
|
return Err(format!(
|
||||||
"Unrecognized config_version: {}, expect {}",
|
"Unrecognized config_version: {}, expect {}",
|
||||||
@@ -34,9 +34,10 @@ pub fn from_toml_str(toml_str: &str) -> Result<SharedConfig, Box<dyn std::error:
|
|||||||
}
|
}
|
||||||
if let Some(ref soapy) = root.phy_io.soapysdr {
|
if let Some(ref soapy) = root.phy_io.soapysdr {
|
||||||
let extra_keys = sorted_keys(&soapy.extra);
|
let extra_keys = sorted_keys(&soapy.extra);
|
||||||
let extra_keys_filtered = extra_keys.iter().filter(|key| {
|
let extra_keys_filtered = extra_keys
|
||||||
!(key.starts_with("rx_gain_") || key.starts_with("tx_gain_"))
|
.iter()
|
||||||
}).collect::<Vec<&&str>>();
|
.filter(|key| !(key.starts_with("rx_gain_") || key.starts_with("tx_gain_")))
|
||||||
|
.collect::<Vec<&&str>>();
|
||||||
if !extra_keys_filtered.is_empty() {
|
if !extra_keys_filtered.is_empty() {
|
||||||
return Err(format!("Unrecognized fields: phy_io.soapysdr::{:?}", extra_keys_filtered).into());
|
return Err(format!("Unrecognized fields: phy_io.soapysdr::{:?}", extra_keys_filtered).into());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,26 +56,40 @@ pub fn phy_dto_to_cfg(src: PhyIoDto) -> CfgPhyIo {
|
|||||||
tx_ch: soapy_dto.tx_channel,
|
tx_ch: soapy_dto.tx_channel,
|
||||||
rx_ant: soapy_dto.rx_antenna,
|
rx_ant: soapy_dto.rx_antenna,
|
||||||
tx_ant: soapy_dto.tx_antenna,
|
tx_ant: soapy_dto.tx_antenna,
|
||||||
rx_gains: soapy_dto.extra.iter().filter_map(|(key, value)| {
|
rx_gains: soapy_dto
|
||||||
key.strip_prefix("rx_gain_").map(|gain_name| {
|
.extra
|
||||||
(gain_name.to_string().to_lowercase(), match value {
|
.iter()
|
||||||
Value::Integer(v) => *v as f64,
|
.filter_map(|(key, value)| {
|
||||||
Value::Float(v) => *v,
|
key.strip_prefix("rx_gain_").map(|gain_name| {
|
||||||
// TODO: should this error be returned somehow?
|
(
|
||||||
_ => panic!("RX gain value must be a number"),
|
gain_name.to_string().to_lowercase(),
|
||||||
|
match value {
|
||||||
|
Value::Integer(v) => *v as f64,
|
||||||
|
Value::Float(v) => *v,
|
||||||
|
// TODO: should this error be returned somehow?
|
||||||
|
_ => panic!("RX gain value must be a number"),
|
||||||
|
},
|
||||||
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}).collect(),
|
.collect(),
|
||||||
tx_gains: soapy_dto.extra.iter().filter_map(|(key, value)| {
|
tx_gains: soapy_dto
|
||||||
key.strip_prefix("tx_gain_").map(|gain_name| {
|
.extra
|
||||||
(gain_name.to_string().to_lowercase(), match value {
|
.iter()
|
||||||
Value::Integer(v) => *v as f64,
|
.filter_map(|(key, value)| {
|
||||||
Value::Float(v) => *v,
|
key.strip_prefix("tx_gain_").map(|gain_name| {
|
||||||
// TODO: should this error be returned somehow?
|
(
|
||||||
_ => panic!("TX gain value must be a number"),
|
gain_name.to_string().to_lowercase(),
|
||||||
|
match value {
|
||||||
|
Value::Integer(v) => *v as f64,
|
||||||
|
Value::Float(v) => *v,
|
||||||
|
// TODO: should this error be returned somehow?
|
||||||
|
_ => panic!("TX gain value must be a number"),
|
||||||
|
},
|
||||||
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}).collect(),
|
.collect(),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
use tetra_config::bluestation::{StackMode, sec_phy_soapy::*};
|
use tetra_config::bluestation::{StackMode, sec_phy_soapy::*};
|
||||||
|
|
||||||
|
|
||||||
/// Enum of all supported devices
|
/// Enum of all supported devices
|
||||||
pub enum SupportedDevice {
|
pub enum SupportedDevice {
|
||||||
LimeSdr(LimeSdrModel),
|
LimeSdr(LimeSdrModel),
|
||||||
@@ -34,43 +33,31 @@ impl SupportedDevice {
|
|||||||
/// Return None if the device is not supported.
|
/// Return None if the device is not supported.
|
||||||
pub fn detect(driver_key: &str, hardware_key: &str) -> Option<Self> {
|
pub fn detect(driver_key: &str, hardware_key: &str) -> Option<Self> {
|
||||||
match (driver_key, hardware_key) {
|
match (driver_key, hardware_key) {
|
||||||
("FX3", "LimeSDR-USB") =>
|
("FX3", "LimeSDR-USB") => Some(Self::LimeSdr(LimeSdrModel::LimeSdrUsb)),
|
||||||
Some(Self::LimeSdr(LimeSdrModel::LimeSdrUsb)),
|
("FX3", _) => Some(Self::LimeSdr(LimeSdrModel::OtherFx3)),
|
||||||
("FX3", _) =>
|
|
||||||
Some(Self::LimeSdr(LimeSdrModel::OtherFx3)),
|
|
||||||
|
|
||||||
("FT601", "LimeSDR-Mini_v2") =>
|
("FT601", "LimeSDR-Mini_v2") => Some(Self::LimeSdr(LimeSdrModel::LimeSdrMiniV2)),
|
||||||
Some(Self::LimeSdr(LimeSdrModel::LimeSdrMiniV2)),
|
("FT601", "LimeNET-Micro") => Some(Self::LimeSdr(LimeSdrModel::LimeNetMicro)),
|
||||||
("FT601", "LimeNET-Micro") =>
|
("FT601", _) => Some(Self::LimeSdr(LimeSdrModel::OtherFt601)),
|
||||||
Some(Self::LimeSdr(LimeSdrModel::LimeNetMicro)),
|
|
||||||
("FT601", _) =>
|
|
||||||
Some(Self::LimeSdr(LimeSdrModel::OtherFt601)),
|
|
||||||
|
|
||||||
("sx", _) =>
|
("sx", _) => Some(Self::SXceiver),
|
||||||
Some(Self::SXceiver),
|
|
||||||
|
|
||||||
("PlutoSDR", _) =>
|
("PlutoSDR", _) => Some(Self::PlutoSdr),
|
||||||
Some(Self::PlutoSdr),
|
|
||||||
|
|
||||||
// USRP B210 seems to report as ("b200", "B210"),
|
// USRP B210 seems to report as ("b200", "B210"),
|
||||||
// but the driver key is also known to be "uhd" in some cases.
|
// but the driver key is also known to be "uhd" in some cases.
|
||||||
// The reason is unknown but might be due to
|
// The reason is unknown but might be due to
|
||||||
// gateware, firmware or driver version differences.
|
// gateware, firmware or driver version differences.
|
||||||
// Try to detect USRP correctly in all cases.
|
// Try to detect USRP correctly in all cases.
|
||||||
("b200", "B200") | ("uhd", "B200") =>
|
("b200", "B200") | ("uhd", "B200") => Some(Self::Usrp(UsrpModel::B200)),
|
||||||
Some(Self::Usrp(UsrpModel::B200)),
|
("b200", "B210") | ("uhd", "B210") => Some(Self::Usrp(UsrpModel::B210)),
|
||||||
("b200", "B210") | ("uhd", "B210") =>
|
("b200", _) | ("uhd", _) => Some(Self::Usrp(UsrpModel::Other)),
|
||||||
Some(Self::Usrp(UsrpModel::B210)),
|
|
||||||
("b200", _) | ("uhd", _) =>
|
|
||||||
Some(Self::Usrp(UsrpModel::Other)),
|
|
||||||
// TODO: add other USRP models if needed
|
// TODO: add other USRP models if needed
|
||||||
|
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct SdrSettings {
|
pub struct SdrSettings {
|
||||||
/// Settings template, holding which SDR is used
|
/// Settings template, holding which SDR is used
|
||||||
@@ -137,7 +124,7 @@ impl SdrSettings {
|
|||||||
}
|
}
|
||||||
if !cfg_gains.is_empty() {
|
if !cfg_gains.is_empty() {
|
||||||
tracing::error!("Unsupported RX gains for {}: {:?}", settings.name, cfg_gains);
|
tracing::error!("Unsupported RX gains for {}: {:?}", settings.name, cfg_gains);
|
||||||
return Err(Error::InvalidConfiguration)
|
return Err(Error::InvalidConfiguration);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut cfg_gains = cfg.tx_gains.clone();
|
let mut cfg_gains = cfg.tx_gains.clone();
|
||||||
@@ -148,7 +135,7 @@ impl SdrSettings {
|
|||||||
}
|
}
|
||||||
if !cfg_gains.is_empty() {
|
if !cfg_gains.is_empty() {
|
||||||
tracing::error!("Unsupported TX gains for {}: {:?}", settings.name, cfg_gains);
|
tracing::error!("Unsupported TX gains for {}: {:?}", settings.name, cfg_gains);
|
||||||
return Err(Error::InvalidConfiguration)
|
return Err(Error::InvalidConfiguration);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: check for extra gain fields in cfg
|
// TODO: check for extra gain fields in cfg
|
||||||
@@ -159,17 +146,13 @@ impl SdrSettings {
|
|||||||
/// Get default settings based on SDR type
|
/// Get default settings based on SDR type
|
||||||
fn get_defaults(cfg: &CfgSoapySdr, device: SupportedDevice, mode: StackMode) -> Self {
|
fn get_defaults(cfg: &CfgSoapySdr, device: SupportedDevice, mode: StackMode) -> Self {
|
||||||
match device {
|
match device {
|
||||||
SupportedDevice::LimeSdr(model) =>
|
SupportedDevice::LimeSdr(model) => Self::settings_limesdr(mode, model),
|
||||||
Self::settings_limesdr(mode, model),
|
|
||||||
|
|
||||||
SupportedDevice::SXceiver =>
|
SupportedDevice::SXceiver => Self::settings_sxceiver(mode, cfg.fs),
|
||||||
Self::settings_sxceiver(mode, cfg.fs),
|
|
||||||
|
|
||||||
SupportedDevice::PlutoSdr =>
|
SupportedDevice::PlutoSdr => Self::settings_pluto(mode),
|
||||||
Self::settings_pluto(mode),
|
|
||||||
|
|
||||||
SupportedDevice::Usrp(model) =>
|
SupportedDevice::Usrp(model) => Self::settings_usrp(mode, model),
|
||||||
Self::settings_usrp(mode, model),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -220,25 +203,24 @@ impl SdrSettings {
|
|||||||
}
|
}
|
||||||
.to_string(),
|
.to_string(),
|
||||||
|
|
||||||
rx_ant: Some(match model {
|
rx_ant: Some(
|
||||||
LimeSdrModel::LimeSdrUsb => "LNAL",
|
match model {
|
||||||
_ => "LNAW",
|
LimeSdrModel::LimeSdrUsb => "LNAL",
|
||||||
}.to_string()),
|
_ => "LNAW",
|
||||||
|
}
|
||||||
|
.to_string(),
|
||||||
|
),
|
||||||
|
|
||||||
tx_ant: Some(match model {
|
tx_ant: Some(
|
||||||
LimeSdrModel::LimeSdrUsb => "BAND1",
|
match model {
|
||||||
_ => "BAND2",
|
LimeSdrModel::LimeSdrUsb => "BAND1",
|
||||||
}.to_string()),
|
_ => "BAND2",
|
||||||
|
}
|
||||||
|
.to_string(),
|
||||||
|
),
|
||||||
|
|
||||||
rx_gain: vec![
|
rx_gain: vec![("LNA".to_string(), 18.0), ("TIA".to_string(), 6.0), ("PGA".to_string(), 10.0)],
|
||||||
("LNA".to_string(), 18.0),
|
tx_gain: vec![("PAD".to_string(), 22.0), ("IAMP".to_string(), 6.0)],
|
||||||
("TIA".to_string(), 6.0),
|
|
||||||
("PGA".to_string(), 10.0),
|
|
||||||
],
|
|
||||||
tx_gain: vec![
|
|
||||||
("PAD".to_string(), 22.0),
|
|
||||||
("IAMP".to_string(), 6.0),
|
|
||||||
],
|
|
||||||
|
|
||||||
// Minimum latency for BS/MS, maximum throughput for monitor
|
// Minimum latency for BS/MS, maximum throughput for monitor
|
||||||
rx_args: vec![("latency".to_string(), if mode == StackMode::Mon { "1" } else { "0" }.to_string())],
|
rx_args: vec![("latency".to_string(), if mode == StackMode::Mon { "1" } else { "0" }.to_string())],
|
||||||
@@ -265,14 +247,8 @@ impl SdrSettings {
|
|||||||
rx_ant: Some("RX".to_string()),
|
rx_ant: Some("RX".to_string()),
|
||||||
tx_ant: Some("TX".to_string()),
|
tx_ant: Some("TX".to_string()),
|
||||||
|
|
||||||
rx_gain: vec![
|
rx_gain: vec![("LNA".to_string(), 42.0), ("PGA".to_string(), 16.0)],
|
||||||
("LNA".to_string(), 42.0),
|
tx_gain: vec![("DAC".to_string(), 9.0), ("MIXER".to_string(), 30.0)],
|
||||||
("PGA".to_string(), 16.0),
|
|
||||||
],
|
|
||||||
tx_gain: vec![
|
|
||||||
("DAC".to_string(), 9.0),
|
|
||||||
("MIXER".to_string(), 30.0),
|
|
||||||
],
|
|
||||||
|
|
||||||
rx_args: vec![("period".to_string(), block_size(fs).to_string())],
|
rx_args: vec![("period".to_string(), block_size(fs).to_string())],
|
||||||
tx_args: vec![("period".to_string(), block_size(fs).to_string())],
|
tx_args: vec![("period".to_string(), block_size(fs).to_string())],
|
||||||
@@ -327,7 +303,6 @@ impl SdrSettings {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Get processing block size in samples for a given sample rate.
|
/// Get processing block size in samples for a given sample rate.
|
||||||
/// This can be used to optimize performance for some SDRs.
|
/// This can be used to optimize performance for some SDRs.
|
||||||
pub fn block_size(fs: f64) -> usize {
|
pub fn block_size(fs: f64) -> usize {
|
||||||
|
|||||||
@@ -336,10 +336,8 @@ impl SoapyIo {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Messy logic related to opening a device follows...
|
// Messy logic related to opening a device follows...
|
||||||
|
|
||||||
|
|
||||||
/// Struct to temporarily hold stuff related to opening and detecting a device
|
/// Struct to temporarily hold stuff related to opening and detecting a device
|
||||||
struct OpenedDevice {
|
struct OpenedDevice {
|
||||||
dev_args: soapysdr::Args,
|
dev_args: soapysdr::Args,
|
||||||
@@ -370,7 +368,11 @@ fn open_given_device(dev_args: soapysdr::Args) -> Result<OpenedDevice, soapysdr:
|
|||||||
|
|
||||||
// Check whether the device is supported
|
// Check whether the device is supported
|
||||||
if let Some(detected_device) = SupportedDevice::detect(&driver_key, &hardware_key) {
|
if let Some(detected_device) = SupportedDevice::detect(&driver_key, &hardware_key) {
|
||||||
tracing::info!("Found supported device with driver_key '{}' hardware_key '{}'", driver_key, hardware_key);
|
tracing::info!(
|
||||||
|
"Found supported device with driver_key '{}' hardware_key '{}'",
|
||||||
|
driver_key,
|
||||||
|
hardware_key
|
||||||
|
);
|
||||||
Ok(OpenedDevice {
|
Ok(OpenedDevice {
|
||||||
dev_args,
|
dev_args,
|
||||||
dev,
|
dev,
|
||||||
@@ -380,7 +382,11 @@ fn open_given_device(dev_args: soapysdr::Args) -> Result<OpenedDevice, soapysdr:
|
|||||||
soapyremote_used,
|
soapyremote_used,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
tracing::info!("Skipping unsupported device with driver_key '{}' hardware_key '{}'", driver_key, hardware_key);
|
tracing::info!(
|
||||||
|
"Skipping unsupported device with driver_key '{}' hardware_key '{}'",
|
||||||
|
driver_key,
|
||||||
|
hardware_key
|
||||||
|
);
|
||||||
Err(soapysdr::Error {
|
Err(soapysdr::Error {
|
||||||
code: soapysdr::ErrorCode::NotSupported,
|
code: soapysdr::ErrorCode::NotSupported,
|
||||||
message: "Unsupported device".to_string(),
|
message: "Unsupported device".to_string(),
|
||||||
@@ -394,7 +400,7 @@ fn find_supported_device(filter_args: soapysdr::Args) -> Result<OpenedDevice, so
|
|||||||
//tracing::info!("Trying to open a device with arguments: {}", args_formatted);
|
//tracing::info!("Trying to open a device with arguments: {}", args_formatted);
|
||||||
match open_given_device(dev_args) {
|
match open_given_device(dev_args) {
|
||||||
Ok(opened_device) => return Ok(opened_device),
|
Ok(opened_device) => return Ok(opened_device),
|
||||||
Err(_) => {},
|
Err(_) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Err(soapysdr::Error {
|
return Err(soapysdr::Error {
|
||||||
@@ -414,10 +420,12 @@ fn open_device(soapy_cfg: &CfgSoapySdr, mode: StackMode) -> Result<(soapysdr::De
|
|||||||
|
|
||||||
let mut sdr_settings = match SdrSettings::get_settings(&soapy_cfg, opened_device.detected_device, mode) {
|
let mut sdr_settings = match SdrSettings::get_settings(&soapy_cfg, opened_device.detected_device, mode) {
|
||||||
Ok(sdr_settings) => sdr_settings,
|
Ok(sdr_settings) => sdr_settings,
|
||||||
Err(soapy_settings::Error::InvalidConfiguration) => return Err(soapysdr::Error {
|
Err(soapy_settings::Error::InvalidConfiguration) => {
|
||||||
code: soapysdr::ErrorCode::Other,
|
return Err(soapysdr::Error {
|
||||||
message: "Invalid SDR device configuration".to_string(),
|
code: soapysdr::ErrorCode::Other,
|
||||||
}),
|
message: "Invalid SDR device configuration".to_string(),
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if opened_device.soapyremote_used {
|
if opened_device.soapyremote_used {
|
||||||
@@ -439,7 +447,10 @@ fn open_device(soapy_cfg: &CfgSoapySdr, mode: StackMode) -> Result<(soapysdr::De
|
|||||||
|
|
||||||
// Make sure device gets closed first. Not sure if needed.
|
// Make sure device gets closed first. Not sure if needed.
|
||||||
std::mem::drop(opened_device.dev);
|
std::mem::drop(opened_device.dev);
|
||||||
opened_device.dev = soapycheck!("open SoapySDR device with additional arguments", soapysdr::Device::new(opened_device.dev_args));
|
opened_device.dev = soapycheck!(
|
||||||
|
"open SoapySDR device with additional arguments",
|
||||||
|
soapysdr::Device::new(opened_device.dev_args)
|
||||||
|
);
|
||||||
// Make sure it is still the same device.
|
// Make sure it is still the same device.
|
||||||
// Unlikely to change, but who knows if a device got connected just in between,
|
// Unlikely to change, but who knows if a device got connected just in between,
|
||||||
// or if the device broke from first opening attempt and something else got opened
|
// or if the device broke from first opening attempt and something else got opened
|
||||||
@@ -447,8 +458,13 @@ fn open_device(soapy_cfg: &CfgSoapySdr, mode: StackMode) -> Result<(soapysdr::De
|
|||||||
let new_driver_key = opened_device.dev.driver_key().unwrap_or_default();
|
let new_driver_key = opened_device.dev.driver_key().unwrap_or_default();
|
||||||
let new_hardware_key = opened_device.dev.hardware_key().unwrap_or_default();
|
let new_hardware_key = opened_device.dev.hardware_key().unwrap_or_default();
|
||||||
if new_driver_key != opened_device.driver_key || new_hardware_key != opened_device.hardware_key {
|
if new_driver_key != opened_device.driver_key || new_hardware_key != opened_device.hardware_key {
|
||||||
tracing::info!("Expected the same driver_key='{}' hardware_key='{}' after reopen, got driver_key='{}' hardware_key='{}'",
|
tracing::info!(
|
||||||
opened_device.driver_key, opened_device.hardware_key, new_driver_key, new_hardware_key);
|
"Expected the same driver_key='{}' hardware_key='{}' after reopen, got driver_key='{}' hardware_key='{}'",
|
||||||
|
opened_device.driver_key,
|
||||||
|
opened_device.hardware_key,
|
||||||
|
new_driver_key,
|
||||||
|
new_hardware_key
|
||||||
|
);
|
||||||
return Err(soapysdr::Error {
|
return Err(soapysdr::Error {
|
||||||
code: soapysdr::ErrorCode::Other,
|
code: soapysdr::ErrorCode::Other,
|
||||||
message: "Reopened a different device".to_string(),
|
message: "Reopened a different device".to_string(),
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
# This is an example configuration file for the TETRA base station stack
|
# This is an example configuration file for the TETRA base station stack
|
||||||
# DO NOT RUN without editing to stay within legal limits of your jurisdiction
|
# DO NOT RUN without editing to stay within legal limits of your jurisdiction
|
||||||
|
|
||||||
config_version = "0.5"
|
config_version = "0.6"
|
||||||
|
|
||||||
# Stack operation mode: "Bs" (Base Station), "Ms" (Mobile Station), or "Mon" (Monitor)
|
# Stack operation mode: "Bs" (Base Station), "Ms" (Mobile Station), or "Mon" (Monitor)
|
||||||
stack_mode = "Bs"
|
stack_mode = "Bs"
|
||||||
@@ -28,7 +28,15 @@ backend = "SoapySdr"
|
|||||||
# !!! Make sure to also edit all related fields in the cell_info section to fit this frequency.
|
# !!! Make sure to also edit all related fields in the cell_info section to fit this frequency.
|
||||||
tx_freq = 438025000
|
tx_freq = 438025000
|
||||||
rx_freq = 433025000
|
rx_freq = 433025000
|
||||||
ppm_err = 0.0 # Adjust if your SDR has a non-negligible tuning error
|
|
||||||
|
# Adjust if your SDR has a non-negligible tuning error
|
||||||
|
# ppm_err = 0.0
|
||||||
|
|
||||||
|
################################################################################################
|
||||||
|
## OPTIONAL: specific device, antenna, gain selection ##
|
||||||
|
## Make sure to check your device for valid settings using SoapySDRUtil --probe ##
|
||||||
|
## or check: https://github.com/MidnightBlueLabs/tetra-bluestation-docs/wiki/03-Configuration ##
|
||||||
|
################################################################################################
|
||||||
|
|
||||||
# Optional device selection arguments.
|
# Optional device selection arguments.
|
||||||
# If not specified, the first supported device found is selected automatically.
|
# If not specified, the first supported device found is selected automatically.
|
||||||
@@ -40,18 +48,17 @@ ppm_err = 0.0 # Adjust if your SDR has a non-negligible tu
|
|||||||
# device = "driver=lime,serial=123456789"
|
# device = "driver=lime,serial=123456789"
|
||||||
|
|
||||||
# Optional antenna selection to override device-specific defaults
|
# Optional antenna selection to override device-specific defaults
|
||||||
|
# Check antenna names with SoapySDRUtil --probe
|
||||||
# rx_antenna = "LNAW"
|
# rx_antenna = "LNAW"
|
||||||
# tx_antenna = "BAND2"
|
# tx_antenna = "BAND2"
|
||||||
|
|
||||||
# Optional gain values to override device-specific defaults.
|
# Optional gain values to override device-specific defaults.
|
||||||
|
# Check valid gain names with SoapySDRUtil --probe
|
||||||
# For example, to increase transmit power on a LimeSDR:
|
# For example, to increase transmit power on a LimeSDR:
|
||||||
# tx_gain_pad = 50.0
|
# tx_gain_pad = 50.0
|
||||||
# To adjust LNA gain to optimize RX performance on a LimeSDR or SXceiver:
|
# To adjust LNA gain to optimize RX performance on a LimeSDR or SXceiver:
|
||||||
# rx_gain_lna = 30.0
|
# rx_gain_lna = 30.0
|
||||||
|
|
||||||
# Antennas, gain names and ranges of gain values are device dependent.
|
|
||||||
# To list them, try something like: SoapySDRUtil --probe=driver=lime
|
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
# Network Information
|
# Network Information
|
||||||
|
|||||||
Reference in New Issue
Block a user