1 Commits
paul ... tmp

Author SHA1 Message Date
a930dc8f6a temporary state at PPMS as of 2024-01-26 2024-01-29 08:29:25 +01:00
215 changed files with 3165 additions and 9984 deletions

View File

@ -1,5 +1,6 @@
#!/usr/bin/env python
# pylint: disable=invalid-name
# -*- coding: utf-8 -*-
# *****************************************************************************
#
# This program is free software; you can redistribute it and/or modify it under

View File

@ -1,4 +1,5 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# *****************************************************************************
# Copyright (c) 2015-2016 by the authors, see LICENSE
#

View File

@ -1,5 +1,6 @@
#!/usr/bin/env python3
# pylint: disable=invalid-name
# -*- coding: utf-8 -*-
# *****************************************************************************
# Copyright (c) 2015-2016 by the authors, see LICENSE
#

View File

@ -1,4 +1,5 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# *****************************************************************************
# Copyright (c) 2015-2016 by the authors, see LICENSE
#

View File

@ -1,4 +1,5 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# *****************************************************************************
#
# This program is free software; you can redistribute it and/or modify it under

View File

@ -1,5 +1,6 @@
#!/usr/bin/env python3
# pylint: disable=invalid-name
# -*- 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

View File

@ -1,22 +0,0 @@
import sys
import os
from glob import glob
from frappy_psi.calcurve import CalCurve
os.chdir('/Users/zolliker/gitpsi/calcurves')
if len(sys.argv) > 1:
calib = sys.argv[1]
c = CalCurve(calib)
else:
for file in sorted(glob('*.*')):
if file.endswith('.md') or file.endswith('.std'):
continue
try:
c = CalCurve(file)
xy = c.export()
print('%9.4g %12.7g %9.4g %9.4g %s' % (tuple(c.extx) + tuple(c.exty) + (file,)))
except Exception as e:
print(file, e)
calib = file

View File

@ -24,7 +24,6 @@ Mod('ts_low',
minrange=13,
range=22,
tolerance = 0.1,
vexc = 3,
htrrng=4,
)
@ -33,8 +32,7 @@ Mod('ts_high',
'sample Cernox',
channel = 1,
switcher = 'lsc_channel',
minrange=11,
vexc = 5,
minrange=9,
range=22,
tolerance = 0.1,
htrrng=5,
@ -47,8 +45,6 @@ Mod('ts',
value=Param(unit='K'),
low='ts_low',
high='ts_high',
#min_high=0.6035,
#max_low=1.6965,
min_high=0.6,
max_low=1.7,
tolerance=0.1,

View File

@ -74,10 +74,10 @@ Mod('currentsource',
Mod('mf',
'frappy_mlz.amagnet.GarfieldMagnet',
'magnetic field module, handling polarity switching and stuff',
currentsource = 'currentsource',
enable = 'enable',
polswitch = 'polarity',
symmetry = 'symmetry',
subdev_currentsource = 'currentsource',
subdev_enable = 'enable',
subdev_polswitch = 'polarity',
subdev_symmetry = 'symmetry',
target = Param(unit='T'),
value = Param(unit='T'),
userlimits = (-0.35, 0.35),

View File

@ -1,19 +0,0 @@
Node('attocube_test.psi.ch',
'a single attocube axis',
interface='tcp://5000',
)
Mod('r',
'frappy_psi.attocube.Axis',
'ANRv220-F3-02882',
axis = 1,
value = Param(unit='deg'),
tolerance = 0.1,
target_min = 0,
target_max = 360,
steps_fwd = 45,
steps_bwd = 85,
step_mode = True,
# gear = 1.2,
)

View File

@ -41,6 +41,6 @@ Mod('label',
'frappy_demo.modules.Label',
'some label indicating the state of the magnet `mf`.',
system = 'Cryomagnet MX15',
mf = 'mf',
ts = 'ts',
subdev_mf = 'mf',
subdev_ts = 'ts',
)

View File

@ -1,231 +0,0 @@
Node('cfg/dilsc1.cfg',
'triton test',
interface='5000',
name='dilsc1',
)
Mod('triton',
'frappy_psi.mercury.IO',
'connection to triton software',
uri='tcp://192.168.2.33:33576',
)
Mod('T_mix',
'frappy_psi.triton.TemperatureSensor',
'mix. chamber temperature',
slot='T8',
io='triton',
)
Mod('T_pt2head',
'frappy_psi.triton.TemperatureSensor',
'PTR2 head temperature',
slot='T1',
io='triton',
)
Mod('T_pt2plate',
'frappy_psi.triton.TemperatureSensor',
'PTR2 plate temperature',
slot='T2',
io='triton',
)
Mod('T_still',
'frappy_psi.triton.TemperatureSensor',
'still temperature',
slot='T3',
io='triton',
)
Mod('htr_still',
'frappy_psi.triton.HeaterOutput',
'still heater',
slot='H2',
io='triton',
)
Mod('T_coldpl',
'frappy_psi.triton.TemperatureSensor',
'cold plate temperature',
slot='T4',
io='triton',
)
Mod('T_mixcx',
'frappy_psi.triton.TemperatureSensor',
'mix. chamber cernox',
slot='T5',
io='triton',
)
Mod('T_pt1head',
'frappy_psi.triton.TemperatureSensor',
'PTR1 head temperature',
slot='T6',
io='triton',
)
Mod('T_pt1plate',
'frappy_psi.triton.TemperatureSensor',
'PTR1 plate temperature',
slot='T7',
io='triton',
)
Mod('T_pucksensor',
'frappy_psi.triton.TemperatureLoop',
'puck sensor temperature',
output_module='htr_pucksensor',
slot='TA',
io='triton',
)
Mod('htr_pucksensor',
'frappy_psi.triton.HeaterOutputWithRange',
'mix. chamber heater',
slot='H1,TA',
io='triton',
)
Mod('T_magnet',
'frappy_psi.triton.TemperatureSensor',
'magnet temperature',
slot='T13',
io='triton',
)
Mod('action',
'frappy_psi.triton.Action',
'higher level scripts',
io='triton',
slot='DR',
)
Mod('p_dump',
'frappy_psi.mercury.PressureSensor',
'dump pressure',
slot='P1',
io='triton',
)
Mod('p_cond',
'frappy_psi.mercury.PressureSensor',
'condenser pressure',
slot='P2',
io='triton',
)
Mod('p_still',
'frappy_psi.mercury.PressureSensor',
'still pressure',
slot='P3',
io='triton',
)
Mod('p_fore',
'frappy_psi.mercury.PressureSensor',
'pressure on the pump side',
slot='P5',
io='triton',
)
Mod('p_back',
'frappy_psi.mercury.PressureSensor',
'pressure on the back side of the pump',
slot='P4',
io='triton',
)
Mod('p_ovc',
'frappy_psi.mercury.PressureSensor',
'outer vacuum pressure',
slot='P6',
io='triton',
)
Mod('V1',
'frappy_psi.triton.Valve',
'valve V1',
slot='V1',
io='triton',
)
Mod('V2',
'frappy_psi.triton.Valve',
'valve V2',
slot='V2',
io='triton',
)
Mod('V4',
'frappy_psi.triton.Valve',
'valve V4',
slot='V4',
io='triton',
)
Mod('V5',
'frappy_psi.triton.Valve',
'valve V5',
slot='V5',
io='triton',
)
Mod('V9',
'frappy_psi.triton.Valve',
'valve V9',
slot='V9',
io='triton',
)
Mod('ips',
'frappy_psi.mercury.IO',
'IPS for magnet',
uri='192.168.127.254:3001',
)
Mod('mf',
'frappy_psi.dilsc.VectorField',
'vector field',
x='mfx',
y='mfy',
z='mfz',
sphere_radius=0.6,
cylinders=((0.23, 5.2), (0.45, 0.8)),
)
Mod('mfx',
'frappy_psi.ips_mercury.SimpleField',
'magnetic field, x-axis',
slot='GRPX',
io='ips',
tolerance=0.0001,
wait_stable_field=0.0,
nunits=2,
target=Param(max=0.6),
ramp=0.225,
)
Mod('mfy',
'frappy_psi.ips_mercury.SimpleField',
'magnetic field, y axis',
slot='GRPY',
io='ips',
tolerance=0.0001,
wait_stable_field=0.0,
nunits=2,
target=Param(max=0.6),
ramp=0.225,
)
Mod('mfz',
'frappy_psi.ips_mercury.Field',
'magnetic field, z-axis',
slot='GRPZ',
io='ips',
tolerance=0.0001,
target=Param(max=5.2),
mode='DRIVEN',
ramp=0.52,
)

View File

@ -1,27 +0,0 @@
Node('relais.psi.ch',
'relais test',
'tcp://5000',
)
Mod('rl',
'frappy_psi.ionopimax.DigitalOutput',
'left relais',
addr = 'o1',
value = 0, # start with relais off
)
Mod('rr',
'frappy_psi.ionopimax.DigitalOutput',
'right relais',
addr = 'o2',
value = 0, # start with relais off
)
Mod('drummer',
'frappy_psi.drums.Drums',
'drummer',
target = 150,
pattern='l2L2rl1R1L2',
left='rl',
right='rr',
)

View File

@ -1,52 +0,0 @@
Node('flowsas.psi.ch',
'flowsas test motors',
'tcp://5000',
)
#Mod('mot_io',
# 'frappy_psi.phytron.PhytronIO',
# 'io for motor control',
# uri = 'serial:///dev/ttyUSB0',
# )
#Mod('hmot',
# 'frappy_psi.phytron.Motor',
# 'horizontal axis',
# axis = 'X',
# io = 'mot_io',
# encoder_mode= 'NO',
# )
#Mod('vmot',
# 'frappy_psi.phytron.Motor',
# 'vertical axis',
# axis = 'Y',
# io = 'mot_io',
# encoder_mode= 'NO',
# )
Mod('syr_io',
'frappy_psi.cetoni_pump.LabCannBus',
'Module for bus',
deviceconfig = "/home/l_samenv/frappy/cetoniSDK/CETONI_SDK_Raspi_64bit_v20220627/config/dual_pumps",
)
Mod('syr1',
'frappy_psi.cetoni_pump.SyringePump',
'First syringe pump',
io='syr_io',
pump_name = "Nemesys_S_1_Pump",
valve_name = "Nemesys_S_1_Valve",
inner_diameter_set = 10,
piston_stroke_set = 60,
)
Mod('syr2',
'frappy_psi.cetoni_pump.SyringePump',
'Second syringe pump',
io='syr_io',
pump_name = "Nemesys_S_2_Pump",
valve_name = "Nemesys_S_2_Valve",
inner_diameter_set = 1,
piston_stroke_set = 60,
)

View File

@ -3,5 +3,3 @@
logdir = ./log
piddir = ./pid
confdir = ./cfg
comlog = True

View File

@ -1,16 +0,0 @@
Node('lockin70test.psi.ch',
'lockin70 test',
'tcp://5000',
)
Mod('io',
'frappy_psi.SR.SR_IO',
'lockin communication',
uri='10105266.psi.ch:50000',
)
Mod('XY',
'frappy_psi.SR.XY70',
'XY channels',
io='io',
)

View File

@ -1,24 +0,0 @@
Node('ft.config.sea.psi.ch',
'FW ILL furnace with W5 thermnocouple (1800 K), old power rack',
)
Mod('sea_main',
'frappy_psi.sea.SeaClient',
'main sea connection for fw.config',
config='fw.config',
service='main',
)
Mod('ts',
'frappy_psi.sea.SeaDrivable', '',
io='sea_main',
sea_object='tt',
rel_paths=['.', 'ts'],
)
Mod('t2',
'frappy_psi.sea.SeaReadable', '',
io='sea_main',
sea_object='tt',
rel_paths=['t2'],
)

View File

@ -83,5 +83,4 @@ Mod('om',
target_min = -180,
target_max = 360,
encoder_mode='READ',
backlash=-1,
)

View File

@ -1,101 +0,0 @@
Node('ma10.config.sea.psi.ch',
'10 Tesla vertical cryomagnet',
)
Mod('sea_main',
'frappy_psi.sea.SeaClient',
'main sea connection for ma10.config',
config='ma10heat.config',
service='main',
)
Mod('ts',
'frappy_psi.sea.SeaDrivable', '',
io='sea_main',
sea_object='tt',
rel_paths=['ts', 'set']
)
Mod('tm',
'frappy_psi.sea.SeaReadable', '',
io='sea_main',
sea_object='tt',
rel_paths=['tm', 'setvti']
)
Mod('ts2',
'frappy_psi.sea.SeaReadable', '',
io='sea_main',
sea_object='tt',
rel_paths=['ts_2']
)
Mod('cc',
'frappy_psi.sea.SeaReadable', '',
io='sea_main',
sea_object='cc',
)
Mod('nv',
'frappy_psi.sea.SeaWritable', '',
io='sea_main',
sea_object='nv',
)
Mod('hepump',
'frappy_psi.sea.SeaWritable', '',
io='sea_main',
sea_object='hepump',
)
Mod('hemot',
'frappy_psi.sea.SeaDrivable', '',
io='sea_main',
sea_object='hemot',
)
Mod('mf',
'frappy_psi.sea.SeaDrivable', '',
io='sea_main',
sea_object='mf',
)
Mod('lev',
'frappy_psi.sea.SeaReadable', '',
io='sea_main',
sea_object='lev',
)
Mod('ln2fill',
'frappy_psi.sea.SeaWritable', '',
io='sea_main',
sea_object='ln2fill',
)
Mod('hefill',
'frappy_psi.sea.SeaWritable', '',
io='sea_main',
sea_object='hefill',
)
Mod('table',
'frappy_psi.sea.SeaReadable', '',
io='sea_main',
sea_object='table',
)
Mod('om_io',
'frappy_psi.phytron.PhytronIO',
'dom motor IO',
uri='ma10-ts.psi.ch:3004',
)
Mod('om',
'frappy_psi.phytron.Motor',
'stick rotation, typically used for omega',
io='om_io',
sign=-1,
target_min = -180,
target_max = 360,
encoder_mode='READ',
)

View File

@ -1,108 +0,0 @@
Node('ma10.config.sea.psi.ch',
'10 Tesla vertical cryomagnet',
)
Mod('sea_main',
'frappy_psi.sea.SeaClient',
'main sea connection for ma10.config',
config='ma10high_t.config',
service='main',
)
Mod('th',
'frappy_psi.sea.SeaReadable',
'sample heater temperature',
io='sea_main',
sea_object='tt',
rel_paths=['ts', 'setsamp']
)
Mod('tm',
'frappy_psi.sea.SeaDrivable', '',
io='sea_main',
sea_object='tt',
rel_paths=['tm', 'set']
)
Mod('ts',
'frappy_psi.parmod.Converging',
'test for parmod',
unit='K',
read='th.value',
write='th.setsamp',
meaning=['temperature', 20],
settling_time=20,
tolerance=1,
)
Mod('ts2',
'frappy_psi.sea.SeaReadable', '',
io='sea_main',
sea_object='tt',
rel_paths=['ts_2']
)
Mod('cc',
'frappy_psi.sea.SeaReadable', '',
io='sea_main',
sea_object='cc',
)
Mod('nv',
'frappy_psi.sea.SeaWritable', '',
io='sea_main',
sea_object='nv',
)
Mod('hepump',
'frappy_psi.sea.SeaWritable', '',
io='sea_main',
sea_object='hepump',
)
Mod('hemot',
'frappy_psi.sea.SeaDrivable', '',
io='sea_main',
sea_object='hemot',
)
Mod('mf',
'frappy_psi.sea.SeaDrivable', '',
io='sea_main',
sea_object='mf',
)
Mod('lev',
'frappy_psi.sea.SeaReadable', '',
io='sea_main',
sea_object='lev',
)
Mod('ln2fill',
'frappy_psi.sea.SeaWritable', '',
io='sea_main',
sea_object='ln2fill',
)
Mod('hefill',
'frappy_psi.sea.SeaWritable', '',
io='sea_main',
sea_object='hefill',
)
Mod('om_io',
'frappy_psi.phytron.PhytronIO',
'dom motor IO',
uri='ma10-ts.psi.ch:3004',
)
Mod('om',
'frappy_psi.phytron.Motor',
'stick rotation, typically used for omega',
io='om_io',
sign=-1,
target_min = -180,
target_max = 360,
encoder_mode='READ',
)

View File

@ -13,7 +13,7 @@ Mod('tt',
'frappy_psi.sea.SeaDrivable', '',
io='sea_main',
sea_object='tt',
rel_paths=['tm', 'set', 'dblctrl'],
rel_paths=['.', 'tm'],
)
Mod('cc',

View File

@ -1,107 +0,0 @@
Node('ma7.config.sea.psi.ch',
'6.8 Tesla horizontal cryomagnet',
)
Mod('sea_main',
'frappy_psi.sea.SeaClient',
'main sea connection for ma7.config',
config='ma7_piezo.config',
service='main',
)
Mod('tt',
'frappy_psi.sea.SeaDrivable', '',
io='sea_main',
sea_object='tt',
rel_paths=['tm', 'set', 'dblctrl', 'voltage'],
extra_modules=['manualpower'],
)
Mod('cc',
'frappy_psi.sea.SeaReadable', '',
io='sea_main',
sea_object='cc',
)
Mod('nv',
'frappy_psi.sea.SeaWritable', '',
io='sea_main',
sea_object='nv',
)
Mod('hefill',
'frappy_psi.sea.SeaWritable', '',
io='sea_main',
sea_object='hefill',
)
Mod('hepump',
'frappy_psi.sea.SeaWritable', '',
io='sea_main',
sea_object='hepump',
)
Mod('hemot',
'frappy_psi.sea.SeaDrivable', '',
io='sea_main',
sea_object='hemot',
)
Mod('ln2fill',
'frappy_psi.sea.SeaWritable', '',
io='sea_main',
sea_object='ln2fill',
)
Mod('mf',
'frappy_psi.sea.SeaDrivable', '',
io='sea_main',
sea_object='mf',
value=Param(unit='T'),
)
Mod('lev',
'frappy_psi.sea.SeaReadable', '',
io='sea_main',
sea_object='lev',
)
Mod('tcoil1',
'frappy_psi.sea.SeaReadable', '',
io='sea_main',
sea_object='tcoil',
rel_paths=['ta'],
)
Mod('tcoil2',
'frappy_psi.sea.SeaReadable', '',
io='sea_main',
sea_object='tcoil',
rel_paths=['tb'],
)
Mod('table',
'frappy_psi.sea.SeaReadable', '',
io='sea_main',
sea_object='table',
)
Mod('stick_io',
'frappy_psi.phytron.PhytronIO',
'dom motor IO',
uri='ma7-ts.psi.ch:3007',
)
Mod('stickrot',
'frappy_psi.phytron.Motor',
'stick rotation, typically not used as omega',
io='stick_io',
encoder_mode='CHECK',
)
Mod('V',
'frappy_psi.sea.SeaWritable',
'voltage',
io='sea_main',
single_module='tt.manualpower',
)

View File

@ -36,8 +36,8 @@ Mod('ts',
'frappy_psi.parmod.Converging',
'test for parmod',
unit='K',
value_param='th.value',
target_param='th.setsamp',
read='th.value',
write='th.setsamp',
meaning=['temperature', 20],
settling_time=20,
tolerance=1,

View File

@ -1,128 +0,0 @@
Node('ma7_thermalc.config.sea.psi.ch',
'''6.8 Tesla horizontal cryomagnet for thrermalcond''',
)
Mod('sea_main',
'frappy_psi.sea.SeaClient',
'main sea connection for ma7_thermalc.config',
config = 'ma7_thermalc.config',
service = 'main',
)
#Mod('tt',
# 'frappy_psi.sea.SeaDrivable', '',
# io='sea_main',
# sea_object='tt',
# rel_paths=['.', 'tm'],
#)
Mod('tt',
'frappy_psi.sea.SeaDrivable', '',
io='sea_main',
sea_object='tt',
rel_paths=['tm', 'set'],
)
Mod('th',
'frappy_psi.sea.SeaReadable',
'sample heater temperature',
io='sea_main',
sea_object='tt',
rel_paths=['ts', 'setsamp']
)
Mod('ts',
'frappy_psi.parmod.Converging',
'test for parmod',
unit='K',
value_param='th.value',
target_param='th.setsamp',
meaning=['temperature', 20],
settling_time=20,
tolerance=1,
)
Mod('samph',
'frappy_psi.sea.SeaWritable', '',
io='sea_main',
sea_object='tt',
rel_paths=['setsamp','power'],
)
Mod('cc',
'frappy_psi.sea.SeaReadable', '',
io = 'sea_main',
sea_object = 'cc',
)
Mod('nv',
'frappy_psi.sea.SeaWritable', '',
io = 'sea_main',
sea_object = 'nv',
)
Mod('hefill',
'frappy_psi.sea.SeaWritable', '',
io = 'sea_main',
sea_object = 'hefill',
)
Mod('hepump',
'frappy_psi.sea.SeaWritable', '',
io = 'sea_main',
sea_object = 'hepump',
)
Mod('hemot',
'frappy_psi.sea.SeaDrivable', '',
io = 'sea_main',
sea_object = 'hemot',
)
Mod('nvflow',
'frappy_psi.sea.SeaReadable', '',
io = 'sea_main',
sea_object = 'nvflow',
)
Mod('ln2fill',
'frappy_psi.sea.SeaWritable', '',
io = 'sea_main',
sea_object = 'ln2fill',
)
Mod('mf',
'frappy_psi.sea.SeaDrivable', '',
io = 'sea_main',
sea_object = 'mf',
)
Mod('lev',
'frappy_psi.sea.SeaReadable', '',
io = 'sea_main',
sea_object = 'lev',
)
Mod('tcoil1',
'frappy_psi.sea.SeaReadable', '',
io='sea_main',
sea_object='tcoil',
rel_paths=['ta'],
)
Mod('tcoil2',
'frappy_psi.sea.SeaReadable', '',
io='sea_main',
sea_object='tcoil',
rel_paths=['tb'],
)
Mod('table',
'frappy_psi.sea.SeaReadable', '',
io = 'sea_main',
sea_object = 'table',
)
Mod('stick_io',
'frappy_psi.phytron.PhytronIO',
'dom motor IO',
uri='ma7-ts.psi.ch:3007',
)
Mod('stickrot',
'frappy_psi.phytron.Motor',
'stick rotation, typically not used as omega',
io='stick_io',
encoder_mode='CHECK',
)

View File

@ -1,16 +0,0 @@
Node('phoenixtest.psi.ch',
'phoenix test',
'tcp://5000',
)
Mod('io',
'frappy_psi.haake.HaakeIO',
'connection for Thermo Haake',
uri='tcp://ldmprep7-ts:3005',
)
Mod('T',
'frappy_psi.haake.TemperatureLoop',
'holder temperature',
io='io',
)

View File

@ -1,139 +0,0 @@
# call $ bin/frappy-server razorbillUC220T
# in frappy directory, with python with frappy libraries installed.
Node('UC220T.psi.ch',
'A Razorbill UC220T controlled by a RP100 high voltage powersupply and a ACM1219 (AD7746) capacitance meter',
interface='tcp://3000')
Mod('io1',
'frappy_psi.RP100.RP100IO',
'communication',
uri='serial:///dev/ttyACM1?baudrate=9600+bytesize=8+parity=none+stopbits=1',
visibility=2)
Mod('Tension',
'frappy_psi.RP100.VoltageChannel',
'Voltage Channel 1',
temp='T',
io='io1',
target=Param(min=-200, max=200),
max_target=120,
min_target=-20,
slew_rate=5,
channel=1)
Mod('Compression',
'frappy_psi.RP100.VoltageChannel',
'Voltage Channel 2',
temp='T',
io='io1',
target=Param(min=-200, max=200),
max_target=120,
min_target=-20,
slew_rate=5,
channel=2)
Mod('io2',
'frappy_psi.ACM1219.ACM1219IO',
'communication',
uri='serial:///dev/ttyUSB1?baudrate=9600+bytesize=8+parity=none+stopbits=1',
visibility=2)
Mod('C1',
'frappy_psi.ACM1219.OneChannel',
'channel 1',
channel_enabled=True,
channel=1,
io='io2',
group='cap')
Mod('io3',
'frappy_psi.ACM1219.ACM1219IO',
'communication',
uri='serial:///dev/ttyUSB2?baudrate=9600+bytesize=8+parity=none+stopbits=1',
visibility=2)
Mod('C2',
'frappy_psi.ACM1219.OneChannel',
'channel 1',
channel_enabled=True,
channel=1,
io='io3',
group='cap')
# Mod('C1',
# 'frappy_psi.ACM1219.Channel',
# 'channel 1',
# group='cap')
# Mod('C2',
# 'frappy_psi.ACM1219.Channel',
# 'channel 2',
# group='cap')
# Mod('C1C2',
# 'frappy_psi.ACM1219.BothChannels',
# 'Capacitance channels 1 and 2',
# chan1='C1',
# chan2='C2',
# channels_enabled=True,
# io='io2',
# group='cap')
Mod('d',
'frappy_psi.razorbill.Displacement',
'razorbill displacement from capacitance',
cap='C1',
alpha290K=56.710,
d0=95.443,
Cp=0.01883,
d0_curve={'a':4.21,'b':-0.00157,'c':-3.38e-5,'d':5.28e-8,'e':-6.93e-11},
temp='T')
Mod('strain',
'frappy_psi.razorbill.Strain',
'Sample strain from force',
displacement='d',
L=3,
)
Mod('F',
'frappy_psi.razorbill.Force',
'razorbill force from capacitance',
cap='C2',
alpha290K=374.23,
f0=315.63,
Cp=0.0755,
f0_curve={'a':38.9,'b':-0.0147,'c':-0.000346,'d':8.96e-7,'e':-1.58e-9},
temp='T')
Mod('stress',
'frappy_psi.razorbill.Stress',
'Sample stress from force',
force='F',
area=0.1,
)
Mod('YM',
'frappy_psi.razorbill.YoungsModulus',
'Sample youngs modulus from stress and strain',
stress='stress',
strain='strain',
)
Mod('T',
'frappy_psi.razorbill.Temp',
'dummy T written from client',
target=Param(value=300, min=1, max=325),
)
Mod('io4',
'frappy_psi.ls372.StringIO',
'the communication device',
uri='tcp://192.168.3.3:7777',
visibility=2
)
Mod('lsswitcher',
'frappy_psi.ls372.Switcher',
'Switcher control of Lsc controller',
uri='tcp://192.168.3.3:7777',
io='io4',
)
Mod('res',
'frappy_psi.ls372.ResChannel',
'resistivity',
iexc='100uA',
range='63.2mOhm',
channel=1,
switcher='lsswitcher',
)

View File

@ -72,7 +72,8 @@
{"path": "min_cpl", "type": "float", "readonly": false, "cmd": "pauto min_cpl"},
{"path": "max_cpl", "type": "float", "readonly": false, "cmd": "pauto max_cpl"},
{"path": "fact_cpl", "type": "float", "readonly": false, "cmd": "pauto fact_cpl"},
{"path": "max_ramp", "type": "float", "readonly": false, "cmd": "pauto max_ramp"}]},
{"path": "max_ramp", "type": "float", "readonly": false, "cmd": "pauto max_ramp"},
{"path": "target", "type": "float"}]},
"tc": {"base": "/tc", "params": [
{"path": "", "type": "float", "readonly": false, "cmd": "run tc", "description": "tc", "kids": 15},

View File

@ -1,395 +0,0 @@
{"tt": {"base": "/tt", "params": [
{"path": "", "type": "float", "readonly": false, "cmd": "run tt", "description": "tt", "kids": 18},
{"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", "kids": 4},
{"path": "ts_2/curve", "type": "text", "readonly": false, "cmd": "tt ts_2/curve", "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"},
{"path": "ts_2/stddev", "type": "float"},
{"path": "ts_2/raw", "type": "float"},
{"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": "setvti", "type": "float", "readonly": false, "cmd": "tt setvti", "kids": 18},
{"path": "setvti/mode", "type": "enum", "enum": {"disabled": -1, "off": 0, "controlling": 1, "manual": 2}, "readonly": false, "cmd": "tt setvti/mode"},
{"path": "setvti/reg", "type": "float"},
{"path": "setvti/ramp", "type": "float", "readonly": false, "cmd": "tt setvti/ramp", "description": "maximum ramp in K/min (0: ramp off)"},
{"path": "setvti/wramp", "type": "float", "readonly": false, "cmd": "tt setvti/wramp"},
{"path": "setvti/smooth", "type": "float", "readonly": false, "cmd": "tt setvti/smooth", "description": "smooth time (minutes)"},
{"path": "setvti/channel", "type": "text", "readonly": false, "cmd": "tt setvti/channel"},
{"path": "setvti/limit", "type": "float", "readonly": false, "cmd": "tt setvti/limit"},
{"path": "setvti/resist", "type": "float", "readonly": false, "cmd": "tt setvti/resist"},
{"path": "setvti/maxheater", "type": "text", "readonly": false, "cmd": "tt setvti/maxheater", "description": "maximum heater limit, units should be given without space: W, mW, A, mA"},
{"path": "setvti/linearpower", "type": "float", "readonly": false, "cmd": "tt setvti/linearpower", "description": "when not 0, it is the maximum effective power, and the power is linear to the heater output"},
{"path": "setvti/maxpowerlim", "type": "float", "description": "the maximum power limit (before any booster or converter)"},
{"path": "setvti/maxpower", "type": "float", "readonly": false, "cmd": "tt setvti/maxpower", "description": "maximum power [W]"},
{"path": "setvti/maxcurrent", "type": "float", "description": "the maximum current before any booster or converter"},
{"path": "setvti/manualpower", "type": "float", "readonly": false, "cmd": "tt setvti/manualpower"},
{"path": "setvti/power", "type": "float"},
{"path": "setvti/prop", "type": "float", "readonly": false, "cmd": "tt setvti/prop", "description": "bigger means more gain"},
{"path": "setvti/integ", "type": "float", "readonly": false, "cmd": "tt setvti/integ", "description": "bigger means faster"},
{"path": "setvti/deriv", "type": "float", "readonly": false, "cmd": "tt setvti/deriv"},
{"path": "display", "type": "text", "readonly": false, "cmd": "tt display"},
{"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": 6}, "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"}]},
"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"},
{"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", "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"}]},
"nvflow": {"base": "/nvflow", "params": [
{"path": "", "type": "float", "kids": 7},
{"path": "send", "type": "text", "readonly": false, "cmd": "nvflow send", "visibility": 3},
{"path": "status", "type": "text", "visibility": 3},
{"path": "stddev", "type": "float"},
{"path": "nsamples", "type": "int", "readonly": false, "cmd": "nvflow nsamples"},
{"path": "offset", "type": "float", "readonly": false, "cmd": "nvflow offset"},
{"path": "scale", "type": "float", "readonly": false, "cmd": "nvflow scale"},
{"path": "save", "type": "bool", "readonly": false, "cmd": "nvflow save", "description": "unchecked: current calib is not saved. set checked: save calib"}]},
"mf": {"base": "/mf", "params": [
{"path": "", "type": "float", "readonly": false, "cmd": "run mf", "kids": 8},
{"path": "send", "type": "text", "readonly": false, "cmd": "mf send", "visibility": 3},
{"path": "status", "type": "text", "visibility": 3},
{"path": "is_running", "type": "int", "readonly": false, "cmd": "mf is_running", "visibility": 3},
{"path": "statustext", "type": "text"},
{"path": "ramp", "type": "float", "readonly": false, "cmd": "mf ramp"},
{"path": "persistent_mode", "type": "enum", "enum": {"forever_off": -1, "off": 0, "on": 1}, "readonly": false, "cmd": "mf persistent_mode", "description": "hidden mode -1: completely off"},
{"path": "gen", "type": "none", "kids": 13},
{"path": "gen/persistent_delay", "type": "float", "readonly": false, "cmd": "mf gen/persistent_delay", "description": "timeout for going automatically into persistent mode"},
{"path": "gen/tolerance", "type": "float", "readonly": false, "cmd": "mf gen/tolerance"},
{"path": "gen/wait_switch_on", "type": "float", "readonly": false, "cmd": "mf gen/wait_switch_on"},
{"path": "gen/wait_switch_off", "type": "float", "readonly": false, "cmd": "mf gen/wait_switch_off"},
{"path": "gen/wait_stable_leads", "type": "float", "readonly": false, "cmd": "mf gen/wait_stable_leads"},
{"path": "gen/wait_stable_field", "type": "float", "readonly": false, "cmd": "mf gen/wait_stable_field"},
{"path": "gen/expectend", "type": "text"},
{"path": "gen/trained_pos", "type": "float", "readonly": false, "cmd": "mf gen/trained_pos"},
{"path": "gen/trained_neg", "type": "float", "readonly": false, "cmd": "mf gen/trained_neg"},
{"path": "gen/profile", "type": "text", "readonly": false, "cmd": "mf gen/profile", "description": "syntax: <field1>:<ramp1> <field2>:<ramp2> ... (<ramp2> is the ramp limit from <field1> to <field2>)"},
{"path": "gen/profile_training", "type": "text", "readonly": false, "cmd": "mf gen/profile_training", "description": "syntax: <field1>:<ramp1> <field2>:<ramp2> ... (<ramp2> is the ramp limit from <field1> to <field2>)"},
{"path": "gen/limit", "type": "float", "readonly": false, "cmd": "mf gen/limit"},
{"path": "gen/bipolar", "type": "bool", "readonly": false, "cmd": "mf gen/bipolar"},
{"path": "ips", "type": "float", "kids": 17},
{"path": "ips/ramp_slow", "type": "float", "readonly": false, "cmd": "mf ips/ramp_slow", "description": "ramp rate for coils Tesla/min."},
{"path": "ips/ramp_fast", "type": "float", "description": "ramp rate for leads Tesla/min."},
{"path": "ips/set_field", "type": "float", "readonly": false, "cmd": "mf ips/set_field"},
{"path": "ips/heater", "type": "bool", "readonly": false, "cmd": "mf ips/heater"},
{"path": "ips/ramp_state", "type": "enum", "enum": {"hold": 0, "to_zero": 1, "to_set": 2, "clamp": 3}, "readonly": false, "cmd": "mf ips/ramp_state"},
{"path": "ips/leads_set", "type": "float", "description": "calculated current in the leads, converted to Tesla"},
{"path": "ips/show_internals", "type": "bool", "readonly": false, "cmd": "mf ips/show_internals"},
{"path": "ips/leads_meas", "type": "float", "description": "measured current in the leads, converted to Tesla"},
{"path": "ips/slave1", "type": "float"},
{"path": "ips/slave2", "type": "float"},
{"path": "ips/slave3", "type": "float"},
{"path": "ips/volt", "type": "float"},
{"path": "ips/symode", "type": "text"},
{"path": "ips/engineering_password", "type": "text", "readonly": false, "cmd": "mf ips/engineering_password"},
{"path": "ips/atob", "type": "float", "readonly": false, "cmd": "mf ips/atob", "description": "Amp/Tesla"},
{"path": "ips/inductance", "type": "float", "readonly": false, "cmd": "mf ips/inductance", "description": "henries"},
{"path": "ips/switch_heater_current", "type": "float", "readonly": false, "cmd": "mf ips/switch_heater_current", "description": "switch heater current [mA]"}]},
"lev": {"base": "/lev", "params": [
{"path": "", "type": "float", "kids": 4},
{"path": "send", "type": "text", "readonly": false, "cmd": "lev send", "visibility": 3},
{"path": "status", "type": "text", "visibility": 3},
{"path": "mode", "type": "enum", "enum": {"slow": 0, "fast": 1}, "readonly": false, "cmd": "lev mode"},
{"path": "n2", "type": "float"}]},
"ln2fill": {"base": "/ln2fill", "params": [
{"path": "", "type": "enum", "enum": {"watching": 0, "filling": 1, "inactive": 2, "manualfill": 3}, "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"},
{"path": "readlevel", "type": "text", "readonly": false, "cmd": "ln2fill readlevel", "visibility": 3},
{"path": "lowlevel", "type": "float", "readonly": false, "cmd": "ln2fill lowlevel"},
{"path": "highlevel", "type": "float", "readonly": false, "cmd": "ln2fill highlevel"},
{"path": "smooth", "type": "float"},
{"path": "minfillminutes", "type": "float", "readonly": false, "cmd": "ln2fill minfillminutes"},
{"path": "maxfillminutes", "type": "float", "readonly": false, "cmd": "ln2fill maxfillminutes"},
{"path": "minholdhours", "type": "float", "readonly": false, "cmd": "ln2fill minholdhours"},
{"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": {"watching": 0, "filling": 1, "inactive": 2, "manualfill": 3}, "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"},
{"path": "readlevel", "type": "text", "readonly": false, "cmd": "hefill readlevel", "visibility": 3},
{"path": "lowlevel", "type": "float", "readonly": false, "cmd": "hefill lowlevel"},
{"path": "highlevel", "type": "float", "readonly": false, "cmd": "hefill highlevel"},
{"path": "smooth", "type": "float"},
{"path": "minfillminutes", "type": "float", "readonly": false, "cmd": "hefill minfillminutes"},
{"path": "maxfillminutes", "type": "float", "readonly": false, "cmd": "hefill maxfillminutes"},
{"path": "minholdhours", "type": "float", "readonly": false, "cmd": "hefill minholdhours"},
{"path": "maxholdhours", "type": "float", "readonly": false, "cmd": "hefill maxholdhours"},
{"path": "tolerance", "type": "float", "readonly": false, "cmd": "hefill tolerance"},
{"path": "badreadingminutes", "type": "float", "readonly": false, "cmd": "hefill badreadingminutes"},
{"path": "tubecoolingminutes", "type": "float", "readonly": false, "cmd": "hefill tubecoolingminutes"},
{"path": "vessellimit", "type": "float", "readonly": false, "cmd": "hefill vessellimit"},
{"path": "vext", "type": "float"}]},
"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 ..."}]}}

View File

@ -1,395 +0,0 @@
{"tt": {"base": "/tt", "params": [
{"path": "", "type": "float", "readonly": false, "cmd": "run tt", "description": "tt", "kids": 18},
{"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", "kids": 4},
{"path": "ts_2/curve", "type": "text", "readonly": false, "cmd": "tt ts_2/curve", "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"},
{"path": "ts_2/stddev", "type": "float"},
{"path": "ts_2/raw", "type": "float"},
{"path": "setsamp", "type": "float", "readonly": false, "cmd": "tt setsamp", "kids": 18},
{"path": "setsamp/mode", "type": "enum", "enum": {"disabled": -1, "off": 0, "controlling": 1, "manual": 2}, "readonly": false, "cmd": "tt setsamp/mode"},
{"path": "setsamp/reg", "type": "float"},
{"path": "setsamp/ramp", "type": "float", "readonly": false, "cmd": "tt setsamp/ramp", "description": "maximum ramp in K/min (0: ramp off)"},
{"path": "setsamp/wramp", "type": "float", "readonly": false, "cmd": "tt setsamp/wramp"},
{"path": "setsamp/smooth", "type": "float", "readonly": false, "cmd": "tt setsamp/smooth", "description": "smooth time (minutes)"},
{"path": "setsamp/channel", "type": "text", "readonly": false, "cmd": "tt setsamp/channel"},
{"path": "setsamp/limit", "type": "float", "readonly": false, "cmd": "tt setsamp/limit"},
{"path": "setsamp/resist", "type": "float", "readonly": false, "cmd": "tt setsamp/resist"},
{"path": "setsamp/maxheater", "type": "text", "readonly": false, "cmd": "tt setsamp/maxheater", "description": "maximum heater limit, units should be given without space: W, mW, A, mA"},
{"path": "setsamp/linearpower", "type": "float", "readonly": false, "cmd": "tt setsamp/linearpower", "description": "when not 0, it is the maximum effective power, and the power is linear to the heater output"},
{"path": "setsamp/maxpowerlim", "type": "float", "description": "the maximum power limit (before any booster or converter)"},
{"path": "setsamp/maxpower", "type": "float", "readonly": false, "cmd": "tt setsamp/maxpower", "description": "maximum power [W]"},
{"path": "setsamp/maxcurrent", "type": "float", "description": "the maximum current before any booster or converter"},
{"path": "setsamp/manualpower", "type": "float", "readonly": false, "cmd": "tt setsamp/manualpower"},
{"path": "setsamp/power", "type": "float"},
{"path": "setsamp/prop", "type": "float", "readonly": false, "cmd": "tt setsamp/prop", "description": "bigger means more gain"},
{"path": "setsamp/integ", "type": "float", "readonly": false, "cmd": "tt setsamp/integ", "description": "bigger means faster"},
{"path": "setsamp/deriv", "type": "float", "readonly": false, "cmd": "tt setsamp/deriv"},
{"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": "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": 6}, "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"}]},
"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"},
{"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", "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"}]},
"nvflow": {"base": "/nvflow", "params": [
{"path": "", "type": "float", "kids": 7},
{"path": "send", "type": "text", "readonly": false, "cmd": "nvflow send", "visibility": 3},
{"path": "status", "type": "text", "visibility": 3},
{"path": "stddev", "type": "float"},
{"path": "nsamples", "type": "int", "readonly": false, "cmd": "nvflow nsamples"},
{"path": "offset", "type": "float", "readonly": false, "cmd": "nvflow offset"},
{"path": "scale", "type": "float", "readonly": false, "cmd": "nvflow scale"},
{"path": "save", "type": "bool", "readonly": false, "cmd": "nvflow save", "description": "unchecked: current calib is not saved. set checked: save calib"}]},
"mf": {"base": "/mf", "params": [
{"path": "", "type": "float", "readonly": false, "cmd": "run mf", "kids": 8},
{"path": "send", "type": "text", "readonly": false, "cmd": "mf send", "visibility": 3},
{"path": "status", "type": "text", "visibility": 3},
{"path": "is_running", "type": "int", "readonly": false, "cmd": "mf is_running", "visibility": 3},
{"path": "statustext", "type": "text"},
{"path": "ramp", "type": "float", "readonly": false, "cmd": "mf ramp"},
{"path": "persistent_mode", "type": "enum", "enum": {"forever_off": -1, "off": 0, "on": 1}, "readonly": false, "cmd": "mf persistent_mode", "description": "hidden mode -1: completely off"},
{"path": "gen", "type": "none", "kids": 13},
{"path": "gen/persistent_delay", "type": "float", "readonly": false, "cmd": "mf gen/persistent_delay", "description": "timeout for going automatically into persistent mode"},
{"path": "gen/tolerance", "type": "float", "readonly": false, "cmd": "mf gen/tolerance"},
{"path": "gen/wait_switch_on", "type": "float", "readonly": false, "cmd": "mf gen/wait_switch_on"},
{"path": "gen/wait_switch_off", "type": "float", "readonly": false, "cmd": "mf gen/wait_switch_off"},
{"path": "gen/wait_stable_leads", "type": "float", "readonly": false, "cmd": "mf gen/wait_stable_leads"},
{"path": "gen/wait_stable_field", "type": "float", "readonly": false, "cmd": "mf gen/wait_stable_field"},
{"path": "gen/expectend", "type": "text"},
{"path": "gen/trained_pos", "type": "float", "readonly": false, "cmd": "mf gen/trained_pos"},
{"path": "gen/trained_neg", "type": "float", "readonly": false, "cmd": "mf gen/trained_neg"},
{"path": "gen/profile", "type": "text", "readonly": false, "cmd": "mf gen/profile", "description": "syntax: <field1>:<ramp1> <field2>:<ramp2> ... (<ramp2> is the ramp limit from <field1> to <field2>)"},
{"path": "gen/profile_training", "type": "text", "readonly": false, "cmd": "mf gen/profile_training", "description": "syntax: <field1>:<ramp1> <field2>:<ramp2> ... (<ramp2> is the ramp limit from <field1> to <field2>)"},
{"path": "gen/limit", "type": "float", "readonly": false, "cmd": "mf gen/limit"},
{"path": "gen/bipolar", "type": "bool", "readonly": false, "cmd": "mf gen/bipolar"},
{"path": "ips", "type": "float", "kids": 17},
{"path": "ips/ramp_slow", "type": "float", "readonly": false, "cmd": "mf ips/ramp_slow", "description": "ramp rate for coils Tesla/min."},
{"path": "ips/ramp_fast", "type": "float", "description": "ramp rate for leads Tesla/min."},
{"path": "ips/set_field", "type": "float", "readonly": false, "cmd": "mf ips/set_field"},
{"path": "ips/heater", "type": "bool", "readonly": false, "cmd": "mf ips/heater"},
{"path": "ips/ramp_state", "type": "enum", "enum": {"hold": 0, "to_zero": 1, "to_set": 2, "clamp": 3}, "readonly": false, "cmd": "mf ips/ramp_state"},
{"path": "ips/leads_set", "type": "float", "description": "calculated current in the leads, converted to Tesla"},
{"path": "ips/show_internals", "type": "bool", "readonly": false, "cmd": "mf ips/show_internals"},
{"path": "ips/leads_meas", "type": "float", "description": "measured current in the leads, converted to Tesla"},
{"path": "ips/slave1", "type": "float"},
{"path": "ips/slave2", "type": "float"},
{"path": "ips/slave3", "type": "float"},
{"path": "ips/volt", "type": "float"},
{"path": "ips/symode", "type": "text"},
{"path": "ips/engineering_password", "type": "text", "readonly": false, "cmd": "mf ips/engineering_password"},
{"path": "ips/atob", "type": "float", "readonly": false, "cmd": "mf ips/atob", "description": "Amp/Tesla"},
{"path": "ips/inductance", "type": "float", "readonly": false, "cmd": "mf ips/inductance", "description": "henries"},
{"path": "ips/switch_heater_current", "type": "float", "readonly": false, "cmd": "mf ips/switch_heater_current", "description": "switch heater current [mA]"}]},
"lev": {"base": "/lev", "params": [
{"path": "", "type": "float", "kids": 4},
{"path": "send", "type": "text", "readonly": false, "cmd": "lev send", "visibility": 3},
{"path": "status", "type": "text", "visibility": 3},
{"path": "mode", "type": "enum", "enum": {"slow": 0, "fast": 1}, "readonly": false, "cmd": "lev mode"},
{"path": "n2", "type": "float"}]},
"ln2fill": {"base": "/ln2fill", "params": [
{"path": "", "type": "enum", "enum": {"watching": 0, "filling": 1, "inactive": 2, "manualfill": 3}, "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"},
{"path": "readlevel", "type": "text", "readonly": false, "cmd": "ln2fill readlevel", "visibility": 3},
{"path": "lowlevel", "type": "float", "readonly": false, "cmd": "ln2fill lowlevel"},
{"path": "highlevel", "type": "float", "readonly": false, "cmd": "ln2fill highlevel"},
{"path": "smooth", "type": "float"},
{"path": "minfillminutes", "type": "float", "readonly": false, "cmd": "ln2fill minfillminutes"},
{"path": "maxfillminutes", "type": "float", "readonly": false, "cmd": "ln2fill maxfillminutes"},
{"path": "minholdhours", "type": "float", "readonly": false, "cmd": "ln2fill minholdhours"},
{"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": {"watching": 0, "filling": 1, "inactive": 2, "manualfill": 3}, "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"},
{"path": "readlevel", "type": "text", "readonly": false, "cmd": "hefill readlevel", "visibility": 3},
{"path": "lowlevel", "type": "float", "readonly": false, "cmd": "hefill lowlevel"},
{"path": "highlevel", "type": "float", "readonly": false, "cmd": "hefill highlevel"},
{"path": "smooth", "type": "float"},
{"path": "minfillminutes", "type": "float", "readonly": false, "cmd": "hefill minfillminutes"},
{"path": "maxfillminutes", "type": "float", "readonly": false, "cmd": "hefill maxfillminutes"},
{"path": "minholdhours", "type": "float", "readonly": false, "cmd": "hefill minholdhours"},
{"path": "maxholdhours", "type": "float", "readonly": false, "cmd": "hefill maxholdhours"},
{"path": "tolerance", "type": "float", "readonly": false, "cmd": "hefill tolerance"},
{"path": "badreadingminutes", "type": "float", "readonly": false, "cmd": "hefill badreadingminutes"},
{"path": "tubecoolingminutes", "type": "float", "readonly": false, "cmd": "hefill tubecoolingminutes"},
{"path": "vessellimit", "type": "float", "readonly": false, "cmd": "hefill vessellimit"},
{"path": "vext", "type": "float"}]},
"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 ..."}]}}

View File

@ -1,426 +0,0 @@
{"tt": {"base": "/tt", "params": [
{"path": "", "type": "float", "readonly": false, "cmd": "run tt", "description": "tt", "kids": 18},
{"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/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": "setsamp", "type": "float", "readonly": false, "cmd": "tt setsamp", "kids": 18},
{"path": "setsamp/mode", "type": "enum", "enum": {"disabled": -1, "off": 0, "controlling": 1, "manual": 2}, "readonly": false, "cmd": "tt setsamp/mode"},
{"path": "setsamp/reg", "type": "float"},
{"path": "setsamp/ramp", "type": "float", "readonly": false, "cmd": "tt setsamp/ramp", "description": "maximum ramp in K/min (0: ramp off)"},
{"path": "setsamp/wramp", "type": "float", "readonly": false, "cmd": "tt setsamp/wramp"},
{"path": "setsamp/smooth", "type": "float", "readonly": false, "cmd": "tt setsamp/smooth", "description": "smooth time (minutes)"},
{"path": "setsamp/channel", "type": "text", "readonly": false, "cmd": "tt setsamp/channel"},
{"path": "setsamp/limit", "type": "float", "readonly": false, "cmd": "tt setsamp/limit"},
{"path": "setsamp/resist", "type": "float", "readonly": false, "cmd": "tt setsamp/resist"},
{"path": "setsamp/maxheater", "type": "text", "readonly": false, "cmd": "tt setsamp/maxheater", "description": "maximum heater limit, units should be given without space: W, mW, A, mA"},
{"path": "setsamp/linearpower", "type": "float", "readonly": false, "cmd": "tt setsamp/linearpower", "description": "when not 0, it is the maximum effective power, and the power is linear to the heater output"},
{"path": "setsamp/maxpowerlim", "type": "float", "description": "the maximum power limit (before any booster or converter)"},
{"path": "setsamp/maxpower", "type": "float", "readonly": false, "cmd": "tt setsamp/maxpower", "description": "maximum power [W]"},
{"path": "setsamp/maxcurrent", "type": "float", "description": "the maximum current before any booster or converter"},
{"path": "setsamp/power", "type": "float"},
{"path": "setsamp/prop", "type": "float", "readonly": false, "cmd": "tt setsamp/prop", "description": "bigger means more gain"},
{"path": "setsamp/integ", "type": "float", "readonly": false, "cmd": "tt setsamp/integ", "description": "bigger means faster"},
{"path": "setsamp/deriv", "type": "float", "readonly": false, "cmd": "tt setsamp/deriv"},
{"path": "voltage/manualpower", "type": "float", "readonly": false, "cmd": "tt voltage/manualpower"},
{"path": "display", "type": "text", "readonly": false, "cmd": "tt display"},
{"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": 6}, "readonly": false, "cmd": "cc hea"},
{"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"},
{"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"}]},
"hefill": {"base": "/hefill", "params": [
{"path": "", "type": "enum", "enum": {"watching": 0, "filling": 1, "inactive": 2, "manualfill": 3}, "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"},
{"path": "readlevel", "type": "text", "readonly": false, "cmd": "hefill readlevel", "visibility": 3},
{"path": "lowlevel", "type": "float", "readonly": false, "cmd": "hefill lowlevel"},
{"path": "highlevel", "type": "float", "readonly": false, "cmd": "hefill highlevel"},
{"path": "smooth", "type": "float"},
{"path": "minfillminutes", "type": "float", "readonly": false, "cmd": "hefill minfillminutes"},
{"path": "maxfillminutes", "type": "float", "readonly": false, "cmd": "hefill maxfillminutes"},
{"path": "minholdhours", "type": "float", "readonly": false, "cmd": "hefill minholdhours"},
{"path": "maxholdhours", "type": "float", "readonly": false, "cmd": "hefill maxholdhours"},
{"path": "tolerance", "type": "float", "readonly": false, "cmd": "hefill tolerance"},
{"path": "badreadingminutes", "type": "float", "readonly": false, "cmd": "hefill badreadingminutes"},
{"path": "tubecoolingminutes", "type": "float", "readonly": false, "cmd": "hefill tubecoolingminutes"},
{"path": "vessellimit", "type": "float", "readonly": false, "cmd": "hefill vessellimit"},
{"path": "vext", "type": "float"}]},
"hepump": {"base": "/hepump", "params": [
{"path": "", "type": "enum", "enum": {"neodry": 8, "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"},
{"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", "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"}]},
"nvflow": {"base": "/nvflow", "params": [
{"path": "", "type": "float", "kids": 7},
{"path": "send", "type": "text", "readonly": false, "cmd": "nvflow send", "visibility": 3},
{"path": "status", "type": "text", "visibility": 3},
{"path": "stddev", "type": "float"},
{"path": "nsamples", "type": "int", "readonly": false, "cmd": "nvflow nsamples"},
{"path": "offset", "type": "float", "readonly": false, "cmd": "nvflow offset"},
{"path": "scale", "type": "float", "readonly": false, "cmd": "nvflow scale"},
{"path": "save", "type": "bool", "readonly": false, "cmd": "nvflow save", "description": "unchecked: current calib is not saved. set checked: save calib"}]},
"ln2fill": {"base": "/ln2fill", "params": [
{"path": "", "type": "enum", "enum": {"watching": 0, "filling": 1, "inactive": 2, "manualfill": 3}, "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"},
{"path": "readlevel", "type": "text", "readonly": false, "cmd": "ln2fill readlevel", "visibility": 3},
{"path": "lowlevel", "type": "float", "readonly": false, "cmd": "ln2fill lowlevel"},
{"path": "highlevel", "type": "float", "readonly": false, "cmd": "ln2fill highlevel"},
{"path": "smooth", "type": "float"},
{"path": "minfillminutes", "type": "float", "readonly": false, "cmd": "ln2fill minfillminutes"},
{"path": "maxfillminutes", "type": "float", "readonly": false, "cmd": "ln2fill maxfillminutes"},
{"path": "minholdhours", "type": "float", "readonly": false, "cmd": "ln2fill minholdhours"},
{"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"}]},
"mf": {"base": "/mf", "params": [
{"path": "", "type": "float", "readonly": false, "cmd": "run mf", "kids": 26},
{"path": "persmode", "type": "int", "readonly": false, "cmd": "mf persmode"},
{"path": "perswitch", "type": "int"},
{"path": "nowait", "type": "int", "readonly": false, "cmd": "mf nowait"},
{"path": "maxlimit", "type": "float", "visibility": 3},
{"path": "limit", "type": "float", "readonly": false, "cmd": "mf limit"},
{"path": "ramp", "type": "float", "readonly": false, "cmd": "mf ramp"},
{"path": "perscurrent", "type": "float", "readonly": false, "cmd": "mf perscurrent"},
{"path": "perslimit", "type": "float", "readonly": false, "cmd": "mf perslimit"},
{"path": "perswait", "type": "int", "readonly": false, "cmd": "mf perswait"},
{"path": "persdelay", "type": "int", "readonly": false, "cmd": "mf persdelay"},
{"path": "current", "type": "float"},
{"path": "measured", "type": "float"},
{"path": "voltage", "type": "float"},
{"path": "lastfield", "type": "float", "visibility": 3},
{"path": "ampRamp", "type": "float", "visibility": 3},
{"path": "inductance", "type": "float", "visibility": 3},
{"path": "trainedTo", "type": "float", "readonly": false, "cmd": "mf trainedTo"},
{"path": "trainMode", "type": "int"},
{"path": "external", "type": "int", "readonly": false, "cmd": "mf external"},
{"path": "startScript", "type": "text", "readonly": false, "cmd": "mf startScript", "visibility": 3},
{"path": "is_running", "type": "int", "readonly": false, "cmd": "mf is_running", "visibility": 3},
{"path": "verbose", "type": "int", "readonly": false, "cmd": "mf verbose", "visibility": 3},
{"path": "driver", "type": "text", "visibility": 3},
{"path": "creationCmd", "type": "text", "visibility": 3},
{"path": "targetValue", "type": "float"},
{"path": "status", "type": "text", "readonly": false, "cmd": "mf status", "visibility": 3}]},
"lev": {"base": "/lev", "params": [
{"path": "", "type": "float", "kids": 4},
{"path": "send", "type": "text", "readonly": false, "cmd": "lev send", "visibility": 3},
{"path": "status", "type": "text", "visibility": 3},
{"path": "mode", "type": "enum", "enum": {"slow": 0, "fast (switches to slow automatically after filling)": 1}, "readonly": false, "cmd": "lev mode"},
{"path": "n2", "type": "float"}]},
"tcoil": {"base": "/tcoil", "params": [
{"path": "", "type": "float", "kids": 11},
{"path": "send", "type": "text", "readonly": false, "cmd": "tcoil send", "visibility": 3},
{"path": "status", "type": "text", "visibility": 3},
{"path": "excitation", "type": "float", "readonly": false, "cmd": "tcoil excitation", "visibility": 3},
{"path": "ta", "type": "float", "kids": 3},
{"path": "ta/enable", "type": "bool", "readonly": false, "cmd": "tcoil ta/enable"},
{"path": "ta/r", "type": "float"},
{"path": "ta/curve", "type": "text", "readonly": false, "cmd": "tcoil ta/curve", "kids": 3},
{"path": "ta/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil ta/curve/adjust"},
{"path": "ta/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil ta/curve/points"},
{"path": "ta/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil ta/curve/cpoints"},
{"path": "tb", "type": "float", "kids": 3},
{"path": "tb/enable", "type": "bool", "readonly": false, "cmd": "tcoil tb/enable"},
{"path": "tb/r", "type": "float"},
{"path": "tb/curve", "type": "text", "readonly": false, "cmd": "tcoil tb/curve", "kids": 3},
{"path": "tb/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil tb/curve/adjust"},
{"path": "tb/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil tb/curve/points"},
{"path": "tb/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil tb/curve/cpoints"},
{"path": "td", "type": "float", "visibility": 3, "kids": 3},
{"path": "td/enable", "type": "bool", "readonly": false, "cmd": "tcoil td/enable"},
{"path": "td/r", "type": "float"},
{"path": "td/curve", "type": "text", "readonly": false, "cmd": "tcoil td/curve", "kids": 3},
{"path": "td/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil td/curve/adjust"},
{"path": "td/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil td/curve/points"},
{"path": "td/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil td/curve/cpoints"},
{"path": "ref", "type": "float", "visibility": 3, "kids": 3},
{"path": "ref/enable", "type": "bool", "readonly": false, "cmd": "tcoil ref/enable"},
{"path": "ref/r", "type": "float"},
{"path": "ref/curve", "type": "text", "readonly": false, "cmd": "tcoil ref/curve", "kids": 3},
{"path": "ref/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil ref/curve/adjust"},
{"path": "ref/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil ref/curve/points"},
{"path": "ref/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil ref/curve/cpoints"},
{"path": "tc", "type": "float", "visibility": 3, "kids": 3},
{"path": "tc/enable", "type": "bool", "readonly": false, "cmd": "tcoil tc/enable"},
{"path": "tc/r", "type": "float"},
{"path": "tc/curve", "type": "text", "readonly": false, "cmd": "tcoil tc/curve", "kids": 3},
{"path": "tc/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil tc/curve/adjust"},
{"path": "tc/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil tc/curve/points"},
{"path": "tc/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil tc/curve/cpoints"},
{"path": "ext", "type": "float", "visibility": 3},
{"path": "com", "type": "float", "visibility": 3},
{"path": "gnd", "type": "float", "visibility": 3}]},
"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 ..."}]}}

View File

@ -1,421 +0,0 @@
{"tt": {"base": "/tt", "params": [
{"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},
{"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": "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": "setsamp", "type": "float", "readonly": false, "cmd": "tt setsamp", "kids": 18},
{"path": "setsamp/mode", "type": "enum", "enum": {"disabled": -1, "off": 0, "controlling": 1, "manual": 2}, "readonly": false, "cmd": "tt setsamp/mode"},
{"path": "setsamp/reg", "type": "float"},
{"path": "setsamp/ramp", "type": "float", "readonly": false, "cmd": "tt setsamp/ramp", "description": "maximum ramp in K/min (0: ramp off)"},
{"path": "setsamp/wramp", "type": "float", "readonly": false, "cmd": "tt setsamp/wramp"},
{"path": "setsamp/smooth", "type": "float", "readonly": false, "cmd": "tt setsamp/smooth", "description": "smooth time (minutes)"},
{"path": "setsamp/channel", "type": "text", "readonly": false, "cmd": "tt setsamp/channel"},
{"path": "setsamp/limit", "type": "float", "readonly": false, "cmd": "tt setsamp/limit"},
{"path": "setsamp/resist", "type": "float", "readonly": false, "cmd": "tt setsamp/resist"},
{"path": "setsamp/maxheater", "type": "text", "readonly": false, "cmd": "tt setsamp/maxheater", "description": "maximum heater limit, units should be given without space: W, mW, A, mA"},
{"path": "setsamp/linearpower", "type": "float", "readonly": false, "cmd": "tt setsamp/linearpower", "description": "when not 0, it is the maximum effective power, and the power is linear to the heater output"},
{"path": "setsamp/maxpowerlim", "type": "float", "description": "the maximum power limit (before any booster or converter)"},
{"path": "setsamp/maxpower", "type": "float", "readonly": false, "cmd": "tt setsamp/maxpower", "description": "maximum power [W]"},
{"path": "setsamp/maxcurrent", "type": "float", "description": "the maximum current before any booster or converter"},
{"path": "setsamp/manualpower", "type": "float", "readonly": false, "cmd": "tt setsamp/manualpower"},
{"path": "setsamp/power", "type": "float"},
{"path": "setsamp/prop", "type": "float", "readonly": false, "cmd": "tt setsamp/prop", "description": "bigger means more gain"},
{"path": "setsamp/integ", "type": "float", "readonly": false, "cmd": "tt setsamp/integ", "description": "bigger means faster"},
{"path": "setsamp/deriv", "type": "float", "readonly": false, "cmd": "tt setsamp/deriv"},
{"path": "display", "type": "text", "readonly": false, "cmd": "tt display"},
{"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": 6}, "readonly": false, "cmd": "cc hea"},
{"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"},
{"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"}]},
"hefill": {"base": "/hefill", "params": [
{"path": "", "type": "enum", "enum": {"watching": 0, "filling": 1, "inactive": 2, "manualfill": 3}, "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"},
{"path": "readlevel", "type": "text", "readonly": false, "cmd": "hefill readlevel", "visibility": 3},
{"path": "lowlevel", "type": "float", "readonly": false, "cmd": "hefill lowlevel"},
{"path": "highlevel", "type": "float", "readonly": false, "cmd": "hefill highlevel"},
{"path": "smooth", "type": "float"},
{"path": "minfillminutes", "type": "float", "readonly": false, "cmd": "hefill minfillminutes"},
{"path": "maxfillminutes", "type": "float", "readonly": false, "cmd": "hefill maxfillminutes"},
{"path": "minholdhours", "type": "float", "readonly": false, "cmd": "hefill minholdhours"},
{"path": "maxholdhours", "type": "float", "readonly": false, "cmd": "hefill maxholdhours"},
{"path": "tolerance", "type": "float", "readonly": false, "cmd": "hefill tolerance"},
{"path": "badreadingminutes", "type": "float", "readonly": false, "cmd": "hefill badreadingminutes"},
{"path": "tubecoolingminutes", "type": "float", "readonly": false, "cmd": "hefill tubecoolingminutes"},
{"path": "vessellimit", "type": "float", "readonly": false, "cmd": "hefill vessellimit"},
{"path": "vext", "type": "float"}]},
"hepump": {"base": "/hepump", "params": [
{"path": "", "type": "enum", "enum": {"neodry": 8, "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"},
{"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", "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"}]},
"nvflow": {"base": "/nvflow", "params": [
{"path": "", "type": "float", "kids": 7},
{"path": "send", "type": "text", "readonly": false, "cmd": "nvflow send", "visibility": 3},
{"path": "status", "type": "text", "visibility": 3},
{"path": "stddev", "type": "float"},
{"path": "nsamples", "type": "int", "readonly": false, "cmd": "nvflow nsamples"},
{"path": "offset", "type": "float", "readonly": false, "cmd": "nvflow offset"},
{"path": "scale", "type": "float", "readonly": false, "cmd": "nvflow scale"},
{"path": "save", "type": "bool", "readonly": false, "cmd": "nvflow save", "description": "unchecked: current calib is not saved. set checked: save calib"}]},
"ln2fill": {"base": "/ln2fill", "params": [
{"path": "", "type": "enum", "enum": {"watching": 0, "filling": 1, "inactive": 2, "manualfill": 3}, "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"},
{"path": "readlevel", "type": "text", "readonly": false, "cmd": "ln2fill readlevel", "visibility": 3},
{"path": "lowlevel", "type": "float", "readonly": false, "cmd": "ln2fill lowlevel"},
{"path": "highlevel", "type": "float", "readonly": false, "cmd": "ln2fill highlevel"},
{"path": "smooth", "type": "float"},
{"path": "minfillminutes", "type": "float", "readonly": false, "cmd": "ln2fill minfillminutes"},
{"path": "maxfillminutes", "type": "float", "readonly": false, "cmd": "ln2fill maxfillminutes"},
{"path": "minholdhours", "type": "float", "readonly": false, "cmd": "ln2fill minholdhours"},
{"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"}]},
"mf": {"base": "/mf", "params": [
{"path": "", "type": "float", "readonly": false, "cmd": "run mf", "kids": 26},
{"path": "persmode", "type": "int", "readonly": false, "cmd": "mf persmode"},
{"path": "perswitch", "type": "int"},
{"path": "nowait", "type": "int", "readonly": false, "cmd": "mf nowait"},
{"path": "maxlimit", "type": "float", "visibility": 3},
{"path": "limit", "type": "float", "readonly": false, "cmd": "mf limit"},
{"path": "ramp", "type": "float", "readonly": false, "cmd": "mf ramp"},
{"path": "perscurrent", "type": "float", "readonly": false, "cmd": "mf perscurrent"},
{"path": "perslimit", "type": "float", "readonly": false, "cmd": "mf perslimit"},
{"path": "perswait", "type": "int", "readonly": false, "cmd": "mf perswait"},
{"path": "persdelay", "type": "int", "readonly": false, "cmd": "mf persdelay"},
{"path": "current", "type": "float"},
{"path": "measured", "type": "float"},
{"path": "voltage", "type": "float"},
{"path": "lastfield", "type": "float", "visibility": 3},
{"path": "ampRamp", "type": "float", "visibility": 3},
{"path": "inductance", "type": "float", "visibility": 3},
{"path": "trainedTo", "type": "float", "readonly": false, "cmd": "mf trainedTo"},
{"path": "trainMode", "type": "int"},
{"path": "external", "type": "int", "readonly": false, "cmd": "mf external"},
{"path": "startScript", "type": "text", "readonly": false, "cmd": "mf startScript", "visibility": 3},
{"path": "is_running", "type": "int", "readonly": false, "cmd": "mf is_running", "visibility": 3},
{"path": "verbose", "type": "int", "readonly": false, "cmd": "mf verbose", "visibility": 3},
{"path": "driver", "type": "text", "visibility": 3},
{"path": "creationCmd", "type": "text", "visibility": 3},
{"path": "targetValue", "type": "float"},
{"path": "status", "type": "text", "readonly": false, "cmd": "mf status", "visibility": 3}]},
"lev": {"base": "/lev", "params": [
{"path": "", "type": "float", "kids": 4},
{"path": "send", "type": "text", "readonly": false, "cmd": "lev send", "visibility": 3},
{"path": "status", "type": "text", "visibility": 3},
{"path": "mode", "type": "enum", "enum": {"slow": 0, "fast (switches to slow automatically after filling)": 1}, "readonly": false, "cmd": "lev mode"},
{"path": "n2", "type": "float"}]},
"tcoil": {"base": "/tcoil", "params": [
{"path": "", "type": "float", "kids": 11},
{"path": "send", "type": "text", "readonly": false, "cmd": "tcoil send", "visibility": 3},
{"path": "status", "type": "text", "visibility": 3},
{"path": "excitation", "type": "float", "readonly": false, "cmd": "tcoil excitation", "visibility": 3},
{"path": "ta", "type": "float", "visibility": 3, "kids": 3},
{"path": "ta/enable", "type": "bool", "readonly": false, "cmd": "tcoil ta/enable"},
{"path": "ta/r", "type": "float"},
{"path": "ta/curve", "type": "text", "readonly": false, "cmd": "tcoil ta/curve", "kids": 3},
{"path": "ta/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil ta/curve/adjust"},
{"path": "ta/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil ta/curve/points"},
{"path": "ta/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil ta/curve/cpoints"},
{"path": "tb", "type": "float", "visibility": 3, "kids": 3},
{"path": "tb/enable", "type": "bool", "readonly": false, "cmd": "tcoil tb/enable"},
{"path": "tb/r", "type": "float"},
{"path": "tb/curve", "type": "text", "readonly": false, "cmd": "tcoil tb/curve", "kids": 3},
{"path": "tb/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil tb/curve/adjust"},
{"path": "tb/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil tb/curve/points"},
{"path": "tb/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil tb/curve/cpoints"},
{"path": "td", "type": "float", "visibility": 3, "kids": 3},
{"path": "td/enable", "type": "bool", "readonly": false, "cmd": "tcoil td/enable"},
{"path": "td/r", "type": "float"},
{"path": "td/curve", "type": "text", "readonly": false, "cmd": "tcoil td/curve", "kids": 3},
{"path": "td/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil td/curve/adjust"},
{"path": "td/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil td/curve/points"},
{"path": "td/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil td/curve/cpoints"},
{"path": "ref", "type": "float", "visibility": 3, "kids": 3},
{"path": "ref/enable", "type": "bool", "readonly": false, "cmd": "tcoil ref/enable"},
{"path": "ref/r", "type": "float"},
{"path": "ref/curve", "type": "text", "readonly": false, "cmd": "tcoil ref/curve", "kids": 3},
{"path": "ref/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil ref/curve/adjust"},
{"path": "ref/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil ref/curve/points"},
{"path": "ref/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil ref/curve/cpoints"},
{"path": "tc", "type": "float", "visibility": 3, "kids": 3},
{"path": "tc/enable", "type": "bool", "readonly": false, "cmd": "tcoil tc/enable"},
{"path": "tc/r", "type": "float"},
{"path": "tc/curve", "type": "text", "readonly": false, "cmd": "tcoil tc/curve", "kids": 3},
{"path": "tc/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil tc/curve/adjust"},
{"path": "tc/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil tc/curve/points"},
{"path": "tc/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil tc/curve/cpoints"},
{"path": "ext", "type": "float", "visibility": 3},
{"path": "com", "type": "float", "visibility": 3},
{"path": "gnd", "type": "float", "visibility": 3}]},
"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 ..."}]}}

View File

@ -1,10 +1,10 @@
Node('ccrpe.config.sea.psi.ch',
'''4 K closed cycle cryostat (PE cell)''',
Node('ori7.config.sea.psi.ch',
'''orange cryostat with 50 mm sample space for ULT''',
)
Mod('sea_main',
'frappy_psi.sea.SeaClient',
'main sea connection for ccrpe.config',
config = 'ccrpe.config',
'main sea connection for ori7.config',
config = 'ori7.config',
service = 'main',
)
Mod('tt',
@ -22,6 +22,16 @@ Mod('nv',
io = 'sea_main',
sea_object = 'nv',
)
Mod('ln2fill',
'frappy_psi.sea.SeaWritable', '',
io = 'sea_main',
sea_object = 'ln2fill',
)
Mod('hefill',
'frappy_psi.sea.SeaWritable', '',
io = 'sea_main',
sea_object = 'hefill',
)
Mod('hepump',
'frappy_psi.sea.SeaWritable', '',
io = 'sea_main',
@ -37,13 +47,8 @@ Mod('nvflow',
io = 'sea_main',
sea_object = 'nvflow',
)
Mod('warmup',
'frappy_psi.sea.SeaDrivable', '',
io = 'sea_main',
sea_object = 'warmup',
)
Mod('p',
Mod('table',
'frappy_psi.sea.SeaReadable', '',
io = 'sea_main',
sea_object = 'p',
sea_object = 'table',
)

View File

@ -1,76 +0,0 @@
{"res": {"base": "/res", "params": [
{"path": "", "type": "int", "kids": 10},
{"path": "send", "type": "text", "readonly": false, "cmd": "res send", "visibility": 3},
{"path": "status", "type": "text", "visibility": 3},
{"path": "autoscan", "type": "bool", "readonly": false, "cmd": "res autoscan", "kids": 4},
{"path": "autoscan/synchronized", "type": "bool", "readonly": false, "cmd": "res autoscan/synchronized"},
{"path": "autoscan/interval", "type": "text", "readonly": false, "cmd": "res autoscan/interval"},
{"path": "autoscan/pause", "type": "text", "readonly": false, "cmd": "res autoscan/pause"},
{"path": "autoscan/dwell", "type": "text", "readonly": false, "cmd": "res autoscan/dwell"},
{"path": "s1", "type": "float", "kids": 14},
{"path": "s1/active", "type": "enum", "enum": {"inactive": 0, "active": 1}, "readonly": false, "cmd": "res s1/active"},
{"path": "s1/autorange", "type": "bool", "readonly": false, "cmd": "res s1/autorange", "description": "autorange (common for all channels)"},
{"path": "s1/range", "type": "text", "readonly": false, "cmd": "res s1/range", "description": "resistance range in Ohm"},
{"path": "s1/range_num", "type": "int"},
{"path": "s1/excitation", "type": "text", "readonly": false, "cmd": "res s1/excitation", "description": "excitation with unit, i.e. 2uV or 3pA"},
{"path": "s1/excitation_num", "type": "int"},
{"path": "s1/excitation_mode", "type": "enum", "enum": {"voltage": 0, "current": 1, "off": 2}},
{"path": "s1/pause", "type": "int", "readonly": false, "cmd": "res s1/pause", "description": "pause time [sec] after channel change"},
{"path": "s1/filter", "type": "int", "readonly": false, "cmd": "res s1/filter", "description": "filter average time [sec]"},
{"path": "s1/dwell", "type": "int", "readonly": false, "cmd": "res s1/dwell", "description": "dwell time [sec]. Total time per channel: pause + filter + dwell"},
{"path": "s1/status", "type": "text"},
{"path": "s1/curve", "type": "text", "readonly": false, "cmd": "res s1/curve", "kids": 1},
{"path": "s1/curve/points", "type": "floatvarar", "readonly": false, "cmd": "res s1/curve/points", "visibility": 3},
{"path": "s1/alarm", "type": "float", "readonly": false, "cmd": "res s1/alarm"},
{"path": "s1/raw", "type": "float"},
{"path": "s2", "type": "float", "kids": 14},
{"path": "s2/active", "type": "enum", "enum": {"inactive": 0, "active": 1}, "readonly": false, "cmd": "res s2/active"},
{"path": "s2/autorange", "type": "bool", "readonly": false, "cmd": "res s2/autorange", "description": "autorange (common for all channels)"},
{"path": "s2/range", "type": "text", "readonly": false, "cmd": "res s2/range", "description": "resistance range in Ohm"},
{"path": "s2/range_num", "type": "int"},
{"path": "s2/excitation", "type": "text", "readonly": false, "cmd": "res s2/excitation", "description": "excitation with unit, i.e. 2uV or 3pA"},
{"path": "s2/excitation_num", "type": "int"},
{"path": "s2/excitation_mode", "type": "enum", "enum": {"voltage": 0, "current": 1, "off": 2}},
{"path": "s2/pause", "type": "int", "readonly": false, "cmd": "res s2/pause", "description": "pause time [sec] after channel change"},
{"path": "s2/filter", "type": "int", "readonly": false, "cmd": "res s2/filter", "description": "filter average time [sec]"},
{"path": "s2/dwell", "type": "int", "readonly": false, "cmd": "res s2/dwell", "description": "dwell time [sec]. Total time per channel: pause + filter + dwell"},
{"path": "s2/status", "type": "text"},
{"path": "s2/curve", "type": "text", "readonly": false, "cmd": "res s2/curve", "kids": 1},
{"path": "s2/curve/points", "type": "floatvarar", "readonly": false, "cmd": "res s2/curve/points", "visibility": 3},
{"path": "s2/alarm", "type": "float", "readonly": false, "cmd": "res s2/alarm"},
{"path": "s2/raw", "type": "float"},
{"path": "s3", "type": "float", "kids": 14},
{"path": "s3/active", "type": "enum", "enum": {"inactive": 0, "active": 1}, "readonly": false, "cmd": "res s3/active"},
{"path": "s3/autorange", "type": "bool", "readonly": false, "cmd": "res s3/autorange", "description": "autorange (common for all channels)"},
{"path": "s3/range", "type": "text", "readonly": false, "cmd": "res s3/range", "description": "resistance range in Ohm"},
{"path": "s3/range_num", "type": "int"},
{"path": "s3/excitation", "type": "text", "readonly": false, "cmd": "res s3/excitation", "description": "excitation with unit, i.e. 2uV or 3pA"},
{"path": "s3/excitation_num", "type": "int"},
{"path": "s3/excitation_mode", "type": "enum", "enum": {"voltage": 0, "current": 1, "off": 2}},
{"path": "s3/pause", "type": "int", "readonly": false, "cmd": "res s3/pause", "description": "pause time [sec] after channel change"},
{"path": "s3/filter", "type": "int", "readonly": false, "cmd": "res s3/filter", "description": "filter average time [sec]"},
{"path": "s3/dwell", "type": "int", "readonly": false, "cmd": "res s3/dwell", "description": "dwell time [sec]. Total time per channel: pause + filter + dwell"},
{"path": "s3/status", "type": "text"},
{"path": "s3/curve", "type": "text", "readonly": false, "cmd": "res s3/curve", "kids": 1},
{"path": "s3/curve/points", "type": "floatvarar", "readonly": false, "cmd": "res s3/curve/points", "visibility": 3},
{"path": "s3/alarm", "type": "float", "readonly": false, "cmd": "res s3/alarm"},
{"path": "s3/raw", "type": "float"},
{"path": "s4", "type": "float", "kids": 14},
{"path": "s4/active", "type": "enum", "enum": {"inactive": 0, "active": 1}, "readonly": false, "cmd": "res s4/active"},
{"path": "s4/autorange", "type": "bool", "readonly": false, "cmd": "res s4/autorange", "description": "autorange (common for all channels)"},
{"path": "s4/range", "type": "text", "readonly": false, "cmd": "res s4/range", "description": "resistance range in Ohm"},
{"path": "s4/range_num", "type": "int"},
{"path": "s4/excitation", "type": "text", "readonly": false, "cmd": "res s4/excitation", "description": "excitation with unit, i.e. 2uV or 3pA"},
{"path": "s4/excitation_num", "type": "int"},
{"path": "s4/excitation_mode", "type": "enum", "enum": {"voltage": 0, "current": 1, "off": 2}},
{"path": "s4/pause", "type": "int", "readonly": false, "cmd": "res s4/pause", "description": "pause time [sec] after channel change"},
{"path": "s4/filter", "type": "int", "readonly": false, "cmd": "res s4/filter", "description": "filter average time [sec]"},
{"path": "s4/dwell", "type": "int", "readonly": false, "cmd": "res s4/dwell", "description": "dwell time [sec]. Total time per channel: pause + filter + dwell"},
{"path": "s4/status", "type": "text"},
{"path": "s4/curve", "type": "text", "readonly": false, "cmd": "res s4/curve", "kids": 1},
{"path": "s4/curve/points", "type": "floatvarar", "readonly": false, "cmd": "res s4/curve/points", "visibility": 3},
{"path": "s4/alarm", "type": "float", "readonly": false, "cmd": "res s4/alarm"},
{"path": "s4/raw", "type": "float"},
{"path": "analog2", "type": "float", "readonly": false, "cmd": "res analog2"},
{"path": "remote", "type": "bool"},
{"path": "display", "type": "text", "readonly": false, "cmd": "res display"}]}}

View File

@ -1,49 +0,0 @@
Node('simulation',
'Auto-generated configuration by frappy.',
'tcp://10767',
)
Mod('analoginput',
'frappy_mlz.entangle.AnalogInput',
'from test/sim/analoginput',
tangodevice = 'tango://localhost:10000/test/sim/analoginput',
)
Mod('sensor',
'frappy_mlz.entangle.Sensor',
'from test/sim/sensor',
tangodevice = 'tango://localhost:10000/test/sim/sensor',
)
Mod('analogoutput',
'frappy_mlz.entangle.AnalogOutput',
'from test/sim/analogoutput',
tangodevice = 'tango://localhost:10000/test/sim/analogoutput',
)
Mod('actuator',
'frappy_mlz.entangle.Actuator',
'from test/sim/actuator',
tangodevice = 'tango://localhost:10000/test/sim/actuator',
)
Mod('motor',
'frappy_mlz.entangle.Motor',
'from test/sim/motor',
tangodevice = 'tango://localhost:10000/test/sim/motor',
)
Mod('powersupply',
'frappy_mlz.entangle.PowerSupply',
'from test/sim/powersupply',
tangodevice = 'tango://localhost:10000/test/sim/powersupply',
)
Mod('digitalinput',
'frappy_mlz.entangle.DigitalInput',
'from test/sim/digitalinput',
tangodevice = 'tango://localhost:10000/test/sim/digitalinput',
)
Mod('digitaloutput',
'frappy_mlz.entangle.DigitalOutput',
'from test/sim/digitaloutput',
tangodevice = 'tango://localhost:10000/test/sim/digitaloutput',
)
Mod('stringio',
'frappy_mlz.entangle.StringIO',
'from test/sim/stringio',
tangodevice = 'tango://localhost:10000/test/sim/stringio',
)

View File

@ -138,6 +138,13 @@ Mod('T_one_K',
io='itc',
)
Mod('htr_one_K',
'frappy_psi.mercury.HeaterOutput',
'1 K plate warmup heater',
slot='DB3.H1',
io='itc',
)
Mod('T_mix_wup',
'frappy_psi.mercury.TemperatureLoop',
'mix. chamber warmup temperature',

View File

@ -10,14 +10,6 @@ Mod('sea_stick',
)
Mod('ts',
'frappy_psi.sea.SeaReadable', '',
io='sea_stick',
sea_object='tt',
json_file='ma6.config.json',
rel_paths=['ts_2'],
)
Mod('ts_reg',
'frappy_psi.sea.SeaReadable', '',
io='sea_stick',
sea_object='tt',
@ -30,11 +22,3 @@ Mod('hcp',
io='sea_stick',
sea_object='hcp',
)
Mod('v',
'frappy_psi.parmod.Driv',
'drivable voltage',
read='hcp.value',
write='hcp.set',
unit='V',
)

View File

@ -22,8 +22,8 @@ Mod('ts',
'frappy_psi.parmod.Converging',
'virtual stick T',
unit='K',
value_param='tsam.value',
target_param='tsam.setsamp',
read='tsam.value',
write='tsam.setsamp',
meaning=['temperature', 20],
settling_time=20,
tolerance=1,

View File

@ -1,11 +0,0 @@
Node('ma6_sampleheat.psi.ch', '', interface='tcp://5000')
Mod('sea_stick',
'frappy_psi.sea.SeaClient',
'stick sea connection for ma6_sampleheat.stick',
config='ma6_sampleheat.stick',
service='stick',
)
# ts is configured on ma7_sampleheat_cfg.py

View File

@ -1,18 +0,0 @@
Node('ma7.stick.sea.psi.ch',
'MA7 standard sample stick',
)
Mod('sea_stick',
'frappy_psi.sea.SeaClient',
'SEA stick connection',
config='ma7_piezo.stick',
service='stick',
)
Mod('ts',
'frappy_psi.sea.SeaReadable', '',
io='sea_stick',
sea_object='tt',
json_file='ma7_piezo.config.json',
rel_paths=['ts'],
)

View File

@ -1,72 +0,0 @@
Node('ma7.stick.sea.psi.ch',
'MA7 standard sample stick',
)
Mod('sea_stick',
'frappy_psi.sea.SeaClient',
'SEA stick connection',
config='ma7.stick',
service='stick',
)
Mod('ts_sea',
'frappy_psi.sea.SeaReadable',
'sample stick temperature',
io='sea_stick',
json_file='ma7.config.json',
sea_object='tt',
rel_paths=['ts', 'setsamp'],
# export=False,
)
Mod('tm_sea',
'frappy_psi.sea.SeaReadable',
'sample stick temperature',
io='sea_stick',
json_file='ma7.config.json',
sea_object='tt',
rel_paths=['tm', 'set'],
# export=False,
)
Mod('ts_writ',
'frappy_psi.parmod.ParWrit',
'writable version of ts',
unit='K',
value_param='ts_sea.value',
target_param='ts_sea.setsamp',
)
Mod('tm_writ',
'frappy_psi.parmod.ParWrit',
'writable version of tm',
unit='K',
value_param='tm_sea.value',
target_param='tm_sea.set',
)
Mod('sam_htr',
'frappy_psi.parmod.Par',
'htr module version',
unit='W',
value_param='ts_sea.power',
)
Mod('vti_htr',
'frappy_psi.parmod.Par',
'htr module version',
unit='W',
value_param='tm_sea.power',
)
Mod('ts',
'frappy_psi.parmod.CombinedSampleVti',
'drivable stick T using setsamp',
sample='ts_writ',
sample_htr='sam_htr',
vti='tm_writ',
vti_htr='vti_htr',
meaning=['temperature', 20],
settling_time=20,
tolerance=1,
)

View File

@ -9,7 +9,7 @@ Mod('sea_stick',
service='stick',
)
Mod('ts_sea',
Mod('tsam',
'frappy_psi.sea.SeaReadable',
'sample stick temperature',
io='sea_stick',
@ -22,8 +22,8 @@ Mod('ts',
'frappy_psi.parmod.Converging',
'drivable stick T using setsamp',
unit='K',
value_param='ts_sea.value',
target_param='ts_sea.setsamp',
read='tsam.value',
write='tsam.setsamp',
meaning=['temperature', 20],
settling_time=20,
tolerance=1,

View File

@ -9,23 +9,10 @@ Mod('sea_stick',
service='stick',
)
Mod('tsam',
'frappy_psi.sea.SeaReadable',
'sample stick temperature',
io='sea_stick',
json_file='ma7.config.json',
sea_object='tt',
rel_paths=['ts', 'setsamp']
)
Mod('ts',
'frappy_psi.parmod.Converging',
'drivable stick T using setsamp',
unit='K',
value_param='tsam.value',
target_param='tsam.setsamp',
meaning=['temperature', 20],
settling_time=20,
tolerance=1,
'frappy_psi.sea.SeaReadable', '',
io='sea_stick',
sea_object='tt',
json_file='ma7.config.json',
rel_paths=['ts'],
)

23
cfg/stick/pgas5.stick Normal file
View File

@ -0,0 +1,23 @@
[NODE]
description = PGAS5 gas pressure cell stick
id = pgas5.stick.sea.psi.ch
[sea_stick]
class = secop_psi.sea.SeaClient
description = stick SEA connection to ill5.stick
config = ill5.stick
service = stick
[ts]
class = secop_psi.sea.SeaReadable
io = sea_stick
sea_object = tt
json_file = ill5.config.json
rel_paths = ts
[T_bottom]
class = secop_psi.sea.SeaReadable
io = sea_stick
sea_object = tt
json_file = ill5.config.json
rel_paths = tb

View File

@ -1,28 +0,0 @@
Node('pgas5.stick.sea.psi.ch',
'PGAS5 gas pressure cell stick',
)
Mod('sea_stick',
'frappy_psi.sea.SeaClient',
'stick SEA connection to ill5.stick',
config = 'pgas5.stick',
service = 'stick',
)
Mod('ts',
'frappy_psi.sea.SeaReadable',
'sample temperature',
io = 'sea_stick',
sea_object = 'tt',
json_file = 'ill5pgas5.config.json',
rel_paths = ['ts'],
)
Mod('T_bottom',
'frappy_psi.sea.SeaReadable',
'bottom T',
io = 'sea_stick',
sea_object = 'tt',
json_file = 'ill5pgas5.config.json',
rel_paths = ['ts_2'],
)

View File

@ -1,67 +0,0 @@
Node('thermalcond.stick.sea.psi.ch',
'''50 mm thermal conductivity stick, version with standard lsc370 driver''',
)
Mod('sea_stick',
'frappy_psi.sea.SeaClient',
'stick sea connection for thermalcond.stick',
config = 'thermalcond.stick',
service = 'stick',
)
#Mod('tsam',
# 'frappy_psi.sea.SeaReadable',
# 'sample stick temperature',
# io='sea_stick',
# json_file='ma7.config.json',
# sea_object='tt',
# rel_paths=['ts', 'setsamp']
#)
#Mod('ts',
# 'frappy_psi.parmod.Converging',
# 'drivable stick T using setsamp',
# unit='K',
# value_param='tsam.value',
# target_param='tsam.setsamp',
# meaning=['temperature', 20],
# settling_time=20,
# tolerance=1,
#)
#Mod('res',
# 'frappy_psi.sea.SeaReadable', '',
# io = 'sea_stick',
# sea_object = 'res',
#)
Mod('R1',
'frappy_psi.sea.SeaReadable', '',
io='sea_stick',
sea_object='res',
rel_paths=['s1'],
)
Mod('R2',
'frappy_psi.sea.SeaReadable', '',
io='sea_stick',
sea_object='res',
rel_paths=['s2'],
)
Mod('R3',
'frappy_psi.sea.SeaReadable', '',
io='sea_stick',
sea_object='res',
rel_paths=['s3'],
)
Mod('R4',
'frappy_psi.sea.SeaReadable', '',
io='sea_stick',
sea_object='res',
rel_paths=['s4'],
)

View File

@ -1,103 +0,0 @@
Node('vf.psi.ch',
'small vacuum furnace',
'tcp://5000',
)
Mod('htr_io',
'frappy_psi.bkpower.IO',
'powersupply communicator',
uri = 'serial:///dev/ttyUSBupper',
)
Mod('htr',
'frappy_psi.bkpower.Power',
'heater power',
io= 'htr_io',
)
Mod('out',
'frappy_psi.bkpower.Output',
'heater output',
io = 'htr_io',
maxvolt = 50,
maxcurrent = 2,
)
Mod('relais',
'frappy_psi.ionopimax.DigitalOutput',
'relais for power output',
addr = 'o2',
)
Mod('T_main',
'frappy_psi.ionopimax.CurrentInput',
'sample temperature',
addr = 'ai4',
valuerange = (0, 1372),
value = Param(unit='degC'),
)
Mod('T_extra',
'frappy_psi.ionopimax.CurrentInput',
'extra temperature',
addr = 'ai3',
valuerange = (0, 1372),
value = Param(unit='degC'),
)
Mod('T_htr',
'frappy_psi.ionopimax.CurrentInput',
'heater temperature',
addr = 'ai2',
valuerange = (0, 1372),
value = Param(unit='degC'),
)
Mod('T_wall',
'frappy_psi.ionopimax.VoltageInput',
'furnace wall temperature',
addr = 'av2',
rawrange = (0, 1.5),
valuerange = (0, 150),
value = Param(unit='degC'),
)
Mod('T',
'frappy_psi.picontrol.PI',
'controlled Temperature',
input = 'T_htr',
output = 'out',
relais = 'relais',
p = 2,
i = 0.01,
)
Mod('interlocks',
'frappy_psi.furnace.Interlocks',
'interlock parameters',
input = 'T_htr',
wall_T = 'T_wall',
vacuum = 'p',
relais = 'relais',
control = 'T',
wall_limit = 50,
vacuum_limit = 0.1,
)
Mod('p_io',
'frappy_psi.pfeiffer.IO',
'pressure io',
uri='serial:///dev/ttyUSBlower',
)
Mod('p',
'frappy_psi.pfeiffer.Pressure',
'pressure reading',
io = 'p_io',
)

11
ci/Jenkinsfile vendored
View File

@ -141,23 +141,12 @@ def run_docs() {
'''
}
/* does not work with too many quote levels
* alternatively use pdf (based on rst2pdf)
* or singlehtml converted to pdf manually from a browser (may produce nicer output)
stage('build latexpdf') {
sh '''
. /home/jenkins/secopvenv/bin/activate
make -C doc latexpdf
'''
}
*/
stage('build pdf') {
sh '''
. /home/jenkins/secopvenv/bin/activate
make -C doc pdf
'''
}
stage('build man') {
sh '''

174
debian/changelog vendored
View File

@ -1,177 +1,3 @@
frappy-core (0.19.0) jammy; urgency=medium
[ Markus Zolliker ]
* simulation: extra_params might be a list
* add FloatEnumParam
* move StructParam to frappy/extparams.py
* bugfix in automatic creation if attached io
* fixes for proxy modules
* simplify callbacks
* fix docstring in frappy.error.OutOfRangeError
[ Alexander Zaft ]
* core: introduce common handler class
* core: cover errors in handler setup()
[ Markus Zolliker ]
* fix command doc string handling and change default stop doc string
* follow up fix for change 33168
* follow up fix: handler export=True correctly
[ Alexander Zaft ]
* core: add websocket interface
[ Georg Brandl ]
* dispatcher: consistent handling of missing timestamps
[ Alexander Zaft ]
* gui: catch invalid inputs
* gui: sort qt imports
[ Markus Zolliker ]
* frappy.client: cleanup properly after a reply timeout
[ Alexander Zaft ]
* gui: more specialized input widgets
* test: add uri attach test
[ Markus Zolliker ]
* frappy.client: catch errors on callbacks
* frappy.client: improve error handling more
* frappy.client.interactive: improve logging and error handling
* frappy.client.SecopClient: add the option to use no logging at all
* SecopClient.__del__ must not call callbacks
* frappy.client: avoid shutdown callback sent twice
[ Georg Brandl ]
* add config for the Entangle simulation server
[ Jens Krüger ]
* Fix abslimits reading from entangle device
[ Georg Brandl ]
* fix LimitsType to be actually used and validated
-- Markus Zolliker <jenkins@frm2.tum.de> Thu, 16 May 2024 11:31:25 +0200
frappy-core (0.18.1) focal; urgency=medium
* mlz: Zapf fix unit handling and small errors
* mlz: entangle fix limit check
-- Alexander Zaft <jenkins@frm2.tum.de> Wed, 24 Jan 2024 14:59:21 +0100
frappy-core (0.18.0) focal; urgency=medium
[ Alexander Zaft ]
* Add shutdownModule function
[ Markus Zolliker ]
* frappy_psi.convergence: bug fixes and improvements
[ Alexander Zaft ]
* server: Add signal handling
* add test cases for server and config
[ Markus Zolliker ]
* fix frappy.lib.merge_status
* frappy_psi.sea: try to reconnect on failure
* pylint: disable use-dict-literal
[ Alexander Zaft ]
* server: add option to dynamically create devices
[ Markus Zolliker ]
* add StructParam
* add frappy_psi.thermofisher
* add frappy_psi.thermofisher to the doc
* frappy.io: make error reporting consistent
* frappy_psi.sea: avoid multiple connections
* frappy_psi.sea: further bug fixes
* frappy.client.interactive: bug fixes
[ Alexander Zaft ]
* mlz: Add Zebra Barcode Reader
* frappy_mlz: Zebra fixes after basic test
* dispatcher: change logging calls to debug
* core: do not call register_module on error
* add zapf to requirements-dev.txt
* frappy_mlz: Add Zapf PLC
* Revert "add zapf to requirements-dev.txt"
* add zapf to requirements-dev
* frappy_mlz: fix one-off error in barcode reader
[ Markus Zolliker ]
* improve error message on client when host/port is bad
* frappy/protocol/interface/tcp.py: use SECoP_DEFAULT_PORT
* frappy_psi.phytron: stop motor before restart
* interactive client: improve keyboard interrupt
* fix frappy/playground.py after change 31470
[ Alexander Zaft ]
* frappy_mlz seop: add count to ampl and phase cmds
[ Markus Zolliker ]
* frappy_psi.phytron: further improvements
* further fixes after change 31470
* fix missing .poll attribute in simulation
* psi: improve sea interface
* fix frappy_demo.lakeshore
* change FloatRange arguments minval/maxval to min/max
* improve client shutdown time
* introduce FrozenParam
* phytron.py: improve status
* frappy_psi.sea: small fixes
* bug in Attached (fix after change 31470)
[ Alexander Zaft ]
* core: split module code
* core: factor out accessibles from init
[ Markus Zolliker ]
* proxy: fix command wrapper
[ Alexander Zaft ]
* server: handle signals during startup
* all: remove coding cookies
* psi: fix Done import in sea
[ Markus Zolliker ]
* frappy.io: change default to retry_first_idn=True
[ Alexander Zaft ]
* core: move module handling out of dispatcher
* mlz/demo: move old examples to Attached
[ Markus Zolliker ]
* frappy.client: fix the case then timestamp is missing
* doc: drop latex support, add pdf support
* add StringIO.writeline, improve StringIO.multicomm
* implement pfeiffer TPG vacuum reading
[ Alexander Zaft ]
* core: allow multiple interfaces
* core: formatting and update server docstring
* mlz: handle unconfigured abslimits
* datatypes: fix optional struct export
* core: better command handling
[ Markus Zolliker ]
* frappy_psi.sea: workaround for bug in sea
[ Alexander Zaft ]
* core: better error on export of internal type
[ Markus Zolliker ]
* fix missing import in change message
* modify arguments of Dispatcher.announce_update
* frappy.secnode: fix strange error message
* fix playground after change 32249
* remove py35 compatibility code
* bug fix in frappy.io.BytesIO.checkHWIdent
-- Alexander Zaft <jenkins@frm2.tum.de> Wed, 17 Jan 2024 12:35:00 +0100
frappy-core (0.17.13) focal; urgency=medium
[ Alexander Zaft ]

View File

@ -1,4 +1,5 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Frappy documentation build configuration file, created by
# sphinx-quickstart on Mon Sep 11 10:58:28 2017.
@ -42,9 +43,7 @@ extensions = ['sphinx.ext.autodoc',
'sphinx.ext.intersphinx',
'sphinx.ext.todo',
'sphinx.ext.mathjax',
'sphinx.ext.viewcode',
'rst2pdf.pdfbuilder',
]
'sphinx.ext.viewcode']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
@ -221,80 +220,3 @@ from frappy.lib.classdoc import class_doc_handler
def setup(app):
app.connect('autodoc-process-docstring', class_doc_handler)
# -- Options for PDF output --------------------------------------------------
# Grouping the document tree into PDF files. List of tuples
# (source start file, target name, title, author, options).
#
# If there is more than one author, separate them with \\.
# For example: r'Guido van Rossum\\Fred L. Drake, Jr., editor'
#
# The options element is a dictionary that lets you override
# this config per-document. For example:
#
# ('index', 'MyProject', 'My Project', 'Author Name', {'pdf_compressed': True})
#
# would mean that specific document would be compressed
# regardless of the global 'pdf_compressed' setting.
pdf_documents = [
('index', project, project, author),
]
# A comma-separated list of custom stylesheets. Example:
pdf_stylesheets = ['sphinx', 'a4']
# A list of folders to search for stylesheets. Example:
pdf_style_path = ['.', '_styles']
# Create a compressed PDF
# Use True/False or 1/0
# Example: compressed=True
# pdf_compressed = False
# A colon-separated list of folders to search for fonts. Example:
# pdf_font_path = ['/usr/share/fonts', '/usr/share/texmf-dist/fonts/']
# Language to be used for hyphenation support
# pdf_language = "en_US"
# Mode for literal blocks wider than the frame. Can be
# overflow, shrink or truncate
# pdf_fit_mode = "shrink"
# Section level that forces a break page.
# For example: 1 means top-level sections start in a new page
# 0 means disabled
# pdf_break_level = 0
# When a section starts in a new page, force it to be 'even', 'odd',
# or just use 'any'
# pdf_breakside = 'any'
# Insert footnotes where they are defined instead of
# at the end.
# pdf_inline_footnotes = True
# verbosity level. 0 1 or 2
# pdf_verbosity = 0
# If false, no index is generated.
# pdf_use_index = True
# If false, no modindex is generated.
# pdf_use_modindex = True
# If false, no coverpage is generated.
# pdf_use_coverpage = True
# Name of the cover page template to use
# pdf_cover_template = 'sphinxcover.tmpl'
# Documents to append as an appendix to all manuals.
# pdf_appendices = []
# Enable experimental feature to split table cells. Use it
# if you get "DelayedTable too big" errors
# pdf_splittables = False
# Set the default DPI for images
# pdf_default_dpi = 72
# Enable rst2pdf extension modules
# pdf_extensions = []
# Page template name for "regular" pages
# pdf_page_template = 'cutePage'
# Show Table Of Contents at the beginning?
# pdf_use_toc = True
# How many levels deep should the table of contents be?
pdf_toc_depth = 9999
# Add section number to section references
pdf_use_numbered_links = False
# Background images fitting mode
pdf_fit_background_mode = 'scale'
# Repeat table header on tables that cross a page boundary?
pdf_repeat_table_rows = True
# Enable smart quotes (1, 2 or 3) or disable by setting to 0
pdf_smartquotes = 0

View File

@ -405,7 +405,7 @@ Appendix 2: Extract from the LakeShore Manual
Reply <range> *term*
**Operation Complete Query**
----------------------------------------------
Command \*OPC?
Command *OPC?
Reply 1
Description in Frappy, we append this command to request in order
to generate a reply

View File

@ -1,4 +1,5 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# *****************************************************************************
# Copyright (c) 2015-2019 by the authors, see LICENSE
#

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
# *****************************************************************************
# Copyright (c) 2015-2016 by the authors, see LICENSE
#

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
# *****************************************************************************
#
# This program is free software; you can redistribute it and/or modify it under
@ -29,10 +30,10 @@ import time
from collections import defaultdict
from threading import Event, RLock, current_thread
import frappy.errors
import frappy.params
from frappy.errors import make_secop_error, SECoPError, WrongTypeError
from frappy.datatypes import get_datatype
from frappy.lib import mkthread
from frappy.lib import mkthread, formatExtendedStack
from frappy.lib.asynconn import AsynConn, ConnectionClosed
from frappy.protocol.interface import decode_msg, encode_msg_frame
from frappy.protocol.messages import COMMANDREQUEST, \
@ -43,7 +44,7 @@ from frappy.protocol.messages import COMMANDREQUEST, \
# replies to be handled for cache
UPDATE_MESSAGES = {EVENTREPLY, READREPLY, WRITEREPLY, ERRORPREFIX + READREQUEST, ERRORPREFIX + EVENTREPLY}
VERSIONFMT = re.compile(r'^[^,]*?ISSE[^,]*,SECoP,')
VERSIONFMT= re.compile(r'^[^,]*?ISSE[^,]*,SECoP,')
class UnregisterCallback(Exception):
@ -68,10 +69,6 @@ class Logger:
error = exception = warning = critical = info
class NullLogger(Logger):
error = exception = warning = critical = info = Logger.noop
class CallbackObject:
"""abstract definition for a target object for callbacks
@ -87,12 +84,6 @@ class CallbackObject:
def unhandledMessage(self, action, ident, data):
"""called on an unhandled message"""
def handleError(self, exc):
"""called on errors handling messages
:param exc: the exception raised (= sys.exception())
"""
def nodeStateChange(self, online, state):
"""called when the state of the connection changes
@ -115,13 +106,19 @@ class CacheItem(tuple):
inheriting from tuple: compatible with old previous version of cache
"""
def __new__(cls, value, timestamp=None, readerror=None, datatype=None):
obj = tuple.__new__(cls, (value, timestamp, readerror))
if datatype:
if readerror:
assert isinstance(readerror, Exception)
else:
try:
value = datatype.import_value(value)
except (KeyError, ValueError, AttributeError):
readerror = ValueError(f'can not import {value!r} as {datatype!r}')
value = None
obj = tuple.__new__(cls, (value, timestamp, readerror))
try:
# override default method
obj.format_value = datatype.format_value
except AttributeError:
pass
obj.format_value = lambda value, unit=None: str(value)
return obj
@property
@ -148,11 +145,6 @@ class CacheItem(tuple):
return repr(self[2])
return self.format_value(self[0])
@staticmethod
def format_value(value, unit=None):
"""typically overridden with datatype.format_value"""
return str(value)
def __repr__(self):
args = (self.value,)
if self.timestamp:
@ -162,22 +154,11 @@ class CacheItem(tuple):
return f'CacheItem{repr(args)}'
class Cache(dict):
class Undefined(Exception):
def __repr__(self):
return '<undefined>'
undefined = CacheItem(None, None, Undefined())
def __missing__(self, key):
return self.undefined
class ProxyClient:
"""common functionality for proxy clients"""
CALLBACK_NAMES = {'updateEvent', 'updateItem', 'descriptiveDataChange',
'nodeStateChange', 'unhandledMessage', 'handleError'}
'nodeStateChange', 'unhandledMessage'}
online = False # connected or reconnecting since a short time
state = 'disconnected' # further possible values: 'connecting', 'reconnecting', 'connected'
log = None
@ -185,7 +166,7 @@ class ProxyClient:
def __init__(self):
self.callbacks = {cbname: defaultdict(list) for cbname in self.CALLBACK_NAMES}
# caches (module, parameter) = value, timestamp, readerror (internal names!)
self.cache = Cache() # dict returning Cache.undefined for missing keys
self.cache = {}
def register_callback(self, key, *args, **kwds):
"""register callback functions
@ -264,18 +245,16 @@ class ProxyClient:
except UnregisterCallback:
cblist.remove(cbfunc)
except Exception as e:
if cbname != 'handleError':
try:
e.args = [f'error in callback {cbname}{args}: {e}']
self.callback(None, 'handleError', e)
except Exception:
pass
# the programmer should catch all errors in callbacks
# if not, the log will be flooded with errors
if self.log:
self.log.exception('error %r calling %s%r', e, cbfunc.__name__, args)
return bool(cblist)
def updateValue(self, module, param, value, timestamp, readerror):
self.callback(None, 'updateEvent', module, param, value, timestamp, readerror)
self.callback(module, 'updateEvent', module, param, value, timestamp, readerror)
self.callback((module, param), 'updateEvent', module, param, value, timestamp, readerror)
self.callback((module, param), 'updateEvent', module, param,value, timestamp, readerror)
class SecopClient(ProxyClient):
@ -290,17 +269,8 @@ class SecopClient(ProxyClient):
descriptive_data = {}
modules = {}
_last_error = None
_update_error_count = 0
_max_error_count = 10
def __init__(self, uri, log=Logger):
"""initialize SecopClient
:param uri: the uri to connect to
:param log: a logger.
when not given, the print command is used for messages with at least info level.
when None, nothing is logged at all
"""
super().__init__()
# maps expected replies to [request, Event, is_error, result] until a response came
# there can only be one entry per thread calling 'request'
@ -308,21 +278,15 @@ class SecopClient(ProxyClient):
self.io = None
self.txq = queue.Queue(30) # queue for tx requests
self.pending = queue.Queue(30) # requests with colliding action + ident
self.log = log or NullLogger
self.log = log
self.uri = uri
self.nodename = uri
self._lock = RLock()
self._shutdown = Event()
self.cleanup = []
self.register_callback(None, self.handleError)
def __del__(self):
# make sure threads are stopping. this is needed in case
# a frappy client object is lost without calling .disconnect()
try:
# avoid callbacks when deleting. may cause deadlocks in NICOS
self.callbacks.clear()
self.disconnect(True)
self.disconnect()
except Exception:
pass
@ -334,11 +298,6 @@ class SecopClient(ProxyClient):
with self._lock:
if self.io:
return
self._shutdown.clear()
self.txq = queue.Queue(30)
self.pending = queue.Queue(30)
self.active_requests.clear()
self.cleanup.clear()
if self.online:
self._set_state(True, 'reconnecting')
else:
@ -370,9 +329,9 @@ class SecopClient(ProxyClient):
# pylint: disable=unsubscriptable-object
self._init_descriptive_data(self.request(DESCRIPTIONREQUEST)[2])
self.nodename = self.properties.get('equipment_id', self.uri)
self._set_state(True, 'connected')
if self.activate:
self.request(ENABLEEVENTSREQUEST)
self._set_state(True, 'connected')
break
except Exception:
# print(formatExtendedTraceback())
@ -408,15 +367,8 @@ class SecopClient(ProxyClient):
def __rxthread(self):
noactivity = 0
shutdown = False
try:
while self._running:
while self.cleanup:
entry = self.cleanup.pop()
for key, prev in self.active_requests.items():
if prev is entry:
self.active_requests.pop(key)
break
# may raise ConnectionClosed
reply = self.io.readline()
if reply is None:
@ -427,7 +379,6 @@ class SecopClient(ProxyClient):
continue
self.log.debug('RX: %r', reply)
noactivity = 0
try:
action, ident, data = decode_msg(reply)
if ident == '.':
ident = None
@ -443,7 +394,7 @@ class SecopClient(ProxyClient):
now = time.time()
if action.startswith(ERRORPREFIX):
timestamp = data[2].get('t', now)
readerror = make_secop_error(*data[0:2])
readerror = frappy.errors.make_secop_error(*data[0:2])
value = None
else:
timestamp = data[1].get('t', now)
@ -451,13 +402,12 @@ class SecopClient(ProxyClient):
readerror = None
module, param = module_param
timestamp = min(now, timestamp) # no timestamps in the future!
try:
self.updateValue(module, param, value, timestamp, readerror)
except KeyError:
pass # ignore updates of unknown parameters
if action in (EVENTREPLY, ERRORPREFIX + EVENTREPLY):
continue
except Exception as e:
e.args = (f'error handling SECoP message {reply!r}: {e}',)
self.callback(None, 'handleError', e)
continue
try:
key = action, ident
entry = self.active_requests.pop(key)
@ -484,11 +434,9 @@ class SecopClient(ProxyClient):
except ConnectionClosed:
pass
except Exception as e:
shutdown = True
self.callback(None, 'handleError', e)
finally:
self.log.error('rxthread ended with %r', e)
self._rxthread = None
self.disconnect(shutdown)
self.disconnect(False)
if self._shutdown.is_set():
return
if self.activate:
@ -624,13 +572,6 @@ class SecopClient(ProxyClient):
if not self.callback(None, 'unhandledMessage', action, ident, data):
self.log.warning('unhandled message: %s %s %r', action, ident, data)
def handleError(self, exc):
if self._update_error_count < self._max_error_count:
self.log.exception('%s', exc)
self._update_error_count += 1
if self._update_error_count == self._max_error_count:
self.log.error('disabled reporting of further update errors')
def _set_state(self, online, state=None):
# remark: reconnecting is treated as online
self.online = online
@ -651,16 +592,12 @@ class SecopClient(ProxyClient):
def get_reply(self, entry):
"""wait for reply and return it"""
if not entry[1].wait(10): # event
self.cleanup.append(entry)
raise TimeoutError('no response within 10s')
if not entry[2]: # reply
if self._shutdown.is_set():
raise ConnectionError('connection shut down')
# no cleanup needed as self.active_requests will be cleared on connect
raise ConnectionError('connection closed before reply')
action, _, data = entry[2] # pylint: disable=unpacking-non-sequence
if action.startswith(ERRORPREFIX):
raise make_secop_error(*data[0:2])
raise frappy.errors.make_secop_error(*data[0:2])
return entry[2] # reply
def request(self, action, ident=None, data=None):
@ -675,14 +612,9 @@ class SecopClient(ProxyClient):
"""forced read over connection"""
try:
self.request(READREQUEST, self.identifier[module, parameter])
except SECoPError as e:
result = self.cache[module, parameter]
if e == result.readerror:
# the update was already done in the rx thread
return result
# e was not originating from a secop error message e.g. a connection problem
# -> we have to do the error update
self.updateValue(module, parameter, None, time.time(), e)
except frappy.errors.SECoPError:
# error reply message is already stored as readerror in cache
pass
return self.cache.get((module, parameter), None)
def getParameter(self, module, parameter, trycache=False):
@ -708,7 +640,7 @@ class SecopClient(ProxyClient):
argument = datatype.export_value(argument)
else:
if argument is not None:
raise WrongTypeError('command has no argument')
raise frappy.errors.WrongTypeError('command has no argument')
# pylint: disable=unsubscriptable-object
data, qualifiers = self.request(COMMANDREQUEST, self.identifier[module, command], argument)[2]
datatype = self.modules[module]['commands'][command]['datatype'].result
@ -717,12 +649,8 @@ class SecopClient(ProxyClient):
return data, qualifiers
def updateValue(self, module, param, value, timestamp, readerror):
datatype = self.modules[module]['parameters'][param]['datatype']
if readerror:
assert isinstance(readerror, Exception)
else:
value = datatype.import_value(value)
entry = CacheItem(value, timestamp, readerror, datatype)
entry = CacheItem(value, timestamp, readerror,
self.modules[module]['parameters'][param]['datatype'])
self.cache[(module, param)] = entry
self.callback(None, 'updateItem', module, param, entry)
self.callback(module, 'updateItem', module, param, entry)

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
# *****************************************************************************
#
# This program is free software; you can redistribute it and/or modify it under
@ -28,9 +29,8 @@ import signal
import os
import traceback
import threading
import logging
from os.path import expanduser
from frappy.client import SecopClient, UnregisterCallback
from frappy.client import SecopClient
from frappy.errors import SECoPError
from frappy.datatypes import get_datatype, StatusType
try:
@ -56,45 +56,40 @@ watch(io, T=True) # watch io and all parameters of T
{tail}"""
LOG_LEVELS = {
'debug': logging.DEBUG,
'comlog': logging.DEBUG+1,
'info': logging.INFO,
'warning': logging.WARN,
'error': logging.ERROR,
'off': logging.ERROR+1}
LOG_LEVELS = {'debug', 'comlog', 'info', 'warning', 'error', 'off'}
CLR = '\r\x1b[K' # code to move to the left and clear current line
class Handler(logging.StreamHandler):
def emit(self, record):
super().emit(record)
if clientenv.sigwinch:
class Logger:
show_time = False
sigwinch = False
def __init__(self, loglevel='info'):
func = self.noop
for lev in 'debug', 'info', 'warning', 'error', 'exception':
if lev == loglevel:
func = self.emit
setattr(self, lev, func)
self._minute = 0
def emit(self, fmt, *args, **kwds):
if self.show_time:
now = time.time()
tm = time.localtime(now)
if tm.tm_min != self._minute:
self._minute = tm.tm_min
print(CLR + time.strftime('--- %H:%M:%S ---', tm))
sec = f'{now % 60.0:6.3f}'.replace(' ', '0')
print(CLR + sec, str(fmt) % args)
else:
print(CLR + (str(fmt) % args))
if self.sigwinch:
# SIGWINCH: 'window size has changed' -> triggers a refresh of the input line
os.kill(os.getpid(), signal.SIGWINCH)
class Logger(logging.Logger):
show_time = False
_minute = None
def __init__(self, name, loglevel='info'):
super().__init__(name, LOG_LEVELS.get(loglevel, logging.INFO))
handler = Handler()
handler.formatter = logging.Formatter('%(asctime)s%(message)s')
handler.formatter.formatTime = self.format_time
self.addHandler(handler)
def format_time(self, record, datefmt=None):
if self.show_time:
now = record.created
tm = time.localtime(now)
sec = f'{now % 60.0:6.3f}'.replace(' ', '0')
if tm.tm_min == self._minute:
return f'{CLR}{sec} '
self._minute = tm.tm_min
return f"{CLR}{time.strftime('--- %H:%M:%S ---', tm)}\n{sec} "
return ''
@staticmethod
def noop(fmt, *args, **kwds):
pass
class PrettyFloat(float):
@ -244,9 +239,6 @@ class Module:
return self.value
def __repr__(self):
return f'<module {self._name}>'
def showAll(self):
wid = max((len(k) for k in self._parameters), default=0)
return '%s\n%s%s' % (
self._title,
@ -280,7 +272,10 @@ class Param:
return value
def formatted(self, obj):
return obj._secnode.cache[obj._name, self.name].formatted()
value, _, error = obj._secnode.cache[obj._name, self.name]
if error:
return repr(error)
return self.format(value)
def __set__(self, obj, value):
try:
@ -292,6 +287,9 @@ class Param:
clientenv.raise_with_short_traceback(e)
obj._secnode.log.error(repr(e))
def format(self, value):
return self.datatype.format_value(value)
class Command:
def __init__(self, name, modname, secnode):
@ -340,28 +338,9 @@ def watch(*args, **kwds):
mobj._set_watching(arg)
print('---')
try:
nodes = set()
for mobj in modules:
nodes.add(mobj._secnode)
mobj._start_watching()
close_event = threading.Event()
def close_node(online, state):
if online and state != 'shutdown':
return
close_event.set()
return UnregisterCallback
def handle_error(*_):
close_event.set()
return UnregisterCallback
for node in nodes:
node.register_callback(None, nodeStateChange=close_node, handleError=handle_error)
close_event.wait()
time.sleep(3600)
except KeyboardInterrupt as e:
clientenv.raise_with_short_traceback(e)
finally:
@ -381,7 +360,7 @@ class Client(SecopClient):
clientenv.init(sys.modules['__main__'].__dict__)
# remove previous client:
prev = self.secnodes.pop(uri, None)
log = Logger(name, loglevel)
log = Logger(loglevel)
removed_modules = []
if prev:
log.info('remove previous client to %s', uri)
@ -455,10 +434,8 @@ def run(filepath):
class ClientEnvironment:
namespace = None
last_frames = 0
sigwinch = False
def init(self, namespace=None):
self.nodes = []
self.namespace = namespace or {}
self.namespace.update(run=run, watch=watch, Client=Client)
@ -468,7 +445,7 @@ class ClientEnvironment:
raise exc
def short_traceback(self):
"""cleanup traceback from irrelevant lines"""
"""cleanup tracback from irrelevant lines"""
lines = traceback.format_exception(*sys.exc_info())
# line 0: Traceback header
# skip line 1+2 (contains unspecific console line and exec code)
@ -506,15 +483,11 @@ class Console(code.InteractiveConsole):
readline.write_history_file(history)
def raw_input(self, prompt=""):
clientenv.sigwinch = bool(readline) # activate refresh signal
Logger.sigwinch = bool(readline) # activate refresh signal
line = input(prompt)
clientenv.sigwinch = False
Logger.sigwinch = False
if line.startswith('/'):
line = f"run('{line[1:].strip()}')"
module = clientenv.namespace.get(line.strip())
if isinstance(module, Module):
print(module.showAll())
line = ''
return line
def showtraceback(self):
@ -527,8 +500,7 @@ def init(*nodes):
for idx, node in enumerate(nodes):
client_name = '_c%d' % idx
try:
node = clientenv.namespace[client_name] = Client(node, name=client_name)
clientenv.nodes.append(node)
clientenv.namespace[client_name] = Client(node, name=client_name)
success = True
except Exception as e:
print(repr(e))

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
# *****************************************************************************
#
# This program is free software; you can redistribute it and/or modify it under

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
# *****************************************************************************
# Copyright (c) 2015-2016 by the authors, see LICENSE
#
@ -28,9 +29,8 @@
from frappy.datatypes import ArrayOf, BLOBType, BoolType, EnumType, \
FloatRange, IntRange, ScaledInteger, StringType, StructOf, TupleOf, StatusType
from frappy.lib.enum import Enum
from frappy.modulebase import Done, Module, Feature
from frappy.modules import Attached, Communicator, \
Drivable, Readable, Writable
Done, Drivable, Feature, Module, Readable, Writable, HasAccessibles
from frappy.params import Command, Parameter, Limit
from frappy.properties import Property
from frappy.proxy import Proxy, SecNode, proxy_class

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
# *****************************************************************************
#
# This program is free software; you can redistribute it and/or modify it under
@ -89,11 +90,7 @@ class DataType(HasProperties):
def export_datatype(self):
"""return a python object which after jsonifying identifies this datatype"""
raise ProgrammingError(
f"{type(self).__name__} is not able to be exported to SECoP. "
f"It is intended for internal use only."
)
raise NotImplementedError
def export_value(self, value):
"""if needed, reformat value for transport"""
@ -105,7 +102,7 @@ class DataType(HasProperties):
note: for importing from gui/configfile/commandline use :meth:`from_string`
instead.
"""
return self(value)
return value
def format_value(self, value, unit=None):
"""format a value of this type into a str string
@ -259,6 +256,10 @@ class FloatRange(HasUnit, DataType):
"""returns a python object fit for serialisation"""
return float(value)
def import_value(self, value):
"""returns a python object from serialisation"""
return float(value)
def from_string(self, text):
value = float(text)
return self(value)
@ -314,7 +315,7 @@ class IntRange(DataType):
except Exception:
raise WrongTypeError(f'can not convert {shortrepr(value)} to an int') from None
if round(fvalue) != fvalue:
raise WrongTypeError(f'{value} should be an int')
raise WrongTypeError('%r should be an int')
return value
def validate(self, value, previous=None):
@ -337,6 +338,10 @@ class IntRange(DataType):
"""returns a python object fit for serialisation"""
return int(value)
def import_value(self, value):
"""returns a python object from serialisation"""
return int(value)
def from_string(self, text):
value = int(text)
return self(value)
@ -453,10 +458,7 @@ class ScaledInteger(HasUnit, DataType):
def import_value(self, value):
"""returns a python object from serialisation"""
try:
return self.scale * int(value)
except Exception:
raise WrongTypeError(f'can not import {shortrepr(value)} to scaled') from None
def from_string(self, text):
value = float(text)
@ -508,6 +510,10 @@ class EnumType(DataType):
"""returns a python object fit for serialisation"""
return int(self(value))
def import_value(self, value):
"""returns a python object from serialisation"""
return self(value)
def __call__(self, value):
"""accepts integers and strings, converts to EnumMember (may be used like an int)"""
try:
@ -579,10 +585,7 @@ class BLOBType(DataType):
def import_value(self, value):
"""returns a python object from serialisation"""
try:
return b64decode(value)
except Exception:
raise WrongTypeError(f'can not b64decode {shortrepr(value)}') from None
def from_string(self, text):
value = text
@ -653,6 +656,10 @@ class StringType(DataType):
"""returns a python object fit for serialisation"""
return f'{value}'
def import_value(self, value):
"""returns a python object from serialisation"""
return str(value)
def from_string(self, text):
value = str(text)
return self(value)
@ -713,6 +720,10 @@ class BoolType(DataType):
"""returns a python object fit for serialisation"""
return self(value)
def import_value(self, value):
"""returns a python object from serialisation"""
return self(value)
def from_string(self, text):
value = text
return self(value)
@ -982,7 +993,7 @@ class StructOf(DataType):
return res
def __repr__(self):
opt = f', optional={self.optional!r}' if set(self.optional) != set(self.members) else ''
opt = f', optional={self.optional!r}' if set(self.optional) == set(self.members) else ''
return 'StructOf(%s%s)' % (', '.join(
['%s=%s' % (n, repr(st)) for n, st in list(self.members.items())]), opt)
@ -1221,7 +1232,6 @@ class OrType(DataType):
self.types = types
self.default = self.types[0].default
def __call__(self, value):
"""accepts any of the given types, takes the first valid"""
for t in self.types:
@ -1244,20 +1254,16 @@ UInt64 = IntRange(0, (1 << 64) - 1)
# Goodie: Convenience Datatypes for Programming
class LimitsType(TupleOf):
def __init__(self, member):
super().__init__(member, member)
def __init__(self, members):
super().__init__(members, members)
def validate(self, value, previous=None):
def __call__(self, value):
"""accepts an ordered tuple of numeric member types"""
limits = TupleOf.validate(self, value, previous)
limits = TupleOf.validate(self, value)
if limits[1] < limits[0]:
raise RangeError(f'maximum value {limits[1]} must be greater than '
f'minimum value {limits[0]}')
raise RangeError(f'Maximum Value {limits[1]} must be greater than minimum value {limits[0]}!')
return limits
def copy(self):
return LimitsType(TupleOf.copy(self).members[0])
class StatusType(TupleOf):
"""convenience type for status

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
# *****************************************************************************
#
# This program is free software; you can redistribute it and/or modify it under
@ -218,7 +219,7 @@ class IsErrorError(SECoPError):
class DisabledError(SECoPError):
"""The requested action can not be performed while the module is disabled"""
name = 'Disabled'
name = 'disabled'
class ImpossibleError(SECoPError):
@ -232,7 +233,7 @@ class ReadFailedError(SECoPError):
class OutOfRangeError(SECoPError):
"""The value read from the hardware is out of sensor or calibration range"""
"""The requested parameter can not be read just now"""
name = 'OutOfRange'

View File

@ -1,304 +0,0 @@
# *****************************************************************************
#
# 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 <markus.zolliker@psi.ch>
#
# *****************************************************************************
"""extended parameters
special parameter classes with some automatic functionality
"""
import re
from frappy.core import Parameter, Property
from frappy.datatypes import BoolType, DataType, DataTypeType, EnumType, \
FloatRange, StringType, StructOf, ValueType
from frappy.errors import ProgrammingError
class StructParam(Parameter):
"""convenience class to create a struct Parameter together with individual params
Usage:
class Controller(Drivable):
...
ctrlpars = StructParam('ctrlpars struct', [
('pid_p', 'p', Parameter('control parameter p', FloatRange())),
('pid_i', 'i', Parameter('control parameter i', FloatRange())),
('pid_d', 'd', Parameter('control parameter d', FloatRange())),
], readonly=False)
...
then implement either read_ctrlpars and write_ctrlpars or
read_pid_p, read_pid_i, read_pid_d, write_pid_p, write_pid_i and write_pid_d
the methods not implemented will be created automatically
"""
# use properties, as simple attributes are not considered on copy()
paramdict = Property('dict <parametername> of Parameter(...)', ValueType())
hasStructRW = Property('has a read_<struct param> or write_<struct param> method',
BoolType(), default=False)
insideRW = 0 # counter for avoiding multiple superfluous updates
def __init__(self, description=None, paramdict=None, prefix_or_map='', *, datatype=None, readonly=False, **kwds):
"""create a struct parameter together with individual parameters
in addition to normal Parameter arguments:
:param paramdict: dict <member name> of Parameter(...)
:param prefix_or_map: either a prefix for the parameter name to add to the member name
or a dict <member name> or <parameter name>
"""
if isinstance(paramdict, DataType):
raise ProgrammingError('second argument must be a dict of Param')
if datatype is None and paramdict is not None: # omit the following on Parameter.copy()
if isinstance(prefix_or_map, str):
prefix_or_map = {m: prefix_or_map + m for m in paramdict}
for membername, param in paramdict.items():
param.name = prefix_or_map[membername]
datatype = StructOf(**{m: p.datatype for m, p in paramdict.items()})
kwds['influences'] = [p.name for p in paramdict.values()]
self.updateEnable = {}
if paramdict:
kwds['paramdict'] = paramdict
super().__init__(description, datatype, readonly=readonly, **kwds)
def __set_name__(self, owner, name):
# names of access methods of structed param (e.g. ctrlpars)
struct_read_name = f'read_{name}' # e.g. 'read_ctrlpars'
struct_write_name = f'write_{name}' # e.h. 'write_ctrlpars'
self.hasStructRW = hasattr(owner, struct_read_name) or hasattr(owner, struct_write_name)
for membername, param in self.paramdict.items():
pname = param.name
changes = {
'readonly': self.readonly,
'influences': set(param.influences) | {name},
}
param.ownProperties.update(changes)
param.init(changes)
setattr(owner, pname, param)
param.__set_name__(owner, param.name)
if self.hasStructRW:
rname = f'read_{pname}'
if not hasattr(owner, rname):
def rfunc(self, membername=membername, struct_read_name=struct_read_name):
return getattr(self, struct_read_name)()[membername]
rfunc.poll = False # read_<struct param> is polled only
setattr(owner, rname, rfunc)
if not self.readonly:
wname = f'write_{pname}'
if not hasattr(owner, wname):
def wfunc(self, value, membername=membername,
name=name, rname=rname, struct_write_name=struct_write_name):
valuedict = dict(getattr(self, name))
valuedict[membername] = value
getattr(self, struct_write_name)(valuedict)
return getattr(self, rname)()
setattr(owner, wname, wfunc)
if not self.hasStructRW:
if not hasattr(owner, struct_read_name):
def struct_read_func(self, name=name, flist=tuple(
(m, f'read_{p.name}') for m, p in self.paramdict.items())):
pobj = self.parameters[name]
# disable updates generated from the callbacks of individual params
pobj.insideRW += 1 # guarded by self.accessLock
try:
return {m: getattr(self, f)() for m, f in flist}
finally:
pobj.insideRW -= 1
setattr(owner, struct_read_name, struct_read_func)
if not (self.readonly or hasattr(owner, struct_write_name)):
def struct_write_func(self, value, name=name, funclist=tuple(
(m, f'write_{p.name}') for m, p in self.paramdict.items())):
pobj = self.parameters[name]
pobj.insideRW += 1 # guarded by self.accessLock
try:
return {m: getattr(self, f)(value[m]) for m, f in funclist}
finally:
pobj.insideRW -= 1
setattr(owner, struct_write_name, struct_write_func)
super().__set_name__(owner, name)
def finish(self, modobj=None):
"""register callbacks for consistency"""
super().finish(modobj)
if modobj:
if self.hasStructRW:
def cb(value, modobj=modobj, structparam=self):
for membername, param in structparam.paramdict.items():
setattr(modobj, param.name, value[membername])
modobj.addCallback(self.name, cb)
else:
for membername, param in self.paramdict.items():
def cb(value, modobj=modobj, structparam=self, membername=membername):
if not structparam.insideRW:
prev = dict(getattr(modobj, structparam.name))
prev[membername] = value
setattr(modobj, structparam.name, prev)
modobj.addCallback(param.name, cb)
class FloatEnumParam(Parameter):
"""combine enum and float parameter
Example Usage:
vrange = FloatEnumParam('sensor range', ['500uV', '20mV', '1V'], 'V')
The following will be created automatically:
- the parameter vrange will get a datatype FloatRange(5e-4, 1, unit='V')
- an additional parameter `vrange_idx` will be created with an enum type
{'500uV': 0, '20mV': 1, '1V': 2}
- the method `write_vrange` will be created automatically
However, the methods `write_vrange_idx` and `read_vrange_idx`, if needed,
have to implemented by the programmer.
Writing to the float parameter involves 'rounding' to the closest allowed value.
Customization:
The individual labels might be customized by defining them as a tuple
(<index>, <label>, <float value>) where either the index or the float value
may be omitted.
When the index is omitted, the element will be the previous index + 1 or
0 when it is the first element.
Omitted values will be determined from the label, assuming that they use
one of the predefined unit prefixes together with the given unit.
The name of the index parameter is by default '<name>_idx' but might be
changed with the idx_name argument.
"""
# use properties, as simple attributes are not considered on copy()
idx_name = Property('name of attached index parameter', StringType(), default='')
valuedict = Property('dict <index> of <value>', ValueType(dict))
enumtype = Property('dict <label> of <index', DataTypeType())
# TODO: factor out unit handling, at the latest when needed elsewhere
PREFIXES = {'q': -30, 'r': -27, 'y': -24, 'z': -21, 'a': -18, 'f': -15,
'p': -12, 'n': -9, 'u': -6, 'µ': -6, 'm': -3,
'': 0, 'k': 3, 'M': 6, 'G': 9, 'T': 12,
'P': 15, 'E': 18, 'Z': 21, 'Y': 24, 'R': 25, 'Q': 30}
def __init__(self, description=None, labels=None, unit='',
*, datatype=None, readonly=False, **kwds):
if labels is None:
# called on Parameter.copy()
super().__init__(description, datatype, readonly=readonly, **kwds)
return
if isinstance(labels, DataType):
raise ProgrammingError('second argument must be a list of labels, not a datatype')
nextidx = 0
try:
edict = {}
vdict = {}
for elem in labels:
if isinstance(elem, str):
idx, label = [nextidx, elem]
else:
if isinstance(elem[0], str):
elem = [nextidx] + list(elem)
idx, label, *tail = elem
if tail:
vdict[idx], = tail
edict[label] = idx
nextidx = idx + 1
except (ValueError, TypeError) as e:
raise ProgrammingError('labels must be a list of labels or tuples '
'([index], label, [value])') from e
pat = re.compile(rf'([+-]?\d*\.?\d*) *({"|".join(self.PREFIXES)}){unit}$')
try:
# determine missing values from labels
for label, idx in edict.items():
if idx not in vdict:
value, prefix = pat.match(label).groups()
vdict[idx] = float(f'{value}e{self.PREFIXES[prefix]}')
except (AttributeError, ValueError) as e:
raise ProgrammingError(f"{label!r} has not the form '<float><prefix>{unit}'") from e
try:
enumtype = EnumType(**edict)
except TypeError as e:
raise ProgrammingError(str(e)) from e
datatype = FloatRange(min(vdict.values()), max(vdict.values()), unit=unit)
super().__init__(description, datatype, enumtype=enumtype, valuedict=vdict,
readonly=readonly, **kwds)
def __set_name__(self, owner, name):
super().__set_name__(owner, name)
if not self.idx_name:
self.idx_name = name + '_idx'
iname = self.idx_name
idx_param = Parameter(f'index of {name}', self.enumtype,
readonly=self.readonly, influences={name})
idx_param.init({})
setattr(owner, iname, idx_param)
idx_param.__set_name__(owner, iname)
self.setProperty('influences', {iname})
if not hasattr(owner, f'write_{name}'):
# customization (like rounding up or down) might be
# achieved by adding write_<name>. if not, the default
# is rounding to the closest value
def wfunc(mobj, value, vdict=self.valuedict, fname=name, wfunc_iname=f'write_{iname}'):
getattr(mobj, wfunc_iname)(
min(vdict, key=lambda i: abs(vdict[i] - value)))
return getattr(mobj, fname)
setattr(owner, f'write_{name}', wfunc)
def __get__(self, instance, owner):
"""getter for value"""
if instance is None:
return self
return self.valuedict[instance.parameters[self.idx_name].value]
def trigger_setter(self, modobj, _):
# trigger update of float parameter on change of enum parameter
modobj.announceUpdate(self.name, getattr(modobj, self.name))
def finish(self, modobj=None):
"""register callbacks for consistency"""
super().finish(modobj)
if modobj:
modobj.addCallback(self.idx_name, self.trigger_setter, modobj)

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
# *****************************************************************************
#
# This program is free software; you can redistribute it and/or modify it under

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
# *****************************************************************************
#
# This program is free software; you can redistribute it and/or modify it under

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
# *****************************************************************************
#
# This program is free software; you can redistribute it and/or modify it under

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
# *****************************************************************************
#
# This program is free software; you can redistribute it and/or modify it under

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
# *****************************************************************************
#
# This program is free software; you can redistribute it and/or modify it under

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
# *****************************************************************************
#
# This program is free software; you can redistribute it and/or modify it under

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
# *****************************************************************************
#
# This program is free software; you can redistribute it and/or modify it under

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
# *****************************************************************************
# Copyright (c) 2015-2023 by the authors, see LICENSE
#

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
# *****************************************************************************
# Copyright (c) 2015-2016 by the authors, see LICENSE
#

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
# *****************************************************************************
# Copyright (c) 2015-2023 by the authors, see LICENSE
#

View File

@ -1,10 +1,6 @@
import sys
from frappy.gui.qt import QCheckBox, QComboBox, QLineEdit, pyqtSignal
from frappy.gui.qt import QCheckBox, QComboBox, QDoubleSpinBox, QLineEdit, \
QSpinBox, pyqtSignal
from frappy.datatypes import BoolType, EnumType, FloatRange, IntRange, \
StringType, TextType
from frappy.datatypes import BoolType, EnumType
# ArrayOf, BLOBType, FloatRange, IntRange, StringType, StructOf, TextType, TupleOf
@ -13,24 +9,11 @@ def get_input_widget(datatype, parent=None):
return {
EnumType: EnumInput,
BoolType: BoolInput,
IntRange: IntInput,
StringType: StringInput,
TextType: StringInput,
}.get(datatype.__class__, GenericInput)(datatype, parent)
class InputBase:
class GenericInput(QLineEdit):
submitted = pyqtSignal()
input_feedback = pyqtSignal(str)
def get_input(self):
raise NotImplementedError
def submit(self):
self.submitted.emit()
class GenericInput(InputBase, QLineEdit):
def __init__(self, datatype, parent=None):
super().__init__(parent)
self.datatype = datatype
@ -40,28 +23,12 @@ class GenericInput(InputBase, QLineEdit):
def get_input(self):
return self.datatype.from_string(self.text())
class StringInput(GenericInput):
def __init__(self, datatype, parent=None):
super().__init__(datatype, parent)
def submit(self):
self.submitted.emit()
class IntInput(InputBase, QSpinBox):
def __init__(self, datatype, parent=None):
super().__init__(parent)
self.datatype = datatype
# we dont use setMaximum and setMinimum because it is quite restrictive
# when typing, so set it as high as possible
self.setMaximum(2147483647)
self.setMinimum(-2147483648)
self.lineEdit().returnPressed.connect(self.submit)
def get_input(self):
return self.datatype(self.value())
class EnumInput(InputBase, QComboBox):
class EnumInput(QComboBox):
submitted = pyqtSignal()
def __init__(self, datatype, parent=None):
super().__init__(parent)
self.setPlaceholderText('choose value')
@ -78,11 +45,18 @@ class EnumInput(InputBase, QComboBox):
def get_input(self):
return self._map[self.currentIndex()].value
def submit(self):
self.submitted.emit()
class BoolInput(InputBase, QCheckBox):
class BoolInput(QCheckBox):
submitted = pyqtSignal()
def __init__(self, datatype, parent=None):
super().__init__(parent)
self.datatype = datatype
def get_input(self):
return self.isChecked()
def submit(self):
self.submitted.emit()

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
# *****************************************************************************
# Copyright (c) 2015-2023 by the authors, see LICENSE
#

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
# *****************************************************************************
# Copyright (c) 2015-2023 by the authors, see LICENSE
#

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
# *****************************************************************************
# Copyright (c) 2015-2023 by the authors, see LICENSE
#

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
# *****************************************************************************
# Copyright (c) 2015-2023 by the authors, see LICENSE
#
@ -24,9 +25,9 @@ from frappy.gui.qt import QColor, QDialog, QHBoxLayout, QIcon, QLabel, \
QLineEdit, QMessageBox, QPropertyAnimation, QPushButton, Qt, QToolButton, \
QWidget, pyqtProperty, pyqtSignal
from frappy.gui.inputwidgets import get_input_widget
from frappy.gui.util import Colors, loadUi
from frappy.gui.valuewidgets import get_widget
from frappy.gui.inputwidgets import get_input_widget
class CommandDialog(QDialog):
@ -54,11 +55,7 @@ class CommandDialog(QDialog):
self.resize(self.sizeHint())
def get_value(self):
try:
return self.widgets[0].get_value()
except Exception as e:
QMessageBox.warning(self.parent(), 'Operation failed', str(e))
return None
return True, self.widgets[0].get_value()
def exec(self):
if super().exec():
@ -99,9 +96,8 @@ class CommandButton(QPushButton):
if self._argintype:
dlg = CommandDialog(self._cmdname, self._argintype)
args = dlg.exec()
if args is not None:
# no errors when converting value and 'Cancel' wasn't clicked
self._cb(self._cmdname, args)
if args: # not 'Cancel' clicked
self._cb(self._cmdname, args[1])
else:
# no need for arguments
self._cb(self._cmdname, None)
@ -447,8 +443,8 @@ class ModuleWidget(QWidget):
self.paramDetails.emit(self._name, param)
def _button_pressed(self, param):
try:
target = self._paramInputs[param].get_input()
try:
self._node.setParameter(self._name, param, target)
except Exception as e:
QMessageBox.warning(self.parent(), 'Operation failed', str(e))

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
# *****************************************************************************
# Copyright (c) 2015-2023 by the authors, see LICENSE
#

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
# *****************************************************************************
# Copyright (c) 2015-2016 by the authors, see LICENSE
#

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
# *****************************************************************************
# Copyright (c) 2015-2017 by the authors, see LICENSE
#

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
# *****************************************************************************
# Copyright (c) 2015-2023 by the authors, see LICENSE
#

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
# *****************************************************************************
#
# This program is free software; you can redistribute it and/or modify it under
@ -42,10 +43,10 @@ try:
QDialogButtonBox, QDoubleSpinBox, QFileDialog, QFrame, QGridLayout, \
QGroupBox, QHBoxLayout, QInputDialog, QLabel, QLineEdit, QMainWindow, \
QMenu, QMessageBox, QPlainTextEdit, QPushButton, QRadioButton, \
QScrollArea, QSizePolicy, QSlider, QSpacerItem, QSpinBox, QStyle, \
QScrollArea, QSizePolicy, QSpacerItem, QSpinBox, QStyle, \
QStyleOptionTab, QStylePainter, QTabBar, QTabWidget, QTextEdit, \
QToolButton, QTreeView, QTreeWidget, QTreeWidgetItem, QVBoxLayout, \
QWidget
QWidget,QSlider
import frappy.gui.resources_qt6
@ -62,9 +63,9 @@ except ImportError as e:
QDialog, QDialogButtonBox, QDoubleSpinBox, QFileDialog, QFrame, \
QGridLayout, QGroupBox, QHBoxLayout, QInputDialog, QLabel, QLineEdit, \
QMainWindow, QMenu, QMessageBox, QPlainTextEdit, QPushButton, \
QRadioButton, QScrollArea, QShortcut, QSizePolicy, QSlider, \
QSpacerItem, QSpinBox, QStyle, QStyleOptionTab, QStylePainter, \
QTabBar, QTabWidget, QTextEdit, QToolButton, QTreeView, QTreeWidget, \
QTreeWidgetItem, QVBoxLayout, QWidget
QRadioButton, QScrollArea, QShortcut, QSizePolicy, QSpacerItem, \
QSpinBox, QStyle, QStyleOptionTab, QStylePainter, QTabBar, \
QTabWidget, QTextEdit, QToolButton, QTreeView, QTreeWidget, \
QTreeWidgetItem, QVBoxLayout, QWidget, QSlider
import frappy.gui.resources_qt5

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
# Resource object code
#

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
# *****************************************************************************
# NICOS, the Networked Instrument Control System of the MLZ
# Copyright (c) 2009-2023 by the NICOS contributors (see AUTHORS)

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
# *****************************************************************************
# Copyright (c) 2015-2016 by the authors, see LICENSE
#

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
# *****************************************************************************
# Copyright (c) 2015-2016 by the authors, see LICENSE
#

View File

@ -1,4 +1,5 @@
#!/usr/bin/env python
# -*- 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
@ -24,17 +25,17 @@ other future extensions of AsynConn
"""
import re
import threading
import time
import threading
from frappy.datatypes import ArrayOf, BLOBType, BoolType, FloatRange, \
IntRange, StringType, StructOf, TupleOf, ValueType
from frappy.errors import CommunicationFailedError, ConfigError, \
ProgrammingError, SilentCommunicationFailedError as SilentError
from frappy.lib import generalConfig
from frappy.lib.asynconn import AsynConn, ConnectionClosed
from frappy.modules import Attached, Command, Communicator, Module, \
Parameter, Property
from frappy.datatypes import ArrayOf, BLOBType, BoolType, FloatRange, IntRange, \
StringType, TupleOf, ValueType
from frappy.errors import CommunicationFailedError, ConfigError, ProgrammingError, \
SilentCommunicationFailedError as SilentError
from frappy.modules import Attached, Command, \
Communicator, Module, Parameter, Property
from frappy.lib import generalConfig
generalConfig.set_default('legacy_hasiodev', False)
@ -61,7 +62,8 @@ class HasIO(Module):
ioname = opts.get('io') or f'{name}_io'
io = self.ioClass(ioname, srv.log.getChild(ioname), opts, srv) # pylint: disable=not-callable
io.callingModule = []
srv.secnode.add_module(io, ioname)
srv.modules[ioname] = io
srv.dispatcher.register_module(io, ioname)
self.ioDict[self.uri] = ioname
self.io = ioname
@ -74,11 +76,8 @@ class HasIO(Module):
def communicate(self, *args):
return self.io.communicate(*args)
def writeline(self, *args):
return self.io.writeline(*args)
def multicomm(self, *args, **kwds):
return self.io.multicomm(*args, **kwds)
def multicomm(self, *args):
return self.io.multicomm(*args)
class HasIodev(HasIO):
@ -288,7 +287,7 @@ class StringIO(IOBase):
f' does not match {regexp!r}')
@Command(StringType(), result=StringType())
def communicate(self, command, noreply=False):
def communicate(self, command):
"""send a command and receive a reply
using end_of_line, encoding and self._lock
@ -315,8 +314,6 @@ class StringIO(IOBase):
self.comLog('garbage: %r', garbage)
self._conn.send(cmd + self._eol_write)
self.comLog('> %s', cmd.decode(self.encoding))
if noreply:
return None
reply = self._conn.readline(self.timeout)
except ConnectionClosed:
self.closeConnection()
@ -332,69 +329,13 @@ class StringIO(IOBase):
self.log.error(self._last_error)
raise SilentError(repr(e)) from e
@Command(StringType())
def writeline(self, command):
"""send a command without needing a reply
For keeping a request-reply scheme it is recommended to overwrite
this method to append a query on the same line, for example:
.. code::
def writeline(self, command):
self.communicate(command + ';*OPC?')
or to add an additional query which is returning always a reply, e.g.:
.. code::
def writeline(self, command):
with self._lock: # important!
self.communicate(command, noreply=True)
self.communicate('*OPC?')
The first version is preferred when the hardware allows to join several
commands by a separator.
"""
self.communicate(command, noreply=True)
@Command(ArrayOf(TupleOf(StringType(), BoolType(), FloatRange(0, unit='s'))),
result=ArrayOf(StringType()))
def multicomm(self, requests):
"""communicate multiple request/replies in one go
:param requests: a sequence of tuple of (command, request_expected, delay)
if called internally, a sequence of strings (command) is also accepted
:return: list of replies
This method may be rarely used, it is intended when the hardware needs
that several commands are not intercepted by an other client or by the poller,
for example selecting a channel before reading it. Or when wait times different
from 'wait_before' have to be specified.
These cases may also handled by adding an additional method to the IO class.
This could also be a custom SECoP command.
Or, in the case where all useful commands in this IO class need it,
:meth:`communicate` may be overridden.
This method should be used in the following cases:
1) you want to use a generic communicator covering above use cases over SECoP.
2) you do not want to subclass the IO class.
"""
@Command(ArrayOf(StringType()), result=ArrayOf(StringType()))
def multicomm(self, commands):
"""communicate multiple request/replies in one row"""
replies = []
with self._lock:
for request in requests:
if isinstance(request, str):
cmd, expect_reply, delay = request, True, 0
else:
cmd, expect_reply, delay = request
if expect_reply:
for cmd in commands:
replies.append(self.communicate(cmd))
else:
self.writeline(cmd)
if delay:
time.sleep(delay)
return replies
@ -454,7 +395,7 @@ class BytesIO(IOBase):
if not replypat.match(reply):
self.closeConnection()
raise CommunicationFailedError(f'bad response: {reply!r}'
f' does not match {expected!r}')
' does not match {expected!r}')
@Command((BLOBType(), IntRange(0)), result=BLOBType())
def communicate(self, request, replylen): # pylint: disable=arguments-differ
@ -485,20 +426,13 @@ class BytesIO(IOBase):
self.log.error(self._last_error)
raise SilentError(repr(e)) from e
@Command(StructOf(requests=ArrayOf(TupleOf(BLOBType(), IntRange(0), FloatRange(0, unit='s')))),
result=ArrayOf(BLOBType()))
@Command((ArrayOf(TupleOf(BLOBType(), IntRange(0)))), result=ArrayOf(BLOBType()))
def multicomm(self, requests):
"""communicate multiple request/replies in one go
:param requests: sequence of tuple (<command>, <expected reply length>, <delay>)
:return: list of replies
"""
"""communicate multiple request/replies in one row"""
replies = []
with self._lock:
for cmd, replylen, delay in requests:
replies.append(self.communicate(cmd, replylen))
if delay:
time.sleep(delay)
for request in requests:
replies.append(self.communicate(*request))
return replies
def readBytes(self, nbytes):

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
# *****************************************************************************
#
# This program is free software; you can redistribute it and/or modify it under

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
# *****************************************************************************
#
# This program is free software; you can redistribute it and/or modify it under
@ -21,14 +22,12 @@
from textwrap import indent
from frappy.modules import Command, Parameter, Property
from frappy.modulebase import HasProperties, Module
from frappy.modules import Command, HasProperties, Module, Parameter, Property
def indent_description(p):
"""indent lines except first one"""
space = ' ' * 6
return indent(p.description, space).replace(space, '', 1)
return indent(p.description, ' ').replace(' ', '', 1)
def fmt_param(name, param):

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
# *****************************************************************************
# Copyright (c) 2015-2016 by the authors, see LICENSE
#

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
# *****************************************************************************
#
# This program is free software; you can redistribute it and/or modify it under

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
# *****************************************************************************
#
# This program is free software; you can redistribute it and/or modify it under

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
# *****************************************************************************
#
# This program is free software; you can redistribute it and/or modify it under
@ -32,7 +33,7 @@ else:
class PEP487Metaclass(type):
# support for __set_name__ and __init_subclass__ for older python versions
# slightly modified from PEP487 doc
def __new__(cls, *args, **kwargs): # pylint: disable=bad-mcs-classmethod-argument
def __new__(cls, *args, **kwargs):
if len(args) != 3:
return super().__new__(cls, *args)
name, bases, ns = args

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
# *****************************************************************************
#
# This program is free software; you can redistribute it and/or modify it under
@ -141,7 +142,6 @@ class SequencerMixin:
return self.Status.IDLE, ''
def stop(self):
"""stop sequence"""
if self.seq_is_alive():
self._seq_stopflag = True

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
# *****************************************************************************
#
# This program is free software; you can redistribute it and/or modify it under

View File

@ -1,4 +1,5 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# *****************************************************************************
#
# This program is free software; you can redistribute it and/or modify it under
@ -54,8 +55,6 @@ class RemoteLogHandler(mlzlog.Handler):
def __init__(self):
super().__init__()
self.subscriptions = {} # dict[modname] of tuple(mobobj, dict [conn] of level)
# None will be replaced by a callback when one is first installed
self.send_log = None
def emit(self, record):
"""unused"""
@ -63,18 +62,18 @@ class RemoteLogHandler(mlzlog.Handler):
def handle(self, record):
modname = record.name.split('.')[-1]
try:
subscriptions = self.subscriptions[modname]
modobj, subscriptions = self.subscriptions[modname]
except KeyError:
return
for conn, lev in subscriptions.items():
if record.levelno >= lev:
self.send_log( # pylint: disable=not-callable
conn, modname, LEVEL_NAMES[record.levelno],
modobj.DISPATCHER.send_log_msg(
conn, modobj.name, LEVEL_NAMES[record.levelno],
record.getMessage())
def set_conn_level(self, modname, conn, level):
def set_conn_level(self, modobj, conn, level):
level = check_level(level)
subscriptions = self.subscriptions.setdefault(modname, {})
modobj, subscriptions = self.subscriptions.setdefault(modobj.name, (modobj, {}))
if level == OFF:
subscriptions.pop(conn, None)
else:
@ -128,7 +127,7 @@ class HasComlog:
if self.comlog and generalConfig.initialized and generalConfig.comlog:
self._comLog = mlzlog.Logger(f'COMLOG.{self.name}')
self._comLog.handlers[:] = []
directory = join(logger.logdir, logger.rootname, 'comlog', self.secNode.name)
directory = join(logger.logdir, logger.rootname, 'comlog', self.DISPATCHER.name)
self._comLog.addHandler(ComLogfileHandler(
directory, self.name, max_days=generalConfig.getint('comlog_days', 7)))
return

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
# *****************************************************************************
#
# This program is free software; you can redistribute it and/or modify it under
@ -70,8 +71,11 @@ class HasOutputModule:
def initModule(self):
super().initModule()
try:
if self.output_module:
self.output_module.register_input(self.name, self.deactivate_control)
except Exception:
self.log.info(f'{self.name} has no output module')
def set_control_active(self, active):
"""to be overridden for switching hw control"""

View File

@ -1,835 +0,0 @@
# *****************************************************************************
#
# 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:
# Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
# Markus Zolliker <markus.zolliker@psi.ch>
# Alexander Zaft <a.zaft@fz-juelich.de>
#
# *****************************************************************************
"""Defines the base Module class"""
import time
import threading
from collections import OrderedDict
from frappy.datatypes import ArrayOf, BoolType, EnumType, FloatRange, \
IntRange, StringType, TextType, TupleOf, \
NoneOr
from frappy.errors import BadValueError, CommunicationFailedError, ConfigError, \
ProgrammingError, SECoPError, secop_error, RangeError
from frappy.lib import formatException, mkthread, UniqueObject
from frappy.params import Accessible, Command, Parameter, Limit
from frappy.properties import HasProperties, Property
from frappy.logging import RemoteLogHandler
# TODO: resolve cirular import
# from .interfaces import SECoP_BASE_CLASSES
# WORKAROUND:
SECoP_BASE_CLASSES = ['Readable', 'Writable', 'Drivable', 'Communicator']
Done = UniqueObject('Done')
"""a special return value for a read_<param>/write_<param> method
indicating that the setter is triggered already"""
wrapperClasses = {}
class HasAccessibles(HasProperties):
"""base class of Module
joining the class's properties, parameters and commands dicts with
those of base classes.
wrap read_*/write_* methods
(so the dispatcher will get notified of changed values)
"""
isWrapped = False
checkedMethods = set()
@classmethod
def __init_subclass__(cls): # pylint: disable=too-many-branches
super().__init_subclass__()
if cls.isWrapped:
return
# merge accessibles from all sub-classes, treat overrides
# for now, allow to use also the old syntax (parameters/commands dict)
accessibles = OrderedDict() # dict of accessibles
merged_properties = {} # dict of dict of merged properties
new_names = [] # list of names of new accessibles
override_values = {} # bare values overriding a parameter and methods overriding a command
for base in reversed(cls.__mro__):
for key, value in base.__dict__.items():
if isinstance(value, Accessible):
value.updateProperties(merged_properties.setdefault(key, {}))
if base == cls and key not in accessibles:
new_names.append(key)
accessibles[key] = value
override_values.pop(key, None)
elif key in accessibles:
override_values[key] = value
# remark: merged_properties contain already the properties of accessibles of cls
for aname, aobj in list(accessibles.items()):
if aname in override_values:
value = override_values[aname]
if value is None:
accessibles.pop(aname)
continue
aobj = aobj.create_from_value(merged_properties[aname], value)
# replace the bare value by the created accessible
setattr(cls, aname, aobj)
else:
aobj.merge(merged_properties[aname])
accessibles[aname] = aobj
# rebuild order: (1) inherited items, (2) items from paramOrder, (3) new accessibles
# move (2) to the end
paramOrder = cls.__dict__.get('paramOrder', ())
for aname in paramOrder:
if aname in accessibles:
accessibles.move_to_end(aname)
# ignore unknown names
# move (3) to the end
for aname in new_names:
if aname not in paramOrder:
accessibles.move_to_end(aname)
cls.accessibles = accessibles
cls.wrappedAttributes = {'isWrapped': True}
# create wrappers for access methods
wrapped_name = '_' + cls.__name__
for pname, pobj in accessibles.items():
# wrap of reading/writing funcs
if not isinstance(pobj, Parameter):
# nothing to do for Commands
continue
rname = 'read_' + pname
rfunc = getattr(cls, rname, None)
# create wrapper
if rfunc:
def new_rfunc(self, pname=pname, rfunc=rfunc):
with self.accessLock:
try:
value = rfunc(self)
self.log.debug("read_%s returned %r", pname, value)
if value is Done: # TODO: to be removed when all code using Done is updated
return getattr(self, pname)
pobj = self.accessibles[pname]
value = pobj.datatype(value)
except Exception as e:
self.log.debug("read_%s failed with %r", pname, e)
if isinstance(e, SECoPError):
e.raising_methods.append(f'{self.name}.read_{pname}')
self.announceUpdate(pname, err=e)
raise
self.announceUpdate(pname, value, validate=False)
return value
new_rfunc.poll = getattr(rfunc, 'poll', True)
else:
def new_rfunc(self, pname=pname):
return getattr(self, pname)
new_rfunc.poll = False
new_rfunc.__name__ = rname
new_rfunc.__qualname__ = wrapped_name + '.' + rname
new_rfunc.__module__ = cls.__module__
cls.wrappedAttributes[rname] = new_rfunc
cname = 'check_' + pname
for postfix in ('_limits', '_min', '_max'):
limname = pname + postfix
if limname in accessibles:
# find the base class, where the parameter <limname> is defined first.
# we have to check all bases, as they may not be treated yet when
# not inheriting from HasAccessibles
base = next(b for b in reversed(cls.__mro__) if limname in b.__dict__)
if cname not in base.__dict__:
# there is no check method yet at this class
# add check function to the class where the limit was defined
setattr(base, cname, lambda self, value, pname=pname: self.checkLimits(value, pname))
cfuncs = tuple(filter(None, (b.__dict__.get(cname) for b in cls.__mro__)))
wname = 'write_' + pname
wfunc = getattr(cls, wname, None)
if wfunc or not pobj.readonly:
# allow write method even when parameter is readonly, but internally writable
def new_wfunc(self, value, pname=pname, wfunc=wfunc, check_funcs=cfuncs):
with self.accessLock:
self.log.debug('validate %r to datatype of %r', value, pname)
validate = self.parameters[pname].datatype.validate
try:
new_value = validate(value)
for c in check_funcs:
if c(self, value):
break
if wfunc:
new_value = wfunc(self, new_value)
self.log.debug('write_%s(%r) returned %r', pname, value, new_value)
if new_value is Done: # TODO: to be removed when all code using Done is updated
return getattr(self, pname)
new_value = value if new_value is None else validate(new_value)
except Exception as e:
if isinstance(e, SECoPError):
e.raising_methods.append(f'{self.name}.write_{pname}')
self.announceUpdate(pname, err=e)
raise
self.announceUpdate(pname, new_value, validate=False)
return new_value
new_wfunc.__name__ = wname
new_wfunc.__qualname__ = wrapped_name + '.' + wname
new_wfunc.__module__ = cls.__module__
cls.wrappedAttributes[wname] = new_wfunc
cls.checkedMethods.update(cls.wrappedAttributes)
# check for programming errors
for attrname in dir(cls):
prefix, _, pname = attrname.partition('_')
if not pname:
continue
if prefix == 'do':
raise ProgrammingError(f'{cls.__name__!r}: old style command {attrname!r} not supported anymore')
if prefix in ('read', 'write') and attrname not in cls.checkedMethods:
raise ProgrammingError(f'{cls.__name__}.{attrname} defined, but {pname!r} is no parameter')
try:
# update Status type
cls.Status = cls.status.datatype.members[0]._enum
except AttributeError:
pass
res = {}
# collect info about properties
for pn, pv in cls.propertyDict.items():
if pv.settable:
res[pn] = pv
# collect info about parameters and their properties
for param, pobj in cls.accessibles.items():
res[param] = {}
for pn, pv in pobj.getProperties().items():
if pv.settable:
res[param][pn] = pv
cls.configurables = res
def __new__(cls, *args, **kwds):
wrapper_class = wrapperClasses.get(cls)
if wrapper_class is None:
wrapper_class = type('_' + cls.__name__, (cls,), cls.wrappedAttributes)
wrapperClasses[cls] = wrapper_class
return super().__new__(wrapper_class)
class Feature(HasAccessibles):
"""all things belonging to a small, predefined functionality influencing the working of a module
a mixin with Feature as a direct base class is recognized as a SECoP feature
and reported in the module property 'features'
"""
class PollInfo:
def __init__(self, pollinterval, trigger_event):
self.interval = pollinterval
self.last_main = 0
self.last_slow = 0
self.pending_errors = set()
self.polled_parameters = []
self.fast_flag = False
self.trigger_event = trigger_event
def trigger(self, immediate=False):
"""trigger a recalculation of poll due times
:param immediate: when True, doPoll should be called as soon as possible
"""
if immediate:
self.last_main = 0
self.trigger_event.set()
def update_interval(self, pollinterval):
if not self.fast_flag:
self.interval = pollinterval
self.trigger()
class Module(HasAccessibles):
"""basic module
all SECoP modules derive from this.
:param name: the modules name
:param logger: a logger instance
:param cfgdict: the dict from this modules section in the config file
:param srv: the server instance
Notes:
- the programmer normally should not need to reimplement :meth:`__init__`
- within modules, parameters should only be addressed as ``self.<pname>``,
i.e. ``self.value``, ``self.target`` etc...
- these are accessing the cached version.
- they can also be written to, generating an async update
- if you want to 'update from the hardware', call ``self.read_<pname>()`` instead
- the return value of this method will be used as the new cached value and
be an async update sent automatically.
- if you want to 'update the hardware' call ``self.write_<pname>(<new value>)``.
- The return value of this method will also update the cache.
"""
# static properties, definitions in derived classes should overwrite earlier ones.
# note: properties don't change after startup and are usually filled
# with data from a cfg file...
# note: only the properties predefined here are allowed to be set in the cfg file
export = Property('flag if this module is to be exported', BoolType(), default=True, export=False)
group = Property('optional group the module belongs to', StringType(), default='', extname='group')
description = Property('description of the module', TextType(), extname='description', mandatory=True)
meaning = Property('optional meaning indicator', TupleOf(StringType(), IntRange(0, 50)),
default=('', 0), extname='meaning')
visibility = Property('optional visibility hint', EnumType('visibility', user=1, advanced=2, expert=3),
default='user', extname='visibility')
implementation = Property('internal name of the implementation class of the module', StringType(),
extname='implementation')
interface_classes = Property('offical highest interface-class of the module', ArrayOf(StringType()),
extname='interface_classes')
features = Property('list of features', ArrayOf(StringType()), extname='features')
pollinterval = Property('poll interval for parameters handled by doPoll', FloatRange(0.1, 120), default=5)
slowinterval = Property('poll interval for other parameters', FloatRange(0.1, 120), default=15)
omit_unchanged_within = Property('default for minimum time between updates of unchanged values',
NoneOr(FloatRange(0)), export=False, default=None)
enablePoll = True
pollInfo = None
triggerPoll = None # trigger event for polls. used on io modules and modules without io
def __init__(self, name, logger, cfgdict, srv):
# remember the secnode for interacting with other modules and the
# server
self.secNode = srv.secnode
self.log = logger
self.name = name
self.paramCallbacks = {}
self.earlyInitDone = False
self.initModuleDone = False
self.startModuleDone = False
self.remoteLogHandler = None
self.accessLock = threading.RLock() # for read_* / write_* methods
self.updateLock = threading.RLock() # for announceUpdate
self.polledModules = [] # modules polled by thread started in self.startModules
self.attachedModules = {}
self.errors = []
self._isinitialized = False
self.updateCallback = srv.dispatcher.announce_update
# handle module properties
# 1) make local copies of properties
super().__init__()
# conversion from exported names to internal attribute names
self.accessiblename2attr = {}
self.writeDict = {} # values of parameters to be written
# properties, parameters and commands are auto-merged upon subclassing
self.parameters = {}
self.commands = {}
# 2) check and apply properties specified in cfgdict as
# '<propertyname> = <propertyvalue>'
# pylint: disable=consider-using-dict-items
for key in self.propertyDict:
value = cfgdict.pop(key, None)
if value is not None:
try:
if isinstance(value, dict):
self.setProperty(key, value['value'])
else:
self.setProperty(key, value)
except BadValueError:
self.errors.append(f'{key}: value {value!r} does not match {self.propertyDict[key].datatype!r}!')
# 3) set automatic properties
mycls, = self.__class__.__bases__ # skip the wrapper class
myclassname = f'{mycls.__module__}.{mycls.__name__}'
self.implementation = myclassname
# list of only the 'highest' secop module class
self.interface_classes = [
b.__name__ for b in mycls.__mro__ if b.__name__ in SECoP_BASE_CLASSES][:1]
# handle Features
self.features = [b.__name__ for b in mycls.__mro__ if Feature in b.__bases__]
# handle accessibles
# 1) make local copies of parameter objects
# they need to be individual per instance since we use them also
# to cache the current value + qualifiers...
# do not re-use self.accessibles as this is the same for all instances
accessibles = self.accessibles
self.accessibles = {}
for aname, aobj in accessibles.items():
# make a copy of the Parameter/Command object
aobj = aobj.copy()
acfg = cfgdict.pop(aname, None)
self._add_accessible(aname, aobj, cfg=acfg)
# 3) complain about names not found as accessible or property names
if cfgdict:
self.errors.append(
f"{', '.join(cfgdict.keys())} does not exist (use one of"
f" {', '.join(list(self.accessibles) + list(self.propertyDict))})")
# 5) ensure consistency of all accessibles added here
for aobj in self.accessibles.values():
aobj.finish(self)
# Modify units AFTER applying the cfgdict
mainvalue = self.parameters.get('value')
if mainvalue:
mainunit = mainvalue.datatype.unit
if mainunit:
self.applyMainUnit(mainunit)
# 6) check complete configuration of * properties
if not self.errors:
try:
self.checkProperties()
except ConfigError as e:
self.errors.append(str(e))
for aname, aobj in self.accessibles.items():
try:
aobj.checkProperties()
except (ConfigError, ProgrammingError) as e:
self.errors.append(f'{aname}: {e}')
if self.errors:
raise ConfigError(self.errors)
# helper cfg-editor
def __iter__(self):
return self.accessibles.__iter__()
def __getitem__(self, item):
return self.accessibles.__getitem__(item)
def applyMainUnit(self, mainunit):
"""replace $ in units of parameters by mainunit"""
for pobj in self.parameters.values():
pobj.datatype.set_main_unit(mainunit)
def _add_accessible(self, name, accessible, cfg=None):
if self.startModuleDone:
raise ProgrammingError('Accessibles can only be added before startModule()!')
if not self.export: # do not export parameters of a module not exported
accessible.export = False
self.accessibles[name] = accessible
if accessible.export:
self.accessiblename2attr[accessible.export] = name
if isinstance(accessible, Parameter):
self.parameters[name] = accessible
if isinstance(accessible, Command):
self.commands[name] = accessible
if cfg:
try:
for propname, propvalue in cfg.items():
accessible.setProperty(propname, propvalue)
except KeyError:
self.errors.append(f"'{name}' has no property '{propname}'")
except BadValueError as e:
self.errors.append(f'{name}.{propname}: {str(e)}')
if isinstance(accessible, Parameter):
self._handle_writes(name, accessible)
def _handle_writes(self, pname, pobj):
""" register value for writing, if given
apply default when no value is given (in cfg or as Parameter argument)
or complain, when cfg is needed
"""
self.paramCallbacks[pname] = []
if isinstance(pobj, Limit):
basepname = pname.rpartition('_')[0]
baseparam = self.parameters.get(basepname)
if not baseparam:
self.errors.append(f'limit {pname!r} is given, but not {basepname!r}')
return
if baseparam.datatype is None:
return # an error will be reported on baseparam
pobj.set_datatype(baseparam.datatype)
if not pobj.hasDatatype():
self.errors.append(f'{pname} needs a datatype')
return
if pobj.value is None:
if pobj.needscfg:
self.errors.append(f'{pname!r} has no default value and was not given in config!')
if pobj.default is None:
# we do not want to call the setter for this parameter for now,
# this should happen on the first read
pobj.readerror = ConfigError(f'parameter {pname!r} not initialized')
# above error will be triggered on activate after startup,
# when not all hardware parameters are read because of startup timeout
pobj.default = pobj.datatype.default
pobj.value = pobj.default
else:
# value given explicitly, either by cfg or as Parameter argument
pobj.given = True # for PersistentMixin
if hasattr(self, 'write_' + pname):
self.writeDict[pname] = pobj.value
if pobj.default is None:
pobj.default = pobj.value
# this checks again for datatype and sets the timestamp
setattr(self, pname, pobj.value)
def announceUpdate(self, pname, value=None, err=None, timestamp=None, validate=True):
"""announce a changed value or readerror
:param pname: parameter name
:param value: new value or None in case of error
:param err: None or an exception
:param timestamp: a timestamp or None for taking current time
:param validate: True: convert to datatype, in case of error store in readerror
:return:
when err=None and validate=False, the value must already be converted to the datatype
"""
with self.updateLock:
pobj = self.parameters[pname]
timestamp = timestamp or time.time()
if not err:
try:
if validate:
value = pobj.datatype(value)
except Exception as e:
err = e
else:
changed = pobj.value != value
# store the value even in case of error
pobj.value = value
if err:
if secop_error(err) == pobj.readerror:
err.report_error = False
return # no updates for repeated errors
err = secop_error(err)
value_err = value, err
else:
if not changed and timestamp < (pobj.timestamp or 0) + pobj.omit_unchanged_within:
# no change within short time -> omit
return
value_err = (value,)
pobj.timestamp = timestamp or time.time()
pobj.readerror = err
for cbfunc, cbargs in self.paramCallbacks[pname]:
try:
cbfunc(*cbargs, *value_err)
except Exception:
pass
if pobj.export:
self.updateCallback(self, pobj)
def addCallback(self, pname, callback_function, *args):
self.paramCallbacks[pname].append((callback_function, args))
def registerCallbacks(self, modobj, autoupdate=()):
"""register callbacks to another module <modobj>
whenever a self.<param> changes or changes its error state:
<modobj>.update_param(<value> [, <exc>]) is called,
where <value> is the new value and <exc> is given only in case of error.
if the method does not exist, and <param> is in autoupdate
<modobj>.announceUpdate(<pname>, <value>, <exc>) is called
with <exc> being None in case of no error.
Remark: when <modobj>.update_<param> does not accept the <exc> argument,
nothing happens (the callback is catched by try / except).
Any exceptions raised by the callback function are silently ignored.
"""
autoupdate = set(autoupdate)
for pname in self.parameters:
cbfunc = getattr(modobj, 'update_' + pname, None)
if cbfunc:
self.addCallback(pname, cbfunc)
elif pname in autoupdate:
self.addCallback(pname, modobj.announceUpdate, pname)
def isBusy(self, status=None):
"""helper function for treating substates of BUSY correctly"""
# defined even for non drivable (used for dynamic polling)
return False
def earlyInit(self):
"""initialise module with stuff to be done before all modules are created"""
self.earlyInitDone = True
def initModule(self):
"""initialise module with stuff to be done after all modules are created"""
self.initModuleDone = True
if self.enablePoll or self.writeDict:
# enablePoll == False: we still need the poll thread for writing values from writeDict
if hasattr(self, 'io'):
self.io.polledModules.append(self)
if not self.io.triggerPoll:
# when self.io.enablePoll is False, triggerPoll is not
# created for self.io in the else clause below
self.io.triggerPoll = threading.Event()
else:
self.triggerPoll = threading.Event()
self.polledModules.append(self)
def startModule(self, start_events):
"""runs after init of all modules
when a thread is started, a trigger function may signal that it
has finished its initial work
start_events.get_trigger(<timeout>) creates such a trigger and
registers it in the server for waiting
<timeout> defaults to 30 seconds
"""
# we do not need self.errors any longer. should we delete it?
# del self.errors
if self.polledModules:
mkthread(self.__pollThread, self.polledModules, start_events.get_trigger())
self.startModuleDone = True
def initialReads(self):
"""initial reads to be done
override to read initial values from HW, when it is not desired
to poll them afterwards
called from the poll thread, after writeInitParams but before
all parameters are polled once
"""
def shutdownModule(self):
"""called when the sever shuts down
any cleanup-work should be performed here, like closing threads and
saving data.
"""
def doPoll(self):
"""polls important parameters like value and status
all other parameters are polled automatically
"""
def setFastPoll(self, flag, fast_interval=0.25):
"""change poll interval
:param flag: enable/disable fast poll mode
:param fast_interval: fast poll interval
"""
if self.pollInfo:
self.pollInfo.fast_flag = flag
self.pollInfo.interval = fast_interval if flag else self.pollinterval
self.pollInfo.trigger()
def callPollFunc(self, rfunc, raise_com_failed=False):
"""call read method with proper error handling"""
try:
rfunc()
if rfunc.__name__ in self.pollInfo.pending_errors:
self.log.info('%s: o.k.', rfunc.__name__)
self.pollInfo.pending_errors.discard(rfunc.__name__)
except Exception as e:
if getattr(e, 'report_error', True):
name = rfunc.__name__
self.pollInfo.pending_errors.add(name) # trigger o.k. message after error is resolved
if isinstance(e, SECoPError):
e.raising_methods.append(name)
if e.silent:
self.log.debug('%s', e.format(False))
else:
self.log.error('%s', e.format(False))
if raise_com_failed and isinstance(e, CommunicationFailedError):
raise
else:
# not a SECoPError: this is proabably a programming error
# we want to log the traceback
self.log.error('%s', formatException())
def __pollThread(self, modules, started_callback):
"""poll thread body
:param modules: list of modules to be handled by this thread
:param started_callback: to be called after all polls are done once
before polling, parameters which need hardware initialisation are written
"""
polled_modules = [m for m in modules if m.enablePoll]
if hasattr(self, 'registerReconnectCallback'):
# self is a communicator supporting reconnections
def trigger_all(trg=self.triggerPoll, polled_modules=polled_modules):
for m in polled_modules:
m.pollInfo.last_main = 0
m.pollInfo.last_slow = 0
trg.set()
self.registerReconnectCallback('trigger_polls', trigger_all)
# collect all read functions
for mobj in polled_modules:
pinfo = mobj.pollInfo = PollInfo(mobj.pollinterval, self.triggerPoll)
# trigger a poll interval change when self.pollinterval changes.
if 'pollinterval' in mobj.paramCallbacks:
mobj.addCallback('pollinterval', pinfo.update_interval)
for pname, pobj in mobj.parameters.items():
rfunc = getattr(mobj, 'read_' + pname)
if rfunc.poll:
pinfo.polled_parameters.append((mobj, rfunc, pobj))
while True:
try:
for mobj in modules:
# TODO when needed: here we might add a call to a method :meth:`beforeWriteInit`
mobj.writeInitParams()
mobj.initialReads()
# call all read functions a first time
for m in polled_modules:
for mobj, rfunc, _ in m.pollInfo.polled_parameters:
mobj.callPollFunc(rfunc, raise_com_failed=True)
# TODO when needed: here we might add calls to a method :meth:`afterInitPolls`
break
except CommunicationFailedError as e:
# when communication failed, probably all parameters and may be more modules are affected.
# as this would take a lot of time (summed up timeouts), we do not continue
# trying and let the server accept connections, further polls might success later
if started_callback:
self.log.error('communication failure on startup: %s', e)
started_callback()
started_callback = None
self.triggerPoll.wait(0.1) # wait for reconnection or max 10 sec.
break
if started_callback:
started_callback()
if not polled_modules: # no polls needed - exit thread
return
to_poll = ()
while True:
now = time.time()
wait_time = 999
for mobj in modules:
pinfo = mobj.pollInfo
wait_time = min(pinfo.last_main + pinfo.interval - now, wait_time,
pinfo.last_slow + mobj.slowinterval - now)
if wait_time > 0 and not to_poll:
# nothing to do
self.triggerPoll.wait(wait_time)
self.triggerPoll.clear()
continue
# call doPoll of all modules where due
for mobj in modules:
pinfo = mobj.pollInfo
if now > pinfo.last_main + pinfo.interval:
try:
pinfo.last_main = (now // pinfo.interval) * pinfo.interval
except ZeroDivisionError:
pinfo.last_main = now
mobj.callPollFunc(mobj.doPoll)
now = time.time()
# find ONE due slow poll and call it
loop = True
while loop: # loops max. 2 times, when to_poll is at end
for mobj, rfunc, pobj in to_poll:
if now > pobj.timestamp + mobj.slowinterval * 0.5:
mobj.callPollFunc(rfunc)
loop = False # one poll done
break
else:
to_poll = []
# collect due slow polls
for mobj in modules:
pinfo = mobj.pollInfo
if now > pinfo.last_slow + mobj.slowinterval:
to_poll.extend(pinfo.polled_parameters)
pinfo.last_slow = (now // mobj.slowinterval) * mobj.slowinterval
if to_poll:
to_poll = iter(to_poll)
else:
loop = False # no slow polls ready
def writeInitParams(self):
"""write values for parameters with configured values
- does proper error handling
called at the beginning of the poller thread and for writing persistent values
"""
for pname in list(self.writeDict):
value = self.writeDict.pop(pname, Done)
# in the mean time, a poller or handler might already have done it
if value is not Done:
wfunc = getattr(self, 'write_' + pname, None)
if wfunc is None:
setattr(self, pname, value)
else:
try:
self.log.debug('initialize parameter %s', pname)
wfunc(value)
except SECoPError as e:
if e.silent:
self.log.debug('%s: %s', pname, str(e))
else:
self.log.error('%s: %s', pname, str(e))
except Exception:
self.log.error(formatException())
def setRemoteLogging(self, conn, level, send_log):
if self.remoteLogHandler is None:
for handler in self.log.handlers:
if isinstance(handler, RemoteLogHandler):
handler.send_log = send_log
self.remoteLogHandler = handler
break
else:
raise ValueError('remote handler not found')
self.remoteLogHandler.set_conn_level(self.name, conn, level)
def checkLimits(self, value, pname='target'):
"""check for limits
:param value: the value to be checked for <pname>_min <= value <= <pname>_max
:param pname: parameter name, default is 'target'
raises RangeError in case the value is not valid
This method is called automatically and needs therefore rarely to be
called by the programmer. It might be used in a check_<param> method,
when no automatic super call is desired.
"""
try:
min_, max_ = getattr(self, pname + '_limits')
if not min_ <= value <= max_:
raise RangeError(f'{pname} outside {pname}_limits')
return
except AttributeError:
pass
min_ = getattr(self, pname + '_min', float('-inf'))
max_ = getattr(self, pname + '_max', float('inf'))
if min_ > max_:
raise RangeError(f'invalid limits: {pname}_min > {pname}_max')
if value < min_:
raise RangeError(f'{pname} below {pname}_min')
if value > max_:
raise RangeError(f'{pname} above {pname}_max')

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
# *****************************************************************************
#
# This program is free software; you can redistribute it and/or modify it under
@ -17,26 +18,842 @@
# Module authors:
# Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
# Markus Zolliker <markus.zolliker@psi.ch>
# Alexander Zaft <a.zaft@fz-juelich.de>
#
# *****************************************************************************
"""Define base classes for real Modules implemented in the server"""
from frappy.datatypes import FloatRange, \
StatusType, StringType
from frappy.errors import ConfigError, ProgrammingError
from frappy.lib.enum import Enum
from frappy.params import Command, Parameter
from frappy.properties import Property
from frappy.logging import HasComlog
import time
import threading
from collections import OrderedDict
from .modulebase import Module
from frappy.datatypes import ArrayOf, BoolType, EnumType, FloatRange, \
IntRange, StatusType, StringType, TextType, TupleOf, \
NoneOr
from frappy.errors import BadValueError, CommunicationFailedError, ConfigError, \
ProgrammingError, SECoPError, secop_error, RangeError
from frappy.lib import formatException, mkthread, UniqueObject
from frappy.lib.enum import Enum
from frappy.params import Accessible, Command, Parameter, Limit
from frappy.properties import HasProperties, Property
from frappy.logging import RemoteLogHandler, HasComlog
Done = UniqueObject('Done')
"""a special return value for a read_<param>/write_<param> method
indicating that the setter is triggered already"""
wrapperClasses = {}
class HasAccessibles(HasProperties):
"""base class of Module
joining the class's properties, parameters and commands dicts with
those of base classes.
wrap read_*/write_* methods
(so the dispatcher will get notified of changed values)
"""
isWrapped = False
checkedMethods = set()
@classmethod
def __init_subclass__(cls): # pylint: disable=too-many-branches
super().__init_subclass__()
if cls.isWrapped:
return
# merge accessibles from all sub-classes, treat overrides
# for now, allow to use also the old syntax (parameters/commands dict)
accessibles = OrderedDict() # dict of accessibles
merged_properties = {} # dict of dict of merged properties
new_names = [] # list of names of new accessibles
override_values = {} # bare values overriding a parameter and methods overriding a command
for base in reversed(cls.__mro__):
for key, value in base.__dict__.items():
if isinstance(value, Accessible):
value.updateProperties(merged_properties.setdefault(key, {}))
if base == cls and key not in accessibles:
new_names.append(key)
accessibles[key] = value
override_values.pop(key, None)
elif key in accessibles:
override_values[key] = value
for aname, aobj in list(accessibles.items()):
if aname in override_values:
aobj = aobj.copy()
value = override_values[aname]
if value is None:
accessibles.pop(aname)
continue
aobj.merge(merged_properties[aname])
aobj.override(value)
# replace the bare value by the created accessible
setattr(cls, aname, aobj)
else:
aobj.merge(merged_properties[aname])
accessibles[aname] = aobj
# rebuild order: (1) inherited items, (2) items from paramOrder, (3) new accessibles
# move (2) to the end
paramOrder = cls.__dict__.get('paramOrder', ())
for aname in paramOrder:
if aname in accessibles:
accessibles.move_to_end(aname)
# ignore unknown names
# move (3) to the end
for aname in new_names:
if aname not in paramOrder:
accessibles.move_to_end(aname)
# note: for python < 3.6 the order of inherited items is not ensured between
# declarations within the same class
cls.accessibles = accessibles
cls.wrappedAttributes = {'isWrapped': True}
# create wrappers for access methods
wrapped_name = '_' + cls.__name__
for pname, pobj in accessibles.items():
# wrap of reading/writing funcs
if not isinstance(pobj, Parameter):
# nothing to do for Commands
continue
rname = 'read_' + pname
rfunc = getattr(cls, rname, None)
# create wrapper
if rfunc:
def new_rfunc(self, pname=pname, rfunc=rfunc):
with self.accessLock:
try:
value = rfunc(self)
self.log.debug("read_%s returned %r", pname, value)
if value is Done: # TODO: to be removed when all code using Done is updated
return getattr(self, pname)
pobj = self.accessibles[pname]
value = pobj.datatype(value)
except Exception as e:
self.log.debug("read_%s failed with %r", pname, e)
if isinstance(e, SECoPError):
e.raising_methods.append(f'{self.name}.read_{pname}')
self.announceUpdate(pname, err=e)
raise
self.announceUpdate(pname, value, validate=False)
return value
new_rfunc.poll = getattr(rfunc, 'poll', True)
else:
def new_rfunc(self, pname=pname):
return getattr(self, pname)
new_rfunc.poll = False
new_rfunc.__name__ = rname
new_rfunc.__qualname__ = wrapped_name + '.' + rname
new_rfunc.__module__ = cls.__module__
cls.wrappedAttributes[rname] = new_rfunc
cname = 'check_' + pname
for postfix in ('_limits', '_min', '_max'):
limname = pname + postfix
if limname in accessibles:
# find the base class, where the parameter <limname> is defined first.
# we have to check all bases, as they may not be treated yet when
# not inheriting from HasAccessibles
base = next(b for b in reversed(cls.__mro__) if limname in b.__dict__)
if cname not in base.__dict__:
# there is no check method yet at this class
# add check function to the class where the limit was defined
setattr(base, cname, lambda self, value, pname=pname: self.checkLimits(value, pname))
cfuncs = tuple(filter(None, (b.__dict__.get(cname) for b in cls.__mro__)))
wname = 'write_' + pname
wfunc = getattr(cls, wname, None)
if wfunc or not pobj.readonly:
# allow write method even when parameter is readonly, but internally writable
def new_wfunc(self, value, pname=pname, wfunc=wfunc, check_funcs=cfuncs):
with self.accessLock:
self.log.debug('validate %r to datatype of %r', value, pname)
validate = self.parameters[pname].datatype.validate
try:
new_value = validate(value)
for c in check_funcs:
if c(self, value):
break
if wfunc:
new_value = wfunc(self, new_value)
self.log.debug('write_%s(%r) returned %r', pname, value, new_value)
if new_value is Done: # TODO: to be removed when all code using Done is updated
return getattr(self, pname)
new_value = value if new_value is None else validate(new_value)
except Exception as e:
if isinstance(e, SECoPError):
e.raising_methods.append(f'{self.name}.write_{pname}')
self.announceUpdate(pname, err=e)
raise
self.announceUpdate(pname, new_value, validate=False)
return new_value
new_wfunc.__name__ = wname
new_wfunc.__qualname__ = wrapped_name + '.' + wname
new_wfunc.__module__ = cls.__module__
cls.wrappedAttributes[wname] = new_wfunc
cls.checkedMethods.update(cls.wrappedAttributes)
# check for programming errors
for attrname in dir(cls):
prefix, _, pname = attrname.partition('_')
if not pname:
continue
if prefix == 'do':
raise ProgrammingError(f'{cls.__name__!r}: old style command {attrname!r} not supported anymore')
if prefix in ('read', 'write') and attrname not in cls.checkedMethods:
raise ProgrammingError(f'{cls.__name__}.{attrname} defined, but {pname!r} is no parameter')
try:
# update Status type
cls.Status = cls.status.datatype.members[0]._enum
except AttributeError:
pass
res = {}
# collect info about properties
for pn, pv in cls.propertyDict.items():
if pv.settable:
res[pn] = pv
# collect info about parameters and their properties
for param, pobj in cls.accessibles.items():
res[param] = {}
for pn, pv in pobj.getProperties().items():
if pv.settable:
res[param][pn] = pv
cls.configurables = res
def __new__(cls, *args, **kwds):
wrapper_class = wrapperClasses.get(cls)
if wrapper_class is None:
wrapper_class = type('_' + cls.__name__, (cls,), cls.wrappedAttributes)
wrapperClasses[cls] = wrapper_class
return super().__new__(wrapper_class)
class Feature(HasAccessibles):
"""all things belonging to a small, predefined functionality influencing the working of a module
a mixin with Feature as a direct base class is recognized as a SECoP feature
and reported in the module property 'features'
"""
class PollInfo:
def __init__(self, pollinterval, trigger_event):
self.interval = pollinterval
self.last_main = 0
self.last_slow = 0
self.pending_errors = set()
self.polled_parameters = []
self.fast_flag = False
self.trigger_event = trigger_event
def trigger(self, immediate=False):
"""trigger a recalculation of poll due times
:param immediate: when True, doPoll should be called as soon as possible
"""
if immediate:
self.last_main = 0
self.trigger_event.set()
def update_interval(self, pollinterval):
if not self.fast_flag:
self.interval = pollinterval
self.trigger()
class Module(HasAccessibles):
"""basic module
all SECoP modules derive from this.
:param name: the modules name
:param logger: a logger instance
:param cfgdict: the dict from this modules section in the config file
:param srv: the server instance
Notes:
- the programmer normally should not need to reimplement :meth:`__init__`
- within modules, parameters should only be addressed as ``self.<pname>``,
i.e. ``self.value``, ``self.target`` etc...
- these are accessing the cached version.
- they can also be written to, generating an async update
- if you want to 'update from the hardware', call ``self.read_<pname>()`` instead
- the return value of this method will be used as the new cached value and
be an async update sent automatically.
- if you want to 'update the hardware' call ``self.write_<pname>(<new value>)``.
- The return value of this method will also update the cache.
"""
# static properties, definitions in derived classes should overwrite earlier ones.
# note: properties don't change after startup and are usually filled
# with data from a cfg file...
# note: only the properties predefined here are allowed to be set in the cfg file
export = Property('flag if this module is to be exported', BoolType(), default=True, export=False)
group = Property('optional group the module belongs to', StringType(), default='', extname='group')
description = Property('description of the module', TextType(), extname='description', mandatory=True)
meaning = Property('optional meaning indicator', TupleOf(StringType(), IntRange(0, 50)),
default=('', 0), extname='meaning')
visibility = Property('optional visibility hint', EnumType('visibility', user=1, advanced=2, expert=3),
default='user', extname='visibility')
implementation = Property('internal name of the implementation class of the module', StringType(),
extname='implementation')
interface_classes = Property('offical highest interface-class of the module', ArrayOf(StringType()),
extname='interface_classes')
features = Property('list of features', ArrayOf(StringType()), extname='features')
pollinterval = Property('poll interval for parameters handled by doPoll', FloatRange(0.1, 120), default=5)
slowinterval = Property('poll interval for other parameters', FloatRange(0.1, 120), default=15)
omit_unchanged_within = Property('default for minimum time between updates of unchanged values',
NoneOr(FloatRange(0)), export=False, default=None)
enablePoll = True
# properties, parameters and commands are auto-merged upon subclassing
parameters = {}
commands = {}
# reference to the dispatcher (used for sending async updates)
DISPATCHER = None
pollInfo = None
triggerPoll = None # trigger event for polls. used on io modules and modules without io
def __init__(self, name, logger, cfgdict, srv):
# remember the dispatcher object (for the async callbacks)
self.DISPATCHER = srv.dispatcher
self.log = logger
self.name = name
self.valueCallbacks = {}
self.errorCallbacks = {}
self.earlyInitDone = False
self.initModuleDone = False
self.startModuleDone = False
self.remoteLogHandler = None
self.accessLock = threading.RLock() # for read_* / write_* methods
self.updateLock = threading.RLock() # for announceUpdate
self.polledModules = [] # modules polled by thread started in self.startModules
self.attachedModules = {}
errors = []
self._isinitialized = False
# handle module properties
# 1) make local copies of properties
super().__init__()
# 2) check and apply properties specified in cfgdict as
# '<propertyname> = <propertyvalue>'
# pylint: disable=consider-using-dict-items
for key in self.propertyDict:
value = cfgdict.pop(key, None)
if value is not None:
try:
if isinstance(value, dict):
self.setProperty(key, value['value'])
else:
self.setProperty(key, value)
except BadValueError:
errors.append(f'{key}: value {value!r} does not match {self.propertyDict[key].datatype!r}!')
# 3) set automatic properties
mycls, = self.__class__.__bases__ # skip the wrapper class
myclassname = f'{mycls.__module__}.{mycls.__name__}'
self.implementation = myclassname
# list of all 'secop' modules
# self.interface_classes = [
# b.__name__ for b in mycls.__mro__ if b.__module__.startswith('frappy.modules')]
# list of only the 'highest' secop module class
self.interface_classes = [
b.__name__ for b in mycls.__mro__ if b in SECoP_BASE_CLASSES][:1]
# handle Features
self.features = [b.__name__ for b in mycls.__mro__ if Feature in b.__bases__]
# handle accessibles
# 1) make local copies of parameter objects
# they need to be individual per instance since we use them also
# to cache the current value + qualifiers...
accessibles = {}
# conversion from exported names to internal attribute names
accessiblename2attr = {}
for aname, aobj in self.accessibles.items():
# make a copy of the Parameter/Command object
aobj = aobj.copy()
if not self.export: # do not export parameters of a module not exported
aobj.export = False
if aobj.export:
accessiblename2attr[aobj.export] = aname
accessibles[aname] = aobj
# do not re-use self.accessibles as this is the same for all instances
self.accessibles = accessibles
self.accessiblename2attr = accessiblename2attr
# provide properties to 'filter' out the parameters/commands
self.parameters = {k: v for k, v in accessibles.items() if isinstance(v, Parameter)}
self.commands = {k: v for k, v in accessibles.items() if isinstance(v, Command)}
# 2) check and apply parameter_properties
bad = []
for aname, cfg in cfgdict.items():
aobj = self.accessibles.get(aname, None)
if aobj:
try:
for propname, propvalue in cfg.items():
aobj.setProperty(propname, propvalue)
except KeyError:
errors.append(f"'{aname}' has no property '{propname}'")
except BadValueError as e:
errors.append(f'{aname}.{propname}: {str(e)}')
else:
bad.append(aname)
# 3) complain about names not found as accessible or property names
if bad:
errors.append(
f"{', '.join(bad)} does not exist (use one of {', '.join(list(self.accessibles) + list(self.propertyDict))})")
# 4) register value for writing, if given
# apply default when no value is given (in cfg or as Parameter argument)
# or complain, when cfg is needed
self.writeDict = {} # values of parameters to be written
for pname, pobj in self.parameters.items():
self.valueCallbacks[pname] = []
self.errorCallbacks[pname] = []
if isinstance(pobj, Limit):
basepname = pname.rpartition('_')[0]
baseparam = self.parameters.get(basepname)
if not baseparam:
errors.append(f'limit {pname!r} is given, but not {basepname!r}')
continue
if baseparam.datatype is None:
continue # an error will be reported on baseparam
pobj.set_datatype(baseparam.datatype)
if not pobj.hasDatatype():
errors.append(f'{pname} needs a datatype')
continue
if pobj.value is None:
if pobj.needscfg:
errors.append(f'{pname!r} has no default value and was not given in config!')
if pobj.default is None:
# we do not want to call the setter for this parameter for now,
# this should happen on the first read
pobj.readerror = ConfigError(f'parameter {pname!r} not initialized')
# above error will be triggered on activate after startup,
# when not all hardware parameters are read because of startup timeout
pobj.default = pobj.datatype.default
pobj.value = pobj.default
else:
# value given explicitly, either by cfg or as Parameter argument
pobj.given = True # for PersistentMixin
if hasattr(self, 'write_' + pname):
self.writeDict[pname] = pobj.value
if pobj.default is None:
pobj.default = pobj.value
# this checks again for datatype and sets the timestamp
setattr(self, pname, pobj.value)
# 5) ensure consistency
for aobj in self.accessibles.values():
aobj.finish(self)
# Modify units AFTER applying the cfgdict
mainvalue = self.parameters.get('value')
if mainvalue:
mainunit = mainvalue.datatype.unit
if mainunit:
self.applyMainUnit(mainunit)
# 6) check complete configuration of * properties
if not errors:
try:
self.checkProperties()
except ConfigError as e:
errors.append(str(e))
for aname, aobj in self.accessibles.items():
try:
aobj.checkProperties()
except (ConfigError, ProgrammingError) as e:
errors.append(f'{aname}: {e}')
if errors:
raise ConfigError(errors)
# helper cfg-editor
def __iter__(self):
return self.accessibles.__iter__()
def __getitem__(self, item):
return self.accessibles.__getitem__(item)
def applyMainUnit(self, mainunit):
"""replace $ in units of parameters by mainunit"""
for pobj in self.parameters.values():
pobj.datatype.set_main_unit(mainunit)
def announceUpdate(self, pname, value=None, err=None, timestamp=None, validate=True):
"""announce a changed value or readerror
:param pname: parameter name
:param value: new value or None in case of error
:param err: None or an exception
:param timestamp: a timestamp or None for taking current time
:param validate: True: convert to datatype, in case of error store in readerror
:return:
when err=None and validate=False, the value must already be converted to the datatype
"""
with self.updateLock:
pobj = self.parameters[pname]
timestamp = timestamp or time.time()
if not err:
try:
if validate:
value = pobj.datatype(value)
except Exception as e:
err = e
else:
changed = pobj.value != value
# store the value even in case of error
pobj.value = value
if err:
if secop_error(err) == pobj.readerror:
err.report_error = False
return # no updates for repeated errors
err = secop_error(err)
elif not changed and timestamp < (pobj.timestamp or 0) + pobj.omit_unchanged_within:
# no change within short time -> omit
return
pobj.timestamp = timestamp or time.time()
if err:
callbacks = self.errorCallbacks
pobj.readerror = arg = err
else:
callbacks = self.valueCallbacks
arg = value
pobj.readerror = None
if pobj.export:
self.DISPATCHER.announce_update(self.name, pname, pobj)
cblist = callbacks[pname]
for cb in cblist:
try:
cb(arg)
except Exception:
# print(formatExtendedTraceback())
pass
def registerCallbacks(self, modobj, autoupdate=()):
"""register callbacks to another module <modobj>
- whenever a self.<param> changes:
<modobj>.update_<param> is called with the new value as argument.
If this method raises an exception, <modobj>.<param> gets into an error state.
If the method does not exist and <param> is in autoupdate,
<modobj>.<param> is updated to self.<param>
- whenever <self>.<param> gets into an error state:
<modobj>.error_update_<param> is called with the exception as argument.
If this method raises an error, <modobj>.<param> gets into an error state.
If this method does not exist, and <param> is in autoupdate,
<modobj>.<param> gets into the same error state as self.<param>
"""
for pname in self.parameters:
errfunc = getattr(modobj, 'error_update_' + pname, None)
if errfunc:
def errcb(err, p=pname, efunc=errfunc):
try:
efunc(err)
except Exception as e:
modobj.announceUpdate(p, err=e)
self.errorCallbacks[pname].append(errcb)
else:
def errcb(err, p=pname):
modobj.announceUpdate(p, err=err)
if pname in autoupdate:
self.errorCallbacks[pname].append(errcb)
updfunc = getattr(modobj, 'update_' + pname, None)
if updfunc:
def cb(value, ufunc=updfunc, efunc=errcb):
try:
ufunc(value)
except Exception as e:
efunc(e)
self.valueCallbacks[pname].append(cb)
elif pname in autoupdate:
def cb(value, p=pname):
modobj.announceUpdate(p, value)
self.valueCallbacks[pname].append(cb)
def isBusy(self, status=None):
"""helper function for treating substates of BUSY correctly"""
# defined even for non drivable (used for dynamic polling)
return False
def earlyInit(self):
"""initialise module with stuff to be done before all modules are created"""
self.earlyInitDone = True
def initModule(self):
"""initialise module with stuff to be done after all modules are created"""
self.initModuleDone = True
if self.enablePoll or self.writeDict:
# enablePoll == False: we still need the poll thread for writing values from writeDict
if hasattr(self, 'io'):
self.io.polledModules.append(self)
else:
self.triggerPoll = threading.Event()
self.polledModules.append(self)
def startModule(self, start_events):
"""runs after init of all modules
when a thread is started, a trigger function may signal that it
has finished its initial work
start_events.get_trigger(<timeout>) creates such a trigger and
registers it in the server for waiting
<timeout> defaults to 30 seconds
"""
if self.polledModules:
mkthread(self.__pollThread, self.polledModules, start_events.get_trigger())
self.startModuleDone = True
def initialReads(self):
"""initial reads to be done
override to read initial values from HW, when it is not desired
to poll them afterwards
called from the poll thread, after writeInitParams but before
all parameters are polled once
"""
def shutdownModule(self):
"""called when the sever shuts down
any cleanup-work should be performed here, like closing threads and
saving data.
"""
def doPoll(self):
"""polls important parameters like value and status
all other parameters are polled automatically
"""
def setFastPoll(self, flag, fast_interval=0.25):
"""change poll interval
:param flag: enable/disable fast poll mode
:param fast_interval: fast poll interval
"""
if self.pollInfo:
self.pollInfo.fast_flag = flag
self.pollInfo.interval = fast_interval if flag else self.pollinterval
self.pollInfo.trigger()
def callPollFunc(self, rfunc, raise_com_failed=False):
"""call read method with proper error handling"""
try:
rfunc()
if rfunc.__name__ in self.pollInfo.pending_errors:
self.log.info('%s: o.k.', rfunc.__name__)
self.pollInfo.pending_errors.discard(rfunc.__name__)
except Exception as e:
if getattr(e, 'report_error', True):
name = rfunc.__name__
self.pollInfo.pending_errors.add(name) # trigger o.k. message after error is resolved
if isinstance(e, SECoPError):
e.raising_methods.append(name)
if e.silent:
self.log.debug('%s', e.format(False))
else:
self.log.error('%s', e.format(False))
if raise_com_failed and isinstance(e, CommunicationFailedError):
raise
else:
# not a SECoPError: this is proabably a programming error
# we want to log the traceback
self.log.error('%s', formatException())
def __pollThread(self, modules, started_callback):
"""poll thread body
:param modules: list of modules to be handled by this thread
:param started_callback: to be called after all polls are done once
before polling, parameters which need hardware initialisation are written
"""
polled_modules = [m for m in modules if m.enablePoll]
if hasattr(self, 'registerReconnectCallback'):
# self is a communicator supporting reconnections
def trigger_all(trg=self.triggerPoll, polled_modules=polled_modules):
for m in polled_modules:
m.pollInfo.last_main = 0
m.pollInfo.last_slow = 0
trg.set()
self.registerReconnectCallback('trigger_polls', trigger_all)
# collect all read functions
for mobj in polled_modules:
pinfo = mobj.pollInfo = PollInfo(mobj.pollinterval, self.triggerPoll)
# trigger a poll interval change when self.pollinterval changes.
if 'pollinterval' in mobj.valueCallbacks:
mobj.valueCallbacks['pollinterval'].append(pinfo.update_interval)
for pname, pobj in mobj.parameters.items():
rfunc = getattr(mobj, 'read_' + pname)
if rfunc.poll:
pinfo.polled_parameters.append((mobj, rfunc, pobj))
while True:
try:
for mobj in modules:
# TODO when needed: here we might add a call to a method :meth:`beforeWriteInit`
mobj.writeInitParams()
mobj.initialReads()
# call all read functions a first time
for m in polled_modules:
for mobj, rfunc, _ in m.pollInfo.polled_parameters:
mobj.callPollFunc(rfunc, raise_com_failed=True)
# TODO when needed: here we might add calls to a method :meth:`afterInitPolls`
break
except CommunicationFailedError as e:
# when communication failed, probably all parameters and may be more modules are affected.
# as this would take a lot of time (summed up timeouts), we do not continue
# trying and let the server accept connections, further polls might success later
if started_callback:
self.log.error('communication failure on startup: %s', e)
started_callback()
started_callback = None
self.triggerPoll.wait(0.1) # wait for reconnection or max 10 sec.
break
if started_callback:
started_callback()
if not polled_modules: # no polls needed - exit thread
return
to_poll = ()
while True:
now = time.time()
wait_time = 999
for mobj in modules:
pinfo = mobj.pollInfo
wait_time = min(pinfo.last_main + pinfo.interval - now, wait_time,
pinfo.last_slow + mobj.slowinterval - now)
if wait_time > 0 and not to_poll:
# nothing to do
self.triggerPoll.wait(wait_time)
self.triggerPoll.clear()
continue
# call doPoll of all modules where due
for mobj in modules:
pinfo = mobj.pollInfo
if now > pinfo.last_main + pinfo.interval:
try:
pinfo.last_main = (now // pinfo.interval) * pinfo.interval
except ZeroDivisionError:
pinfo.last_main = now
mobj.callPollFunc(mobj.doPoll)
now = time.time()
# find ONE due slow poll and call it
loop = True
while loop: # loops max. 2 times, when to_poll is at end
for mobj, rfunc, pobj in to_poll:
if now > pobj.timestamp + mobj.slowinterval * 0.5:
mobj.callPollFunc(rfunc)
loop = False # one poll done
break
else:
to_poll = []
# collect due slow polls
for mobj in modules:
pinfo = mobj.pollInfo
if now > pinfo.last_slow + mobj.slowinterval:
to_poll.extend(pinfo.polled_parameters)
pinfo.last_slow = (now // mobj.slowinterval) * mobj.slowinterval
if to_poll:
to_poll = iter(to_poll)
else:
loop = False # no slow polls ready
def writeInitParams(self):
"""write values for parameters with configured values
- does proper error handling
called at the beginning of the poller thread and for writing persistent values
"""
for pname in list(self.writeDict):
value = self.writeDict.pop(pname, Done)
# in the mean time, a poller or handler might already have done it
if value is not Done:
wfunc = getattr(self, 'write_' + pname, None)
if wfunc is None:
setattr(self, pname, value)
else:
try:
self.log.debug('initialize parameter %s', pname)
wfunc(value)
except SECoPError as e:
if e.silent:
self.log.debug('%s: %s', pname, str(e))
else:
self.log.error('%s: %s', pname, str(e))
except Exception:
self.log.error(formatException())
def setRemoteLogging(self, conn, level):
if self.remoteLogHandler is None:
for handler in self.log.handlers:
if isinstance(handler, RemoteLogHandler):
self.remoteLogHandler = handler
break
else:
raise ValueError('remote handler not found')
self.remoteLogHandler.set_conn_level(self, conn, level)
def checkLimits(self, value, pname='target'):
"""check for limits
:param value: the value to be checked for <pname>_min <= value <= <pname>_max
:param pname: parameter name, default is 'target'
raises RangeError in case the value is not valid
This method is called automatically and needs therefore rarely to be
called by the programmer. It might be used in a check_<param> method,
when no automatic super call is desired.
"""
try:
min_, max_ = getattr(self, pname + '_limits')
if not min_ <= value <= max_:
raise RangeError(f'{pname} outside {pname}_limits')
return
except AttributeError:
pass
min_ = getattr(self, pname + '_min', float('-inf'))
max_ = getattr(self, pname + '_max', float('inf'))
if min_ > max_:
raise RangeError(f'invalid limits: {pname}_min > {pname}_max')
if value < min_:
raise RangeError(f'{pname} below {pname}_min')
if value > max_:
raise RangeError(f'{pname} above {pname}_max')
class Readable(Module):
"""basic readable module"""
# pylint: disable=invalid-name
Status = Enum('Status',
IDLE=StatusType.IDLE,
WARN=StatusType.WARN,
@ -93,7 +910,7 @@ class Drivable(Writable):
@Command(None, result=None)
def stop(self):
"""not implemented - this is a no-op"""
"""cease driving, go to IDLE state"""
class Communicator(HasComlog, Module):
@ -108,18 +925,13 @@ class Communicator(HasComlog, Module):
"""
raise NotImplementedError()
SECoP_BASE_CLASSES = {Readable, Writable, Drivable, Communicator}
class Attached(Property):
"""a special property, defining an attached module
assign a module name to this property in the cfg file,
and the server will create an attribute with this module
When mandatory is set to False, and there is no value or an empty string
given in the config file, the value of the attribute will be None.
"""
def __init__(self, basecls=Module, description='attached module', mandatory=True):
self.basecls = basecls
@ -128,20 +940,13 @@ class Attached(Property):
def __get__(self, obj, owner):
if obj is None:
return self
modobj = obj.attachedModules.get(self.name)
if not modobj:
modulename = super().__get__(obj, owner)
if not modulename:
return None # happens when mandatory=False and modulename is not given
modobj = obj.secNode.get_module(modulename)
if not modobj:
raise ConfigError(f'attached module {self.name}={modulename!r} '
f'does not exist')
if self.name not in obj.attachedModules:
modobj = obj.DISPATCHER.get_module(super().__get__(obj, owner))
if not isinstance(modobj, self.basecls):
raise ConfigError(f'attached module {self.name}={modobj.name!r} '
raise ConfigError(f'attached module {self.name}={modobj.name!r} '\
f'must inherit from {self.basecls.__qualname__!r}')
obj.attachedModules[self.name] = modobj
return modobj
return obj.attachedModules.get(self.name) # return None if not given
def copy(self):
return Attached(self.basecls, self.description, self.mandatory)

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
# *****************************************************************************
#
# This program is free software; you can redistribute it and/or modify it under
@ -24,12 +25,12 @@
import inspect
from frappy.datatypes import ArrayOf, BoolType, CommandType, DataType, \
DataTypeType, EnumType, FloatRange, NoneOr, OrType, StringType, StructOf, \
TextType, TupleOf, ValueType
from frappy.errors import BadValueError, ProgrammingError, WrongTypeError
from frappy.lib import generalConfig
from frappy.datatypes import BoolType, CommandType, DataType, \
DataTypeType, EnumType, NoneOr, OrType, FloatRange, \
StringType, StructOf, TextType, TupleOf, ValueType, ArrayOf
from frappy.errors import BadValueError, WrongTypeError, ProgrammingError
from frappy.properties import HasProperties, Property
from frappy.lib import generalConfig
generalConfig.set_default('tolerate_poll_property', False)
generalConfig.set_default('omit_unchanged_within', 0.1)
@ -57,17 +58,13 @@ class Accessible(HasProperties):
def as_dict(self):
return self.propertyValues
def create_from_value(self, properties, value):
"""return a clone with given value and inherited properties"""
raise NotImplementedError
def clone(self, properties, **kwds):
"""return a clone of ourselfs with inherited properties"""
def override(self, value):
"""override with a bare value"""
raise NotImplementedError
def copy(self):
"""return a (deep) copy of ourselfs"""
return self.clone(self.propertyValues)
raise NotImplementedError
def updateProperties(self, merged_properties):
"""update merged_properties with our own properties"""
@ -98,16 +95,6 @@ class Accessible(HasProperties):
props.append(f'{k}={v!r}')
return f"{self.__class__.__name__}({', '.join(props)})"
def fixExport(self):
if self.export is True:
predefined_cls = PREDEFINED_ACCESSIBLES.get(self.name)
if predefined_cls is None:
self.export = '_' + self.name
elif isinstance(self, predefined_cls):
self.export = self.name
else:
raise ProgrammingError(f'can not use {self.name!r} as name of a {type(self).__name__}')
class Parameter(Accessible):
"""defines a parameter
@ -235,17 +222,26 @@ class Parameter(Accessible):
self.name = name
if isinstance(self.datatype, EnumType):
self.datatype.set_name(name)
self.fixExport()
def clone(self, properties, **kwds):
"""return a clone of ourselfs with inherited properties"""
res = type(self)(**kwds)
if self.export is True:
predefined_cls = PREDEFINED_ACCESSIBLES.get(self.name, None)
if predefined_cls is Parameter:
self.export = self.name
elif predefined_cls is None:
self.export = '_' + self.name
else:
raise ProgrammingError(f'can not use {self.name!r} as name of a Parameter')
if 'export' in self.ownProperties:
# avoid export=True overrides export=<name>
self.ownProperties['export'] = self.export
def copy(self):
"""return a (deep) copy of ourselfs"""
res = type(self)()
res.name = self.name
res.init(properties)
res.init(res.ownProperties)
res.init(self.propertyValues)
if 'datatype' in self.propertyValues:
res.datatype = res.datatype.copy()
res.finish()
return res
def updateProperties(self, merged_properties):
@ -258,9 +254,9 @@ class Parameter(Accessible):
merged_properties.pop(key)
merged_properties.update(self.ownProperties)
def create_from_value(self, properties, value):
"""return a clone with given value and inherited properties"""
return self.clone(properties, value=self.datatype(value))
def override(self, value):
"""override default"""
self.value = self.datatype(value)
def merge(self, merged_properties):
"""merge with inherited properties
@ -279,7 +275,7 @@ class Parameter(Accessible):
:param modobj: final call, called from Module.__init__
"""
self.fixExport()
if self.constant is not None:
constant = self.datatype(self.constant)
# The value of the `constant` property should be the
@ -395,7 +391,7 @@ class Command(Accessible):
else:
# goodie: allow @Command instead of @Command()
self.func = argument # this is the wrapped method!
if argument.__doc__ is not None:
if argument.__doc__:
self.description = inspect.cleandoc(argument.__doc__)
self.name = self.func.__name__ # this is probably not needed
self._inherit = inherit # save for __set_name__
@ -406,8 +402,18 @@ class Command(Accessible):
if self.func is None:
raise ProgrammingError(f'Command {owner.__name__}.{name} must be used as a method decorator')
self.fixExport()
self.datatype = CommandType(self.argument, self.result)
if self.export is True:
predefined_cls = PREDEFINED_ACCESSIBLES.get(name, None)
if predefined_cls is Command:
self.export = name
elif predefined_cls is None:
self.export = '_' + name
else:
raise ProgrammingError(f'can not use {name!r} as name of a Command') from None
if 'export' in self.ownProperties:
# avoid export=True overrides export=<name>
self.ownProperties['export'] = self.export
if not self._inherit:
for key, pobj in self.properties.items():
if key not in self.propertyValues:
@ -422,50 +428,38 @@ class Command(Accessible):
def __call__(self, func):
"""called when used as decorator"""
if isinstance(self.argument, StructOf):
# automatically set optional struct members
sig = inspect.signature(func)
params = set(sig.parameters.keys())
params.discard('self')
members = set(self.argument.members)
if params != members:
raise ProgrammingError(f'Command {func.__name__}: Function'
f' argument names do not match struct'
f' members!: {params} != {members}')
self.argument.optional = [p for p,v in sig.parameters.items()
if v.default is not inspect.Parameter.empty]
if 'description' not in self.ownProperties and func.__doc__ is not None:
if 'description' not in self.propertyValues and func.__doc__:
self.description = inspect.cleandoc(func.__doc__)
self.ownProperties['description'] = self.description
self.func = func
return self
def clone(self, properties, **kwds):
"""return a clone of ourselfs with inherited properties"""
res = type(self)(**kwds)
def copy(self):
"""return a (deep) copy of ourselfs"""
res = type(self)()
res.name = self.name
self.fixExport()
res.func = self.func
res.init(properties)
res.init(res.ownProperties)
res.init(self.propertyValues)
if res.argument:
res.argument = res.argument.copy()
if res.result:
res.result = res.result.copy()
res.finish()
self.finish()
return res
def updateProperties(self, merged_properties):
"""update merged_properties with our own properties"""
merged_properties.update(self.ownProperties)
def create_from_value(self, properties, value):
"""return a clone with given value and inherited properties
def override(self, value):
"""override method
this is needed when the @Command is missing on a method overriding a command"""
if not callable(value):
raise ProgrammingError(f'{self.name} = {value!r} is overriding a Command')
return self.clone(properties)(value)
self.func = value
if value.__doc__:
self.description = inspect.cleandoc(value.__doc__)
def merge(self, merged_properties):
"""merge with inherited properties
@ -494,7 +488,7 @@ class Command(Accessible):
"""perform function call
:param module_obj: the module on which the command is to be executed
:param argument: the argument from the do command (transported value!)
:param argument: the argument from the do command
:returns: the return value converted to the result type
- when the argument type is TupleOf, the function is called with multiple arguments
@ -504,15 +498,6 @@ class Command(Accessible):
# pylint: disable=unnecessary-dunder-call
func = self.__get__(module_obj)
if self.argument:
if argument is None:
raise WrongTypeError(
f'{module_obj.__class__.__name__}.{self.name} needs an'
f' argument of type {self.argument}!'
)
# convert transported value to internal value
argument = self.argument.import_value(argument)
# verify range
self.argument.validate(argument)
if isinstance(self.argument, TupleOf):
res = func(*argument)
elif isinstance(self.argument, StructOf):

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
# *****************************************************************************
#
# This program is free software; you can redistribute it and/or modify it under

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
# *****************************************************************************
#
# This program is free software; you can redistribute it and/or modify it under
@ -77,14 +78,17 @@ class PersistentMixin(Module):
super().__init__(name, logger, cfgdict, srv)
persistentdir = os.path.join(generalConfig.logdir, 'persistent')
os.makedirs(persistentdir, exist_ok=True)
self.persistentFile = os.path.join(persistentdir, f'{self.secNode.equipment_id}.{self.name}.json')
self.persistentFile = os.path.join(persistentdir, f'{self.DISPATCHER.equipment_id}.{self.name}.json')
self.initData = {} # "factory" settings
loaded = self.loadPersistentData()
for pname, pobj in self.parameters.items():
for pname in self.parameters:
pobj = self.parameters[pname]
flag = getattr(pobj, 'persistent', False)
if flag:
if flag == 'auto':
self.addCallback(pname, self.saveParameters)
def cb(value, m=self):
m.saveParameters()
self.valueCallbacks[pname].append(cb)
self.initData[pname] = pobj.value
if not pobj.given:
if pname in loaded:
@ -127,18 +131,16 @@ class PersistentMixin(Module):
self.writeInitParams()
return loaded
def saveParameters(self, _=None):
def saveParameters(self):
"""save persistent parameters
- to be called regularly explicitly by the module
- the caller has to make sure that this is not called after
a power down of the connected hardware before loadParameters
dummy argument to avoid closure for callback
"""
if self.writeDict:
# do not save before all values are written to the hw, as potentially
# factory default values were read in the meantime
# factory default values were read in the mean time
return
self.__save_params()

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
# *****************************************************************************
#
# This program is free software; you can redistribute it and/or modify it under
@ -69,8 +70,8 @@ class MainLogger:
self.log = None
self.console_handler = None
mlzlog.setLoggerClass(mlzlog.MLZLogger)
mlzlog.log = mlzlog.MLZLogger('')
self.log = mlzlog.log.getChild('')
assert self.log is None
self.log = mlzlog.log = mlzlog.MLZLogger('')
self.log.setLevel(mlzlog.DEBUG)
self.log.addHandler(mlzlog.ColoredConsoleHandler())
self.log.handlers[0].setLevel(LOG_LEVELS['comlog'])
@ -81,12 +82,20 @@ class Dispatcher(dispatcher.Dispatcher):
super().__init__(name, log, options, srv)
self.log = srv.log # overwrite child logger
def announce_update(self, moduleobj, pobj):
def announce_update(self, modulename, pname, pobj):
if pobj.readerror:
value = repr(pobj.readerror)
else:
value = pobj.value
moduleobj.log.info('%s %r', pobj.name, value)
logobj = self._modules.get(modulename, self)
# self.log.info('%s:%s %r', modulename, pname, value)
logobj.log.info('%s %r', pname, value)
def register_module(self, moduleobj, modulename, export=True):
self.log.info('registering %s', modulename)
super().register_module(moduleobj, modulename, export)
setattr(main, modulename, moduleobj)
self.get_module(modulename)
logger = MainLogger()
@ -110,10 +119,6 @@ class Playground(Server):
merged_cfg.pop('node', None)
self.module_cfg = merged_cfg
self._processCfg()
for modulename, moduleobj in self.secnode.modules.items():
cls = type(moduleobj).__bases__[0]
moduleobj.log.info('created as %s.%s', cls.__module__, cls.__name__)
setattr(main, modulename, moduleobj)
play = Playground()

Some files were not shown because too many files have changed in this diff Show More