show sdr device log messages in the web configuration
This commit is contained in:
@ -18,6 +18,7 @@ from owrx.form.input.device import GainInput, SchedulerInput, WaterfallLevelsInp
|
||||
from owrx.form.input.validator import RequiredValidator
|
||||
from owrx.form.section import OptionalSection
|
||||
from owrx.feature import FeatureDetector
|
||||
from owrx.log import LogPipe, HistoryHandler
|
||||
from typing import List
|
||||
from enum import Enum
|
||||
|
||||
@ -114,6 +115,10 @@ class SdrSource(ABC):
|
||||
self.commandMapper = None
|
||||
self.tcpSource = None
|
||||
self.buffer = None
|
||||
self.logger = logger.getChild(id) if id is not None else logger
|
||||
self.logger.addHandler(HistoryHandler.getHandler(self.logger.name))
|
||||
self.stdoutPipe = None
|
||||
self.stderrPipe = None
|
||||
|
||||
self.props = PropertyStack()
|
||||
|
||||
@ -185,17 +190,17 @@ class SdrSource(ABC):
|
||||
for id, p in self.props["profiles"].items():
|
||||
props.replaceLayer(0, p)
|
||||
if "center_freq" not in props:
|
||||
logger.warning('Profile "%s" does not specify a center_freq', id)
|
||||
self.logger.warning('Profile "%s" does not specify a center_freq', id)
|
||||
continue
|
||||
if "samp_rate" not in props:
|
||||
logger.warning('Profile "%s" does not specify a samp_rate', id)
|
||||
self.logger.warning('Profile "%s" does not specify a samp_rate', id)
|
||||
continue
|
||||
if "start_freq" in props:
|
||||
start_freq = props["start_freq"]
|
||||
srh = props["samp_rate"] / 2
|
||||
center_freq = props["center_freq"]
|
||||
if start_freq < center_freq - srh or start_freq > center_freq + srh:
|
||||
logger.warning('start_freq for profile "%s" is out of range', id)
|
||||
self.logger.warning('start_freq for profile "%s" is out of range', id)
|
||||
|
||||
def isAlwaysOn(self):
|
||||
return "always-on" in self.props and self.props["always-on"]
|
||||
@ -225,11 +230,11 @@ class SdrSource(ABC):
|
||||
return [self.getCommandMapper().map(self.getCommandValues())]
|
||||
|
||||
def activateProfile(self, profile_id):
|
||||
logger.debug("activating profile {0} for {1}".format(profile_id, self.getId()))
|
||||
self.logger.debug("activating profile {0} for {1}".format(profile_id, self.getId()))
|
||||
try:
|
||||
self.profileCarousel.switch(profile_id)
|
||||
except KeyError:
|
||||
logger.warning("invalid profile %s for sdr %s. ignoring", profile_id, self.getId())
|
||||
self.logger.warning("invalid profile %s for sdr %s. ignoring", profile_id, self.getId())
|
||||
|
||||
def getId(self):
|
||||
return self.id
|
||||
@ -283,23 +288,37 @@ class SdrSource(ABC):
|
||||
try:
|
||||
self.preStart()
|
||||
except Exception:
|
||||
logger.exception("Exception during preStart()")
|
||||
self.logger.exception("Exception during preStart()")
|
||||
|
||||
cmd = self.getCommand()
|
||||
cmd = [c for c in cmd if c is not None]
|
||||
|
||||
self.stdoutPipe = LogPipe(logging.INFO, self.logger, "STDOUT")
|
||||
self.stderrPipe = LogPipe(logging.WARNING, self.logger, "STDERR")
|
||||
|
||||
# don't use shell mode for commands without piping
|
||||
if len(cmd) > 1:
|
||||
# multiple commands with pipes
|
||||
cmd = "|".join(cmd)
|
||||
self.process = subprocess.Popen(cmd, shell=True, start_new_session=True)
|
||||
self.process = subprocess.Popen(
|
||||
cmd,
|
||||
shell=True,
|
||||
start_new_session=True,
|
||||
stdout=self.stdoutPipe,
|
||||
stderr=self.stderrPipe
|
||||
)
|
||||
else:
|
||||
# single command
|
||||
cmd = cmd[0]
|
||||
# start_new_session can go as soon as there's no piped commands left
|
||||
# the os.killpg call must be replaced with something more reasonable at the same time
|
||||
self.process = subprocess.Popen(shlex.split(cmd), start_new_session=True)
|
||||
logger.info("Started sdr source: " + cmd)
|
||||
self.process = subprocess.Popen(
|
||||
shlex.split(cmd),
|
||||
start_new_session=True,
|
||||
stdout=self.stdoutPipe,
|
||||
stderr=self.stderrPipe
|
||||
)
|
||||
self.logger.info("Started sdr source: " + cmd)
|
||||
|
||||
available = False
|
||||
failed = False
|
||||
@ -307,9 +326,13 @@ class SdrSource(ABC):
|
||||
def wait_for_process_to_end():
|
||||
nonlocal failed
|
||||
rc = self.process.wait()
|
||||
logger.debug("shut down with RC={0}".format(rc))
|
||||
self.logger.debug("shut down with RC={0}".format(rc))
|
||||
self.process = None
|
||||
self.monitor = None
|
||||
self.stdoutPipe.close()
|
||||
self.stdoutPipe = None
|
||||
self.stderrPipe.close()
|
||||
self.stderrPipe = None
|
||||
if self.getState() is SdrSourceState.RUNNING:
|
||||
self.fail()
|
||||
else:
|
||||
@ -340,7 +363,7 @@ class SdrSource(ABC):
|
||||
try:
|
||||
self.postStart()
|
||||
except Exception:
|
||||
logger.exception("Exception during postStart()")
|
||||
self.logger.exception("Exception during postStart()")
|
||||
failed = True
|
||||
|
||||
if failed:
|
||||
@ -374,7 +397,7 @@ class SdrSource(ABC):
|
||||
self.monitor.join(10)
|
||||
# if the monitor is still running, the process still hasn't ended, so kill it
|
||||
if self.monitor:
|
||||
logger.warning("source has not shut down normally within 10 seconds, sending SIGKILL")
|
||||
self.logger.warning("source has not shut down normally within 10 seconds, sending SIGKILL")
|
||||
os.killpg(os.getpgid(self.process.pid), signal.SIGKILL)
|
||||
except ProcessLookupError:
|
||||
# been killed by something else, ignore
|
||||
|
@ -6,10 +6,6 @@ from owrx.command import Flag, Option
|
||||
from typing import List
|
||||
from owrx.form.input import Input, NumberInput, CheckboxInput
|
||||
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ConnectorSource(SdrSource):
|
||||
def __init__(self, id, props):
|
||||
@ -40,7 +36,7 @@ class ConnectorSource(SdrSource):
|
||||
for prop, value in changes.items():
|
||||
if value is PropertyDeleted:
|
||||
value = None
|
||||
logger.debug("sending property change over control socket: {0} changed to {1}".format(prop, value))
|
||||
self.logger.debug("sending property change over control socket: {0} changed to {1}".format(prop, value))
|
||||
self.controlSocket.sendall("{prop}:{value}\n".format(prop=prop, value=value).encode())
|
||||
|
||||
def onPropertyChange(self, changes):
|
||||
@ -56,7 +52,7 @@ class ConnectorSource(SdrSource):
|
||||
self.sendControlMessage(changes)
|
||||
|
||||
def postStart(self):
|
||||
logger.debug("opening control socket...")
|
||||
self.logger.debug("opening control socket...")
|
||||
self.controlSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self.controlSocket.connect(("localhost", self.controlPort))
|
||||
|
||||
|
@ -5,10 +5,6 @@ from typing import Optional
|
||||
from pycsdr.modules import Buffer
|
||||
from pycsdr.types import Format
|
||||
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class DirectSource(SdrSource, metaclass=ABCMeta):
|
||||
def __init__(self, id, props):
|
||||
@ -16,7 +12,7 @@ class DirectSource(SdrSource, metaclass=ABCMeta):
|
||||
super().__init__(id, props)
|
||||
|
||||
def onPropertyChange(self, changes):
|
||||
logger.debug("restarting sdr source due to property changes: {0}".format(changes))
|
||||
self.logger.debug("restarting sdr source due to property changes: {0}".format(changes))
|
||||
self.stop()
|
||||
self.sleepOnRestart()
|
||||
self.start()
|
||||
|
@ -1,16 +1,14 @@
|
||||
from owrx.command import Option
|
||||
from owrx.source.direct import DirectSource, DirectSourceDeviceDescription
|
||||
from owrx.log import LogPipe
|
||||
from subprocess import Popen
|
||||
from csdr.chain import Chain
|
||||
from pycsdr.modules import Convert, Gain
|
||||
from pycsdr.types import Format
|
||||
from typing import List
|
||||
from owrx.form.input import Input, TextInput
|
||||
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class FifiSdrSource(DirectSource):
|
||||
def getCommandMapper(self):
|
||||
@ -29,11 +27,19 @@ class FifiSdrSource(DirectSource):
|
||||
return Chain([Convert(Format.COMPLEX_SHORT, Format.COMPLEX_FLOAT), Gain(Format.COMPLEX_FLOAT, 5.0)])
|
||||
|
||||
def sendRockProgFrequency(self, frequency):
|
||||
process = Popen(["rockprog", "--vco", "-w", "--freq={}".format(frequency / 1e6)])
|
||||
stdoutPipe = LogPipe(logging.DEBUG, self.logger, "STDOUT")
|
||||
stderrPipe = LogPipe(logging.DEBUG, self.logger, "STDERR")
|
||||
process = Popen(
|
||||
["rockprog", "--vco", "-w", "--freq={}".format(frequency / 1e6)],
|
||||
stdout=stdoutPipe,
|
||||
stderr=stderrPipe
|
||||
)
|
||||
process.communicate()
|
||||
rc = process.wait()
|
||||
if rc != 0:
|
||||
logger.warning("rockprog failed to set frequency; rc=%i", rc)
|
||||
self.logger.warning("rockprog failed to set frequency; rc=%i", rc)
|
||||
stdoutPipe.close()
|
||||
stderrPipe.close()
|
||||
|
||||
def preStart(self):
|
||||
values = self.getCommandValues()
|
||||
|
@ -3,14 +3,10 @@ from pycsdr.modules import Buffer, FirDecimate, Shift
|
||||
from pycsdr.types import Format
|
||||
from csdr.chain import Chain
|
||||
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Resampler(SdrSource):
|
||||
def onPropertyChange(self, changes):
|
||||
logger.warning("Resampler is unable to handle property changes: {0}".format(changes))
|
||||
self.logger.warning("Resampler is unable to handle property changes: {0}".format(changes))
|
||||
|
||||
def __init__(self, props, sdr):
|
||||
sdrProps = sdr.getProps()
|
||||
@ -41,7 +37,7 @@ class Resampler(SdrSource):
|
||||
super().stop()
|
||||
|
||||
def activateProfile(self, profile_id=None):
|
||||
logger.warning("Resampler does not support setting profiles")
|
||||
self.logger.warning("Resampler does not support setting profiles")
|
||||
pass
|
||||
|
||||
def validateProfiles(self):
|
||||
|
Reference in New Issue
Block a user