separate PVInfo from serve code

This commit is contained in:
2021-02-13 12:17:07 +00:00
parent 8892b1f320
commit bca92d0ff7
3 changed files with 101 additions and 94 deletions

View File

@ -2,10 +2,10 @@ from time import sleep
from datetime import datetime
from threading import Thread
from pcaspy import SimpleServer, Driver
from pcaspy.driver import manager, _ait_d as AIT_D
from pcaspy.driver import manager
from context import Context
from utils import typename
from pvinfo import make_pvinfos, make_pvdb, make_values
INITIAL_PVDB = { #TODO make wait_time caput-able
@ -14,15 +14,6 @@ INITIAL_PVDB = { #TODO make wait_time caput-able
}
}
D_AIT = {v:k for k, v in AIT_D.items()}
#PV data type: enum, string, char, float or int
DTYPES = {
str: "string",
float: "float",
int: "int"
}
class DefaultDriver(Driver): #TODO: caget on START_TIME crashes without this subclass?!
@ -49,6 +40,7 @@ class MorIOC(Context):
self.driver.setParam("START_TIME", str(now))
self.driver.updatePVs()
self.running = False
self.thread = Thread(target=self.run, daemon=True)
self.thread.start()
@ -65,14 +57,16 @@ class MorIOC(Context):
def serve(self, **kwargs):
ts, vs = make_mappings(kwargs, parse_string=False)
pvdb = make_pvdb(ts)
pvis = make_pvinfos(kwargs, parse_string=False)
pvdb = make_pvdb(pvis)
self.createPV(pvdb)
self.setParams(**vs)
pvvs = make_values(pvis)
self.setParams(**pvvs)
def host(self, **kwargs):
ts, _vs = make_mappings(kwargs, parse_string=True)
pvdb = make_pvdb(ts)
pvis = make_pvinfos(kwargs, parse_string=True)
pvdb = make_pvdb(pvis)
self.createPV(pvdb)
@ -81,7 +75,7 @@ class MorIOC(Context):
return
print("new PVs", pvdb)
current_pvdb = self.driver.pvDB #TODO crash due to keyerror otherwise
self.server.createPV(self.prefix, pvdb)
self.server.createPV(self.prefix, pvdb) #TODO if pv name already contains ":", don't prepend self.prefix?!
self.driver = self.DriverClass()
self.driver.pvDB.update(current_pvdb)
@ -111,75 +105,3 @@ class MorIOC(Context):
def make_mappings(name_to_dtype_or_value, *args, **kwargs):
name_to_dtype = {}
name_to_value = {}
for name, type_or_value in name_to_dtype_or_value.items():
name = name.upper()
dtype, value = infer_type(type_or_value, *args, **kwargs)
name_to_dtype[name] = dtype
name_to_value[name] = value
return name_to_dtype, name_to_value
def infer_type(value, parse_string=True): #TODO arrays? strings?
# str -> "string", ""
# "test" -> "string", "test"
#TODO parse_string, when?
# "string" -> "string", ""
# "float" -> "float", 0.0
# or
# "string" -> "string", "string"
# "float" -> "string", "float"
if isinstance(value, type):
dtype = value
value = dtype()
else:
dtype = type(value)
if parse_string and isinstance(value, str):
if value in DTYPES.values():
dtype = value
value = ""
if not isinstance(dtype, str):
dtype = DTYPES.get(dtype, "string") #TODO default?
return dtype, value
def make_pvdb(name_to_dtype):
pvdb = {}
for name, dtype in name_to_dtype.items():
if not pv_is_managed(name):
print("will create", name)
pvdb[name] = {"type": dtype}
else:
pv_type = get_managed_pv_type(name)
if pv_type != dtype:
print(f"type for {name} changed:", pv_type, "->", dtype) #TODO what should be done if this happens?
# self.deletePV(name)
# pvdb[name] = {"type": dtype}
return pvdb
def pv_is_managed(name):
managed_pvs = manager.pvs["default"]
return name in managed_pvs
def get_managed_pv_type(name):
managed_pvs = manager.pvs["default"]
pv = managed_pvs[name]
pv_type = pv.info.type
return D_AIT[pv_type]
#TODO:
# - if pv name already contains ":", don't prepend prefix?!

90
morioc/pvinfo.py Normal file
View File

@ -0,0 +1,90 @@
from pcaspy.driver import manager, _ait_d as AIT_D
D_AIT = {v:k for k, v in AIT_D.items()}
#PV data type: enum, string, char, float or int
DTYPES = {
str: "string",
float: "float",
int: "int"
}
def make_values(pvinfos):
return {pvi.name: pvi.value for pvi in pvinfos}
def make_pvinfos(kwargs, parse_string=True):
return [PVInfo(*args, parse_string=parse_string) for args in kwargs.items()]
class PVInfo:
def __init__(self, name, data, parse_string=True):
self.name = name.upper()
self.dtype, self.value = infer_type(data, parse_string=parse_string)
def infer_type(value, parse_string=True): #TODO arrays? strings?
# str -> "string", ""
# "test" -> "string", "test"
#TODO parse_string, when?
# "string" -> "string", ""
# "float" -> "float", 0.0
# or
# "string" -> "string", "string"
# "float" -> "string", "float"
if isinstance(value, type):
dtype = value
value = dtype()
else:
dtype = type(value)
if parse_string and isinstance(value, str):
if value in DTYPES.values():
dtype = value
value = ""
if not isinstance(dtype, str):
dtype = DTYPES.get(dtype, "string") #TODO default?
return dtype, value
def make_pvdb(pvinfos):
pvdb = {}
for pvi in pvinfos:
name, dtype = pvi.name, pvi.dtype
if not pv_is_managed(name):
print("will create", name)
pvdb[name] = {"type": dtype}
else:
pv_type = get_managed_pv_type(name)
if pv_type != dtype:
print(f"type for {name} changed:", pv_type, "->", dtype) #TODO what should be done if this happens?
# self.deletePV(name)
# pvdb[name] = {"type": dtype}
return pvdb
def pv_is_managed(name):
managed_pvs = manager.pvs["default"]
return name in managed_pvs
def get_managed_pv_type(name):
managed_pvs = manager.pvs["default"]
pv = managed_pvs[name]
pv_type = pv.info.type
return D_AIT[pv_type]

View File

@ -1,5 +0,0 @@
def typename(obj):
return type(obj).__name__