introduce enums for state management
This commit is contained in:
parent
dd5ab32b47
commit
c2e8ac516c
@ -2,7 +2,7 @@ from owrx.details import ReceiverDetails
|
|||||||
from owrx.dsp import DspManager
|
from owrx.dsp import DspManager
|
||||||
from owrx.cpu import CpuUsageThread
|
from owrx.cpu import CpuUsageThread
|
||||||
from owrx.sdr import SdrService
|
from owrx.sdr import SdrService
|
||||||
from owrx.source import SdrSource, SdrSourceEventClient
|
from owrx.source import SdrSourceState, SdrBusyState, SdrClientClass, SdrSourceEventClient
|
||||||
from owrx.client import ClientRegistry, TooManyClientsException
|
from owrx.client import ClientRegistry, TooManyClientsException
|
||||||
from owrx.feature import FeatureDetector
|
from owrx.feature import FeatureDetector
|
||||||
from owrx.version import openwebrx_version
|
from owrx.version import openwebrx_version
|
||||||
@ -216,10 +216,10 @@ class OpenWebRxReceiverClient(OpenWebRxClient, SdrSourceEventClient):
|
|||||||
self.configSubs.append(globalConfig.wire(writeConfig))
|
self.configSubs.append(globalConfig.wire(writeConfig))
|
||||||
writeConfig(globalConfig.__dict__())
|
writeConfig(globalConfig.__dict__())
|
||||||
|
|
||||||
def onStateChange(self, state):
|
def onStateChange(self, state: SdrSourceState):
|
||||||
if state == SdrSource.STATE_RUNNING:
|
if state is SdrSourceState.RUNNING:
|
||||||
self.handleSdrAvailable()
|
self.handleSdrAvailable()
|
||||||
elif state == SdrSource.STATE_FAILED:
|
elif state is SdrSourceState.FAILED:
|
||||||
self.handleSdrFailed()
|
self.handleSdrFailed()
|
||||||
|
|
||||||
def handleSdrFailed(self):
|
def handleSdrFailed(self):
|
||||||
@ -227,11 +227,11 @@ class OpenWebRxReceiverClient(OpenWebRxClient, SdrSourceEventClient):
|
|||||||
self.write_log_message('SDR device "{0}" has failed, selecting new device'.format(self.sdr.getName()))
|
self.write_log_message('SDR device "{0}" has failed, selecting new device'.format(self.sdr.getName()))
|
||||||
self.setSdr()
|
self.setSdr()
|
||||||
|
|
||||||
def onBusyStateChange(self, state):
|
def onBusyStateChange(self, state: SdrBusyState):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def getClientClass(self):
|
def getClientClass(self) -> SdrClientClass:
|
||||||
return SdrSource.CLIENT_USER
|
return SdrClientClass.USER
|
||||||
|
|
||||||
def __sendProfiles(self):
|
def __sendProfiles(self):
|
||||||
profiles = [
|
profiles = [
|
||||||
|
16
owrx/dsp.py
16
owrx/dsp.py
@ -3,7 +3,7 @@ from owrx.wsjt import WsjtParser
|
|||||||
from owrx.js8 import Js8Parser
|
from owrx.js8 import Js8Parser
|
||||||
from owrx.aprs import AprsParser
|
from owrx.aprs import AprsParser
|
||||||
from owrx.pocsag import PocsagParser
|
from owrx.pocsag import PocsagParser
|
||||||
from owrx.source import SdrSource, SdrSourceEventClient
|
from owrx.source import SdrSourceEventClient, SdrSourceState, SdrBusyState, SdrClientClass
|
||||||
from owrx.property import PropertyStack, PropertyLayer, PropertyValidator
|
from owrx.property import PropertyStack, PropertyLayer, PropertyValidator
|
||||||
from owrx.property.validators import OrValidator, RegexValidator, BoolValidator
|
from owrx.property.validators import OrValidator, RegexValidator, BoolValidator
|
||||||
from owrx.modes import Modes
|
from owrx.modes import Modes
|
||||||
@ -198,21 +198,21 @@ class DspManager(csdr.output, SdrSourceEventClient):
|
|||||||
def setProperty(self, prop, value):
|
def setProperty(self, prop, value):
|
||||||
self.localProps[prop] = value
|
self.localProps[prop] = value
|
||||||
|
|
||||||
def getClientClass(self):
|
def getClientClass(self) -> SdrClientClass:
|
||||||
return SdrSource.CLIENT_USER
|
return SdrClientClass.USER
|
||||||
|
|
||||||
def onStateChange(self, state):
|
def onStateChange(self, state: SdrSourceState):
|
||||||
if state == SdrSource.STATE_RUNNING:
|
if state is SdrSourceState.RUNNING:
|
||||||
logger.debug("received STATE_RUNNING, attempting DspSource restart")
|
logger.debug("received STATE_RUNNING, attempting DspSource restart")
|
||||||
if self.startOnAvailable:
|
if self.startOnAvailable:
|
||||||
self.dsp.start()
|
self.dsp.start()
|
||||||
self.startOnAvailable = False
|
self.startOnAvailable = False
|
||||||
elif state == SdrSource.STATE_STOPPING:
|
elif state is SdrSourceState.STOPPING:
|
||||||
logger.debug("received STATE_STOPPING, shutting down DspSource")
|
logger.debug("received STATE_STOPPING, shutting down DspSource")
|
||||||
self.dsp.stop()
|
self.dsp.stop()
|
||||||
elif state == SdrSource.STATE_FAILED:
|
elif state is SdrSourceState.FAILED:
|
||||||
logger.debug("received STATE_FAILED, shutting down DspSource")
|
logger.debug("received STATE_FAILED, shutting down DspSource")
|
||||||
self.dsp.stop()
|
self.dsp.stop()
|
||||||
|
|
||||||
def onBusyStateChange(self, state):
|
def onBusyStateChange(self, state: SdrBusyState):
|
||||||
pass
|
pass
|
||||||
|
14
owrx/fft.py
14
owrx/fft.py
@ -2,7 +2,7 @@ from owrx.config.core import CoreConfig
|
|||||||
from owrx.config import Config
|
from owrx.config import Config
|
||||||
from csdr import csdr
|
from csdr import csdr
|
||||||
import threading
|
import threading
|
||||||
from owrx.source import SdrSource, SdrSourceEventClient
|
from owrx.source import SdrSourceEventClient, SdrSourceState, SdrBusyState, SdrClientClass
|
||||||
from owrx.property import PropertyStack
|
from owrx.property import PropertyStack
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
@ -73,14 +73,14 @@ class SpectrumThread(csdr.output, SdrSourceEventClient):
|
|||||||
c.cancel()
|
c.cancel()
|
||||||
self.subscriptions = []
|
self.subscriptions = []
|
||||||
|
|
||||||
def getClientClass(self):
|
def getClientClass(self) -> SdrClientClass:
|
||||||
return SdrSource.CLIENT_USER
|
return SdrClientClass.USER
|
||||||
|
|
||||||
def onStateChange(self, state):
|
def onStateChange(self, state: SdrSourceState):
|
||||||
if state in [SdrSource.STATE_STOPPING, SdrSource.STATE_FAILED]:
|
if state in [SdrSourceState.STOPPING, SdrSourceState.FAILED]:
|
||||||
self.dsp.stop()
|
self.dsp.stop()
|
||||||
elif state == SdrSource.STATE_RUNNING:
|
elif state is SdrSourceState.RUNNING:
|
||||||
self.dsp.start()
|
self.dsp.start()
|
||||||
|
|
||||||
def onBusyStateChange(self, state):
|
def onBusyStateChange(self, state: SdrBusyState):
|
||||||
pass
|
pass
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import threading
|
import threading
|
||||||
from owrx.source import SdrSource, SdrSourceEventClient
|
from owrx.source import SdrSourceEventClient, SdrSourceState, SdrBusyState, SdrClientClass
|
||||||
from owrx.sdr import SdrService
|
from owrx.sdr import SdrService
|
||||||
from owrx.bands import Bandplan
|
from owrx.bands import Bandplan
|
||||||
from csdr.csdr import dsp, output
|
from csdr.csdr import dsp, output
|
||||||
@ -75,22 +75,22 @@ class ServiceHandler(SdrSourceEventClient):
|
|||||||
if "schedule" in props or "scheduler" in props:
|
if "schedule" in props or "scheduler" in props:
|
||||||
self.scheduler = ServiceScheduler(self.source)
|
self.scheduler = ServiceScheduler(self.source)
|
||||||
|
|
||||||
def getClientClass(self):
|
def getClientClass(self) -> SdrClientClass:
|
||||||
return SdrSource.CLIENT_INACTIVE
|
return SdrClientClass.INACTIVE
|
||||||
|
|
||||||
def onStateChange(self, state):
|
def onStateChange(self, state: SdrSourceState):
|
||||||
if state == SdrSource.STATE_RUNNING:
|
if state is SdrSourceState.RUNNING:
|
||||||
self.scheduleServiceStartup()
|
self.scheduleServiceStartup()
|
||||||
elif state == SdrSource.STATE_STOPPING:
|
elif state is SdrSourceState.STOPPING:
|
||||||
logger.debug("sdr source becoming unavailable; stopping services.")
|
logger.debug("sdr source becoming unavailable; stopping services.")
|
||||||
self.stopServices()
|
self.stopServices()
|
||||||
elif state == SdrSource.STATE_FAILED:
|
elif state is SdrSourceState.FAILED:
|
||||||
logger.debug("sdr source failed; stopping services.")
|
logger.debug("sdr source failed; stopping services.")
|
||||||
self.stopServices()
|
self.stopServices()
|
||||||
if self.scheduler:
|
if self.scheduler:
|
||||||
self.scheduler.shutdown()
|
self.scheduler.shutdown()
|
||||||
|
|
||||||
def onBusyStateChange(self, state):
|
def onBusyStateChange(self, state: SdrBusyState):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def isSupported(self, mode):
|
def isSupported(self, mode):
|
||||||
@ -164,7 +164,8 @@ class ServiceHandler(SdrSourceEventClient):
|
|||||||
for dial in group:
|
for dial in group:
|
||||||
self.services.append(self.setupService(dial["mode"], dial["frequency"], resampler))
|
self.services.append(self.setupService(dial["mode"], dial["frequency"], resampler))
|
||||||
|
|
||||||
# resampler goes in after the services since it must not be shutdown as long as the services are still running
|
# resampler goes in after the services since it must not be shutdown as long as the services are
|
||||||
|
# still running
|
||||||
self.services.append(resampler)
|
self.services.append(resampler)
|
||||||
|
|
||||||
def get_min_max(self, group):
|
def get_min_max(self, group):
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
from datetime import datetime, timezone, timedelta
|
from datetime import datetime, timezone, timedelta
|
||||||
from owrx.source import SdrSource, SdrSourceEventClient
|
from owrx.source import SdrSourceEventClient, SdrSourceState, SdrClientClass, SdrBusyState
|
||||||
from owrx.config import Config
|
from owrx.config import Config
|
||||||
import threading
|
import threading
|
||||||
import math
|
import math
|
||||||
@ -220,7 +220,7 @@ class ServiceScheduler(SdrSourceEventClient):
|
|||||||
self.source.removeClient(self)
|
self.source.removeClient(self)
|
||||||
|
|
||||||
def scheduleSelection(self, time=None):
|
def scheduleSelection(self, time=None):
|
||||||
if self.source.getState() == SdrSource.STATE_FAILED:
|
if self.source.getState() is SdrSourceState.FAILED:
|
||||||
return
|
return
|
||||||
seconds = 10
|
seconds = 10
|
||||||
if time is not None:
|
if time is not None:
|
||||||
@ -234,24 +234,24 @@ class ServiceScheduler(SdrSourceEventClient):
|
|||||||
if self.selectionTimer:
|
if self.selectionTimer:
|
||||||
self.selectionTimer.cancel()
|
self.selectionTimer.cancel()
|
||||||
|
|
||||||
def getClientClass(self):
|
def getClientClass(self) -> SdrClientClass:
|
||||||
return SdrSource.CLIENT_BACKGROUND
|
return SdrClientClass.BACKGROUND
|
||||||
|
|
||||||
def onStateChange(self, state):
|
def onStateChange(self, state: SdrSourceState):
|
||||||
if state == SdrSource.STATE_STOPPING:
|
if state is SdrSourceState.STOPPING:
|
||||||
self.scheduleSelection()
|
self.scheduleSelection()
|
||||||
elif state == SdrSource.STATE_FAILED:
|
elif state is SdrSourceState.FAILED:
|
||||||
self.cancelTimer()
|
self.cancelTimer()
|
||||||
|
|
||||||
def onBusyStateChange(self, state):
|
def onBusyStateChange(self, state: SdrBusyState):
|
||||||
if state == SdrSource.BUSYSTATE_IDLE:
|
if state is SdrBusyState.IDLE:
|
||||||
self.scheduleSelection()
|
self.scheduleSelection()
|
||||||
|
|
||||||
def onFrequencyChange(self, changes):
|
def onFrequencyChange(self, changes):
|
||||||
self.scheduleSelection()
|
self.scheduleSelection()
|
||||||
|
|
||||||
def selectProfile(self):
|
def selectProfile(self):
|
||||||
if self.source.hasClients(SdrSource.CLIENT_USER):
|
if self.source.hasClients(SdrClientClass.USER):
|
||||||
logger.debug("source has active users; not touching")
|
logger.debug("source has active users; not touching")
|
||||||
return
|
return
|
||||||
logger.debug("source seems to be idle, selecting profile for background services")
|
logger.debug("source seems to be idle, selecting profile for background services")
|
||||||
|
@ -15,40 +15,50 @@ from owrx.form.converter import IntConverter, OptionalConverter
|
|||||||
from owrx.form.device import GainInput
|
from owrx.form.device import GainInput
|
||||||
from owrx.controllers.settings import Section
|
from owrx.controllers.settings import Section
|
||||||
from typing import List
|
from typing import List
|
||||||
|
from enum import Enum, auto
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class SdrSourceState(Enum):
|
||||||
|
STOPPED = "Stopped"
|
||||||
|
STARTING = "Starting"
|
||||||
|
RUNNING = "Running"
|
||||||
|
STOPPING = "Stopping"
|
||||||
|
TUNING = "Tuning"
|
||||||
|
FAILED = "Failed"
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.value
|
||||||
|
|
||||||
|
|
||||||
|
class SdrBusyState(Enum):
|
||||||
|
IDLE = auto()
|
||||||
|
BUSY = auto()
|
||||||
|
|
||||||
|
|
||||||
|
class SdrClientClass(Enum):
|
||||||
|
INACTIVE = auto()
|
||||||
|
BACKGROUND = auto()
|
||||||
|
USER = auto()
|
||||||
|
|
||||||
|
|
||||||
class SdrSourceEventClient(ABC):
|
class SdrSourceEventClient(ABC):
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def onStateChange(self, state):
|
def onStateChange(self, state: SdrSourceState):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def onBusyStateChange(self, state):
|
def onBusyStateChange(self, state: SdrBusyState):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def getClientClass(self):
|
def getClientClass(self) -> SdrClientClass:
|
||||||
return SdrSource.CLIENT_INACTIVE
|
return SdrClientClass.INACTIVE
|
||||||
|
|
||||||
|
|
||||||
class SdrSource(ABC):
|
class SdrSource(ABC):
|
||||||
STATE_STOPPED = 0
|
|
||||||
STATE_STARTING = 1
|
|
||||||
STATE_RUNNING = 2
|
|
||||||
STATE_STOPPING = 3
|
|
||||||
STATE_TUNING = 4
|
|
||||||
STATE_FAILED = 5
|
|
||||||
|
|
||||||
BUSYSTATE_IDLE = 0
|
|
||||||
BUSYSTATE_BUSY = 1
|
|
||||||
|
|
||||||
CLIENT_INACTIVE = 0
|
|
||||||
CLIENT_BACKGROUND = 1
|
|
||||||
CLIENT_USER = 2
|
|
||||||
|
|
||||||
def __init__(self, id, props):
|
def __init__(self, id, props):
|
||||||
self.id = id
|
self.id = id
|
||||||
|
|
||||||
@ -78,8 +88,8 @@ class SdrSource(ABC):
|
|||||||
self.process = None
|
self.process = None
|
||||||
self.modificationLock = threading.Lock()
|
self.modificationLock = threading.Lock()
|
||||||
self.failed = False
|
self.failed = False
|
||||||
self.state = SdrSource.STATE_STOPPED
|
self.state = SdrSourceState.STOPPED
|
||||||
self.busyState = SdrSource.BUSYSTATE_IDLE
|
self.busyState = SdrBusyState.IDLE
|
||||||
|
|
||||||
self.validateProfiles()
|
self.validateProfiles()
|
||||||
|
|
||||||
@ -218,11 +228,11 @@ class SdrSource(ABC):
|
|||||||
rc = self.process.wait()
|
rc = self.process.wait()
|
||||||
logger.debug("shut down with RC={0}".format(rc))
|
logger.debug("shut down with RC={0}".format(rc))
|
||||||
self.monitor = None
|
self.monitor = None
|
||||||
if self.getState() == SdrSource.STATE_RUNNING:
|
if self.getState() is SdrSourceState.RUNNING:
|
||||||
self.failed = True
|
self.failed = True
|
||||||
self.setState(SdrSource.STATE_FAILED)
|
self.setState(SdrSourceState.FAILED)
|
||||||
else:
|
else:
|
||||||
self.setState(SdrSource.STATE_STOPPED)
|
self.setState(SdrSourceState.STOPPED)
|
||||||
|
|
||||||
self.monitor = threading.Thread(target=wait_for_process_to_end, name="source_monitor")
|
self.monitor = threading.Thread(target=wait_for_process_to_end, name="source_monitor")
|
||||||
self.monitor.start()
|
self.monitor.start()
|
||||||
@ -250,7 +260,7 @@ class SdrSource(ABC):
|
|||||||
logger.exception("Exception during postStart()")
|
logger.exception("Exception during postStart()")
|
||||||
self.failed = True
|
self.failed = True
|
||||||
|
|
||||||
self.setState(SdrSource.STATE_FAILED if self.failed else SdrSource.STATE_RUNNING)
|
self.setState(SdrSourceState.FAILED if self.failed else SdrSourceState.RUNNING)
|
||||||
|
|
||||||
def preStart(self):
|
def preStart(self):
|
||||||
"""
|
"""
|
||||||
@ -271,7 +281,7 @@ class SdrSource(ABC):
|
|||||||
return self.failed
|
return self.failed
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
self.setState(SdrSource.STATE_STOPPING)
|
self.setState(SdrSourceState.STOPPING)
|
||||||
|
|
||||||
with self.modificationLock:
|
with self.modificationLock:
|
||||||
|
|
||||||
@ -291,11 +301,11 @@ class SdrSource(ABC):
|
|||||||
def addClient(self, c: SdrSourceEventClient):
|
def addClient(self, c: SdrSourceEventClient):
|
||||||
self.clients.append(c)
|
self.clients.append(c)
|
||||||
c.onStateChange(self.getState())
|
c.onStateChange(self.getState())
|
||||||
hasUsers = self.hasClients(SdrSource.CLIENT_USER)
|
hasUsers = self.hasClients(SdrClientClass.USER)
|
||||||
hasBackgroundTasks = self.hasClients(SdrSource.CLIENT_BACKGROUND)
|
hasBackgroundTasks = self.hasClients(SdrClientClass.BACKGROUND)
|
||||||
if hasUsers or hasBackgroundTasks:
|
if hasUsers or hasBackgroundTasks:
|
||||||
self.start()
|
self.start()
|
||||||
self.setBusyState(SdrSource.BUSYSTATE_BUSY if hasUsers else SdrSource.BUSYSTATE_IDLE)
|
self.setBusyState(SdrBusyState.BUSY if hasUsers else SdrBusyState.IDLE)
|
||||||
|
|
||||||
def removeClient(self, c: SdrSourceEventClient):
|
def removeClient(self, c: SdrSourceEventClient):
|
||||||
try:
|
try:
|
||||||
@ -303,14 +313,14 @@ class SdrSource(ABC):
|
|||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
hasUsers = self.hasClients(SdrSource.CLIENT_USER)
|
hasUsers = self.hasClients(SdrClientClass.USER)
|
||||||
self.setBusyState(SdrSource.BUSYSTATE_BUSY if hasUsers else SdrSource.BUSYSTATE_IDLE)
|
self.setBusyState(SdrBusyState.BUSY if hasUsers else SdrBusyState.IDLE)
|
||||||
|
|
||||||
# no need to check for users if we are always-on
|
# no need to check for users if we are always-on
|
||||||
if self.isAlwaysOn():
|
if self.isAlwaysOn():
|
||||||
return
|
return
|
||||||
|
|
||||||
hasBackgroundTasks = self.hasClients(SdrSource.CLIENT_BACKGROUND)
|
hasBackgroundTasks = self.hasClients(SdrClientClass.BACKGROUND)
|
||||||
if not hasUsers and not hasBackgroundTasks:
|
if not hasUsers and not hasBackgroundTasks:
|
||||||
self.stop()
|
self.stop()
|
||||||
|
|
||||||
@ -341,17 +351,17 @@ class SdrSource(ABC):
|
|||||||
for c in self.spectrumClients:
|
for c in self.spectrumClients:
|
||||||
c.write_spectrum_data(data)
|
c.write_spectrum_data(data)
|
||||||
|
|
||||||
def getState(self):
|
def getState(self) -> SdrSourceState:
|
||||||
return self.state
|
return self.state
|
||||||
|
|
||||||
def setState(self, state):
|
def setState(self, state: SdrSourceState):
|
||||||
if state == self.state:
|
if state == self.state:
|
||||||
return
|
return
|
||||||
self.state = state
|
self.state = state
|
||||||
for c in self.clients:
|
for c in self.clients:
|
||||||
c.onStateChange(state)
|
c.onStateChange(state)
|
||||||
|
|
||||||
def setBusyState(self, state):
|
def setBusyState(self, state: SdrBusyState):
|
||||||
if state == self.busyState:
|
if state == self.busyState:
|
||||||
return
|
return
|
||||||
self.busyState = state
|
self.busyState = state
|
||||||
|
Loading…
Reference in New Issue
Block a user