refactor state handling: uncouple failed and enabled flags
This commit is contained in:
		| @@ -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 SdrSourceState, SdrBusyState, SdrClientClass, SdrSourceEventClient | ||||
| from owrx.source import SdrSourceState, SdrClientClass, SdrSourceEventClient | ||||
| from owrx.client import ClientRegistry, TooManyClientsException | ||||
| from owrx.feature import FeatureDetector | ||||
| from owrx.version import openwebrx_version | ||||
| @@ -219,17 +219,15 @@ class OpenWebRxReceiverClient(OpenWebRxClient, SdrSourceEventClient): | ||||
|     def onStateChange(self, state: SdrSourceState): | ||||
|         if state is SdrSourceState.RUNNING: | ||||
|             self.handleSdrAvailable() | ||||
|         elif state is SdrSourceState.FAILED: | ||||
|             self.handleSdrFailed() | ||||
|  | ||||
|     def onFail(self): | ||||
|         self.handleSdrFailed() | ||||
|  | ||||
|     def handleSdrFailed(self): | ||||
|         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.setSdr() | ||||
|  | ||||
|     def onBusyStateChange(self, state: SdrBusyState): | ||||
|         pass | ||||
|  | ||||
|     def getClientClass(self) -> SdrClientClass: | ||||
|         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.aprs import AprsParser | ||||
| 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.validators import OrValidator, RegexValidator, BoolValidator | ||||
| from owrx.modes import Modes | ||||
| @@ -210,9 +210,7 @@ class DspManager(csdr.output, SdrSourceEventClient): | ||||
|         elif state is SdrSourceState.STOPPING: | ||||
|             logger.debug("received STATE_STOPPING, shutting down DspSource") | ||||
|             self.dsp.stop() | ||||
|         elif state is SdrSourceState.FAILED: | ||||
|             logger.debug("received STATE_FAILED, shutting down DspSource") | ||||
|             self.dsp.stop() | ||||
|  | ||||
|     def onBusyStateChange(self, state: SdrBusyState): | ||||
|         pass | ||||
|     def onFail(self): | ||||
|         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 csdr import csdr | ||||
| import threading | ||||
| from owrx.source import SdrSourceEventClient, SdrSourceState, SdrBusyState, SdrClientClass | ||||
| from owrx.source import SdrSourceEventClient, SdrSourceState, SdrClientClass | ||||
| from owrx.property import PropertyStack | ||||
|  | ||||
| import logging | ||||
| @@ -77,10 +77,10 @@ class SpectrumThread(csdr.output, SdrSourceEventClient): | ||||
|         return SdrClientClass.USER | ||||
|  | ||||
|     def onStateChange(self, state: SdrSourceState): | ||||
|         if state in [SdrSourceState.STOPPING, SdrSourceState.FAILED]: | ||||
|         if state is SdrSourceState.STOPPING: | ||||
|             self.dsp.stop() | ||||
|         elif state is SdrSourceState.RUNNING: | ||||
|             self.dsp.start() | ||||
|  | ||||
|     def onBusyStateChange(self, state: SdrBusyState): | ||||
|         pass | ||||
|     def onFail(self): | ||||
|         self.dsp.stop() | ||||
|   | ||||
| @@ -1,7 +1,6 @@ | ||||
| from owrx.config import Config | ||||
| from owrx.property import PropertyManager, PropertyDeleted, PropertyDelegator, PropertyLayer | ||||
| from owrx.feature import FeatureDetector, UnknownFeatureException | ||||
| from owrx.source import SdrSourceState | ||||
| from functools import partial | ||||
|  | ||||
| import logging | ||||
| @@ -114,5 +113,5 @@ class SdrService(object): | ||||
|         return { | ||||
|             key: s | ||||
|             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 | ||||
| from owrx.source import SdrSourceEventClient, SdrSourceState, SdrBusyState, SdrClientClass | ||||
| from owrx.source import SdrSourceEventClient, SdrSourceState, SdrClientClass | ||||
| from owrx.sdr import SdrService | ||||
| from owrx.bands import Bandplan | ||||
| from csdr.csdr import dsp, output | ||||
| @@ -117,12 +117,10 @@ class ServiceHandler(SdrSourceEventClient): | ||||
|         elif state is SdrSourceState.STOPPING: | ||||
|             logger.debug("sdr source becoming unavailable; stopping services.") | ||||
|             self.stopServices() | ||||
|         elif state is SdrSourceState.FAILED: | ||||
|             logger.debug("sdr source failed; stopping services.") | ||||
|             self.stopServices() | ||||
|  | ||||
|     def onBusyStateChange(self, state: SdrBusyState): | ||||
|         pass | ||||
|     def onFail(self): | ||||
|         logger.debug("sdr source failed; stopping services.") | ||||
|         self.stopServices() | ||||
|  | ||||
|     def isSupported(self, mode): | ||||
|         configured = Config.get()["services_decoders"] | ||||
|   | ||||
| @@ -231,7 +231,7 @@ class ServiceScheduler(SdrSourceEventClient): | ||||
|         self.source.removeClient(self) | ||||
|  | ||||
|     def scheduleSelection(self, time=None): | ||||
|         if self.source.getState() is SdrSourceState.FAILED: | ||||
|         if self.source.isFailed(): | ||||
|             return | ||||
|         seconds = 10 | ||||
|         if time is not None: | ||||
| @@ -254,8 +254,9 @@ class ServiceScheduler(SdrSourceEventClient): | ||||
|     def onStateChange(self, state: SdrSourceState): | ||||
|         if state is SdrSourceState.STOPPING: | ||||
|             self.scheduleSelection() | ||||
|         elif state is SdrSourceState.FAILED: | ||||
|             self.shutdown() | ||||
|  | ||||
|     def onFail(self): | ||||
|         self.shutdown() | ||||
|  | ||||
|     def onBusyStateChange(self, state: SdrBusyState): | ||||
|         if state is SdrBusyState.IDLE: | ||||
|   | ||||
| @@ -30,8 +30,6 @@ class SdrSourceState(Enum): | ||||
|     RUNNING = "Running" | ||||
|     STOPPING = "Stopping" | ||||
|     TUNING = "Tuning" | ||||
|     FAILED = "Failed" | ||||
|     DISABLED = "Disabled" | ||||
|  | ||||
|     def __str__(self): | ||||
|         return self.value | ||||
| @@ -48,15 +46,22 @@ class SdrClientClass(Enum): | ||||
|     USER = auto() | ||||
|  | ||||
|  | ||||
| class SdrSourceEventClient(ABC): | ||||
|     @abstractmethod | ||||
| class SdrSourceEventClient(object): | ||||
|     def onStateChange(self, state: SdrSourceState): | ||||
|         pass | ||||
|  | ||||
|     @abstractmethod | ||||
|     def onBusyStateChange(self, state: SdrBusyState): | ||||
|         pass | ||||
|  | ||||
|     def onFail(self): | ||||
|         pass | ||||
|  | ||||
|     def onDisable(self): | ||||
|         pass | ||||
|  | ||||
|     def onEnable(self): | ||||
|         pass | ||||
|  | ||||
|     def getClientClass(self) -> SdrClientClass: | ||||
|         return SdrClientClass.INACTIVE | ||||
|  | ||||
| @@ -129,14 +134,39 @@ class SdrSource(ABC): | ||||
|         self.spectrumLock = threading.Lock() | ||||
|         self.process = None | ||||
|         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.validateProfiles() | ||||
|  | ||||
|         if self.isAlwaysOn() and self.state is not SdrSourceState.DISABLED: | ||||
|         if self.isAlwaysOn() and self.isEnabled(): | ||||
|             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): | ||||
|         props = PropertyStack() | ||||
|         props.addLayer(1, self.props) | ||||
| @@ -220,7 +250,7 @@ class SdrSource(ABC): | ||||
|             if self.monitor: | ||||
|                 return | ||||
|  | ||||
|             if self.getState() is SdrSourceState.FAILED: | ||||
|             if self.isFailed(): | ||||
|                 return | ||||
|  | ||||
|             try: | ||||
| @@ -254,9 +284,8 @@ class SdrSource(ABC): | ||||
|                 self.monitor = None | ||||
|                 if self.getState() is SdrSourceState.RUNNING: | ||||
|                     failed = True | ||||
|                     self.setState(SdrSourceState.FAILED) | ||||
|                 else: | ||||
|                     self.setState(SdrSourceState.STOPPED) | ||||
|                     self.fail() | ||||
|                 self.setState(SdrSourceState.STOPPED) | ||||
|  | ||||
|             self.monitor = threading.Thread(target=wait_for_process_to_end, name="source_monitor") | ||||
|             self.monitor.start() | ||||
| @@ -284,7 +313,10 @@ class SdrSource(ABC): | ||||
|                 logger.exception("Exception during postStart()") | ||||
|                 failed = True | ||||
|  | ||||
|         self.setState(SdrSourceState.FAILED if failed else SdrSourceState.RUNNING) | ||||
|         if failed: | ||||
|             self.fail() | ||||
|         else: | ||||
|             self.setState(SdrSourceState.RUNNING) | ||||
|  | ||||
|     def preStart(self): | ||||
|         """ | ||||
| @@ -302,10 +334,7 @@ class SdrSource(ABC): | ||||
|         return self.monitor is not None | ||||
|  | ||||
|     def stop(self): | ||||
|         # don't overwrite failed flag | ||||
|         # TODO introduce a better solution? | ||||
|         if self.getState() is not SdrSourceState.FAILED: | ||||
|             self.setState(SdrSourceState.STOPPING) | ||||
|         self.setState(SdrSourceState.STOPPING) | ||||
|  | ||||
|         with self.modificationLock: | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Jakob Ketterl
					Jakob Ketterl