activate more scheduler and service settings

This commit is contained in:
Jakob Ketterl 2021-02-26 21:27:42 +01:00
parent 0231d98ab8
commit 4e7f02fc2c
2 changed files with 66 additions and 28 deletions

View File

@ -9,7 +9,7 @@ from owrx.js8 import Js8Parser
from owrx.config.core import CoreConfig from owrx.config.core import CoreConfig
from owrx.config import Config from owrx.config import Config
from owrx.source.resampler import Resampler from owrx.source.resampler import Resampler
from owrx.property import PropertyLayer from owrx.property import PropertyLayer, PropertyDeleted
from js8py import Js8Frame from js8py import Js8Frame
from abc import ABCMeta, abstractmethod from abc import ABCMeta, abstractmethod
from .schedule import ServiceScheduler from .schedule import ServiceScheduler
@ -66,13 +66,42 @@ class ServiceHandler(SdrSourceEventClient):
self.services = [] self.services = []
self.source = source self.source = source
self.startupTimer = None self.startupTimer = None
self.scheduler = None self.activitySub = None
self.running = False
props = self.source.getProps()
self.enabledSub = props.wireProperty("services", self._receiveEvent)
# need to call _start() manually if property is not set since the default is True, but the initial call is only
# made if the property is present
if "services" not in props:
self._start()
def _receiveEvent(self, state):
# deletion means fall back to default, which is True
if state is PropertyDeleted:
state = True
if self.running == state:
return
if state:
self._start()
else:
self._stop()
def _start(self):
self.running = True
self.source.addClient(self) self.source.addClient(self)
props = self.source.getProps() props = self.source.getProps()
self.subscriptions = [props.filter("center_freq", "samp_rate").wire(self.onFrequencyChange)] self.activitySub = props.filter("center_freq", "samp_rate").wire(self.onFrequencyChange)
if self.source.isAvailable(): if self.source.isAvailable():
self.scheduleServiceStartup() self.scheduleServiceStartup()
self.scheduler = ServiceScheduler(self.source)
def _stop(self):
if self.activitySub is not None:
self.activitySub.cancel()
self.activitySub = None
self._cancelStartupTimer()
self.source.removeClient(self)
self.stopServices()
self.running = False
def getClientClass(self) -> SdrClientClass: def getClientClass(self) -> SdrClientClass:
return SdrClientClass.INACTIVE return SdrClientClass.INACTIVE
@ -86,8 +115,6 @@ class ServiceHandler(SdrSourceEventClient):
elif state is SdrSourceState.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:
self.scheduler.shutdown()
def onBusyStateChange(self, state: SdrBusyState): def onBusyStateChange(self, state: SdrBusyState):
pass pass
@ -98,12 +125,10 @@ class ServiceHandler(SdrSourceEventClient):
return mode in configured and mode in available return mode in configured and mode in available
def shutdown(self): def shutdown(self):
while self.subscriptions: self._stop()
self.subscriptions.pop().cancel() if self.enabledSub is not None:
self.stopServices() self.enabledSub.cancel()
self.source.removeClient(self) self.enabledSub = None
if self.scheduler:
self.scheduler.shutdown()
def stopServices(self): def stopServices(self):
with self.lock: with self.lock:
@ -119,9 +144,13 @@ class ServiceHandler(SdrSourceEventClient):
return return
self.scheduleServiceStartup() self.scheduleServiceStartup()
def scheduleServiceStartup(self): def _cancelStartupTimer(self):
if self.startupTimer: if self.startupTimer:
self.startupTimer.cancel() self.startupTimer.cancel()
self.startupTimer = None
def scheduleServiceStartup(self):
self._cancelStartupTimer()
self.startupTimer = threading.Timer(10, self.updateServices) self.startupTimer = threading.Timer(10, self.updateServices)
self.startupTimer.start() self.startupTimer.start()
@ -281,23 +310,27 @@ class Js8Handler(object):
class Services(object): class Services(object):
handlers = [] handlers = []
schedulers = []
@staticmethod @staticmethod
def start(): def start():
config = Config.get() config = Config.get()
config.wireProperty("services_enabled", Services._receiveEvent) config.wireProperty("services_enabled", Services._receiveEvent)
for source in SdrService.getSources().values():
Services.schedulers.append(ServiceScheduler(source))
@staticmethod @staticmethod
def _receiveEvent(state): def _receiveEvent(state):
if state: if state:
for source in SdrService.getSources().values(): for source in SdrService.getSources().values():
props = source.getProps() Services.handlers.append(ServiceHandler(source))
if "services" not in props or props["services"] is not False:
Services.handlers.append(ServiceHandler(source))
else: else:
Services.stop() while Services.handlers:
Services.handlers.pop().shutdown()
@staticmethod @staticmethod
def stop(): def stop():
while Services.handlers: while Services.handlers:
Services.handlers.pop().shutdown() Services.handlers.pop().shutdown()
while Services.schedulers:
Services.schedulers.pop().shutdown()

View File

@ -209,10 +209,13 @@ class ServiceScheduler(SdrSourceEventClient):
def __init__(self, source): def __init__(self, source):
self.source = source self.source = source
self.selectionTimer = None self.selectionTimer = None
self.currentProfile = None
self.source.addClient(self)
self.schedule = None self.schedule = None
props = self.source.getProps() props = self.source.getProps()
props.filter("center_freq", "samp_rate").wire(self.onFrequencyChange) self.subscriptions = []
props.wireProperty("scheduler", self.parseSchedule) self.subscriptions.append(props.filter("center_freq", "samp_rate").wire(self.onFrequencyChange))
self.subscriptions.append(props.wireProperty("scheduler", self.parseSchedule))
# wireProperty calls parseSchedule with the initial value # wireProperty calls parseSchedule with the initial value
# self.parseSchedule() # self.parseSchedule()
@ -222,6 +225,8 @@ class ServiceScheduler(SdrSourceEventClient):
self.scheduleSelection() self.scheduleSelection()
def shutdown(self): def shutdown(self):
while self.subscriptions:
self.subscriptions.pop().cancel()
self.cancelTimer() self.cancelTimer()
self.source.removeClient(self) self.source.removeClient(self)
@ -241,13 +246,16 @@ class ServiceScheduler(SdrSourceEventClient):
self.selectionTimer.cancel() self.selectionTimer.cancel()
def getClientClass(self) -> SdrClientClass: def getClientClass(self) -> SdrClientClass:
return SdrClientClass.BACKGROUND if self.currentProfile is None:
return SdrClientClass.INACTIVE
else:
return SdrClientClass.BACKGROUND
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: elif state is SdrSourceState.FAILED:
self.cancelTimer() self.shutdown()
def onBusyStateChange(self, state: SdrBusyState): def onBusyStateChange(self, state: SdrBusyState):
if state is SdrBusyState.IDLE: if state is SdrBusyState.IDLE:
@ -262,17 +270,15 @@ class ServiceScheduler(SdrSourceEventClient):
return return
if self.schedule is None: if self.schedule is None:
logger.debug("no active schedule. releasing source...") self.currentProfile = None
self.source.removeClient(self) logger.debug("no active schedule, scheduler standing by for external events.")
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")
entry = self.schedule.getCurrentEntry() self.currentProfile = entry = self.schedule.getCurrentEntry()
if entry is None: if entry is None:
logger.debug("schedule did not return a current profile. releasing source...") logger.debug("schedule did not return a current profile. checking next (future) entry...")
self.source.removeClient(self)
logger.debug("checking next (future) entry...")
nextEntry = self.schedule.getNextEntry() nextEntry = self.schedule.getNextEntry()
if nextEntry is not None: if nextEntry is not None:
self.scheduleSelection(nextEntry.getNextActivation()) self.scheduleSelection(nextEntry.getNextActivation())
@ -280,7 +286,6 @@ class ServiceScheduler(SdrSourceEventClient):
logger.debug("no next entry available, scheduler standing by for external events.") logger.debug("no next entry available, scheduler standing by for external events.")
return return
self.source.addClient(self)
logger.debug("selected profile %s until %s", entry.getProfile(), entry.getScheduledEnd()) logger.debug("selected profile %s until %s", entry.getProfile(), entry.getScheduledEnd())
self.scheduleSelection(entry.getScheduledEnd()) self.scheduleSelection(entry.getScheduledEnd())