refactor state handling: uncouple failed and enabled flags
This commit is contained in:
parent
916f19ac60
commit
b25a673829
@ -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 SdrSourceState, SdrBusyState, SdrClientClass, SdrSourceEventClient
|
from owrx.source import SdrSourceState, 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
|
||||||
@ -219,17 +219,15 @@ class OpenWebRxReceiverClient(OpenWebRxClient, SdrSourceEventClient):
|
|||||||
def onStateChange(self, state: SdrSourceState):
|
def onStateChange(self, state: SdrSourceState):
|
||||||
if state is SdrSourceState.RUNNING:
|
if state is SdrSourceState.RUNNING:
|
||||||
self.handleSdrAvailable()
|
self.handleSdrAvailable()
|
||||||
elif state is SdrSourceState.FAILED:
|
|
||||||
self.handleSdrFailed()
|
def onFail(self):
|
||||||
|
self.handleSdrFailed()
|
||||||
|
|
||||||
def handleSdrFailed(self):
|
def handleSdrFailed(self):
|
||||||
logger.warning('SDR device "%s" has failed, selecting new device', self.sdr.getName())
|
logger.warning('SDR device "%s" has failed, selecting new device', self.sdr.getName())
|
||||||
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: SdrBusyState):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def getClientClass(self) -> SdrClientClass:
|
def getClientClass(self) -> SdrClientClass:
|
||||||
return SdrClientClass.USER
|
return SdrClientClass.USER
|
||||||
|
|
||||||
|
10
owrx/dsp.py
10
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 SdrSourceEventClient, SdrSourceState, SdrBusyState, SdrClientClass
|
from owrx.source import SdrSourceEventClient, SdrSourceState, 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
|
||||||
@ -210,9 +210,7 @@ class DspManager(csdr.output, SdrSourceEventClient):
|
|||||||
elif state is SdrSourceState.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 is SdrSourceState.FAILED:
|
|
||||||
logger.debug("received STATE_FAILED, shutting down DspSource")
|
|
||||||
self.dsp.stop()
|
|
||||||
|
|
||||||
def onBusyStateChange(self, state: SdrBusyState):
|
def onFail(self):
|
||||||
pass
|
logger.debug("received onFail(), shutting down DspSource")
|
||||||
|
self.dsp.stop()
|
||||||
|
@ -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 SdrSourceEventClient, SdrSourceState, SdrBusyState, SdrClientClass
|
from owrx.source import SdrSourceEventClient, SdrSourceState, SdrClientClass
|
||||||
from owrx.property import PropertyStack
|
from owrx.property import PropertyStack
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
@ -77,10 +77,10 @@ class SpectrumThread(csdr.output, SdrSourceEventClient):
|
|||||||
return SdrClientClass.USER
|
return SdrClientClass.USER
|
||||||
|
|
||||||
def onStateChange(self, state: SdrSourceState):
|
def onStateChange(self, state: SdrSourceState):
|
||||||
if state in [SdrSourceState.STOPPING, SdrSourceState.FAILED]:
|
if state is SdrSourceState.STOPPING:
|
||||||
self.dsp.stop()
|
self.dsp.stop()
|
||||||
elif state is SdrSourceState.RUNNING:
|
elif state is SdrSourceState.RUNNING:
|
||||||
self.dsp.start()
|
self.dsp.start()
|
||||||
|
|
||||||
def onBusyStateChange(self, state: SdrBusyState):
|
def onFail(self):
|
||||||
pass
|
self.dsp.stop()
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
from owrx.config import Config
|
from owrx.config import Config
|
||||||
from owrx.property import PropertyManager, PropertyDeleted, PropertyDelegator, PropertyLayer
|
from owrx.property import PropertyManager, PropertyDeleted, PropertyDelegator, PropertyLayer
|
||||||
from owrx.feature import FeatureDetector, UnknownFeatureException
|
from owrx.feature import FeatureDetector, UnknownFeatureException
|
||||||
from owrx.source import SdrSourceState
|
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
@ -114,5 +113,5 @@ class SdrService(object):
|
|||||||
return {
|
return {
|
||||||
key: s
|
key: s
|
||||||
for key, s in SdrService.sources.items()
|
for key, s in SdrService.sources.items()
|
||||||
if s.getState() not in [SdrSourceState.FAILED, SdrSourceState.DISABLED]
|
if not s.isFailed() and s.isEnabled()
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import threading
|
import threading
|
||||||
from owrx.source import SdrSourceEventClient, SdrSourceState, SdrBusyState, SdrClientClass
|
from owrx.source import SdrSourceEventClient, SdrSourceState, 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
|
||||||
@ -117,12 +117,10 @@ class ServiceHandler(SdrSourceEventClient):
|
|||||||
elif state is SdrSourceState.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 is SdrSourceState.FAILED:
|
|
||||||
logger.debug("sdr source failed; stopping services.")
|
|
||||||
self.stopServices()
|
|
||||||
|
|
||||||
def onBusyStateChange(self, state: SdrBusyState):
|
def onFail(self):
|
||||||
pass
|
logger.debug("sdr source failed; stopping services.")
|
||||||
|
self.stopServices()
|
||||||
|
|
||||||
def isSupported(self, mode):
|
def isSupported(self, mode):
|
||||||
configured = Config.get()["services_decoders"]
|
configured = Config.get()["services_decoders"]
|
||||||
|
@ -231,7 +231,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() is SdrSourceState.FAILED:
|
if self.source.isFailed():
|
||||||
return
|
return
|
||||||
seconds = 10
|
seconds = 10
|
||||||
if time is not None:
|
if time is not None:
|
||||||
@ -254,8 +254,9 @@ class ServiceScheduler(SdrSourceEventClient):
|
|||||||
def onStateChange(self, state: SdrSourceState):
|
def onStateChange(self, state: SdrSourceState):
|
||||||
if state is SdrSourceState.STOPPING:
|
if state is SdrSourceState.STOPPING:
|
||||||
self.scheduleSelection()
|
self.scheduleSelection()
|
||||||
elif state is SdrSourceState.FAILED:
|
|
||||||
self.shutdown()
|
def onFail(self):
|
||||||
|
self.shutdown()
|
||||||
|
|
||||||
def onBusyStateChange(self, state: SdrBusyState):
|
def onBusyStateChange(self, state: SdrBusyState):
|
||||||
if state is SdrBusyState.IDLE:
|
if state is SdrBusyState.IDLE:
|
||||||
|
@ -30,8 +30,6 @@ class SdrSourceState(Enum):
|
|||||||
RUNNING = "Running"
|
RUNNING = "Running"
|
||||||
STOPPING = "Stopping"
|
STOPPING = "Stopping"
|
||||||
TUNING = "Tuning"
|
TUNING = "Tuning"
|
||||||
FAILED = "Failed"
|
|
||||||
DISABLED = "Disabled"
|
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.value
|
return self.value
|
||||||
@ -48,15 +46,22 @@ class SdrClientClass(Enum):
|
|||||||
USER = auto()
|
USER = auto()
|
||||||
|
|
||||||
|
|
||||||
class SdrSourceEventClient(ABC):
|
class SdrSourceEventClient(object):
|
||||||
@abstractmethod
|
|
||||||
def onStateChange(self, state: SdrSourceState):
|
def onStateChange(self, state: SdrSourceState):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def onBusyStateChange(self, state: SdrBusyState):
|
def onBusyStateChange(self, state: SdrBusyState):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def onFail(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def onDisable(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def onEnable(self):
|
||||||
|
pass
|
||||||
|
|
||||||
def getClientClass(self) -> SdrClientClass:
|
def getClientClass(self) -> SdrClientClass:
|
||||||
return SdrClientClass.INACTIVE
|
return SdrClientClass.INACTIVE
|
||||||
|
|
||||||
@ -129,14 +134,39 @@ class SdrSource(ABC):
|
|||||||
self.spectrumLock = threading.Lock()
|
self.spectrumLock = threading.Lock()
|
||||||
self.process = None
|
self.process = None
|
||||||
self.modificationLock = threading.Lock()
|
self.modificationLock = threading.Lock()
|
||||||
self.state = SdrSourceState.STOPPED if "enabled" not in props or props["enabled"] else SdrSourceState.DISABLED
|
self.state = SdrSourceState.STOPPED
|
||||||
|
self.enabled = "enabled" not in props or props["enabled"]
|
||||||
|
props.filter("enabled").wire(self._handleEnableChanged)
|
||||||
|
self.failed = False
|
||||||
self.busyState = SdrBusyState.IDLE
|
self.busyState = SdrBusyState.IDLE
|
||||||
|
|
||||||
self.validateProfiles()
|
self.validateProfiles()
|
||||||
|
|
||||||
if self.isAlwaysOn() and self.state is not SdrSourceState.DISABLED:
|
if self.isAlwaysOn() and self.isEnabled():
|
||||||
self.start()
|
self.start()
|
||||||
|
|
||||||
|
def isEnabled(self):
|
||||||
|
return self.enabled
|
||||||
|
|
||||||
|
def _handleEnableChanged(self, changes):
|
||||||
|
if "enabled" in changes and changes["enabled"] is not PropertyDeleted:
|
||||||
|
self.enabled = changes["enabled"]
|
||||||
|
else:
|
||||||
|
self.enabled = True
|
||||||
|
for c in self.clients:
|
||||||
|
if self.isEnabled():
|
||||||
|
c.onEnable()
|
||||||
|
else:
|
||||||
|
c.onDisable()
|
||||||
|
|
||||||
|
def isFailed(self):
|
||||||
|
return self.failed
|
||||||
|
|
||||||
|
def fail(self):
|
||||||
|
self.failed = True
|
||||||
|
for c in self.clients:
|
||||||
|
c.onFail()
|
||||||
|
|
||||||
def validateProfiles(self):
|
def validateProfiles(self):
|
||||||
props = PropertyStack()
|
props = PropertyStack()
|
||||||
props.addLayer(1, self.props)
|
props.addLayer(1, self.props)
|
||||||
@ -220,7 +250,7 @@ class SdrSource(ABC):
|
|||||||
if self.monitor:
|
if self.monitor:
|
||||||
return
|
return
|
||||||
|
|
||||||
if self.getState() is SdrSourceState.FAILED:
|
if self.isFailed():
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -254,9 +284,8 @@ class SdrSource(ABC):
|
|||||||
self.monitor = None
|
self.monitor = None
|
||||||
if self.getState() is SdrSourceState.RUNNING:
|
if self.getState() is SdrSourceState.RUNNING:
|
||||||
failed = True
|
failed = True
|
||||||
self.setState(SdrSourceState.FAILED)
|
self.fail()
|
||||||
else:
|
self.setState(SdrSourceState.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()
|
||||||
@ -284,7 +313,10 @@ class SdrSource(ABC):
|
|||||||
logger.exception("Exception during postStart()")
|
logger.exception("Exception during postStart()")
|
||||||
failed = True
|
failed = True
|
||||||
|
|
||||||
self.setState(SdrSourceState.FAILED if failed else SdrSourceState.RUNNING)
|
if failed:
|
||||||
|
self.fail()
|
||||||
|
else:
|
||||||
|
self.setState(SdrSourceState.RUNNING)
|
||||||
|
|
||||||
def preStart(self):
|
def preStart(self):
|
||||||
"""
|
"""
|
||||||
@ -302,10 +334,7 @@ class SdrSource(ABC):
|
|||||||
return self.monitor is not None
|
return self.monitor is not None
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
# don't overwrite failed flag
|
self.setState(SdrSourceState.STOPPING)
|
||||||
# TODO introduce a better solution?
|
|
||||||
if self.getState() is not SdrSourceState.FAILED:
|
|
||||||
self.setState(SdrSourceState.STOPPING)
|
|
||||||
|
|
||||||
with self.modificationLock:
|
with self.modificationLock:
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user