Исходный код soniks_client.sdr_check
"""Проверка приёмника перед применением конфигурации с портала.
Открывает устройство python-биндингом SoapySDR и выставляет частоту
дискретизации, антенный вход и усиление — то, что в реальном проходе делает
граф. Работает в подпроцессе с таймаутом: зависший драйвер не должен вешать
поток планировщика. Запускать только вне прохода — приёмник занят графом.
Без биндинга (старая база образа) проверка пропускается с предупреждением:
иначе на такой станции не применился бы ни один конфиг.
"""
import json
import subprocess
import sys
TIMEOUT_SECONDS = 20
NO_BINDING = 3
[документация]
def check(
device: str,
sample_rate: float | None,
antenna: str | None,
gain: float | None,
timeout: float = TIMEOUT_SECONDS,
) -> str | None:
"""Открыть приёмник с заданными параметрами.
Returns:
``None``, если устройство открылось (или проверить нечем), иначе
текст ошибки для лога и портала.
"""
# Здесь, а не на уровне модуля: тот же файл запускается дочерним процессом,
# которому настройки станции ни к чему.
from core.configs import logger
args = json.dumps(
{"device": device, "sample_rate": sample_rate, "antenna": antenna, "gain": gain}
)
try:
proc = subprocess.run(
[sys.executable, __file__, args],
capture_output=True,
text=True,
timeout=timeout,
)
except subprocess.TimeoutExpired:
return f"приёмник {device} не ответил за {timeout:g} с"
except OSError as e:
return f"проверка приёмника не запустилась: {e}"
if proc.returncode == 0:
return None
if proc.returncode == NO_BINDING:
logger.warning("Биндинг SoapySDR недоступен, проверка приёмника пропущена")
return None
lines = proc.stderr.strip().splitlines()
return f"приёмник {device}: {lines[-1] if lines else f'код {proc.returncode}'}"
def _probe(args: dict) -> None:
try:
import SoapySDR
except ImportError:
sys.exit(NO_BINDING)
try:
device = SoapySDR.Device(args["device"])
rx = SoapySDR.SOAPY_SDR_RX
if args.get("sample_rate") is not None:
device.setSampleRate(rx, 0, float(args["sample_rate"]))
if args.get("antenna"):
device.setAntenna(rx, 0, args["antenna"])
if args.get("gain") is not None:
device.setGain(rx, 0, float(args["gain"]))
except Exception as e:
print(e, file=sys.stderr)
sys.exit(1)
if __name__ == "__main__":
_probe(json.loads(sys.argv[1]))