introduce enums for state management

This commit is contained in:
Jakob Ketterl 2021-02-20 22:54:07 +01:00
parent dd5ab32b47
commit c2e8ac516c
6 changed files with 86 additions and 75 deletions

View File

@ -2,7 +2,7 @@ from owrx.details import ReceiverDetails
from owrx.dsp import DspManager
from owrx.cpu import CpuUsageThread
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.feature import FeatureDetector
from owrx.version import openwebrx_version
@ -216,10 +216,10 @@ class OpenWebRxReceiverClient(OpenWebRxClient, SdrSourceEventClient):
self.configSubs.append(globalConfig.wire(writeConfig))
writeConfig(globalConfig.__dict__())
def onStateChange(self, state):
if state == SdrSource.STATE_RUNNING:
def onStateChange(self, state: SdrSourceState):
if state is SdrSourceState.RUNNING:
self.handleSdrAvailable()
elif state == SdrSource.STATE_FAILED:
elif state is SdrSourceState.FAILED:
self.handleSdrFailed()
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.setSdr()
def onBusyStateChange(self, state):
def onBusyStateChange(self, state: SdrBusyState):
pass
def getClientClass(self):
return SdrSource.CLIENT_USER
def getClientClass(self) -> SdrClientClass:
return SdrClientClass.USER
def __sendProfiles(self):
profiles = [

View File

@ -3,7 +3,7 @@ from owrx.wsjt import WsjtParser
from owrx.js8 import Js8Parser
from owrx.aprs import AprsParser
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.validators import OrValidator, RegexValidator, BoolValidator
from owrx.modes import Modes
@ -198,21 +198,21 @@ class DspManager(csdr.output, SdrSourceEventClient):
def setProperty(self, prop, value):
self.localProps[prop] = value
def getClientClass(self):
return SdrSource.CLIENT_USER
def getClientClass(self) -> SdrClientClass:
return SdrClientClass.USER
def onStateChange(self, state):
if state == SdrSource.STATE_RUNNING:
def onStateChange(self, state: SdrSourceState):
if state is SdrSourceState.RUNNING:
logger.debug("received STATE_RUNNING, attempting DspSource restart")
if self.startOnAvailable:
self.dsp.start()
self.startOnAvailable = False
elif state == SdrSource.STATE_STOPPING:
elif state is SdrSourceState.STOPPING:
logger.debug("received STATE_STOPPING, shutting down DspSource")
self.dsp.stop()
elif state == SdrSource.STATE_FAILED:
elif state is SdrSourceState.FAILED:
logger.debug("received STATE_FAILED, shutting down DspSource")
self.dsp.stop()
def onBusyStateChange(self, state):
def onBusyStateChange(self, state: SdrBusyState):
pass

View File

@ -2,7 +2,7 @@ from owrx.config.core import CoreConfig
from owrx.config import Config
from csdr import csdr
import threading
from owrx.source import SdrSource, SdrSourceEventClient
from owrx.source import SdrSourceEventClient, SdrSourceState, SdrBusyState, SdrClientClass
from owrx.property import PropertyStack
import logging
@ -73,14 +73,14 @@ class SpectrumThread(csdr.output, SdrSourceEventClient):
c.cancel()
self.subscriptions = []
def getClientClass(self):
return SdrSource.CLIENT_USER
def getClientClass(self) -> SdrClientClass:
return SdrClientClass.USER
def onStateChange(self, state):
if state in [SdrSource.STATE_STOPPING, SdrSource.STATE_FAILED]:
def onStateChange(self, state: SdrSourceState):
if state in [SdrSourceState.STOPPING, SdrSourceState.FAILED]:
self.dsp.stop()
elif state == SdrSource.STATE_RUNNING:
elif state is SdrSourceState.RUNNING:
self.dsp.start()
def onBusyStateChange(self, state):
def onBusyStateChange(self, state: SdrBusyState):
pass

View File

@ -1,5 +1,5 @@
import threading
from owrx.source import SdrSource, SdrSourceEventClient
from owrx.source import SdrSourceEventClient, SdrSourceState, SdrBusyState, SdrClientClass
from owrx.sdr import SdrService
from owrx.bands import Bandplan
from csdr.csdr import dsp, output
@ -75,22 +75,22 @@ class ServiceHandler(SdrSourceEventClient):
if "schedule" in props or "scheduler" in props:
self.scheduler = ServiceScheduler(self.source)
def getClientClass(self):
return SdrSource.CLIENT_INACTIVE
def getClientClass(self) -> SdrClientClass:
return SdrClientClass.INACTIVE
def onStateChange(self, state):
if state == SdrSource.STATE_RUNNING:
def onStateChange(self, state: SdrSourceState):
if state is SdrSourceState.RUNNING:
self.scheduleServiceStartup()
elif state == SdrSource.STATE_STOPPING:
elif state is SdrSourceState.STOPPING:
logger.debug("sdr source becoming unavailable; stopping services.")
self.stopServices()
elif state == SdrSource.STATE_FAILED:
elif state is SdrSourceState.FAILED:
logger.debug("sdr source failed; stopping services.")
self.stopServices()
if self.scheduler:
self.scheduler.shutdown()
def onBusyStateChange(self, state):
def onBusyStateChange(self, state: SdrBusyState):
pass
def isSupported(self, mode):
@ -164,7 +164,8 @@ class ServiceHandler(SdrSourceEventClient):
for dial in group:
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)
def get_min_max(self, group):

View File

@ -1,5 +1,5 @@
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
import threading
import math
@ -220,7 +220,7 @@ class ServiceScheduler(SdrSourceEventClient):
self.source.removeClient(self)
def scheduleSelection(self, time=None):
if self.source.getState() == SdrSource.STATE_FAILED:
if self.source.getState() is SdrSourceState.FAILED:
return
seconds = 10
if time is not None:
@ -234,24 +234,24 @@ class ServiceScheduler(SdrSourceEventClient):
if self.selectionTimer:
self.selectionTimer.cancel()
def getClientClass(self):
return SdrSource.CLIENT_BACKGROUND
def getClientClass(self) -> SdrClientClass:
return SdrClientClass.BACKGROUND
def onStateChange(self, state):
if state == SdrSource.STATE_STOPPING:
def onStateChange(self, state: SdrSourceState):
if state is SdrSourceState.STOPPING:
self.scheduleSelection()
elif state == SdrSource.STATE_FAILED:
elif state is SdrSourceState.FAILED:
self.cancelTimer()
def onBusyStateChange(self, state):
if state == SdrSource.BUSYSTATE_IDLE:
def onBusyStateChange(self, state: SdrBusyState):
if state is SdrBusyState.IDLE:
self.scheduleSelection()
def onFrequencyChange(self, changes):
self.scheduleSelection()
def selectProfile(self):
if self.source.hasClients(SdrSource.CLIENT_USER):
if self.source.hasClients(SdrClientClass.USER):
logger.debug("source has active users; not touching")
return
logger.debug("source seems to be idle, selecting profile for background services")

View File

@ -15,40 +15,50 @@ from owrx.form.converter import IntConverter, OptionalConverter
from owrx.form.device import GainInput
from owrx.controllers.settings import Section
from typing import List
from enum import Enum, auto
import logging
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):
@abstractmethod
def onStateChange(self, state):
def onStateChange(self, state: SdrSourceState):
pass
@abstractmethod
def onBusyStateChange(self, state):
def onBusyStateChange(self, state: SdrBusyState):
pass
def getClientClass(self):
return SdrSource.CLIENT_INACTIVE
def getClientClass(self) -> SdrClientClass:
return SdrClientClass.INACTIVE
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):
self.id = id
@ -78,8 +88,8 @@ class SdrSource(ABC):
self.process = None
self.modificationLock = threading.Lock()
self.failed = False
self.state = SdrSource.STATE_STOPPED
self.busyState = SdrSource.BUSYSTATE_IDLE
self.state = SdrSourceState.STOPPED
self.busyState = SdrBusyState.IDLE
self.validateProfiles()
@ -218,11 +228,11 @@ class SdrSource(ABC):
rc = self.process.wait()
logger.debug("shut down with RC={0}".format(rc))
self.monitor = None
if self.getState() == SdrSource.STATE_RUNNING:
if self.getState() is SdrSourceState.RUNNING:
self.failed = True
self.setState(SdrSource.STATE_FAILED)
self.setState(SdrSourceState.FAILED)
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.start()
@ -250,7 +260,7 @@ class SdrSource(ABC):
logger.exception("Exception during postStart()")
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):
"""
@ -271,7 +281,7 @@ class SdrSource(ABC):
return self.failed
def stop(self):
self.setState(SdrSource.STATE_STOPPING)
self.setState(SdrSourceState.STOPPING)
with self.modificationLock:
@ -291,11 +301,11 @@ class SdrSource(ABC):
def addClient(self, c: SdrSourceEventClient):
self.clients.append(c)
c.onStateChange(self.getState())
hasUsers = self.hasClients(SdrSource.CLIENT_USER)
hasBackgroundTasks = self.hasClients(SdrSource.CLIENT_BACKGROUND)
hasUsers = self.hasClients(SdrClientClass.USER)
hasBackgroundTasks = self.hasClients(SdrClientClass.BACKGROUND)
if hasUsers or hasBackgroundTasks:
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):
try:
@ -303,14 +313,14 @@ class SdrSource(ABC):
except ValueError:
pass
hasUsers = self.hasClients(SdrSource.CLIENT_USER)
self.setBusyState(SdrSource.BUSYSTATE_BUSY if hasUsers else SdrSource.BUSYSTATE_IDLE)
hasUsers = self.hasClients(SdrClientClass.USER)
self.setBusyState(SdrBusyState.BUSY if hasUsers else SdrBusyState.IDLE)
# no need to check for users if we are always-on
if self.isAlwaysOn():
return
hasBackgroundTasks = self.hasClients(SdrSource.CLIENT_BACKGROUND)
hasBackgroundTasks = self.hasClients(SdrClientClass.BACKGROUND)
if not hasUsers and not hasBackgroundTasks:
self.stop()
@ -341,17 +351,17 @@ class SdrSource(ABC):
for c in self.spectrumClients:
c.write_spectrum_data(data)
def getState(self):
def getState(self) -> SdrSourceState:
return self.state
def setState(self, state):
def setState(self, state: SdrSourceState):
if state == self.state:
return
self.state = state
for c in self.clients:
c.onStateChange(state)
def setBusyState(self, state):
def setBusyState(self, state: SdrBusyState):
if state == self.busyState:
return
self.busyState = state