104 lines
2.3 KiB
Python
104 lines
2.3 KiB
Python
from time import sleep
|
|
from bsread import source, dispatcher
|
|
from .bsvar import BSVar
|
|
from .prodthread import ProdThread
|
|
|
|
|
|
class BSCache:
|
|
|
|
def __init__(self):
|
|
self.channels = {}
|
|
self.data = None
|
|
self.pt = ProdThread(self.run)
|
|
|
|
|
|
def __iter__(self):
|
|
return self
|
|
|
|
def __next__(self):
|
|
self.pt.start()
|
|
self.data = data = self.pt.get()
|
|
return data
|
|
|
|
|
|
def run(self, running):
|
|
channels = self.channels.keys()
|
|
configs = self.channels.values()
|
|
with source(channels=configs, receive_timeout=-1) as src:
|
|
while running.is_set():
|
|
msg = src.receive()
|
|
data = repack(msg)
|
|
if data:
|
|
yield data
|
|
|
|
|
|
def stop(self):
|
|
self.pt.stop()
|
|
|
|
|
|
def get_var(self, name, modulo=None, offset=None):
|
|
if name is not "pid" and not name in self.channels:
|
|
if not is_available(name):
|
|
raise ValueError(f"channel {name} is not available")
|
|
cfg = make_channel_config(name, modulo, offset)
|
|
self.update_source(name, cfg)
|
|
return BSVar(name, self)
|
|
|
|
|
|
def update_source(self, name, cfg):
|
|
self.pt.stop()
|
|
print("add channel", name)
|
|
self.channels[name] = cfg
|
|
self.pt.start()
|
|
|
|
while self.data is None or name not in self.data:
|
|
print("dropping data that is missing new channel:", name)
|
|
next(self)
|
|
|
|
|
|
|
|
|
|
|
|
def is_available(name):
|
|
available = get_available_channels()
|
|
return name in available
|
|
|
|
def get_available_channels():
|
|
channels = dispatcher.get_current_channels()
|
|
return set(ch["name"] for ch in channels)
|
|
|
|
|
|
|
|
def make_channel_config(name, modulo, offset):
|
|
res = {}
|
|
if modulo is not None:
|
|
res["modulo"] = modulo
|
|
if offset is not None:
|
|
res["offset"] = offset
|
|
if not res:
|
|
return name
|
|
res["name"] = name
|
|
return res
|
|
|
|
|
|
|
|
def repack(message):
|
|
data = message.data.data
|
|
pulse_id = message.data.pulse_id
|
|
|
|
res = {n: v.value for n, v in data.items()}
|
|
# res = {k: v for k, v in res.items() if v is not None}
|
|
|
|
#TODO: should this be a ValueError?
|
|
if any(v is None for v in res.values()):
|
|
return None
|
|
|
|
if not res:
|
|
return None
|
|
|
|
res["pid"] = pulse_id
|
|
return res
|
|
|
|
|
|
|