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]]
|
||||
name = "bluestation-bs"
|
||||
version = "0.5.5"
|
||||
version = "0.5.6"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"ctrlc",
|
||||
@@ -719,7 +719,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "net-tnmm-test"
|
||||
version = "0.5.5"
|
||||
version = "0.5.6"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"tetra-config",
|
||||
@@ -734,7 +734,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "net-tnmm-test-quic"
|
||||
version = "0.5.5"
|
||||
version = "0.5.6"
|
||||
dependencies = [
|
||||
"quinn",
|
||||
"rcgen",
|
||||
@@ -886,7 +886,7 @@ checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe"
|
||||
|
||||
[[package]]
|
||||
name = "pdu-tool"
|
||||
version = "0.5.5"
|
||||
version = "0.5.6"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"tetra-config",
|
||||
@@ -1501,7 +1501,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tetra-config"
|
||||
version = "0.5.5"
|
||||
version = "0.5.6"
|
||||
dependencies = [
|
||||
"chrono-tz",
|
||||
"serde",
|
||||
@@ -1511,7 +1511,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tetra-core"
|
||||
version = "0.5.5"
|
||||
version = "0.5.6"
|
||||
dependencies = [
|
||||
"const_format",
|
||||
"git-version",
|
||||
@@ -1523,7 +1523,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tetra-entities"
|
||||
version = "0.5.5"
|
||||
version = "0.5.6"
|
||||
dependencies = [
|
||||
"as-any",
|
||||
"bitcode",
|
||||
@@ -1553,7 +1553,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tetra-pdus"
|
||||
version = "0.5.5"
|
||||
version = "0.5.6"
|
||||
dependencies = [
|
||||
"tetra-config",
|
||||
"tetra-core",
|
||||
@@ -1563,7 +1563,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tetra-saps"
|
||||
version = "0.5.5"
|
||||
version = "0.5.6"
|
||||
dependencies = [
|
||||
"tetra-core",
|
||||
"tracing",
|
||||
|
||||
@@ -17,7 +17,7 @@ members = [
|
||||
]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.5.5"
|
||||
version = "0.5.6"
|
||||
edition = "2024"
|
||||
authors = ["Wouter Bokslag / Midnight Blue"]
|
||||
license = "MIT"
|
||||
|
||||
@@ -92,9 +92,9 @@ fn main() {
|
||||
eprintln!("░▀█▀░█▀▀░▀█▀░█▀▄░█▀█░░░░░█▀▄░█░░░█░█░█▀▀░█▀▀░▀█▀░█▀█░▀█▀░▀█▀░█▀█░█▀█");
|
||||
eprintln!("░░█░░█▀▀░░█░░█▀▄░█▀█░▄▄▄░█▀▄░█░░░█░█░█▀▀░▀▀█░░█░░█▀█░░█░░░█░░█░█░█░█");
|
||||
eprintln!("░░▀░░▀▀▀░░▀░░▀░▀░▀░▀░░░░░▀▀░░▀▀▀░▀▀▀░▀▀▀░▀▀▀░░▀░░▀░▀░░▀░░▀▀▀░▀▀▀░▀░▀\n");
|
||||
eprintln!(" Wouter Bokslag / Midnight Blue");
|
||||
eprintln!(" -> https://github.com/MidnightBlueLabs/tetra-bluestation");
|
||||
eprintln!(" -> https://midnightblue.nl\n");
|
||||
eprintln!(" Wouter Bokslag / Midnight Blue");
|
||||
eprintln!(" https://github.com/MidnightBlueLabs/tetra-bluestation");
|
||||
eprintln!(" Version: {}", tetra_core::STACK_VERSION);
|
||||
|
||||
let args = Args::parse();
|
||||
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)?;
|
||||
|
||||
// Various sanity checks
|
||||
let expected_config_version = "0.5";
|
||||
let expected_config_version = "0.6";
|
||||
if !root.config_version.eq(expected_config_version) {
|
||||
return Err(format!(
|
||||
"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 {
|
||||
let extra_keys = sorted_keys(&soapy.extra);
|
||||
let extra_keys_filtered = extra_keys.iter().filter(|key| {
|
||||
!(key.starts_with("rx_gain_") || key.starts_with("tx_gain_"))
|
||||
}).collect::<Vec<&&str>>();
|
||||
let extra_keys_filtered = extra_keys
|
||||
.iter()
|
||||
.filter(|key| !(key.starts_with("rx_gain_") || key.starts_with("tx_gain_")))
|
||||
.collect::<Vec<&&str>>();
|
||||
if !extra_keys_filtered.is_empty() {
|
||||
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,
|
||||
rx_ant: soapy_dto.rx_antenna,
|
||||
tx_ant: soapy_dto.tx_antenna,
|
||||
rx_gains: soapy_dto.extra.iter().filter_map(|(key, value)| {
|
||||
key.strip_prefix("rx_gain_").map(|gain_name| {
|
||||
(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"),
|
||||
rx_gains: soapy_dto
|
||||
.extra
|
||||
.iter()
|
||||
.filter_map(|(key, value)| {
|
||||
key.strip_prefix("rx_gain_").map(|gain_name| {
|
||||
(
|
||||
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(),
|
||||
tx_gains: soapy_dto.extra.iter().filter_map(|(key, value)| {
|
||||
key.strip_prefix("tx_gain_").map(|gain_name| {
|
||||
(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(),
|
||||
tx_gains: soapy_dto
|
||||
.extra
|
||||
.iter()
|
||||
.filter_map(|(key, value)| {
|
||||
key.strip_prefix("tx_gain_").map(|gain_name| {
|
||||
(
|
||||
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::*};
|
||||
|
||||
|
||||
/// Enum of all supported devices
|
||||
pub enum SupportedDevice {
|
||||
LimeSdr(LimeSdrModel),
|
||||
@@ -34,43 +33,31 @@ impl SupportedDevice {
|
||||
/// Return None if the device is not supported.
|
||||
pub fn detect(driver_key: &str, hardware_key: &str) -> Option<Self> {
|
||||
match (driver_key, hardware_key) {
|
||||
("FX3", "LimeSDR-USB") =>
|
||||
Some(Self::LimeSdr(LimeSdrModel::LimeSdrUsb)),
|
||||
("FX3", _) =>
|
||||
Some(Self::LimeSdr(LimeSdrModel::OtherFx3)),
|
||||
("FX3", "LimeSDR-USB") => Some(Self::LimeSdr(LimeSdrModel::LimeSdrUsb)),
|
||||
("FX3", _) => Some(Self::LimeSdr(LimeSdrModel::OtherFx3)),
|
||||
|
||||
("FT601", "LimeSDR-Mini_v2") =>
|
||||
Some(Self::LimeSdr(LimeSdrModel::LimeSdrMiniV2)),
|
||||
("FT601", "LimeNET-Micro") =>
|
||||
Some(Self::LimeSdr(LimeSdrModel::LimeNetMicro)),
|
||||
("FT601", _) =>
|
||||
Some(Self::LimeSdr(LimeSdrModel::OtherFt601)),
|
||||
("FT601", "LimeSDR-Mini_v2") => Some(Self::LimeSdr(LimeSdrModel::LimeSdrMiniV2)),
|
||||
("FT601", "LimeNET-Micro") => Some(Self::LimeSdr(LimeSdrModel::LimeNetMicro)),
|
||||
("FT601", _) => Some(Self::LimeSdr(LimeSdrModel::OtherFt601)),
|
||||
|
||||
("sx", _) =>
|
||||
Some(Self::SXceiver),
|
||||
("sx", _) => Some(Self::SXceiver),
|
||||
|
||||
("PlutoSDR", _) =>
|
||||
Some(Self::PlutoSdr),
|
||||
("PlutoSDR", _) => Some(Self::PlutoSdr),
|
||||
|
||||
// USRP B210 seems to report as ("b200", "B210"),
|
||||
// but the driver key is also known to be "uhd" in some cases.
|
||||
// The reason is unknown but might be due to
|
||||
// gateware, firmware or driver version differences.
|
||||
// Try to detect USRP correctly in all cases.
|
||||
("b200", "B200") | ("uhd", "B200") =>
|
||||
Some(Self::Usrp(UsrpModel::B200)),
|
||||
("b200", "B210") | ("uhd", "B210") =>
|
||||
Some(Self::Usrp(UsrpModel::B210)),
|
||||
("b200", _) | ("uhd", _) =>
|
||||
Some(Self::Usrp(UsrpModel::Other)),
|
||||
("b200", "B200") | ("uhd", "B200") => Some(Self::Usrp(UsrpModel::B200)),
|
||||
("b200", "B210") | ("uhd", "B210") => Some(Self::Usrp(UsrpModel::B210)),
|
||||
("b200", _) | ("uhd", _) => Some(Self::Usrp(UsrpModel::Other)),
|
||||
// TODO: add other USRP models if needed
|
||||
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SdrSettings {
|
||||
/// Settings template, holding which SDR is used
|
||||
@@ -137,7 +124,7 @@ impl SdrSettings {
|
||||
}
|
||||
if !cfg_gains.is_empty() {
|
||||
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();
|
||||
@@ -148,7 +135,7 @@ impl SdrSettings {
|
||||
}
|
||||
if !cfg_gains.is_empty() {
|
||||
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
|
||||
@@ -159,17 +146,13 @@ impl SdrSettings {
|
||||
/// Get default settings based on SDR type
|
||||
fn get_defaults(cfg: &CfgSoapySdr, device: SupportedDevice, mode: StackMode) -> Self {
|
||||
match device {
|
||||
SupportedDevice::LimeSdr(model) =>
|
||||
Self::settings_limesdr(mode, model),
|
||||
SupportedDevice::LimeSdr(model) => Self::settings_limesdr(mode, model),
|
||||
|
||||
SupportedDevice::SXceiver =>
|
||||
Self::settings_sxceiver(mode, cfg.fs),
|
||||
SupportedDevice::SXceiver => Self::settings_sxceiver(mode, cfg.fs),
|
||||
|
||||
SupportedDevice::PlutoSdr =>
|
||||
Self::settings_pluto(mode),
|
||||
SupportedDevice::PlutoSdr => Self::settings_pluto(mode),
|
||||
|
||||
SupportedDevice::Usrp(model) =>
|
||||
Self::settings_usrp(mode, model),
|
||||
SupportedDevice::Usrp(model) => Self::settings_usrp(mode, model),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -220,25 +203,24 @@ impl SdrSettings {
|
||||
}
|
||||
.to_string(),
|
||||
|
||||
rx_ant: Some(match model {
|
||||
LimeSdrModel::LimeSdrUsb => "LNAL",
|
||||
_ => "LNAW",
|
||||
}.to_string()),
|
||||
rx_ant: Some(
|
||||
match model {
|
||||
LimeSdrModel::LimeSdrUsb => "LNAL",
|
||||
_ => "LNAW",
|
||||
}
|
||||
.to_string(),
|
||||
),
|
||||
|
||||
tx_ant: Some(match model {
|
||||
LimeSdrModel::LimeSdrUsb => "BAND1",
|
||||
_ => "BAND2",
|
||||
}.to_string()),
|
||||
tx_ant: Some(
|
||||
match model {
|
||||
LimeSdrModel::LimeSdrUsb => "BAND1",
|
||||
_ => "BAND2",
|
||||
}
|
||||
.to_string(),
|
||||
),
|
||||
|
||||
rx_gain: vec![
|
||||
("LNA".to_string(), 18.0),
|
||||
("TIA".to_string(), 6.0),
|
||||
("PGA".to_string(), 10.0),
|
||||
],
|
||||
tx_gain: vec![
|
||||
("PAD".to_string(), 22.0),
|
||||
("IAMP".to_string(), 6.0),
|
||||
],
|
||||
rx_gain: vec![("LNA".to_string(), 18.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
|
||||
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()),
|
||||
tx_ant: Some("TX".to_string()),
|
||||
|
||||
rx_gain: vec![
|
||||
("LNA".to_string(), 42.0),
|
||||
("PGA".to_string(), 16.0),
|
||||
],
|
||||
tx_gain: vec![
|
||||
("DAC".to_string(), 9.0),
|
||||
("MIXER".to_string(), 30.0),
|
||||
],
|
||||
rx_gain: vec![("LNA".to_string(), 42.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())],
|
||||
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.
|
||||
/// This can be used to optimize performance for some SDRs.
|
||||
pub fn block_size(fs: f64) -> usize {
|
||||
|
||||
@@ -336,10 +336,8 @@ impl SoapyIo {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Messy logic related to opening a device follows...
|
||||
|
||||
|
||||
/// Struct to temporarily hold stuff related to opening and detecting a device
|
||||
struct OpenedDevice {
|
||||
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
|
||||
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 {
|
||||
dev_args,
|
||||
dev,
|
||||
@@ -380,7 +382,11 @@ fn open_given_device(dev_args: soapysdr::Args) -> Result<OpenedDevice, soapysdr:
|
||||
soapyremote_used,
|
||||
})
|
||||
} 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 {
|
||||
code: soapysdr::ErrorCode::NotSupported,
|
||||
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);
|
||||
match open_given_device(dev_args) {
|
||||
Ok(opened_device) => return Ok(opened_device),
|
||||
Err(_) => {},
|
||||
Err(_) => {}
|
||||
}
|
||||
}
|
||||
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) {
|
||||
Ok(sdr_settings) => sdr_settings,
|
||||
Err(soapy_settings::Error::InvalidConfiguration) => return Err(soapysdr::Error {
|
||||
code: soapysdr::ErrorCode::Other,
|
||||
message: "Invalid SDR device configuration".to_string(),
|
||||
}),
|
||||
Err(soapy_settings::Error::InvalidConfiguration) => {
|
||||
return Err(soapysdr::Error {
|
||||
code: soapysdr::ErrorCode::Other,
|
||||
message: "Invalid SDR device configuration".to_string(),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
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.
|
||||
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.
|
||||
// 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
|
||||
@@ -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_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 {
|
||||
tracing::info!("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);
|
||||
tracing::info!(
|
||||
"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 {
|
||||
code: soapysdr::ErrorCode::Other,
|
||||
message: "Reopened a different device".to_string(),
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# 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
|
||||
|
||||
config_version = "0.5"
|
||||
config_version = "0.6"
|
||||
|
||||
# Stack operation mode: "Bs" (Base Station), "Ms" (Mobile Station), or "Mon" (Monitor)
|
||||
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.
|
||||
tx_freq = 438025000
|
||||
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.
|
||||
# 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"
|
||||
|
||||
# Optional antenna selection to override device-specific defaults
|
||||
# Check antenna names with SoapySDRUtil --probe
|
||||
# rx_antenna = "LNAW"
|
||||
# tx_antenna = "BAND2"
|
||||
|
||||
# Optional gain values to override device-specific defaults.
|
||||
# Check valid gain names with SoapySDRUtil --probe
|
||||
# For example, to increase transmit power on a LimeSDR:
|
||||
# tx_gain_pad = 50.0
|
||||
# To adjust LNA gain to optimize RX performance on a LimeSDR or SXceiver:
|
||||
# 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
|
||||
|
||||
Reference in New Issue
Block a user