From 8f739b11dc8f17730c5d02fd7ad8e097a606e28e Mon Sep 17 00:00:00 2001 From: l_samenv Date: Wed, 6 Jul 2022 16:14:16 +0200 Subject: [PATCH 01/22] ILL1 .cfg created and ILL1stick --- cfg/main/ill1.cfg | 57 ++++++++ cfg/sea/ill1.config.json | 299 +++++++++++++++++++++++++++++++++++++++ cfg/stick/ill1stick.cfg | 17 +++ 3 files changed, 373 insertions(+) create mode 100644 cfg/main/ill1.cfg create mode 100644 cfg/sea/ill1.config.json create mode 100644 cfg/stick/ill1stick.cfg diff --git a/cfg/main/ill1.cfg b/cfg/main/ill1.cfg new file mode 100644 index 0000000..5d45c71 --- /dev/null +++ b/cfg/main/ill1.cfg @@ -0,0 +1,57 @@ +[NODE] +description = orange cryostat with 50 mm sample space +id = ill1.config.sea.psi.ch + +[sea_main] +class = secop_psi.sea.SeaClient +description = main sea connection for ill1.config +config = ill1.config +service = main + +[tt] +class = secop_psi.sea.SeaDrivable +io = sea_main +sea_object = tt + +[cc] +class = secop_psi.sea.SeaReadable +io = sea_main +sea_object = cc +extra_modules = h +visibility = 3 + + +[lev] +class = secop_psi.sea.SeaReadable +io = sea_main +single_module = cc.h + +[nv] +class = secop_psi.sea.SeaWritable +io = sea_main +sea_object = nv + +[ln2fill] +class = secop_psi.sea.SeaWritable +io = sea_main +sea_object = ln2fill + +[hefill] +class = secop_psi.sea.SeaWritable +io = sea_main +sea_object = hefill + +[hepump] +class = secop_psi.sea.SeaWritable +io = sea_main +sea_object = hepump + +[hemot] +class = secop_psi.sea.SeaDrivable +io = sea_main +sea_object = hemot + +[table] +class = secop_psi.sea.SeaReadable +io = sea_main +sea_object = table diff --git a/cfg/sea/ill1.config.json b/cfg/sea/ill1.config.json new file mode 100644 index 0000000..e5c6d60 --- /dev/null +++ b/cfg/sea/ill1.config.json @@ -0,0 +1,299 @@ +{"tt": {"base": "/tt", "params": [ +{"path": "", "type": "float", "readonly": false, "cmd": "run tt", "description": "tt", "kids": 19}, +{"path": "send", "type": "text", "readonly": false, "cmd": "tt send", "visibility": 3}, +{"path": "status", "type": "text", "visibility": 3}, +{"path": "is_running", "type": "int", "readonly": false, "cmd": "tt is_running", "visibility": 3}, +{"path": "mainloop", "type": "text", "readonly": false, "cmd": "tt mainloop", "visibility": 3}, +{"path": "target", "type": "float"}, +{"path": "running", "type": "int"}, +{"path": "tolerance", "type": "float", "readonly": false, "cmd": "tt tolerance"}, +{"path": "maxwait", "type": "float", "readonly": false, "cmd": "tt maxwait"}, +{"path": "settle", "type": "float", "readonly": false, "cmd": "tt settle"}, +{"path": "log", "type": "text", "readonly": false, "cmd": "tt log", "visibility": 3, "kids": 4}, +{"path": "log/mean", "type": "float", "visibility": 3}, +{"path": "log/m2", "type": "float", "visibility": 3}, +{"path": "log/stddev", "type": "float", "visibility": 3}, +{"path": "log/n", "type": "float", "visibility": 3}, +{"path": "dblctrl", "type": "bool", "readonly": false, "cmd": "tt dblctrl", "kids": 9}, +{"path": "dblctrl/tshift", "type": "float", "readonly": false, "cmd": "tt dblctrl/tshift"}, +{"path": "dblctrl/mode", "type": "enum", "enum": {"disabled": -1, "inactive": 0, "stable": 1, "up": 2, "down": 3}, "readonly": false, "cmd": "tt dblctrl/mode"}, +{"path": "dblctrl/shift_up", "type": "float"}, +{"path": "dblctrl/shift_lo", "type": "float"}, +{"path": "dblctrl/t_min", "type": "float"}, +{"path": "dblctrl/t_max", "type": "float"}, +{"path": "dblctrl/int2", "type": "float", "readonly": false, "cmd": "tt dblctrl/int2"}, +{"path": "dblctrl/prop_up", "type": "float", "readonly": false, "cmd": "tt dblctrl/prop_up"}, +{"path": "dblctrl/prop_lo", "type": "float", "readonly": false, "cmd": "tt dblctrl/prop_lo"}, +{"path": "tm", "type": "float", "kids": 4}, +{"path": "tm/curve", "type": "text", "readonly": false, "cmd": "tt tm/curve", "kids": 1}, +{"path": "tm/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tt tm/curve/points", "visibility": 3}, +{"path": "tm/alarm", "type": "float", "readonly": false, "cmd": "tt tm/alarm"}, +{"path": "tm/stddev", "type": "float"}, +{"path": "tm/raw", "type": "float"}, +{"path": "ts", "type": "float", "kids": 4}, +{"path": "ts/curve", "type": "text", "readonly": false, "cmd": "tt ts/curve", "kids": 1}, +{"path": "ts/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tt ts/curve/points", "visibility": 3}, +{"path": "ts/alarm", "type": "float", "readonly": false, "cmd": "tt ts/alarm"}, +{"path": "ts/stddev", "type": "float"}, +{"path": "ts/raw", "type": "float"}, +{"path": "ts_2", "type": "float", "visibility": 3, "kids": 4}, +{"path": "ts_2/curve", "type": "text", "readonly": false, "cmd": "tt ts_2/curve", "visibility": 3, "kids": 1}, +{"path": "ts_2/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tt ts_2/curve/points", "visibility": 3}, +{"path": "ts_2/alarm", "type": "float", "readonly": false, "cmd": "tt ts_2/alarm", "visibility": 3}, +{"path": "ts_2/stddev", "type": "float", "visibility": 3}, +{"path": "ts_2/raw", "type": "float", "visibility": 3}, +{"path": "set", "type": "float", "readonly": false, "cmd": "tt set", "kids": 18}, +{"path": "set/mode", "type": "enum", "enum": {"disabled": -1, "off": 0, "controlling": 1, "manual": 2}, "readonly": false, "cmd": "tt set/mode"}, +{"path": "set/reg", "type": "float"}, +{"path": "set/ramp", "type": "float", "readonly": false, "cmd": "tt set/ramp", "description": "maximum ramp in K/min (0: ramp off)"}, +{"path": "set/wramp", "type": "float", "readonly": false, "cmd": "tt set/wramp"}, +{"path": "set/smooth", "type": "float", "readonly": false, "cmd": "tt set/smooth", "description": "smooth time (minutes)"}, +{"path": "set/channel", "type": "text", "readonly": false, "cmd": "tt set/channel"}, +{"path": "set/limit", "type": "float", "readonly": false, "cmd": "tt set/limit"}, +{"path": "set/resist", "type": "float", "readonly": false, "cmd": "tt set/resist"}, +{"path": "set/maxheater", "type": "text", "readonly": false, "cmd": "tt set/maxheater", "description": "maximum heater limit, units should be given without space: W, mW, A, mA"}, +{"path": "set/linearpower", "type": "float", "readonly": false, "cmd": "tt set/linearpower", "description": "when not 0, it is the maximum effective power, and the power is linear to the heater output"}, +{"path": "set/maxpowerlim", "type": "float", "description": "the maximum power limit (before any booster or converter)"}, +{"path": "set/maxpower", "type": "float", "readonly": false, "cmd": "tt set/maxpower", "description": "maximum power [W]"}, +{"path": "set/maxcurrent", "type": "float", "description": "the maximum current before any booster or converter"}, +{"path": "set/manualpower", "type": "float", "readonly": false, "cmd": "tt set/manualpower"}, +{"path": "set/power", "type": "float"}, +{"path": "set/prop", "type": "float", "readonly": false, "cmd": "tt set/prop", "description": "bigger means more gain"}, +{"path": "set/integ", "type": "float", "readonly": false, "cmd": "tt set/integ", "description": "bigger means faster"}, +{"path": "set/deriv", "type": "float", "readonly": false, "cmd": "tt set/deriv"}, +{"path": "display", "type": "text", "readonly": false, "cmd": "tt display"}, +{"path": "dout", "type": "int", "readonly": false, "cmd": "tt dout"}, +{"path": "dinp", "type": "int"}, +{"path": "remote", "type": "bool"}]}, + +"cc": {"base": "/cc", "params": [ +{"path": "", "type": "bool", "kids": 96}, +{"path": "send", "type": "text", "readonly": false, "cmd": "cc send", "visibility": 3}, +{"path": "status", "type": "text", "visibility": 3}, +{"path": "autodevice", "type": "bool", "readonly": false, "cmd": "cc autodevice"}, +{"path": "fav", "type": "bool", "readonly": false, "cmd": "cc fav"}, +{"path": "f", "type": "float"}, +{"path": "fs", "type": "enum", "enum": {"ok": 0, "no_sens": 1}, "readonly": false, "cmd": "cc fs"}, +{"path": "mav", "type": "bool", "readonly": false, "cmd": "cc mav"}, +{"path": "fm", "type": "enum", "enum": {"idle": 0, "opening": 1, "closing": 2, "opened": 3, "closed": 4, "no_motor": 5}}, +{"path": "fa", "type": "enum", "enum": {"fixed": 0, "controlled": 1, "automatic": 2, "offline": 3}, "readonly": false, "cmd": "cc fa"}, +{"path": "mp", "type": "float", "readonly": false, "cmd": "cc mp"}, +{"path": "msp", "type": "float"}, +{"path": "mmp", "type": "float"}, +{"path": "mc", "type": "float", "readonly": false, "cmd": "cc mc"}, +{"path": "mfc", "type": "float", "readonly": false, "cmd": "cc mfc"}, +{"path": "moc", "type": "float", "readonly": false, "cmd": "cc moc"}, +{"path": "mtc", "type": "float", "readonly": false, "cmd": "cc mtc"}, +{"path": "mtl", "type": "float"}, +{"path": "mft", "type": "float", "readonly": false, "cmd": "cc mft"}, +{"path": "mt", "type": "float"}, +{"path": "mo", "type": "float"}, +{"path": "mcr", "type": "float"}, +{"path": "mot", "type": "float"}, +{"path": "mw", "type": "float", "readonly": false, "cmd": "cc mw", "description": "correction pulse after automatic open"}, +{"path": "hav", "type": "bool", "readonly": false, "cmd": "cc hav"}, +{"path": "h", "type": "float"}, +{"path": "hr", "type": "float"}, +{"path": "hc", "type": "float"}, +{"path": "hu", "type": "float"}, +{"path": "hh", "type": "float", "readonly": false, "cmd": "cc hh"}, +{"path": "hl", "type": "float", "readonly": false, "cmd": "cc hl"}, +{"path": "htf", "type": "float", "readonly": false, "cmd": "cc htf", "description": "meas. period in fast mode"}, +{"path": "hts", "type": "float", "readonly": false, "cmd": "cc hts", "description": "meas. period in slow mode"}, +{"path": "hd", "type": "float", "readonly": false, "cmd": "cc hd"}, +{"path": "hwr", "type": "float", "readonly": false, "cmd": "cc hwr"}, +{"path": "hem", "type": "float", "readonly": false, "cmd": "cc hem", "description": "sensor length in mm from top to empty pos."}, +{"path": "hfu", "type": "float", "readonly": false, "cmd": "cc hfu", "description": "sensor length in mm from top to full pos."}, +{"path": "hcd", "type": "enum", "enum": {"stop": 0, "fill": 1, "off": 2, "auto": 3, "manual": 7}, "readonly": false, "cmd": "cc hcd"}, +{"path": "hv", "type": "enum", "enum": {"fill_valve_off": 0, "filling": 1, "no_fill_valve": 2, "timeout": 3, "timeout1": 4}}, +{"path": "hsf", "type": "enum", "enum": {"sens_ok": 0, "sens_warm": 1, "no_sens": 2, "timeout": 3, "not_yet_read": 4, "disabled": 5}}, +{"path": "ha", "type": "bool", "readonly": false, "cmd": "cc ha"}, +{"path": "hm", "type": "bool"}, +{"path": "hf", "type": "enum", "enum": {"slow": 0, "fast": 1}, "readonly": false, "cmd": "cc hf"}, +{"path": "hbe", "type": "bool", "readonly": false, "cmd": "cc hbe"}, +{"path": "hmf", "type": "float"}, +{"path": "hms", "type": "float"}, +{"path": "hit", "type": "float", "readonly": false, "cmd": "cc hit"}, +{"path": "hft", "type": "int", "readonly": false, "cmd": "cc hft"}, +{"path": "hea", "type": "enum", "enum": {"0": 0, "1": 1, "6": 2}, "readonly": false, "cmd": "cc hea"}, +{"path": "hch", "type": "int", "readonly": false, "cmd": "cc hch", "visibility": 3}, +{"path": "hwr0", "type": "float", "readonly": false, "cmd": "cc hwr0", "visibility": 3}, +{"path": "hem0", "type": "float", "readonly": false, "cmd": "cc hem0", "description": "sensor length in mm from top to empty pos.", "visibility": 3}, +{"path": "hfu0", "type": "float", "readonly": false, "cmd": "cc hfu0", "description": "sensor length in mm from top to full pos.", "visibility": 3}, +{"path": "hd0", "type": "float", "readonly": false, "cmd": "cc hd0", "description": "external sensor drive current (mA)", "visibility": 3}, +{"path": "h0", "type": "float", "visibility": 3}, +{"path": "hs0", "type": "enum", "enum": {"sens_ok": 0, "sens_warm": 1, "no_sens": 2, "timeout": 3, "not_yet_read": 4, "disabled": 5}, "visibility": 3}, +{"path": "h1", "type": "float", "visibility": 3}, +{"path": "hs1", "type": "enum", "enum": {"sens_ok": 0, "sens_warm": 1, "no_sens": 2, "timeout": 3, "not_yet_read": 4, "disabled": 5}, "visibility": 3}, +{"path": "h2", "type": "float", "visibility": 3}, +{"path": "hs2", "type": "enum", "enum": {"sens_ok": 0, "sens_warm": 1, "no_sens": 2, "timeout": 3, "not_yet_read": 4, "disabled": 5}, "visibility": 3}, +{"path": "h3", "type": "float", "visibility": 3}, +{"path": "hs3", "type": "enum", "enum": {"sens_ok": 0, "sens_warm": 1, "no_sens": 2, "timeout": 3, "not_yet_read": 4, "disabled": 5}, "visibility": 3}, +{"path": "h4", "type": "float", "visibility": 3}, +{"path": "hs4", "type": "enum", "enum": {"sens_ok": 0, "sens_warm": 1, "no_sens": 2, "timeout": 3, "not_yet_read": 4, "disabled": 5}, "visibility": 3}, +{"path": "h5", "type": "float", "visibility": 3}, +{"path": "hs5", "type": "enum", "enum": {"sens_ok": 0, "sens_warm": 1, "no_sens": 2, "timeout": 3, "not_yet_read": 4, "disabled": 5}, "visibility": 3}, +{"path": "hfb", "type": "float"}, +{"path": "nav", "type": "bool", "readonly": false, "cmd": "cc nav"}, +{"path": "nu", "type": "float"}, +{"path": "nl", "type": "float"}, +{"path": "nth", "type": "float", "readonly": false, "cmd": "cc nth"}, +{"path": "ntc", "type": "float", "readonly": false, "cmd": "cc ntc"}, +{"path": "ntm", "type": "float", "readonly": false, "cmd": "cc ntm"}, +{"path": "ns", "type": "enum", "enum": {"sens_ok": 0, "no_sens": 1, "short_circuit": 2, "upside_down": 3, "sens_warm": 4, "empty": 5}}, +{"path": "na", "type": "bool", "readonly": false, "cmd": "cc na"}, +{"path": "nv", "type": "enum", "enum": {"fill_valve_off": 0, "filling": 1, "no_fill_valve": 2, "timeout": 3, "timeout1": 4, "boost": 5}}, +{"path": "nc", "type": "enum", "enum": {"stop": 0, "fill": 1, "off": 2, "auto": 3}, "readonly": false, "cmd": "cc nc"}, +{"path": "nfb", "type": "float"}, +{"path": "cda", "type": "float"}, +{"path": "cdb", "type": "float"}, +{"path": "cba", "type": "float"}, +{"path": "cbb", "type": "float"}, +{"path": "cvs", "type": "int"}, +{"path": "csp", "type": "int"}, +{"path": "cdv", "type": "text", "readonly": false, "cmd": "cc cdv"}, +{"path": "cic", "type": "text", "readonly": false, "cmd": "cc cic"}, +{"path": "cin", "type": "text"}, +{"path": "cds", "type": "enum", "enum": {"local": 0, "remote": 1, "loading": 2, "by_code": 3, "by_touch": 4}, "readonly": false, "cmd": "cc cds"}, +{"path": "timing", "type": "bool", "readonly": false, "cmd": "cc timing"}, +{"path": "tc", "type": "float", "visibility": 3}, +{"path": "tn", "type": "float", "visibility": 3}, +{"path": "th", "type": "float", "visibility": 3}, +{"path": "tf", "type": "float", "visibility": 3}, +{"path": "tm", "type": "float", "visibility": 3}, +{"path": "tv", "type": "float", "visibility": 3}, +{"path": "tq", "type": "float", "visibility": 3}, +{"path": "bdl", "type": "float", "readonly": false, "cmd": "cc bdl"}]}, + +"nv": {"base": "/nv", "params": [ +{"path": "", "type": "enum", "enum": {"fixed": 0, "controlled": 1, "automatic": 2, "close": 3, "open": 4}, "readonly": false, "cmd": "nv", "kids": 11}, +{"path": "send", "type": "text", "readonly": false, "cmd": "nv send", "visibility": 3}, +{"path": "status", "type": "text", "visibility": 3}, +{"path": "motstat", "type": "enum", "enum": {"idle": 0, "opening": 1, "closing": 2, "opened": 3, "closed": 4, "no_motor": 5}}, +{"path": "flow", "type": "float"}, +{"path": "set", "type": "float", "readonly": false, "cmd": "nv set"}, +{"path": "flowmax", "type": "float", "readonly": false, "cmd": "nv flowmax"}, +{"path": "flowp", "type": "float"}, +{"path": "span", "type": "float"}, +{"path": "ctrl", "type": "none", "kids": 13}, +{"path": "ctrl/regtext", "type": "text"}, +{"path": "ctrl/prop_o", "type": "float", "readonly": false, "cmd": "nv ctrl/prop_o", "description": "prop [sec/mbar] when opening. above 4 mbar a 10 times lower value is used"}, +{"path": "ctrl/prop_c", "type": "float", "readonly": false, "cmd": "nv ctrl/prop_c", "description": "prop [sec/mbar] when closing. above 4 mbar a 10 times lower value is used"}, +{"path": "ctrl/deriv_o", "type": "float", "readonly": false, "cmd": "nv ctrl/deriv_o", "description": "convergence target time [sec] when opening"}, +{"path": "ctrl/deriv_c", "type": "float", "readonly": false, "cmd": "nv ctrl/deriv_c", "description": "convergence target time [sec] when closing"}, +{"path": "ctrl/minpulse_o", "type": "float", "readonly": false, "cmd": "nv ctrl/minpulse_o", "description": "minimum close pulse [sec]"}, +{"path": "ctrl/minpulse_c", "type": "float", "readonly": false, "cmd": "nv ctrl/minpulse_c", "description": "standard close pulse [sec]"}, +{"path": "ctrl/hystpulse_o", "type": "float", "readonly": false, "cmd": "nv ctrl/hystpulse_o", "description": "motor pulse to overcome hysteresis when opening"}, +{"path": "ctrl/hystpulse_c", "type": "float", "readonly": false, "cmd": "nv ctrl/hystpulse_c", "description": "motor pulse to overcome hysteresis when closing"}, +{"path": "ctrl/tol", "type": "float", "readonly": false, "cmd": "nv ctrl/tol", "description": "valid below 3 mbar"}, +{"path": "ctrl/tolhigh", "type": "float", "readonly": false, "cmd": "nv ctrl/tolhigh", "description": "valid above 4 mbar"}, +{"path": "ctrl/openpulse", "type": "float", "readonly": false, "cmd": "nv ctrl/openpulse", "description": "time to open from completely closed to a significant opening"}, +{"path": "ctrl/adjust_minpulse", "type": "bool", "readonly": false, "cmd": "nv ctrl/adjust_minpulse", "description": "adjust minpulse automatically"}, +{"path": "autoflow", "type": "none", "kids": 24}, +{"path": "autoflow/suspended", "type": "bool", "readonly": false, "cmd": "nv autoflow/suspended"}, +{"path": "autoflow/prop", "type": "float", "readonly": false, "cmd": "nv autoflow/prop"}, +{"path": "autoflow/flowstd", "type": "float", "readonly": false, "cmd": "nv autoflow/flowstd"}, +{"path": "autoflow/flowlim", "type": "float", "readonly": false, "cmd": "nv autoflow/flowlim"}, +{"path": "autoflow/smooth", "type": "float", "readonly": false, "cmd": "nv autoflow/smooth"}, +{"path": "autoflow/difSize", "type": "float", "readonly": false, "cmd": "nv autoflow/difSize"}, +{"path": "autoflow/difRange", "type": "float", "readonly": false, "cmd": "nv autoflow/difRange"}, +{"path": "autoflow/flowSize", "type": "float", "readonly": false, "cmd": "nv autoflow/flowSize"}, +{"path": "autoflow/convTime", "type": "float", "readonly": false, "cmd": "nv autoflow/convTime"}, +{"path": "autoflow/Tmin", "type": "float", "readonly": false, "cmd": "nv autoflow/Tmin"}, +{"path": "autoflow/script", "type": "text", "readonly": false, "cmd": "nv autoflow/script"}, +{"path": "autoflow/getTemp", "type": "text", "readonly": false, "cmd": "nv autoflow/getTemp"}, +{"path": "autoflow/getTset", "type": "text", "readonly": false, "cmd": "nv autoflow/getTset"}, +{"path": "autoflow/getFlow", "type": "text", "readonly": false, "cmd": "nv autoflow/getFlow"}, +{"path": "autoflow/difBuf", "type": "text"}, +{"path": "autoflow/flowBuf", "type": "text"}, +{"path": "autoflow/flowset", "type": "float"}, +{"path": "autoflow/flowmin", "type": "float"}, +{"path": "autoflow/flowmax", "type": "float"}, +{"path": "autoflow/difmin", "type": "float"}, +{"path": "autoflow/difmax", "type": "float"}, +{"path": "autoflow/setmin", "type": "float"}, +{"path": "autoflow/setmax", "type": "float"}, +{"path": "autoflow/flowtarget", "type": "float"}, +{"path": "calib", "type": "none", "kids": 2}, +{"path": "calib/ln_per_min_per_mbar", "type": "float", "readonly": false, "cmd": "nv calib/ln_per_min_per_mbar"}, +{"path": "calib/mbar_offset", "type": "float", "readonly": false, "cmd": "nv calib/mbar_offset"}]}, + +"ln2fill": {"base": "/ln2fill", "params": [ +{"path": "", "type": "enum", "enum": {"no fill valve": 2}, "readonly": false, "cmd": "ln2fill", "kids": 3}, +{"path": "send", "type": "text", "readonly": false, "cmd": "ln2fill send", "visibility": 3}, +{"path": "status", "type": "text", "visibility": 3}, +{"path": "state", "type": "text"}]}, + +"hefill": {"base": "/hefill", "params": [ +{"path": "", "type": "enum", "enum": {"watching": 0, "fill": 1, "inactive": 2, "manualfill": 3}, "readonly": false, "cmd": "hefill", "kids": 6}, +{"path": "send", "type": "text", "readonly": false, "cmd": "hefill send", "visibility": 3}, +{"path": "status", "type": "text", "visibility": 3}, +{"path": "fast", "type": "enum", "enum": {"slow": 0, "fast": 1}, "readonly": false, "cmd": "cc hf"}, +{"path": "state", "type": "text"}, +{"path": "hefull", "type": "float", "readonly": false, "cmd": "cc hh"}, +{"path": "helow", "type": "float", "readonly": false, "cmd": "cc hl"}]}, + +"hepump": {"base": "/hepump", "params": [ +{"path": "", "type": "enum", "enum": {"xds35_auto": 0, "xds35_manual": 1, "sv65": 2, "other": 3, "no": -1}, "readonly": false, "cmd": "hepump", "description": "xds35: scroll pump, sv65: leybold", "kids": 10}, +{"path": "send", "type": "text", "readonly": false, "cmd": "hepump send", "visibility": 3}, +{"path": "status", "type": "text", "visibility": 3}, +{"path": "running", "type": "bool", "readonly": false, "cmd": "hepump running", "visibility": 3}, +{"path": "eco", "type": "bool", "readonly": false, "cmd": "hepump eco", "visibility": 3}, +{"path": "auto", "type": "bool", "readonly": false, "cmd": "hepump auto", "visibility": 3}, +{"path": "valve", "type": "enum", "enum": {"closed": 0, "closing": 1, "opening": 2, "opened": 3, "undefined": 4}, "readonly": false, "cmd": "hepump valve", "visibility": 3}, +{"path": "eco_t_lim", "type": "float", "readonly": false, "cmd": "hepump eco_t_lim", "description": "switch off eco mode when T_set < eco_t_lim and T < eco_t_lim * 2", "visibility": 3}, +{"path": "calib", "type": "float", "readonly": false, "cmd": "hepump calib", "visibility": 3}, +{"path": "health", "type": "float"}]}, + +"hemot": {"base": "/hepump/hemot", "params": [ +{"path": "", "type": "float", "readonly": false, "cmd": "run hemot", "visibility": 3, "kids": 30}, +{"path": "send", "type": "text", "readonly": false, "cmd": "hemot send", "visibility": 3}, +{"path": "status", "type": "text", "visibility": 3}, +{"path": "is_running", "type": "int", "readonly": false, "cmd": "hemot is_running", "visibility": 3}, +{"path": "pos", "type": "float"}, +{"path": "encoder", "type": "float"}, +{"path": "zero", "type": "float", "readonly": false, "cmd": "hemot zero"}, +{"path": "lowerlimit", "type": "float", "readonly": false, "cmd": "hemot lowerlimit"}, +{"path": "upperlimit", "type": "float", "readonly": false, "cmd": "hemot upperlimit"}, +{"path": "disablelimits", "type": "bool", "readonly": false, "cmd": "hemot disablelimits"}, +{"path": "verbose", "type": "bool", "readonly": false, "cmd": "hemot verbose"}, +{"path": "target", "type": "float"}, +{"path": "runstate", "type": "enum", "enum": {"idle": 0, "running": 1, "finished": 2, "error": 3}}, +{"path": "precision", "type": "float", "readonly": false, "cmd": "hemot precision"}, +{"path": "maxencdif", "type": "float", "readonly": false, "cmd": "hemot maxencdif"}, +{"path": "id", "type": "float", "readonly": false, "cmd": "hemot id"}, +{"path": "pump_number", "type": "float", "readonly": false, "cmd": "hemot pump_number"}, +{"path": "init", "type": "float", "readonly": false, "cmd": "hemot init"}, +{"path": "maxspeed", "type": "float", "readonly": false, "cmd": "hemot maxspeed"}, +{"path": "acceleration", "type": "float", "readonly": false, "cmd": "hemot acceleration"}, +{"path": "maxcurrent", "type": "float", "readonly": false, "cmd": "hemot maxcurrent"}, +{"path": "standbycurrent", "type": "float", "readonly": false, "cmd": "hemot standbycurrent"}, +{"path": "freewheeling", "type": "bool", "readonly": false, "cmd": "hemot freewheeling"}, +{"path": "output0", "type": "bool", "readonly": false, "cmd": "hemot output0"}, +{"path": "output1", "type": "bool", "readonly": false, "cmd": "hemot output1"}, +{"path": "input3", "type": "bool"}, +{"path": "pullup", "type": "float", "readonly": false, "cmd": "hemot pullup"}, +{"path": "nopumpfeedback", "type": "bool", "readonly": false, "cmd": "hemot nopumpfeedback"}, +{"path": "eeprom", "type": "enum", "enum": {"ok": 0, "dirty": 1, "save": 2, "load": 3}, "readonly": false, "cmd": "hemot eeprom"}, +{"path": "customadr", "type": "text", "readonly": false, "cmd": "hemot customadr"}, +{"path": "custompar", "type": "float", "readonly": false, "cmd": "hemot custompar"}]}, + +"table": {"base": "/table", "params": [ +{"path": "", "type": "none", "kids": 17}, +{"path": "send", "type": "text", "readonly": false, "cmd": "table send", "visibility": 3}, +{"path": "status", "type": "text", "visibility": 3}, +{"path": "fix_tt_set_prop", "type": "bool", "readonly": false, "cmd": "table fix_tt_set_prop"}, +{"path": "val_tt_set_prop", "type": "float"}, +{"path": "tbl_tt_set_prop", "type": "text", "readonly": false, "cmd": "table tbl_tt_set_prop", "description": "enter value pair separated with colon T1:par1 T2:par2 ..."}, +{"path": "fix_tt_set_integ", "type": "bool", "readonly": false, "cmd": "table fix_tt_set_integ"}, +{"path": "val_tt_set_integ", "type": "float"}, +{"path": "tbl_tt_set_integ", "type": "text", "readonly": false, "cmd": "table tbl_tt_set_integ", "description": "enter value pair separated with colon T1:par1 T2:par2 ..."}, +{"path": "fix_tt_dblctrl_int2", "type": "bool", "readonly": false, "cmd": "table fix_tt_dblctrl_int2"}, +{"path": "val_tt_dblctrl_int2", "type": "float"}, +{"path": "tbl_tt_dblctrl_int2", "type": "text", "readonly": false, "cmd": "table tbl_tt_dblctrl_int2", "description": "enter value pair separated with colon T1:par1 T2:par2 ..."}, +{"path": "fix_tt_dblctrl_prop_up", "type": "bool", "readonly": false, "cmd": "table fix_tt_dblctrl_prop_up"}, +{"path": "val_tt_dblctrl_prop_up", "type": "float"}, +{"path": "tbl_tt_dblctrl_prop_up", "type": "text", "readonly": false, "cmd": "table tbl_tt_dblctrl_prop_up", "description": "enter value pair separated with colon T1:par1 T2:par2 ..."}, +{"path": "fix_tt_dblctrl_prop_lo", "type": "bool", "readonly": false, "cmd": "table fix_tt_dblctrl_prop_lo"}, +{"path": "val_tt_dblctrl_prop_lo", "type": "float"}, +{"path": "tbl_tt_dblctrl_prop_lo", "type": "text", "readonly": false, "cmd": "table tbl_tt_dblctrl_prop_lo", "description": "enter value pair separated with colon T1:par1 T2:par2 ..."}]}} diff --git a/cfg/stick/ill1stick.cfg b/cfg/stick/ill1stick.cfg new file mode 100644 index 0000000..ad589aa --- /dev/null +++ b/cfg/stick/ill1stick.cfg @@ -0,0 +1,17 @@ +[NODE] +description = ILL1 standard sample stick +id = ill1.stick.sea.psi.ch + +[sea_stick] +class = secop_psi.sea.SeaClient +description = SEA stick connection +config = ill1.stick +service = stick + +[ts] +class = secop_psi.sea.SeaReadable +io = sea_stick +sea_object = tt +json_file = ill1.config.json +rel_paths = ts + From bb40a0820c9c9167c165b5f288f1cbaa57bd2237 Mon Sep 17 00:00:00 2001 From: camea Date: Fri, 29 Jul 2022 15:12:44 +0200 Subject: [PATCH 02/22] use flag instead tolerance for redo check when target is changed, a flag is set, and this is used to jump back in the sequence to the right step for redoing --- secop_psi/magfield.py | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/secop_psi/magfield.py b/secop_psi/magfield.py index 5a71ff4..cdf04c7 100644 --- a/secop_psi/magfield.py +++ b/secop_psi/magfield.py @@ -84,6 +84,7 @@ class Magfield(HasLimits, Drivable): _state = None _init = True _super_sw_check = False + _target_changed = False switch_time = None def doPoll(self): @@ -113,6 +114,7 @@ class Magfield(HasLimits, Drivable): def write_target(self, target): self.check_limits(target) + self._target_changed = target != self.target self.target = target if not self._state.is_active: # as long as the state machine is still running, it takes care of changing targets @@ -145,7 +147,7 @@ class Magfield(HasLimits, Drivable): def start_field_change(self, state): self.setFastPoll(True, 1.0) self.status = Status.PREPARING, 'changed target field' - if self.persistent_field == self.target: + if abs(self.target - self.persistent_field) <= self.tolerance: # short cut return self.check_switch_off return self.start_ramp_to_field @@ -158,7 +160,7 @@ class Magfield(HasLimits, Drivable): def ramp_to_field(self, state): """ramping, wait for current at persistent field""" - if self.persistent_field == self.target: # short cut + if abs(self.target - self.persistent_field) <= self.tolerance: # short cut return self.check_switch_off if abs(self.current - self.persistent_field) > self.tolerance: if state.init: @@ -196,11 +198,11 @@ class Magfield(HasLimits, Drivable): def switch_on(self, state): """wait for switch heater open""" - if self.persistent_field == self.target: # short cut + if abs(self.target - self.persistent_field) <= self.tolerance: # short cut return self.check_switch_off if state.now - self.switch_time < self.wait_switch_on: return Retry() - state.set_point = self.target + self._target_changed = False return self.start_ramp_to_target def start_ramp_to_target(self, state): @@ -212,8 +214,8 @@ class Magfield(HasLimits, Drivable): def ramp_to_target(self, state): """ramp field to target""" - if state.set_point != self.target: # target changed - state.set_point = self.target + if self._target_changed: + self._target_changed = False return self.start_ramp_to_target self.persistent_field = self.value # Remarks: assume there is a ramp limiting feature @@ -226,6 +228,9 @@ class Magfield(HasLimits, Drivable): def stabilize_field(self, state): """stabilize field""" + if self._target_changed: + self._target_changed = False + return self.start_ramp_to_target self.persistent_field = self.value if state.now - state.stabilize_start < self.wait_stable_field: if state.init: @@ -253,9 +258,8 @@ class Magfield(HasLimits, Drivable): def switch_off(self, state): """wait for switch heater closed""" - if self.persistent_field != self.target: # redo - return self.start_switch_on - if self.mode == Mode.DRIVEN: + if self._target_changed or self.mode == Mode.DRIVEN: + # target or mode has changed -> redo return self.start_switch_on self.persistent_field = self.value if state.now - self.switch_time < self.wait_switch_off: @@ -272,7 +276,8 @@ class Magfield(HasLimits, Drivable): def ramp_to_zero(self, state): """ramp field to zero""" - if self.persistent_field != self.target or self.mode == Mode.DRIVEN: # redo + if self._target_changed or self.mode == Mode.DRIVEN: + # target or mode has changed -> redo return self.start_field_change if abs(self.current) > self.tolerance: if state.init: From 3496e391f6def1c9a53458835feec7e1f63093d5 Mon Sep 17 00:00:00 2001 From: camea Date: Tue, 2 Aug 2022 11:19:30 +0200 Subject: [PATCH 03/22] check for last_target in conditions for redo --- secop_psi/magfield.py | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/secop_psi/magfield.py b/secop_psi/magfield.py index cdf04c7..5e55270 100644 --- a/secop_psi/magfield.py +++ b/secop_psi/magfield.py @@ -84,7 +84,7 @@ class Magfield(HasLimits, Drivable): _state = None _init = True _super_sw_check = False - _target_changed = False + _last_target = None switch_time = None def doPoll(self): @@ -114,7 +114,6 @@ class Magfield(HasLimits, Drivable): def write_target(self, target): self.check_limits(target) - self._target_changed = target != self.target self.target = target if not self._state.is_active: # as long as the state machine is still running, it takes care of changing targets @@ -147,7 +146,8 @@ class Magfield(HasLimits, Drivable): def start_field_change(self, state): self.setFastPoll(True, 1.0) self.status = Status.PREPARING, 'changed target field' - if abs(self.target - self.persistent_field) <= self.tolerance: # short cut + if (self.target == self._last_target and + abs(self.target - self.persistent_field) <= self.tolerance): # short cut return self.check_switch_off return self.start_ramp_to_field @@ -160,7 +160,8 @@ class Magfield(HasLimits, Drivable): def ramp_to_field(self, state): """ramping, wait for current at persistent field""" - if abs(self.target - self.persistent_field) <= self.tolerance: # short cut + if (self.target == self._last_target and + abs(self.target - self.persistent_field) <= self.tolerance): # short cut return self.check_switch_off if abs(self.current - self.persistent_field) > self.tolerance: if state.init: @@ -186,11 +187,11 @@ class Magfield(HasLimits, Drivable): def start_switch_on(self, state): """switch heater on""" - self._super_sw_check = False if self.switch_heater != 0: self.status = Status.PREPARING, 'wait for heater on' else: self.status = Status.PREPARING, 'turn switch heater on' + self._super_sw_check = False self.write_switch_heater(True) if not self._super_sw_check: raise ProgrammingError('missing super call in write_switch_heater') @@ -198,11 +199,12 @@ class Magfield(HasLimits, Drivable): def switch_on(self, state): """wait for switch heater open""" - if abs(self.target - self.persistent_field) <= self.tolerance: # short cut + if (self.target == self._last_target and + abs(self.target - self.persistent_field) <= self.tolerance): # short cut return self.check_switch_off if state.now - self.switch_time < self.wait_switch_on: return Retry() - self._target_changed = False + self._last_target = self.target return self.start_ramp_to_target def start_ramp_to_target(self, state): @@ -214,8 +216,8 @@ class Magfield(HasLimits, Drivable): def ramp_to_target(self, state): """ramp field to target""" - if self._target_changed: - self._target_changed = False + if self.target != self._last_target: # target was changed + self._last_target = self.target return self.start_ramp_to_target self.persistent_field = self.value # Remarks: assume there is a ramp limiting feature @@ -228,8 +230,8 @@ class Magfield(HasLimits, Drivable): def stabilize_field(self, state): """stabilize field""" - if self._target_changed: - self._target_changed = False + if self.target != self._last_target: # target was changed + self._last_target = self.target return self.start_ramp_to_target self.persistent_field = self.value if state.now - state.stabilize_start < self.wait_stable_field: @@ -250,16 +252,15 @@ class Magfield(HasLimits, Drivable): self.status = Status.FINALIZING, 'turn switch heater off' else: self.status = Status.FINALIZING, 'wait for heater off' - self._super_sw_check = False self.write_switch_heater(False) - if not self._super_sw_check: - raise ProgrammingError('missing super call in write_switch_heater') + # no check for super call needed here (would have been detected in start_switch_on) return self.switch_off def switch_off(self, state): """wait for switch heater closed""" - if self._target_changed or self.mode == Mode.DRIVEN: + if self.target != self._last_target or self.mode == Mode.DRIVEN: # target or mode has changed -> redo + self._last_target = None return self.start_switch_on self.persistent_field = self.value if state.now - self.switch_time < self.wait_switch_off: @@ -269,15 +270,16 @@ class Magfield(HasLimits, Drivable): def start_ramp_to_zero(self, state): """start ramping current to target - initiate ramp to zero (with corresponding ramp rate + initiate ramp to zero (with corresponding ramp rate) should return ramp_to_zero """ raise NotImplementedError def ramp_to_zero(self, state): """ramp field to zero""" - if self._target_changed or self.mode == Mode.DRIVEN: + if self.target != self._last_target or self.mode == Mode.DRIVEN: # target or mode has changed -> redo + self._last_target = None return self.start_field_change if abs(self.current) > self.tolerance: if state.init: From 8e3cdc80e4a392edeb2f02a85f87a3e8cbf1c164 Mon Sep 17 00:00:00 2001 From: camea Date: Fri, 12 Aug 2022 15:10:23 +0200 Subject: [PATCH 04/22] improvements in magfiels/ips_mercury - read voltage - fix a bug with ._init name conflict --- cfg/main/mb11.cfg | 1 + secop_psi/convergence.py | 11 +++++++++++ secop_psi/ips_mercury.py | 10 +++++++--- secop_psi/magfield.py | 10 ++++++---- 4 files changed, 25 insertions(+), 7 deletions(-) diff --git a/cfg/main/mb11.cfg b/cfg/main/mb11.cfg index 56b4248..b863724 100644 --- a/cfg/main/mb11.cfg +++ b/cfg/main/mb11.cfg @@ -161,6 +161,7 @@ class = secop_psi.ips_mercury.Field description = magnetic field slot = GRPZ io = ips +tolerance = 0.001 target.max = 11 [om_io] diff --git a/secop_psi/convergence.py b/secop_psi/convergence.py index 15833b5..385a098 100644 --- a/secop_psi/convergence.py +++ b/secop_psi/convergence.py @@ -89,6 +89,10 @@ class HasConvergence: """to be called from write_target""" self.convergence_state.start(self.state_approach) + def interrupt_state(self): + """to be called from stop""" + self.convergence_state.start(self.state_instable) + def state_approach(self, state): """approaching, checking progress (busy)""" state.spent_inside = 0 @@ -157,3 +161,10 @@ class HasConvergence: else: state.spent_inside = max(0, state.spent_inside - state.delta()) return Retry() + + def state_interrupt(self, state): + self.status = IDLE, 'stopped' # stop called + return self.state_instable + + def stop(self): + self.convergence_state.start(self.state_interrupt) diff --git a/secop_psi/ips_mercury.py b/secop_psi/ips_mercury.py index e965f5e..c3ee708 100644 --- a/secop_psi/ips_mercury.py +++ b/secop_psi/ips_mercury.py @@ -35,6 +35,7 @@ CURRENT_CHECK_SIZE = 2 class Field(MercuryChannel, Magfield): action = Parameter('action', EnumType(Action), readonly=False) setpoint = Parameter('field setpoint', FloatRange(unit='T'), default=0) + voltage = Parameter('leads voltage', FloatRange(unit='V'), default=0) atob = Parameter('field to amp', FloatRange(0, unit='A/T'), default=0) forced_persistent_field = Parameter( 'manual indication that persistent field is bad', BoolType(), readonly=False, default=False) @@ -43,13 +44,13 @@ class Field(MercuryChannel, Magfield): _field_mismatch = None nslaves = 3 slave_currents = None - _init = True + __init = True def read_value(self): self.current = self.query('PSU:SIG:FLD') pf = self.query('PSU:SIG:PFLD') - if self._init: - self._init = False + if self.__init: + self.__init = False self.persistent_field = pf if self.switch_heater != 0 or self._field_mismatch is None: self.forced_persistent_field = False @@ -92,6 +93,9 @@ class Field(MercuryChannel, Magfield): def read_atob(self): return self.query('PSU:ATOB') + def read_voltage(self): + return self.query('PSU:SIG:VOLT') + def read_setpoint(self): return self.query('PSU:SIG:FSET') diff --git a/secop_psi/magfield.py b/secop_psi/magfield.py index 5e55270..65a33af 100644 --- a/secop_psi/magfield.py +++ b/secop_psi/magfield.py @@ -82,19 +82,21 @@ class Magfield(HasLimits, Drivable): 'wait time to ensure field is stable', FloatRange(0, unit='s'), readonly=False, default=31) _state = None - _init = True + __init = True _super_sw_check = False _last_target = None switch_time = None def doPoll(self): - if self._init: - self._init = False + if self.__init: + self.__init = False self.switch_time = time.time() if self.read_switch_heater() and self.mode == Mode.PERSISTENT: self.read_value() # check for persistent field mismatch # switch off heater from previous live or manual intervention - self.write_target(self.persistent_value) + self.write_target(self.persistent_field) + else: + self._last_target = self.persistent_field else: self.read_value() self._state.cycle() From 704bba292a785cdd82a793fc7a0efbd0c6b2d272 Mon Sep 17 00:00:00 2001 From: camea Date: Fri, 12 Aug 2022 15:13:07 +0200 Subject: [PATCH 05/22] add mb11 stick --- cfg/stick/mb11stick.cfg | 43 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 cfg/stick/mb11stick.cfg diff --git a/cfg/stick/mb11stick.cfg b/cfg/stick/mb11stick.cfg new file mode 100644 index 0000000..8f900e3 --- /dev/null +++ b/cfg/stick/mb11stick.cfg @@ -0,0 +1,43 @@ +[NODE] +description = MB11 standard sample stick +id = mb11.stick.sea.psi.ch + + +[INTERFACE] +uri = tcp://5000 + +[itc] +class = secop.proxy.Proxy +remote_class = secop_psi.mercury.IO +description = connection to MB11 mercury +module = itc1 +#uri = mb11-ts:3001 +#timeout = 5 + +#[t3] +#class = secop_psi.softcal.Sensor +#rawsensor = r2 +##calib USstick +#calib = /home/l_samenv/sea/tcl/calcurves/X163059.340 +##calib dilatometer stick +#calib = /home/l_samenv/sea/tcl/calcurves/X86023.340 +## unknown +#calib = /home/l_samenv/sea/tcl/calcurves/X70197.340 +#svalue.unit = K + + + + +[ts] +class = secop_psi.mercury.TemperatureLoop +description = sample temperature +output_module = htr_ts +slot = MB1.T1 +io = itc +tolerance = 1 + +[htr_ts] +class = secop_psi.mercury.HeaterOutput +description = sample stick heater power +slot = MB0.H1 +io = itc From b81fc7b122e9f1d7580943d34cb8c974b91205c9 Mon Sep 17 00:00:00 2001 From: dmc Date: Mon, 15 Aug 2022 16:22:02 +0200 Subject: [PATCH 06/22] remove tm from ill5.cfg only one SeaDrivable per sea drivable allowed! --- cfg/main/ill5.cfg | 6 ---- cfg/sea/ill5.config.json | 67 +++++++++++++++++++++++----------------- secop_psi/sea.py | 3 +- 3 files changed, 39 insertions(+), 37 deletions(-) diff --git a/cfg/main/ill5.cfg b/cfg/main/ill5.cfg index f2c5e94..288b2a5 100644 --- a/cfg/main/ill5.cfg +++ b/cfg/main/ill5.cfg @@ -13,12 +13,6 @@ class = secop_psi.sea.SeaDrivable io = sea_main sea_object = tt -[tm] -class = secop_psi.sea.SeaDrivable -io = sea_main -sea_object = tt -rel_paths = tm - [cc] class = secop_psi.sea.SeaReadable io = sea_main diff --git a/cfg/sea/ill5.config.json b/cfg/sea/ill5.config.json index c960299..1e1c09c 100644 --- a/cfg/sea/ill5.config.json +++ b/cfg/sea/ill5.config.json @@ -1,5 +1,5 @@ {"tt": {"base": "/tt", "params": [ -{"path": "", "type": "float", "readonly": false, "cmd": "run tt", "description": "tt", "kids": 19}, +{"path": "", "type": "float", "readonly": false, "cmd": "run tt", "description": "tt", "kids": 17}, {"path": "send", "type": "text", "readonly": false, "cmd": "tt send", "visibility": 3}, {"path": "status", "type": "text", "visibility": 3}, {"path": "is_running", "type": "int", "readonly": false, "cmd": "tt is_running", "visibility": 3}, @@ -62,8 +62,6 @@ {"path": "set/integ", "type": "float", "readonly": false, "cmd": "tt set/integ", "description": "bigger means faster"}, {"path": "set/deriv", "type": "float", "readonly": false, "cmd": "tt set/deriv"}, {"path": "display", "type": "text", "readonly": false, "cmd": "tt display"}, -{"path": "dout", "type": "int", "readonly": false, "cmd": "tt dout"}, -{"path": "dinp", "type": "int"}, {"path": "remote", "type": "bool"}]}, "cc": {"base": "/cc", "params": [ @@ -116,23 +114,23 @@ {"path": "hit", "type": "float", "readonly": false, "cmd": "cc hit"}, {"path": "hft", "type": "int", "readonly": false, "cmd": "cc hft"}, {"path": "hea", "type": "enum", "enum": {"0": 0, "1": 1, "6": 2}, "readonly": false, "cmd": "cc hea"}, -{"path": "hch", "type": "int", "readonly": false, "cmd": "cc hch", "visibility": 3}, -{"path": "hwr0", "type": "float", "readonly": false, "cmd": "cc hwr0", "visibility": 3}, -{"path": "hem0", "type": "float", "readonly": false, "cmd": "cc hem0", "description": "sensor length in mm from top to empty pos.", "visibility": 3}, -{"path": "hfu0", "type": "float", "readonly": false, "cmd": "cc hfu0", "description": "sensor length in mm from top to full pos.", "visibility": 3}, -{"path": "hd0", "type": "float", "readonly": false, "cmd": "cc hd0", "description": "external sensor drive current (mA)", "visibility": 3}, -{"path": "h0", "type": "float", "visibility": 3}, -{"path": "hs0", "type": "enum", "enum": {"sens_ok": 0, "sens_warm": 1, "no_sens": 2, "timeout": 3, "not_yet_read": 4, "disabled": 5}, "visibility": 3}, -{"path": "h1", "type": "float", "visibility": 3}, -{"path": "hs1", "type": "enum", "enum": {"sens_ok": 0, "sens_warm": 1, "no_sens": 2, "timeout": 3, "not_yet_read": 4, "disabled": 5}, "visibility": 3}, -{"path": "h2", "type": "float", "visibility": 3}, -{"path": "hs2", "type": "enum", "enum": {"sens_ok": 0, "sens_warm": 1, "no_sens": 2, "timeout": 3, "not_yet_read": 4, "disabled": 5}, "visibility": 3}, -{"path": "h3", "type": "float", "visibility": 3}, -{"path": "hs3", "type": "enum", "enum": {"sens_ok": 0, "sens_warm": 1, "no_sens": 2, "timeout": 3, "not_yet_read": 4, "disabled": 5}, "visibility": 3}, -{"path": "h4", "type": "float", "visibility": 3}, -{"path": "hs4", "type": "enum", "enum": {"sens_ok": 0, "sens_warm": 1, "no_sens": 2, "timeout": 3, "not_yet_read": 4, "disabled": 5}, "visibility": 3}, -{"path": "h5", "type": "float", "visibility": 3}, -{"path": "hs5", "type": "enum", "enum": {"sens_ok": 0, "sens_warm": 1, "no_sens": 2, "timeout": 3, "not_yet_read": 4, "disabled": 5}, "visibility": 3}, +{"path": "hch", "type": "int", "readonly": false, "cmd": "cc hch"}, +{"path": "hwr0", "type": "float", "readonly": false, "cmd": "cc hwr0"}, +{"path": "hem0", "type": "float", "readonly": false, "cmd": "cc hem0", "description": "sensor length in mm from top to empty pos."}, +{"path": "hfu0", "type": "float", "readonly": false, "cmd": "cc hfu0", "description": "sensor length in mm from top to full pos."}, +{"path": "hd0", "type": "float", "readonly": false, "cmd": "cc hd0", "description": "external sensor drive current (mA)"}, +{"path": "h0", "type": "float"}, +{"path": "hs0", "type": "enum", "enum": {"sens_ok": 0, "sens_warm": 1, "no_sens": 2, "timeout": 3, "not_yet_read": 4, "disabled": 5}}, +{"path": "h1", "type": "float"}, +{"path": "hs1", "type": "enum", "enum": {"sens_ok": 0, "sens_warm": 1, "no_sens": 2, "timeout": 3, "not_yet_read": 4, "disabled": 5}}, +{"path": "h2", "type": "float"}, +{"path": "hs2", "type": "enum", "enum": {"sens_ok": 0, "sens_warm": 1, "no_sens": 2, "timeout": 3, "not_yet_read": 4, "disabled": 5}}, +{"path": "h3", "type": "float"}, +{"path": "hs3", "type": "enum", "enum": {"sens_ok": 0, "sens_warm": 1, "no_sens": 2, "timeout": 3, "not_yet_read": 4, "disabled": 5}}, +{"path": "h4", "type": "float"}, +{"path": "hs4", "type": "enum", "enum": {"sens_ok": 0, "sens_warm": 1, "no_sens": 2, "timeout": 3, "not_yet_read": 4, "disabled": 5}}, +{"path": "h5", "type": "float"}, +{"path": "hs5", "type": "enum", "enum": {"sens_ok": 0, "sens_warm": 1, "no_sens": 2, "timeout": 3, "not_yet_read": 4, "disabled": 5}}, {"path": "hfb", "type": "float"}, {"path": "nav", "type": "bool", "readonly": false, "cmd": "cc nav"}, {"path": "nu", "type": "float"}, @@ -225,28 +223,29 @@ {"path": "state", "type": "text"}]}, "hefill": {"base": "/hefill", "params": [ -{"path": "", "type": "enum", "enum": {"watching": 0, "fill": 1, "inactive": 2, "manualfill": 3}, "readonly": false, "cmd": "hefill", "kids": 6}, +{"path": "", "type": "enum", "enum": {"watching": 0, "fill": 1, "inactive": 2, "manualfill": 3}, "readonly": false, "cmd": "hefill", "kids": 7}, {"path": "send", "type": "text", "readonly": false, "cmd": "hefill send", "visibility": 3}, {"path": "status", "type": "text", "visibility": 3}, {"path": "fast", "type": "enum", "enum": {"slow": 0, "fast": 1}, "readonly": false, "cmd": "cc hf"}, {"path": "state", "type": "text"}, {"path": "hefull", "type": "float", "readonly": false, "cmd": "cc hh"}, -{"path": "helow", "type": "float", "readonly": false, "cmd": "cc hl"}]}, +{"path": "helow", "type": "float", "readonly": false, "cmd": "cc hl"}, +{"path": "smooth", "type": "float"}]}, "hepump": {"base": "/hepump", "params": [ {"path": "", "type": "enum", "enum": {"xds35_auto": 0, "xds35_manual": 1, "sv65": 2, "other": 3, "no": -1}, "readonly": false, "cmd": "hepump", "description": "xds35: scroll pump, sv65: leybold", "kids": 10}, {"path": "send", "type": "text", "readonly": false, "cmd": "hepump send", "visibility": 3}, {"path": "status", "type": "text", "visibility": 3}, -{"path": "running", "type": "bool", "readonly": false, "cmd": "hepump running", "visibility": 3}, -{"path": "eco", "type": "bool", "readonly": false, "cmd": "hepump eco", "visibility": 3}, -{"path": "auto", "type": "bool", "readonly": false, "cmd": "hepump auto", "visibility": 3}, -{"path": "valve", "type": "enum", "enum": {"closed": 0, "closing": 1, "opening": 2, "opened": 3, "undefined": 4}, "readonly": false, "cmd": "hepump valve", "visibility": 3}, -{"path": "eco_t_lim", "type": "float", "readonly": false, "cmd": "hepump eco_t_lim", "description": "switch off eco mode when T_set < eco_t_lim and T < eco_t_lim * 2", "visibility": 3}, +{"path": "running", "type": "bool", "readonly": false, "cmd": "hepump running"}, +{"path": "eco", "type": "bool", "readonly": false, "cmd": "hepump eco"}, +{"path": "auto", "type": "bool", "readonly": false, "cmd": "hepump auto"}, +{"path": "valve", "type": "enum", "enum": {"closed": 0, "closing": 1, "opening": 2, "opened": 3, "undefined": 4}, "readonly": false, "cmd": "hepump valve"}, +{"path": "eco_t_lim", "type": "float", "readonly": false, "cmd": "hepump eco_t_lim", "description": "switch off eco mode when T_set < eco_t_lim and T < eco_t_lim * 2"}, {"path": "calib", "type": "float", "readonly": false, "cmd": "hepump calib", "visibility": 3}, {"path": "health", "type": "float"}]}, "hemot": {"base": "/hepump/hemot", "params": [ -{"path": "", "type": "float", "readonly": false, "cmd": "run hemot", "visibility": 3, "kids": 30}, +{"path": "", "type": "float", "readonly": false, "cmd": "run hemot", "kids": 30}, {"path": "send", "type": "text", "readonly": false, "cmd": "hemot send", "visibility": 3}, {"path": "status", "type": "text", "visibility": 3}, {"path": "is_running", "type": "int", "readonly": false, "cmd": "hemot is_running", "visibility": 3}, @@ -296,4 +295,14 @@ {"path": "tbl_tt_dblctrl_prop_up", "type": "text", "readonly": false, "cmd": "table tbl_tt_dblctrl_prop_up", "description": "enter value pair separated with colon T1:par1 T2:par2 ..."}, {"path": "fix_tt_dblctrl_prop_lo", "type": "bool", "readonly": false, "cmd": "table fix_tt_dblctrl_prop_lo"}, {"path": "val_tt_dblctrl_prop_lo", "type": "float"}, -{"path": "tbl_tt_dblctrl_prop_lo", "type": "text", "readonly": false, "cmd": "table tbl_tt_dblctrl_prop_lo", "description": "enter value pair separated with colon T1:par1 T2:par2 ..."}]}} +{"path": "tbl_tt_dblctrl_prop_lo", "type": "text", "readonly": false, "cmd": "table tbl_tt_dblctrl_prop_lo", "description": "enter value pair separated with colon T1:par1 T2:par2 ..."}]}, + +"prep0v": {"base": "/prep0v", "params": [ +{"path": "", "type": "text", "readonly": false, "cmd": "prep0v", "kids": 2}, +{"path": "send", "type": "text", "readonly": false, "cmd": "prep0v send", "visibility": 3}, +{"path": "status", "type": "text", "visibility": 3}]}, + +"prep0": {"base": "/prep0", "params": [ +{"path": "", "type": "text", "readonly": false, "cmd": "prep0", "kids": 2}, +{"path": "send", "type": "text", "readonly": false, "cmd": "prep0 send", "visibility": 3}, +{"path": "status", "type": "text", "visibility": 3}]}} diff --git a/secop_psi/sea.py b/secop_psi/sea.py index f4b0eb6..749207c 100644 --- a/secop_psi/sea.py +++ b/secop_psi/sea.py @@ -401,7 +401,6 @@ class SeaModule(Module): hdbpath = None # hdbpath for main writable def __new__(cls, name, logger, cfgdict, srv): - print('N', cls, name) if hasattr(srv, 'extra_sea_modules'): extra_modules = srv.extra_sea_modules else: @@ -667,7 +666,7 @@ class SeaDrivable(SeaModule, Drivable): def write_target(self, value): self.io.query('run %s %s' % (self.sea_object, value)) - #self.status = [self.Status.BUSY, 'driving'] + # self.status = [self.Status.BUSY, 'driving'] return value def update_status(self, value, timestamp, readerror): From 2f6954c4f39af22d58b761c2d760a4bb2aaefc2b Mon Sep 17 00:00:00 2001 From: Markus Zolliker Date: Tue, 16 Aug 2022 10:02:57 +0200 Subject: [PATCH 07/22] magfield: add persistent_limit parameter - use update_switch_heater instead of write_switch_heater for detecting switch time - switch_time split into switch_on_time/switch_off_time Change-Id: Id90a8b2c2520e24f3ee4a34aee25d41210e5d6d4 --- secop_psi/ips_mercury.py | 1 - secop_psi/magfield.py | 44 ++++++++++++++++++++++++++-------------- 2 files changed, 29 insertions(+), 16 deletions(-) diff --git a/secop_psi/ips_mercury.py b/secop_psi/ips_mercury.py index c3ee708..252f755 100644 --- a/secop_psi/ips_mercury.py +++ b/secop_psi/ips_mercury.py @@ -87,7 +87,6 @@ class Field(MercuryChannel, Magfield): return self.query('PSU:SIG:SWHT', off_on) def write_switch_heater(self, value): - super().write_switch_heater(value) return self.change('PSU:SIG:SWHT', value, off_on) def read_atob(self): diff --git a/secop_psi/magfield.py b/secop_psi/magfield.py index 65a33af..3efa025 100644 --- a/secop_psi/magfield.py +++ b/secop_psi/magfield.py @@ -80,17 +80,19 @@ class Magfield(HasLimits, Drivable): 'wait time to ensure current is stable', FloatRange(0, unit='s'), readonly=False, default=6) wait_stable_field = Parameter( 'wait time to ensure field is stable', FloatRange(0, unit='s'), readonly=False, default=31) + persistent_limit = Parameter( + 'above this limit, lead currents are not driven to 0', + FloatRange(0, unit='$'), readonly=False, default=99) _state = None __init = True - _super_sw_check = False _last_target = None - switch_time = None + switch_on_time = None + switch_off_time = None def doPoll(self): if self.__init: self.__init = False - self.switch_time = time.time() if self.read_switch_heater() and self.mode == Mode.PERSISTENT: self.read_value() # check for persistent field mismatch # switch off heater from previous live or manual intervention @@ -112,6 +114,7 @@ class Magfield(HasLimits, Drivable): def initModule(self): super().initModule() + self.registerCallbacks(self) # for update_switch_heater self._state = StateMachine(logger=self.log, threaded=False, cleanup=self.cleanup_state) def write_target(self, target): @@ -180,12 +183,16 @@ class Magfield(HasLimits, Drivable): return Retry() return self.start_switch_on - def write_switch_heater(self, value): - """implementations must super call this!""" - self._super_sw_check = True - if value != self.switch_heater: - self.switch_time = time.time() - return value + def update_switch_heater(self, value): + """is called whenever switch heater was changed""" + if value: + self.switch_off_time = None + if self.switch_on_time is None: + self.switch_on_time = time.time() + else: + self.switch_on_time = None + if self.switch_off_time is None: + self.switch_off_time = time.time() def start_switch_on(self, state): """switch heater on""" @@ -193,10 +200,7 @@ class Magfield(HasLimits, Drivable): self.status = Status.PREPARING, 'wait for heater on' else: self.status = Status.PREPARING, 'turn switch heater on' - self._super_sw_check = False self.write_switch_heater(True) - if not self._super_sw_check: - raise ProgrammingError('missing super call in write_switch_heater') return self.switch_on def switch_on(self, state): @@ -204,7 +208,11 @@ class Magfield(HasLimits, Drivable): if (self.target == self._last_target and abs(self.target - self.persistent_field) <= self.tolerance): # short cut return self.check_switch_off - if state.now - self.switch_time < self.wait_switch_on: + self.read_switch_heater() + if self.switch_on_time is None: + self.log.warning('switch turned off manually - try again') + return self.start_switch_on + if state.now - self.switch_on_time < self.wait_switch_on: return Retry() self._last_target = self.target return self.start_ramp_to_target @@ -255,7 +263,6 @@ class Magfield(HasLimits, Drivable): else: self.status = Status.FINALIZING, 'wait for heater off' self.write_switch_heater(False) - # no check for super call needed here (would have been detected in start_switch_on) return self.switch_off def switch_off(self, state): @@ -265,8 +272,15 @@ class Magfield(HasLimits, Drivable): self._last_target = None return self.start_switch_on self.persistent_field = self.value - if state.now - self.switch_time < self.wait_switch_off: + self.read_switch_heater() + if self.switch_off_time is None: + self.log.warning('switch turned on manually - try again') + return self.start_switch_off + if state.now - self.switch_off_time < self.wait_switch_off: return Retry() + if abs(self.value) > self.persistent_limit: + self.status = Status.IDLE, 'leads current at field, switch off' + return self.finish_state return self.start_ramp_to_zero def start_ramp_to_zero(self, state): From f23e42de1f868796b0aa716dea920a4e53f435c3 Mon Sep 17 00:00:00 2001 From: camea Date: Tue, 16 Aug 2022 16:54:30 +0200 Subject: [PATCH 08/22] fix bugs with persistent_limit parameter take into account that reading the switch heater might be delayed --- cfg/main/mb11.cfg | 18 ++++++++++-------- secop_psi/ips_mercury.py | 21 ++++++++++++++++----- secop_psi/magfield.py | 30 +++++++++++++++++++----------- 3 files changed, 45 insertions(+), 24 deletions(-) diff --git a/cfg/main/mb11.cfg b/cfg/main/mb11.cfg index b863724..359b2ba 100644 --- a/cfg/main/mb11.cfg +++ b/cfg/main/mb11.cfg @@ -82,6 +82,16 @@ description = dynamic needle valve position slot = DB8.P1,DB4.G1 io = itc1 +[mf] +class = secop_psi.ips_mercury.Field +description = magnetic field +slot = GRPZ +io = ips +tolerance = 0.001 +wait_stable_field = 60 +target.max = 11 +persistent_limit = 7 + [lev] class = secop_psi.mercury.HeLevel description = LHe level @@ -156,14 +166,6 @@ description = coil temperature slot = MB1.T1 io = ips -[mf] -class = secop_psi.ips_mercury.Field -description = magnetic field -slot = GRPZ -io = ips -tolerance = 0.001 -target.max = 11 - [om_io] description = dom motor IO class = secop_psi.phytron.PhytronIO diff --git a/secop_psi/ips_mercury.py b/secop_psi/ips_mercury.py index 252f755..6020359 100644 --- a/secop_psi/ips_mercury.py +++ b/secop_psi/ips_mercury.py @@ -119,16 +119,27 @@ class Field(MercuryChannel, Magfield): return current / self.atob return 0 - def start_ramp_to_field(self, state): - self.change('PSU:SIG:FSET', self.persistent_field) + def set_and_go(self, value): + self.change('PSU:SIG:FSET', value) assert self.write_action('hold') == 'hold' assert self.write_action('run_to_set') == 'run_to_set' + + def start_ramp_to_field(self, state): + try: + self.set_and_go(self.persistent_field) + except (HardwareError, AssertionError): + state.switch_undef = self.switch_on_time or state.now + return self.wait_for_switch return self.ramp_to_field + def wait_for_switch(self, state): + if self.now - self.switch_undef < self.wait_switch_on: + return Retry() + self.set_and_go(self.persistent_field) + return self.ramp_to_field + def start_ramp_to_target(self, state): - self.change('PSU:SIG:FSET', self.target) - assert self.write_action('hold') == 'hold' - assert self.write_action('run_to_set') == 'run_to_set' + self.set_and_go(self.target) return self.ramp_to_target def start_ramp_to_zero(self, state): diff --git a/secop_psi/magfield.py b/secop_psi/magfield.py index 3efa025..1d800b2 100644 --- a/secop_psi/magfield.py +++ b/secop_psi/magfield.py @@ -185,7 +185,7 @@ class Magfield(HasLimits, Drivable): def update_switch_heater(self, value): """is called whenever switch heater was changed""" - if value: + if value != 0: self.switch_off_time = None if self.switch_on_time is None: self.switch_on_time = time.time() @@ -196,11 +196,15 @@ class Magfield(HasLimits, Drivable): def start_switch_on(self, state): """switch heater on""" - if self.switch_heater != 0: - self.status = Status.PREPARING, 'wait for heater on' - else: + if self.switch_heater == 0: self.status = Status.PREPARING, 'turn switch heater on' - self.write_switch_heater(True) + try: + self.write_switch_heater(True) + except Exception as e: + self.log.warning('write_switch_heater %r', e) + return Retry() + else: + self.status = Status.PREPARING, 'wait for heater on' return self.switch_on def switch_on(self, state): @@ -210,8 +214,10 @@ class Magfield(HasLimits, Drivable): return self.check_switch_off self.read_switch_heater() if self.switch_on_time is None: - self.log.warning('switch turned off manually - try again') - return self.start_switch_on + if state.now - self.switch_off_time > 10: + self.log.warning('switch turned off manually?') + return self.start_switch_on + return Retry() if state.now - self.switch_on_time < self.wait_switch_on: return Retry() self._last_target = self.target @@ -258,11 +264,11 @@ class Magfield(HasLimits, Drivable): def start_switch_off(self, state): """turn off switch heater""" - if self.switch_heater != 0: + if self.switch_heater == 1: self.status = Status.FINALIZING, 'turn switch heater off' + self.write_switch_heater(False) else: self.status = Status.FINALIZING, 'wait for heater off' - self.write_switch_heater(False) return self.switch_off def switch_off(self, state): @@ -274,8 +280,10 @@ class Magfield(HasLimits, Drivable): self.persistent_field = self.value self.read_switch_heater() if self.switch_off_time is None: - self.log.warning('switch turned on manually - try again') - return self.start_switch_off + if state.now - self.switch_on_time > 10: + self.log.warning('switch turned on manually?') + return self.start_switch_off + return Retry() if state.now - self.switch_off_time < self.wait_switch_off: return Retry() if abs(self.value) > self.persistent_limit: From d5d04dc82f83a090cfb94ad90cb2826e32025413 Mon Sep 17 00:00:00 2001 From: Markus Zolliker Date: Tue, 9 Aug 2022 15:29:12 +0200 Subject: [PATCH 09/22] add simple interactive python client - SECoP modules are accessible as objects in the main python module - parameters are accessed as attributes of these objects - __repr__ is used for listing all parameters - __call__ is used for 'change target and wait until no more busy' typically used from a python interpreter or in a jupyter notebook Change-Id: Idb55684eeff6d1262e5d1517a3ff934f1c1bf208 Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/28980 Tested-by: Jenkins Automated Tests Reviewed-by: Markus Zolliker --- secop/client/interactive.py | 263 ++++++++++++++++++++++++++++++++++++ 1 file changed, 263 insertions(+) create mode 100644 secop/client/interactive.py diff --git a/secop/client/interactive.py b/secop/client/interactive.py new file mode 100644 index 0000000..85d6428 --- /dev/null +++ b/secop/client/interactive.py @@ -0,0 +1,263 @@ +# -*- coding: utf-8 -*- +# ***************************************************************************** +# +# This program is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free Software +# Foundation; either version 2 of the License, or (at your option) any later +# version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License along with +# this program; if not, write to the Free Software Foundation, Inc., +# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# Module authors: +# Markus Zolliker +# +# ***************************************************************************** +"""simple interactive python client""" + +import sys +import time +import json +from queue import Queue +from secop.client import SecopClient +from secop.errors import SECoPError + +USAGE = """ +Usage: + +from secop.client.interactive import Client + +client = Client('localhost:5000') # start client. +# this connects and creates objects for all SECoP modules in the main namespace + + # list all parameters +. = # change parameter +() # set target and wait until not busy + # 'status' and 'value' changes are shown every 1 sec +client.mininterval = 0.2 # change minimal update interval to 0.2 sec (default is 1 second) + +.watch(1) # watch changes of all parameters of a module +.watch(0) # remove all watching +.watch(status=1, value=1) # add 'status' and 'value' to watched parameters +.watch(value=0) # remove 'value' from watched parameters +""" + +main = sys.modules['__main__'] + + +class Logger: + def __init__(self, loglevel='info'): + func = self.noop + for lev in 'debug', 'info', 'warning', 'error': + if lev == loglevel: + func = self.emit + setattr(self, lev, func) + + @staticmethod + def emit(fmt, *args, **kwds): + print(str(fmt) % args) + + @staticmethod + def noop(fmt, *args, **kwds): + pass + + +class PrettyFloat(float): + def __repr__(self): + result = '%.12g' % self + if '.' in result or 'e' in result: + return result + return result + '.' + + +class Module: + def __init__(self, name, secnode): + self._name = name + self._secnode = secnode + self._parameters = list(secnode.modules[name]['parameters']) + self._commands = list(secnode.modules[name]['commands']) + self._running = None + self._status = None + props = secnode.modules[name]['properties'] + self._title = '# %s (%s)' % (props.get('implementation', ''), props.get('interface_classes', [''])[0]) + + def _one_line(self, pname, minwid=0): + """return . = truncated to one line""" + try: + value = getattr(self, pname) + # make floats appear with 7 digits only + r = repr(json.loads(json.dumps(value), parse_float=PrettyFloat)) + except Exception as e: + r = repr(e) + unit = getattr(type(self), pname).unit + if unit: + r += ' %s' % unit + pname = pname.ljust(minwid) + vallen = 113 - len(self._name) - len(pname) + if len(r) > vallen: + r = r[:vallen - 4] + ' ...' + return '%s.%s = %s' % (self._name, pname, r) + + def _isBusy(self): + return 300 <= self.status[0] < 400 + + def _status_value_update(self, m, p, status, t, e): + if self._running: + try: + self._running.put(True) + if self._running and not self._isBusy(): + self._running.put(False) + except TypeError: # may happen when _running is removed during above lines + pass + + def _watch_parameter(self, m, pname, *args, forced=False, mininterval=0): + """show parameter update""" + pobj = getattr(type(self), pname) + if not args: + args = self._secnode.cache[self._name, pname] + value = args[0] + now = time.time() + if (value != pobj.prev and now >= pobj.prev_time + mininterval) or forced: + self._secnode.log.info('%s', self._one_line(pname)) + pobj.prev = value + pobj.prev_time = now + + def watch(self, *args, **kwds): + enabled = {} + for arg in args: + if arg == 1: # or True + enabled.update({k: True for k in self._parameters}) + elif arg == 0: # or False + enabled.update({k: False for k in self._parameters}) + else: + enabled.update(arg) + enabled.update(kwds) + for pname, enable in enabled.items(): + self._secnode.unregister_callback((self._name, pname), updateEvent=self._watch_parameter) + if enable: + self._secnode.register_callback((self._name, pname), updateEvent=self._watch_parameter) + + def read(self, pname='value'): + value, _, error = self._secnode.readParameter(self._name, pname) + if error: + raise error + return value + + def __call__(self, target=None): + if target is None: + return self.read() + self.target = target # this sets self._running + type(self).value.prev = None # show at least one value + show_final_value = True + try: + while self._running.get(): + self._watch_parameter(self._name, 'value', mininterval=self._secnode.mininterval) + self._watch_parameter(self._name, 'status') + except KeyboardInterrupt: + self._secnode.log.info('-- interrupted --') + self._running = None + self._watch_parameter(self._name, 'status') + self._secnode.readParameter(self._name, 'value') + self._watch_parameter(self._name, 'value', forced=show_final_value) + return self.value + + def __repr__(self): + wid = max(len(k) for k in self._parameters) + return '%s\n%s\nCommands: %s' % ( + self._title, + '\n'.join(self._one_line(k, wid) for k in self._parameters), + ', '.join(k + '()' for k in self._commands)) + + +class Param: + def __init__(self, name, unit=None): + self.name = name + self.prev = None + self.prev_time = 0 + self.unit = unit + + def __get__(self, obj, owner): + if obj is None: + return self + value, _, error = obj._secnode.cache[obj._name, self.name] + if error: + raise error + return value + + def __set__(self, obj, value): + if self.name == 'target': + obj._running = Queue() + try: + obj._secnode.setParameter(obj._name, self.name, value) + except SECoPError as e: + obj._secnode.log.error(repr(e)) + + +class Command: + def __init__(self, name, modname, secnode): + self.name = name + self.modname = modname + self.exec = secnode.execCommand + + def call(self, *args, **kwds): + if kwds: + if args: + raise TypeError('mixed arguments forbidden') + result, _ = self.exec(self.modname, self.name, kwds) + else: + result, _ = self.exec(self.modname, self.name, args or None) + return result + + def __get__(self, obj, owner=None): + if obj is None: + return self + return self.call + + +class Client(SecopClient): + activate = True + secnodes = {} + mininterval = 1 + + def __init__(self, uri, loglevel='info'): + # remove previous client: + prev = self.secnodes.pop(uri, None) + if prev: + prev.log.info('remove previous client to %s', uri) + for modname in prev.modules: + prevnode = getattr(getattr(main, modname, None), 'secnode', None) + if prevnode == prev: + prev.log.info('remove previous module %s', modname) + delattr(main, modname) + prev.disconnect() + self.secnodes[uri] = self + super().__init__(uri, Logger(loglevel)) + self.connect() + for modname, moddesc in self.modules.items(): + prev = getattr(main, modname, None) + if prev is None: + self.log.info('create module %s', modname) + else: + if getattr(prev, 'secnode', None) is None: + self.log.error('skip module %s overwriting a global variable' % modname) + continue + self.log.info('overwrite module %s', modname) + attrs = {} + for pname, pinfo in moddesc['parameters'].items(): + unit = pinfo['datainfo'].get('unit') + attrs[pname] = Param(pname, unit) + for cname in moddesc['commands']: + attrs[cname] = Command(cname, modname, self) + mobj = type('M_%s' % modname, (Module,), attrs)(modname, self) + if 'status' in mobj._parameters: + self.register_callback((modname, 'status'), updateEvent=mobj._status_value_update) + self.register_callback((modname, 'value'), updateEvent=mobj._status_value_update) + + setattr(main, modname, mobj) + self.log.info('%s', USAGE) From ab2fe6200aaf778837bfcf6bd15a24437a4280ee Mon Sep 17 00:00:00 2001 From: Markus Zolliker Date: Wed, 23 Mar 2022 13:53:46 +0100 Subject: [PATCH 10/22] reintroduced individual init of generalConfig.defaults revert basically the former change "init generalConfig.defaults only in secop-server" The problem of import order when setting generalConfig.defaults has to be solved by not overriding already existing keys when setting the default. Change-Id: I82121e346607dd74146279c4241e13ab63c14096 Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/28011 Tested-by: Jenkins Automated Tests Reviewed-by: Enrico Faulhaber Reviewed-by: Markus Zolliker From 33a7c56fa22dce60d1b8d9efaab61ae9cb10c2c5 Mon Sep 17 00:00:00 2001 From: Markus Zolliker Date: Wed, 25 May 2022 09:23:16 +0200 Subject: [PATCH 11/22] allow to convert numpy arrays to ArrayOf accept all sequences instead of just tuple / list + change Module.announceUpdate to convert value before comparing with previous one (comparing will not work with numpy arrays) Change-Id: I5eceef4297607107e2dde688af2833d3651a8775 Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/28525 Tested-by: Markus Zolliker Reviewed-by: Markus Zolliker --- secop/datatypes.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/secop/datatypes.py b/secop/datatypes.py index 3f5f3df..220a3a9 100644 --- a/secop/datatypes.py +++ b/secop/datatypes.py @@ -760,7 +760,7 @@ class ArrayOf(DataType): def __call__(self, value): """validate an external representation to an internal one""" - if isinstance(value, (tuple, list)): + try: # check number of elements if self.minlen is not None and len(value) < self.minlen: raise BadValueError( @@ -771,8 +771,9 @@ class ArrayOf(DataType): 'Array too big, holds at most %d elements!' % self.minlen) # apply subtype valiation to all elements and return as list return tuple(self.members(elem) for elem in value) - raise BadValueError( - 'Can not convert %s to ArrayOf DataType!' % repr(value)) + except TypeError: + raise BadValueError('%s can not be converted to ArrayOf DataType!' + % type(value).__name__) from None def export_value(self, value): """returns a python object fit for serialisation""" From 7b9c099321507900b556508d40002a0a54e597f2 Mon Sep 17 00:00:00 2001 From: Enrico Faulhaber Date: Mon, 1 Aug 2022 16:40:45 +0200 Subject: [PATCH 12/22] default unit to UTF8 Change-Id: Ic958346beb1a3b164c8d7b2826d59cf7e3991e15 Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/28946 Tested-by: Jenkins Automated Tests Tested-by: Enrico Faulhaber Reviewed-by: Markus Zolliker Reviewed-by: Enrico Faulhaber --- secop/datatypes.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/secop/datatypes.py b/secop/datatypes.py index 220a3a9..5da9a99 100644 --- a/secop/datatypes.py +++ b/secop/datatypes.py @@ -130,10 +130,11 @@ class Stub(DataType): this workaround because datatypes need properties with datatypes defined later """ - def __init__(self, datatype_name, *args): + def __init__(self, datatype_name, *args, **kwds): super().__init__() self.name = datatype_name self.args = args + self.kwds = kwds def __call__(self, value): """validate""" @@ -151,7 +152,7 @@ class Stub(DataType): for prop in dtcls.propertyDict.values(): stub = prop.datatype if isinstance(stub, cls): - prop.datatype = globals()[stub.name](*stub.args) + prop.datatype = globals()[stub.name](*stub.args, **stub.kwds) # SECoP types: @@ -165,7 +166,7 @@ class FloatRange(DataType): """ min = Property('low limit', Stub('FloatRange'), extname='min', default=-sys.float_info.max) max = Property('high limit', Stub('FloatRange'), extname='max', default=sys.float_info.max) - unit = Property('physical unit', Stub('StringType'), extname='unit', default='') + unit = Property('physical unit', Stub('StringType', isUTF8=True), extname='unit', default='') fmtstr = Property('format string', Stub('StringType'), extname='fmtstr', default='%g') absolute_resolution = Property('absolute resolution', Stub('FloatRange', 0), extname='absolute_resolution', default=0.0) @@ -343,7 +344,7 @@ class ScaledInteger(DataType): scale = Property('scale factor', FloatRange(sys.float_info.min), extname='scale', mandatory=True) min = Property('low limit', FloatRange(), extname='min', mandatory=True) max = Property('high limit', FloatRange(), extname='max', mandatory=True) - unit = Property('physical unit', Stub('StringType'), extname='unit', default='') + unit = Property('physical unit', Stub('StringType', isUTF8=True), extname='unit', default='') fmtstr = Property('format string', Stub('StringType'), extname='fmtstr', default='%g') absolute_resolution = Property('absolute resolution', FloatRange(0), extname='absolute_resolution', default=0.0) From 21bcc7ce981c954fa24282396abfe683b0b3875f Mon Sep 17 00:00:00 2001 From: Markus Zolliker Date: Wed, 1 Jun 2022 16:19:27 +0200 Subject: [PATCH 13/22] an enum with value 0 should be interpreted as False for example: bool(Enum(off=0, on=1)('off')) is False Change-Id: Ieb200b4ecf0eed50b657ecc00f73a69810ad828f Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/28586 Tested-by: Jenkins Automated Tests Reviewed-by: Enrico Faulhaber Reviewed-by: Markus Zolliker --- secop/lib/enum.py | 11 +++++++---- test/test_lib_enum.py | 6 ++++++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/secop/lib/enum.py b/secop/lib/enum.py index 0fb0b38..2bdcf1c 100644 --- a/secop/lib/enum.py +++ b/secop/lib/enum.py @@ -106,6 +106,9 @@ class EnumMember: def __repr__(self): return '<%s%s (%d)>' % (self.enum.name + '.' if self.enum.name else '', self.name, self.value) + def __bool__(self): + return bool(self.value) + # numeric operations: delegate to int. Do we really need any of those? def __add__(self, other): return self.value.__add__(other.value if isinstance(other, EnumMember) else other) @@ -242,7 +245,7 @@ class Enum(dict): name = '' def __init__(self, name='', parent=None, **kwds): - super(Enum, self).__init__() + super().__init__() if isinstance(name, (dict, Enum)) and parent is None: # swap if only parent is given as positional argument name, parent = '', name @@ -309,17 +312,17 @@ class Enum(dict): try: return self[key] except KeyError as e: - raise AttributeError(str(e)) + raise AttributeError(str(e)) from None def __setattr__(self, key, value): if self.name and key != 'name': raise TypeError('Enum %r can not be changed!' % self.name) - super(Enum, self).__setattr__(key, value) + super().__setattr__(key, value) def __setitem__(self, key, value): if self.name: raise TypeError('Enum %r can not be changed!' % self.name) - super(Enum, self).__setitem__(key, value) + super().__setitem__(key, value) def __delitem__(self, key): raise TypeError('Enum %r can not be changed!' % self.name) diff --git a/test/test_lib_enum.py b/test/test_lib_enum.py index 97228e1..7077834 100644 --- a/test/test_lib_enum.py +++ b/test/test_lib_enum.py @@ -77,3 +77,9 @@ def test_Enum(): assert e3.c >= e2.a assert e3.b <= e2.b assert Enum({'self': 0, 'other': 1})('self') == 0 + + +def test_Enum_bool(): + e = Enum('OffOn', off=0, on=1) + assert bool(e(0)) is False + assert bool(e(1)) is True From db43a77614630a6c26c964b235c36876eb316a86 Mon Sep 17 00:00:00 2001 From: Markus Zolliker Date: Tue, 16 Aug 2022 17:17:54 +0200 Subject: [PATCH 14/22] remove some log.debug statements in order to sync with frappy@mlz Change-Id: Iab89cb313fb6969c91663b8ebc56bdcb96ed2dd1 --- secop/lib/statemachine.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/secop/lib/statemachine.py b/secop/lib/statemachine.py index 6ed94c6..309cabf 100644 --- a/secop/lib/statemachine.py +++ b/secop/lib/statemachine.py @@ -186,7 +186,6 @@ class StateMachine: ret = self.state(self) self.init = False if self.stopped: - self.log.debug('%r', self.stopped) self.last_error = self.stopped self.cleanup(self) self.stopped = False @@ -269,7 +268,6 @@ class StateMachine: self.stopped = Restart with self._lock: # wait for running cycle finished if self.stopped: # cleanup is not yet done - self.log.debug('restart') self.last_error = self.stopped self.cleanup(self) # ignore return state on restart self.stopped = False From aa0c0421c345fba19287a2f795426fb05e70a5a1 Mon Sep 17 00:00:00 2001 From: boa Date: Fri, 19 Aug 2022 12:43:36 +0200 Subject: [PATCH 15/22] add Be-Filter addon for boa --- cfg/addons/be-filter-boa.cfg | 14 ++++++++++++++ cfg/sea/be-filter-boa.addon.json | 19 +++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 cfg/addons/be-filter-boa.cfg create mode 100644 cfg/sea/be-filter-boa.addon.json diff --git a/cfg/addons/be-filter-boa.cfg b/cfg/addons/be-filter-boa.cfg new file mode 100644 index 0000000..304c4be --- /dev/null +++ b/cfg/addons/be-filter-boa.cfg @@ -0,0 +1,14 @@ +[NODE] +description = CryoTel be-filter BOA +id = be-filter-boa.addon.sea.psi.ch + +[sea_addons] +class = secop_psi.sea.SeaClient +description = addons sea connection for be-filter-boa.addon +config = be-filter-boa.addon +service = addons + +[befilter] +class = secop_psi.sea.SeaReadable +iodev = sea_addons +sea_object = befilter diff --git a/cfg/sea/be-filter-boa.addon.json b/cfg/sea/be-filter-boa.addon.json new file mode 100644 index 0000000..c170c4d --- /dev/null +++ b/cfg/sea/be-filter-boa.addon.json @@ -0,0 +1,19 @@ +{"befilter": {"base": "/befilter", "params": [ +{"path": "", "type": "float", "kids": 12}, +{"path": "send", "type": "text", "readonly": false, "cmd": "befilter send", "visibility": 3}, +{"path": "status", "type": "text", "visibility": 3}, +{"path": "cool", "type": "enum", "enum": {"on": 0, "off": 1}, "readonly": false, "cmd": "befilter cool"}, +{"path": "control", "type": "enum", "enum": {"auto_power": 1, "manual_power": 0, "controlled_T": 2}, "readonly": false, "cmd": "befilter control", "description": "recommended mode: auto_power, use coolpower or holdpower depending on T"}, +{"path": "set", "type": "float", "readonly": false, "cmd": "befilter set"}, +{"path": "setpower", "type": "float", "readonly": false, "cmd": "befilter setpower", "visibility": 3}, +{"path": "coolpower", "type": "float", "readonly": false, "cmd": "befilter coolpower", "visibility": 3}, +{"path": "holdpower", "type": "float", "readonly": false, "cmd": "befilter holdpower", "visibility": 3}, +{"path": "cool_threshold", "type": "float", "readonly": false, "cmd": "befilter cool_threshold", "description": "switch to coolpower above this value", "visibility": 3}, +{"path": "hold_threshold", "type": "float", "readonly": false, "cmd": "befilter hold_threshold", "description": "switch to holdpower below this value", "visibility": 3}, +{"path": "power", "type": "float"}, +{"path": "filter", "type": "none", "kids": 5}, +{"path": "filter/period", "type": "float", "readonly": false, "cmd": "befilter filter/period", "description": "oszillation period / sec"}, +{"path": "filter/amplitude", "type": "float", "readonly": false, "cmd": "befilter filter/amplitude", "description": "oszillation amplitude / K (+/-)"}, +{"path": "filter/precision", "type": "float", "readonly": false, "cmd": "befilter filter/precision"}, +{"path": "filter/raw", "type": "float"}, +{"path": "filter/intdif", "type": "float"}]}} From 292d028fe6e14d1bd2a986accc2777e5fd0affb2 Mon Sep 17 00:00:00 2001 From: dmc Date: Mon, 22 Aug 2022 15:55:58 +0200 Subject: [PATCH 16/22] add ill5 p sample stick --- cfg/stick/ill5p.cfg | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 cfg/stick/ill5p.cfg diff --git a/cfg/stick/ill5p.cfg b/cfg/stick/ill5p.cfg new file mode 100644 index 0000000..12f04ee --- /dev/null +++ b/cfg/stick/ill5p.cfg @@ -0,0 +1,16 @@ +[NODE] +description = ILL5 sample stick for pressure cells +id = ill5p.stick.sea.psi.ch + +[sea_stick] +class = secop_psi.sea.SeaClient +description = stick SEA connection to ill5p.stick +config = ill5p.stick +service = stick + +[ts] +class = secop_psi.sea.SeaReadable +io = sea_stick +sea_object = tt +json_file = ill5.config.json +rel_paths = ts From ea960f2250e30d11443d26e6200ce051d85123c9 Mon Sep 17 00:00:00 2001 From: l_samenv Date: Tue, 23 Aug 2022 17:21:01 +0200 Subject: [PATCH 17/22] fix ln2fill enum --- cfg/sea/ill1.config.json | 2 +- cfg/sea/ill5pgas5.config.json | 2 +- cfg/sea/ma02.config.json | 2 +- cfg/sea/ma10.config.json | 2 +- cfg/sea/ma11.config.json | 6 ++++-- cfg/sea/ma6.config.json | 4 ++-- cfg/sea/ma7.config.json | 4 ++-- cfg/sea/ori4.config.json | 2 +- cfg/sea/ori6.config.json | 2 +- 9 files changed, 14 insertions(+), 12 deletions(-) diff --git a/cfg/sea/ill1.config.json b/cfg/sea/ill1.config.json index e5c6d60..c960299 100644 --- a/cfg/sea/ill1.config.json +++ b/cfg/sea/ill1.config.json @@ -219,7 +219,7 @@ {"path": "calib/mbar_offset", "type": "float", "readonly": false, "cmd": "nv calib/mbar_offset"}]}, "ln2fill": {"base": "/ln2fill", "params": [ -{"path": "", "type": "enum", "enum": {"no fill valve": 2}, "readonly": false, "cmd": "ln2fill", "kids": 3}, +{"path": "", "type": "enum", "enum": {"watching": 0, "fill": 1, "inactive": 2}, "readonly": false, "cmd": "ln2fill", "kids": 3}, {"path": "send", "type": "text", "readonly": false, "cmd": "ln2fill send", "visibility": 3}, {"path": "status", "type": "text", "visibility": 3}, {"path": "state", "type": "text"}]}, diff --git a/cfg/sea/ill5pgas5.config.json b/cfg/sea/ill5pgas5.config.json index 741c1f8..35a52ad 100644 --- a/cfg/sea/ill5pgas5.config.json +++ b/cfg/sea/ill5pgas5.config.json @@ -282,7 +282,7 @@ {"path": "calib/mbar_offset", "type": "float", "readonly": false, "cmd": "nv calib/mbar_offset"}]}, "ln2fill": {"base": "/ln2fill", "params": [ -{"path": "", "type": "enum", "enum": {"no fill valve": 2}, "readonly": false, "cmd": "ln2fill", "kids": 3}, +{"path": "", "type": "enum", "enum": {"watching": 0, "fill": 1, "inactive": 2}, "readonly": false, "cmd": "ln2fill", "kids": 3}, {"path": "send", "type": "text", "readonly": false, "cmd": "ln2fill send", "visibility": 3}, {"path": "status", "type": "text", "visibility": 3}, {"path": "state", "type": "text"}]}, diff --git a/cfg/sea/ma02.config.json b/cfg/sea/ma02.config.json index af757bc..d13c63c 100644 --- a/cfg/sea/ma02.config.json +++ b/cfg/sea/ma02.config.json @@ -305,7 +305,7 @@ {"path": "mode", "type": "enum", "enum": {"slow": 0, "fast (switches to slow automatically after filling)": 1}, "readonly": false, "cmd": "lev mode"}]}, "hefill": {"base": "/hefill", "params": [ -{"path": "", "type": "enum", "enum": {"no fill valve": 2}, "readonly": false, "cmd": "hefill", "kids": 16}, +{"path": "", "type": "enum", "enum": {"watching": 0, "fill": 1, "inactive": 2}, "readonly": false, "cmd": "hefill", "kids": 16}, {"path": "send", "type": "text", "readonly": false, "cmd": "hefill send", "visibility": 3}, {"path": "status", "type": "text", "visibility": 3}, {"path": "state", "type": "text"}, diff --git a/cfg/sea/ma10.config.json b/cfg/sea/ma10.config.json index 53a232e..f5ce954 100644 --- a/cfg/sea/ma10.config.json +++ b/cfg/sea/ma10.config.json @@ -346,7 +346,7 @@ {"path": "tubecoolingminutes", "type": "float", "readonly": false, "cmd": "ln2fill tubecoolingminutes"}]}, "hefill": {"base": "/hefill", "params": [ -{"path": "", "type": "enum", "enum": {"no fill valve": 2}, "readonly": false, "cmd": "hefill", "kids": 16}, +{"path": "", "type": "enum", "enum": {"watching": 0, "fill": 1, "inactive": 2}, "readonly": false, "cmd": "hefill", "kids": 16}, {"path": "send", "type": "text", "readonly": false, "cmd": "hefill send", "visibility": 3}, {"path": "status", "type": "text", "visibility": 3}, {"path": "state", "type": "text"}, diff --git a/cfg/sea/ma11.config.json b/cfg/sea/ma11.config.json index 126e3d7..9cc5b5e 100644 --- a/cfg/sea/ma11.config.json +++ b/cfg/sea/ma11.config.json @@ -269,7 +269,9 @@ {"path": "pullup", "type": "float", "readonly": false, "cmd": "hemot pullup"}, {"path": "eeprom", "type": "enum", "enum": {"ok": 0, "dirty": 1, "save": 2, "load": 3}, "readonly": false, "cmd": "hemot eeprom"}, {"path": "customadr", "type": "text", "readonly": false, "cmd": "hemot customadr"}, -{"path": "custompar", "type": "float", "readonly": false, "cmd": "hemot custompar"}]}, "ln2fill": {"base": "/ln2fill", "params": [{"path": "", "type": "enum", "enum": {"no fill valve": 2}, "readonly": false, "cmd": "ln2fill", "kids": 14}, +{"path": "custompar", "type": "float", "readonly": false, "cmd": "hemot custompar"}]}, +"ln2fill": {"base": "/ln2fill", "params": [ +{"path": "", "type": "enum", "enum": {"watching": 0, "fill": 1, "inactive": 2}, "readonly": false, "cmd": "ln2fill", "kids": 14}, {"path": "send", "type": "text", "readonly": false, "cmd": "ln2fill send", "visibility": 3}, {"path": "status", "type": "text", "visibility": 3}, {"path": "state", "type": "text"}, @@ -283,7 +285,7 @@ {"path": "maxholdhours", "type": "float", "readonly": false, "cmd": "ln2fill maxholdhours"}, {"path": "tolerance", "type": "float", "readonly": false, "cmd": "ln2fill tolerance"}, {"path": "badreadingminutes", "type": "float", "readonly": false, "cmd": "ln2fill badreadingminutes"}, -{"path": "tubecoolingminutes", "type": "float", "readonly": false, "cmd": "ln2fill tubecoolingminutes"}]}, "hefill": {"base": "/hefill", "params": [{"path": "", "type": "enum", "enum": {"no fill valve": 2}, "readonly": false, "cmd": "hefill", "kids": 16}, +{"path": "tubecoolingminutes", "type": "float", "readonly": false, "cmd": "ln2fill tubecoolingminutes"}]}, "hefill": {"base": "/hefill", "params": [{"path": "", "type": "enum", "enum": {"watching": 0, "fill": 1, "inactive": 2}, "readonly": false, "cmd": "hefill", "kids": 16}, {"path": "send", "type": "text", "readonly": false, "cmd": "hefill send", "visibility": 3}, {"path": "status", "type": "text", "visibility": 3}, {"path": "state", "type": "text"}, diff --git a/cfg/sea/ma6.config.json b/cfg/sea/ma6.config.json index b16c12c..0ebe15e 100644 --- a/cfg/sea/ma6.config.json +++ b/cfg/sea/ma6.config.json @@ -281,7 +281,7 @@ {"path": "custompar", "type": "float", "readonly": false, "cmd": "hemot custompar"}]}, "ln2fill": {"base": "/ln2fill", "params": [ -{"path": "", "type": "enum", "enum": {"no fill valve": 2}, "readonly": false, "cmd": "ln2fill", "kids": 14}, +{"path": "", "type": "enum", "enum": {"watching": 0, "fill": 1, "inactive": 2}, "readonly": false, "cmd": "ln2fill", "kids": 14}, {"path": "send", "type": "text", "readonly": false, "cmd": "ln2fill send", "visibility": 3}, {"path": "status", "type": "text", "visibility": 3}, {"path": "state", "type": "text"}, @@ -298,7 +298,7 @@ {"path": "tubecoolingminutes", "type": "float", "readonly": false, "cmd": "ln2fill tubecoolingminutes"}]}, "hefill": {"base": "/hefill", "params": [ -{"path": "", "type": "enum", "enum": {"no fill valve": 2}, "readonly": false, "cmd": "hefill", "kids": 16}, +{"path": "", "type": "enum", "enum": {"watching": 0, "fill": 1, "inactive": 2}, "readonly": false, "cmd": "hefill", "kids": 16}, {"path": "send", "type": "text", "readonly": false, "cmd": "hefill send", "visibility": 3}, {"path": "status", "type": "text", "visibility": 3}, {"path": "state", "type": "text"}, diff --git a/cfg/sea/ma7.config.json b/cfg/sea/ma7.config.json index 470a38c..74d2e2f 100644 --- a/cfg/sea/ma7.config.json +++ b/cfg/sea/ma7.config.json @@ -208,7 +208,7 @@ {"path": "autoflow/flowtarget", "type": "float"}, {"path": "calib", "type": "none", "kids": 2}, {"path": "calib/ln_per_min_per_mbar", "type": "float", "readonly": false, "cmd": "nv calib/ln_per_min_per_mbar"}, -{"path": "calib/mbar_offset", "type": "float", "readonly": false, "cmd": "nv calib/mbar_offset"}]}, "hefill": {"base": "/hefill", "params": [{"path": "", "type": "enum", "enum": {"no fill valve": 2}, "readonly": false, "cmd": "hefill", "kids": 16}, +{"path": "calib/mbar_offset", "type": "float", "readonly": false, "cmd": "nv calib/mbar_offset"}]}, "hefill": {"base": "/hefill", "params": [{"path": "", "type": "enum", "enum": {"watching": 0, "fill": 1, "inactive": 2}, "readonly": false, "cmd": "hefill", "kids": 16}, {"path": "send", "type": "text", "readonly": false, "cmd": "hefill send", "visibility": 3}, {"path": "status", "type": "text", "visibility": 3}, {"path": "state", "type": "text"}, @@ -264,7 +264,7 @@ {"path": "nopumpfeedback", "type": "bool", "readonly": false, "cmd": "hemot nopumpfeedback"}, {"path": "eeprom", "type": "enum", "enum": {"ok": 0, "dirty": 1, "save": 2, "load": 3}, "readonly": false, "cmd": "hemot eeprom"}, {"path": "customadr", "type": "text", "readonly": false, "cmd": "hemot customadr"}, -{"path": "custompar", "type": "float", "readonly": false, "cmd": "hemot custompar"}]}, "ln2fill": {"base": "/ln2fill", "params": [{"path": "", "type": "enum", "enum": {"no fill valve": 2}, "readonly": false, "cmd": "ln2fill", "kids": 14}, +{"path": "custompar", "type": "float", "readonly": false, "cmd": "hemot custompar"}]}, "ln2fill": {"base": "/ln2fill", "params": [{"path": "", "type": "enum", "enum": {"watching": 0, "fill": 1, "inactive": 2}, "readonly": false, "cmd": "ln2fill", "kids": 14}, {"path": "send", "type": "text", "readonly": false, "cmd": "ln2fill send", "visibility": 3}, {"path": "status", "type": "text", "visibility": 3}, {"path": "state", "type": "text"}, diff --git a/cfg/sea/ori4.config.json b/cfg/sea/ori4.config.json index 8b881f2..b1e84ae 100644 --- a/cfg/sea/ori4.config.json +++ b/cfg/sea/ori4.config.json @@ -234,7 +234,7 @@ {"path": "custompar", "type": "float", "readonly": false, "cmd": "nvmot custompar"}]}, "ln2fill": {"base": "/ln2fill", "params": [{"path": "", "type": "enum", "enum": {"watching": 0, "fill": 1, "inactive": 2}, "readonly": false, "cmd": "ln2fill", "kids": 3}, {"path": "send", "type": "text", "readonly": false, "cmd": "ln2fill send", "visibility": 3}, {"path": "status", "type": "text", "visibility": 3}, -{"path": "state", "type": "text"}]}, "hefill": {"base": "/hefill", "params": [{"path": "", "type": "enum", "enum": {"no fill valve": 2}, "readonly": false, "cmd": "hefill", "kids": 6}, +{"path": "state", "type": "text"}]}, "hefill": {"base": "/hefill", "params": [{"path": "", "type": "enum", "enum": {"watching": 0, "fill": 1, "inactive": 2}, "readonly": false, "cmd": "hefill", "kids": 6}, {"path": "send", "type": "text", "readonly": false, "cmd": "hefill send", "visibility": 3}, {"path": "status", "type": "text", "visibility": 3}, {"path": "fast", "type": "enum", "enum": {"slow": 0, "fast": 1}, "readonly": false, "cmd": "cc hf"}, diff --git a/cfg/sea/ori6.config.json b/cfg/sea/ori6.config.json index d892321..45d102b 100644 --- a/cfg/sea/ori6.config.json +++ b/cfg/sea/ori6.config.json @@ -217,7 +217,7 @@ {"path": "calib/mbar_offset", "type": "float", "readonly": false, "cmd": "nv calib/mbar_offset"}]}, "ln2fill": {"base": "/ln2fill", "params": [ -{"path": "", "type": "enum", "enum": {"no fill valve": 2}, "readonly": false, "cmd": "ln2fill", "kids": 3}, +{"path": "", "type": "enum", "enum": {"watching": 0, "fill": 1, "inactive": 2}, "readonly": false, "cmd": "ln2fill", "kids": 3}, {"path": "send", "type": "text", "readonly": false, "cmd": "ln2fill send", "visibility": 3}, {"path": "status", "type": "text", "visibility": 3}, {"path": "state", "type": "text"}]}, From 2cd66c2e084a6f121834e2a69032abdba058ea82 Mon Sep 17 00:00:00 2001 From: l_samenv Date: Wed, 24 Aug 2022 16:57:27 +0200 Subject: [PATCH 18/22] sea: allow multiple parameters being updated with one hdb path --- secop_psi/sea.py | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/secop_psi/sea.py b/secop_psi/sea.py index 749207c..d16bfad 100644 --- a/secop_psi/sea.py +++ b/secop_psi/sea.py @@ -121,7 +121,7 @@ class SeaClient(ProxyClient, Module): if port is None: raise ConfigError('missing sea port for %s' % instance) opts['uri'] = 'tcp://localhost:%s' % port - self.objects = [] + self.objects = set() self.shutdown = False self.path2param = {} self._write_lock = threading.Lock() @@ -134,8 +134,9 @@ class SeaClient(ProxyClient, Module): Module.__init__(self, name, log, opts, srv) def register_obj(self, module, obj): - self.objects.append(obj) - self.path2param.update(module.path2param) + self.objects.add(obj) + for k, v in module.path2param.items(): + self.path2param.setdefault(k, []).extend(v) self.register_callback(module.name, module.updateEvent) def startModule(self, start_events): @@ -272,9 +273,8 @@ class SeaClient(ProxyClient, Module): readerror = HardwareError(value) path = path.rsplit('.', 1)[0] value = None - try: - module, param = self.path2param[path] - except KeyError: + mplist = self.path2param.get(path) + if mplist is None: if path.startswith('/device'): if path == '/device/changetime': result = self.request('check_config %s %s' % (self.service, self.config)) @@ -284,15 +284,14 @@ class SeaClient(ProxyClient, Module): self.DISPATCHER.shutdown() elif path.startswith('/device/frappy_%s' % self.service) and value == '': self.DISPATCHER.shutdown() - # print('UNUSED', msg) - continue # unused parameter - oldv, oldt, oldr = self.cache.get((module, param), [None, None, None]) - if value is None: - value = oldv - if value != oldv or str(readerror) != str(oldr) or abs(now - oldt) > 60: - # do not update unchanged values within 60 sec - self.updateValue(module, param, value, now, readerror) - + else: + for module, param in mplist: + oldv, oldt, oldr = self.cache.get((module, param), [None, None, None]) + if value is None: + value = oldv + if value != oldv or str(readerror) != str(oldr) or abs(now - oldt) > 60: + # do not update unchanged values within 60 sec + self.updateValue(module, param, value, now, readerror) @Command(StringType(), result=StringType()) def communicate(self, command): @@ -453,8 +452,8 @@ class SeaModule(Module): include = True for paramdesc in descr['params']: path = paramdesc['path'] - if path.endswith('is_running'): - # take this always + if path.endswith('is_running') and issubclass(cls, Drivable): + # take this independent of visibility is_running = paramdesc continue if paramdesc.get('visibility', 1) > visibility_level: @@ -550,7 +549,7 @@ class SeaModule(Module): if key in extra_module_set: extra_modules[name + '.' + key] = sea_object, base, paramdesc continue # skip this parameter - path2param[hdbpath] = (name, key) + path2param.setdefault(hdbpath, []).append((name, key)) attributes[key] = pobj # if hasattr(cls, 'read_' + key): # print('override %s.read_%s' % (cls.__name__, key)) From 6929422b948f3cdf4a64b158097d2883feb7e7c2 Mon Sep 17 00:00:00 2001 From: Markus Zolliker Date: Wed, 24 Aug 2022 17:02:21 +0200 Subject: [PATCH 19/22] fox update of param2path dict Change-Id: Ie8de3d7f549ba29954058f3d516d1c3965932aa0 --- secop_psi/sea.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/secop_psi/sea.py b/secop_psi/sea.py index d16bfad..a91f798 100644 --- a/secop_psi/sea.py +++ b/secop_psi/sea.py @@ -136,7 +136,7 @@ class SeaClient(ProxyClient, Module): def register_obj(self, module, obj): self.objects.add(obj) for k, v in module.path2param.items(): - self.path2param.setdefault(k, []).extend(v) + self.path2param.setdefault(k, []).extend(v) self.register_callback(module.name, module.updateEvent) def startModule(self, start_events): From 9a40d27354746936f791c919526ce28225206b39 Mon Sep 17 00:00:00 2001 From: Markus Zolliker Date: Wed, 7 Sep 2022 13:10:37 +0200 Subject: [PATCH 20/22] fix bug in ls340res return value must be converted to float --- secop_psi/ls340res.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/secop_psi/ls340res.py b/secop_psi/ls340res.py index 8bf37be..5709f34 100644 --- a/secop_psi/ls340res.py +++ b/secop_psi/ls340res.py @@ -42,4 +42,4 @@ class ResChannel(HasIodev, Readable): channel = Property('the channel A,B,C or D', StringType()) def read_value(self): - return self._iodev.communicate('SRDG?%s' % self.channel) + return float(self._iodev.communicate('SRDG?%s' % self.channel)) From ada4c43ebf4949a9da6627297fe1ba557aa507a9 Mon Sep 17 00:00:00 2001 From: Markus Zolliker Date: Wed, 7 Sep 2022 13:11:42 +0200 Subject: [PATCH 21/22] change max force to 190 N --- secop_psi/uniax.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/secop_psi/uniax.py b/secop_psi/uniax.py index ba555c8..bd97ab7 100644 --- a/secop_psi/uniax.py +++ b/secop_psi/uniax.py @@ -32,7 +32,7 @@ class Uniax(PersistentMixin, Drivable): value = Parameter(unit='N') motor = Attached() transducer = Attached() - limit = Parameter('abs limit of force', FloatRange(0, 150, unit='N'), readonly=False, default=150) + limit = Parameter('abs limit of force', FloatRange(0, 190, unit='N'), readonly=False, default=150) tolerance = Parameter('force tolerance', FloatRange(0, 10, unit='N'), readonly=False, default=0.1) slope = PersistentParam('spring constant', FloatRange(unit='deg/N'), readonly=False, default=0.5, persistent='auto') @@ -41,7 +41,7 @@ class Uniax(PersistentMixin, Drivable): current_step = Parameter('', FloatRange(unit='deg'), default=0) force_offset = PersistentParam('transducer offset', FloatRange(unit='N'), readonly=False, default=0, initwrite=True, persistent='auto') - hysteresis = PersistentParam('force hysteresis', FloatRange(0, 150, unit='N'), readonly=False, default=5, + hysteresis = PersistentParam('force hysteresis', FloatRange(0, 190, unit='N'), readonly=False, default=5, persistent='auto') adjusting = Parameter('', BoolType(), readonly=False, default=False, initwrite=True) adjusting_current = PersistentParam('current when adjusting force', FloatRange(0, 2.8, unit='A'), readonly=False, From 95eb4e969a1ec37f5b4babc8707744125a90f3bf Mon Sep 17 00:00:00 2001 From: Markus Zolliker Date: Wed, 7 Sep 2022 13:13:59 +0200 Subject: [PATCH 22/22] change safe current to 0.3, set offset to 15 --- cfg/uniax.cfg | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cfg/uniax.cfg b/cfg/uniax.cfg index 9a03b8b..c1cbf18 100644 --- a/cfg/uniax.cfg +++ b/cfg/uniax.cfg @@ -10,6 +10,7 @@ description = force control class = secop_psi.uniax.Uniax motor = drv transducer = transducer +force_offset = 15 #[drv_io] #description = @@ -23,10 +24,10 @@ class = secop_psi.trinamic.Motor # io = drv_io uri = tcp://192.168.127.254:3002 standby_current=0.1 -maxcurrent=0.2 +maxcurrent=0.3 acceleration=150. move_limit=5 -safe_current=0.2 +safe_current=0.3 speed=40 encoder_tolerance=3.6 free_wheeling=0.1 @@ -39,6 +40,7 @@ class = secop_psi.dpm.DPM3 uri = tcp://192.168.127.254:3001 digits = 2 scale_factor = 0.0156 +offset = 15 [res] description = temperature on uniax stick