Compare commits
261 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1bb869b43e | |||
| 3ede9eb9f4 | |||
| f57400feb9 | |||
| 38dd5b8ebb | |||
| 3cc9cadeb9 | |||
| dfb8037a65 | |||
| e8e5d2743a | |||
| 77bda6a72f | |||
| 42ebe05d5b | |||
| 765218eed2 | |||
| f00d37b7a6 | |||
| 3575921ac0 | |||
| f832e40898 | |||
| 495ad01ff6 | |||
| e786c5ec77 | |||
| a7b3f23bef | |||
| 151627b4f4 | |||
| ee26c72ed4 | |||
| 9fe040e9d3 | |||
| 943995b1d7 | |||
| 8291976c5d | |||
|
|
2ec2954159 | ||
|
|
7769a5daa6 | ||
|
|
a31e5a5009 | ||
|
|
cf220382b9 | ||
|
|
66f0e64b2e | ||
| 6e10382d98 | |||
|
|
6600ec63fd | ||
|
|
a62d85dc47 | ||
| ef9b257a54 | |||
| af28f33018 | |||
| a8b8fa1cc4 | |||
| 17511b8bf2 | |||
| 308283412e | |||
| ebfb8a005d | |||
| 03c2f6eb98 | |||
| e68ee356df | |||
| 21c20c966c | |||
|
|
183f6dcec2 | ||
| 71629c1d3a | |||
| b45635e4f8 | |||
| 2a4a37ed2f | |||
| 03ae83dbbc | |||
|
|
07377c8bf5 | ||
| 84ee2dd508 | |||
| 174da915d2 | |||
| 24153d2584 | |||
| 8575a2f785 | |||
| 51725d6d0d | |||
| 08f9416de5 | |||
| 7adb4d6f04 | |||
| ea5fc16a51 | |||
| 542079c876 | |||
| 160c3bfaf9 | |||
| 576723c650 | |||
| 65e27e0913 | |||
| 82663a142e | |||
|
|
cda6e08d6c | ||
|
|
fed7ce2197 | ||
|
|
cb142c580d | ||
| 53497df207 | |||
| 866cb7569c | |||
| e327bb0974 | |||
| 08244e17e0 | |||
| 431f4d1198 | |||
| bea6ea38ae | |||
|
|
8ba9f91f8a | ||
|
|
52def86ac8 | ||
|
|
c54ab5b9dd | ||
|
|
30e7e52524 | ||
|
|
cbf387ed87 | ||
| 96ef11ef84 | |||
| 1128b5aba4 | |||
|
|
cd3fdb6b62 | ||
| cdc2748818 | |||
| eab846d28e | |||
| db0ea2cc34 | |||
| 49c4edaa88 | |||
| 337b91b799 | |||
| 7814d054b9 | |||
| 8dc2677158 | |||
| cf151dd324 | |||
| 1e73440149 | |||
| 03dfb6aeb0 | |||
| 73c620797c | |||
| abf5f21e16 | |||
| c7496fa21f | |||
| 926dcd09e2 | |||
| 83f40f0c33 | |||
| 57b245c5ac | |||
| a5a4212691 | |||
| a3d0549199 | |||
| 8385461163 | |||
| 1a70099974 | |||
| c2b97a8dac | |||
| 27778e80f5 | |||
| 6c74c957a8 | |||
| eecbe9ca6b | |||
| 385480a8cc | |||
| c92cb22d97 | |||
| d85d80ba36 | |||
| 2b7ee0a72c | |||
| 97140aa3b4 | |||
| 1ad699fb66 | |||
| 52f90fe5be | |||
| 404b38d91a | |||
| 3203c6c9b3 | |||
| 472ae3f04d | |||
| 04f7f6ece5 | |||
| 54c9fb9db9 | |||
| c0f6569f1b | |||
| 745e15c709 | |||
| 62adec4874 | |||
| 9131bdab51 | |||
| a0629db53d | |||
| 415acb42cf | |||
| ee67a135e9 | |||
| ef826297fd | |||
| 50118e4ead | |||
| f9880f1473 | |||
| 0dd13d7ef9 | |||
| 6aec38d03e | |||
| 2238c20a37 | |||
| 018ed920b9 | |||
| 14f61b01db | |||
| 6fed5a3651 | |||
| f3c7cdc7c4 | |||
| 4f3ebf0aaf | |||
| 85f14ace40 | |||
| bc1ba4abb9 | |||
| cf50a372b3 | |||
| 67ea5340ee | |||
| 7d6ac4d742 | |||
| a76e529a82 | |||
| 7dfe2925aa | |||
| a6c86a5fe7 | |||
| d3280474c3 | |||
| 7cf32c4e7c | |||
|
|
48b79af96a | ||
| b1c920819e | |||
| 8f2973c39d | |||
| 6343edc3cb | |||
| bd00758460 | |||
|
|
d2cce8f21c | ||
| f6a5ef8f4d | |||
| dad9536eb5 | |||
| ccc66468d4 | |||
| 52215f9ec1 | |||
| 58549065fb | |||
| 0230641b1d | |||
| b264455ad3 | |||
| 07c5b32c5f | |||
|
|
80cb3f08d7 | ||
| fb4755502b | |||
| 3580cb9dc0 | |||
| d681507f94 | |||
| e0bd84cc3b | |||
| 9545cb4188 | |||
| 1fead8b2c6 | |||
| 809eda314b | |||
| ca6fd1dd5e | |||
| d0c063c60b | |||
| 7a59cf4956 | |||
| 7254d7f95c | |||
| c368292873 | |||
| 6a2aece383 | |||
| ad76a5d752 | |||
| 42e40db14b | |||
| 343ce90321 | |||
| 75783b211a | |||
|
|
36f2919ec2 | ||
| 7cca3192df | |||
| a632c53405 | |||
| a76425cb2e | |||
| d231e9ce06 | |||
| 44750572d9 | |||
| e0ef6047e2 | |||
| 421eb67b93 | |||
| 3048b8cb7d | |||
| 0ef484e082 | |||
| 8560384529 | |||
|
|
16d419c0f3 | ||
|
|
8c548da2e0 | ||
|
|
d9f340dce6 | ||
|
|
1325c8924d | ||
|
|
f8e3bd9ad2 | ||
| 6f547f0781 | |||
|
|
322cd39e0a | ||
|
|
41b51b35fd | ||
| 19571ab83d | |||
| b35c97f311 | |||
| 5d175b89ca | |||
| f8c52af3ac | |||
| bf9c946b1d | |||
| 09e596f847 | |||
|
|
7e2ccd214e | ||
| 907a52ccdb | |||
| 51dba895a5 | |||
|
|
d86718b81e | ||
|
|
42a6bfb5d2 | ||
| 895f66f713 | |||
| 3663c62b46 | |||
|
|
8c2588a5ed | ||
|
|
95dc8b186e | ||
|
|
265dbb1a57 | ||
| 73e9c8915b | |||
| 2e99e45aea | |||
| b7bc81710d | |||
| eee63ee3df | |||
| fd43687465 | |||
| a25a368491 | |||
| 4397d8db1a | |||
| e60ac5e655 | |||
| 0b5b40cfba | |||
| 2a617fbaf0 | |||
| 72d09ea73a | |||
| 1ae19d03b3 | |||
| 41cb107f50 | |||
| 8b0c4c78a9 | |||
| 7ac10d2260 | |||
| 6cbb3a094b | |||
|
|
405d316568 | ||
|
|
ac92a6ca3d | ||
|
|
a9e3489325 | ||
| 654a472a7e | |||
|
|
ddc72d0ea7 | ||
| ede07e266c | |||
| 4b543d02a0 | |||
| a4d5d8d3b7 | |||
| b37e625df3 | |||
| 1dbd7c145a | |||
| 2aa27f1ea5 | |||
| b28cdefe8a | |||
| e0e442814f | |||
| 66895f4f82 | |||
| 49bf0d21a9 | |||
| e8cd193d0d | |||
| 142add9109 | |||
|
|
c2673952f4 | ||
|
|
9fc2aa65d5 | ||
| 09fbaedb16 | |||
|
|
5deaf4cfd9 | ||
| 81f7426739 | |||
|
|
c69e516873 | ||
|
|
64732eb0c8 | ||
|
|
1535448090 | ||
|
|
554996ffd3 | ||
|
|
2d824978a9 | ||
|
|
35dd166fee | ||
|
|
aee99df2d0 | ||
| 8e05090795 | |||
|
|
eac58982d9 | ||
|
|
0f34418435 | ||
|
|
1423800ff4 | ||
|
|
e333763105 | ||
|
|
c09e02a01e | ||
|
|
337be1b2bc | ||
|
|
752942483f | ||
| 0204bdfe2f | |||
| facaca94eb | |||
| 0f0a177254 |
@@ -24,12 +24,14 @@
|
||||
|
||||
import sys
|
||||
import argparse
|
||||
import socket
|
||||
from pathlib import Path
|
||||
|
||||
# Add import path for inplace usage
|
||||
sys.path.insert(0, str(Path(__file__).absolute().parents[1]))
|
||||
|
||||
from frappy.client.interactive import init, run, clientenv, interact
|
||||
from frappy.protocol.discovery import scan
|
||||
|
||||
|
||||
def parseArgv(argv):
|
||||
@@ -37,6 +39,9 @@ def parseArgv(argv):
|
||||
parser.add_argument('-i', '--include',
|
||||
help='file to execute after connecting to the clients', metavar='file',
|
||||
type=Path, action='append', default=[])
|
||||
parser.add_argument('-s', '--scan',
|
||||
help='hosts to scan for (-s subnet for all nodes in subnet)',
|
||||
action='append', default=[])
|
||||
parser.add_argument('-o', '--only-execute',
|
||||
help='Do not go into interactive mode after executing files. \
|
||||
Has no effect without --include.', action='store_true')
|
||||
@@ -46,9 +51,38 @@ def parseArgv(argv):
|
||||
return parser.parse_args(argv)
|
||||
|
||||
|
||||
def own_ip():
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
s.settimeout(0)
|
||||
try:
|
||||
# doesn't even have to be reachable
|
||||
s.connect(('10.254.254.254', 1))
|
||||
return s.getsockname()[0]
|
||||
except Exception:
|
||||
return '127.0.0.1'
|
||||
finally:
|
||||
s.close()
|
||||
|
||||
|
||||
args = parseArgv(sys.argv[1:])
|
||||
|
||||
success = init(*args.node)
|
||||
nodes = args.node
|
||||
hosts = args.scan
|
||||
if not nodes and not hosts:
|
||||
hosts = ['localhost']
|
||||
if hosts:
|
||||
answers = []
|
||||
for host in hosts:
|
||||
ans = scan()
|
||||
if host == 'subnet': # all in subnet
|
||||
answers.extend(ans)
|
||||
else: # filter by ip
|
||||
ip = socket.gethostbyname(host)
|
||||
if ip == '127.0.0.1':
|
||||
ip = own_ip()
|
||||
answers.extend(a for a in ans if a.address == ip)
|
||||
nodes.extend(f'{h.hostname}:{h.port}' for h in answers)
|
||||
success = init(*nodes)
|
||||
|
||||
run_error = ''
|
||||
file_success = False
|
||||
|
||||
@@ -23,54 +23,20 @@
|
||||
"""SEC node autodiscovery tool."""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import select
|
||||
import socket
|
||||
import sys
|
||||
from collections import namedtuple
|
||||
from time import time as currenttime
|
||||
|
||||
UDP_PORT = 10767
|
||||
|
||||
Answer = namedtuple('Answer',
|
||||
'address, port, equipment_id, firmware, description')
|
||||
|
||||
|
||||
def decode(msg, addr):
|
||||
msg = msg.decode('utf-8')
|
||||
try:
|
||||
data = json.loads(msg)
|
||||
except Exception:
|
||||
return None
|
||||
if not isinstance(data, dict):
|
||||
return None
|
||||
if data.get('SECoP') != 'node':
|
||||
return None
|
||||
try:
|
||||
eq_id = data['equipment_id']
|
||||
fw = data['firmware']
|
||||
desc = data['description']
|
||||
port = data['port']
|
||||
except KeyError:
|
||||
return None
|
||||
addr, _scanport = addr
|
||||
return Answer(addr, port, eq_id, fw, desc)
|
||||
from pathlib import Path
|
||||
# Add import path for inplace usage
|
||||
sys.path.append(str(Path(__file__).absolute().parents[1]))
|
||||
from frappy.protocol.discovery import scan, listen
|
||||
|
||||
|
||||
def print_answer(answer, *, short=False):
|
||||
try:
|
||||
hostname = socket.gethostbyaddr(answer.address)[0]
|
||||
address = hostname
|
||||
numeric = f' ({answer.address})'
|
||||
except Exception:
|
||||
address = answer.address
|
||||
numeric = ''
|
||||
if short:
|
||||
# NOTE: keep this easily parseable!
|
||||
print(f'{answer.equipment_id} {address}:{answer.port}')
|
||||
print(f'{answer.equipment_id} {answer.hostname}:{answer.port}')
|
||||
return
|
||||
print(f'Found {answer.equipment_id} at {address}{numeric}:')
|
||||
numeric = f' ({answer.address})' if answer.address == answer.hostname else ''
|
||||
print(f'Found {answer.equipment_id} at {answer.hostname}{numeric}:')
|
||||
print(f' Port: {answer.port}')
|
||||
print(f' Firmware: {answer.firmware}')
|
||||
desc = answer.description.replace('\n', '\n ')
|
||||
@@ -78,51 +44,6 @@ def print_answer(answer, *, short=False):
|
||||
print('-' * 80)
|
||||
|
||||
|
||||
def scan(max_wait=1.0):
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
|
||||
# send a general broadcast
|
||||
try:
|
||||
s.sendto(json.dumps(dict(SECoP='discover')).encode('utf-8'),
|
||||
('255.255.255.255', UDP_PORT))
|
||||
except OSError as e:
|
||||
print('could not send the broadcast:', e)
|
||||
# we still keep listening for self-announcements
|
||||
start = currenttime()
|
||||
seen = set()
|
||||
while currenttime() < start + max_wait:
|
||||
res = select.select([s], [], [], 0.1)
|
||||
if res[0]:
|
||||
try:
|
||||
msg, addr = s.recvfrom(1024)
|
||||
except socket.error: # pragma: no cover
|
||||
continue
|
||||
answer = decode(msg, addr)
|
||||
if answer is None:
|
||||
continue
|
||||
if (answer.address, answer.equipment_id, answer.port) in seen:
|
||||
continue
|
||||
seen.add((answer.address, answer.equipment_id, answer.port))
|
||||
yield answer
|
||||
|
||||
|
||||
def listen(*, short=False):
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
if os.name == 'nt':
|
||||
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
else:
|
||||
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
|
||||
s.bind(('0.0.0.0', UDP_PORT))
|
||||
while True:
|
||||
try:
|
||||
msg, addr = s.recvfrom(1024)
|
||||
except KeyboardInterrupt:
|
||||
break
|
||||
answer = decode(msg, addr)
|
||||
if answer:
|
||||
print_answer(answer, short=short)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('-l', '--listen', action='store_true',
|
||||
@@ -136,4 +57,5 @@ if __name__ == '__main__':
|
||||
for answer in scan():
|
||||
print_answer(answer, short=short)
|
||||
if args.listen:
|
||||
listen(short=short)
|
||||
for answer in listen():
|
||||
print_answer(short=short)
|
||||
|
||||
40
cfg/acquisition_cfg.py
Normal file
40
cfg/acquisition_cfg.py
Normal file
@@ -0,0 +1,40 @@
|
||||
Node('measure.frappy.demo',
|
||||
'''Measureable demo''',
|
||||
'tcp://10770',
|
||||
)
|
||||
Mod('control',
|
||||
'frappy_demo.acquisition.Controller',
|
||||
'simple demo controller',
|
||||
channels = {'first': 'chan1', 'second': 'chan2', 'third': 'chan3'},
|
||||
pollinterval = 1,
|
||||
)
|
||||
Mod('chan1',
|
||||
'frappy_demo.acquisition.Channel',
|
||||
'simple channel demo',
|
||||
goal = 50,
|
||||
goal_enable = True,
|
||||
pollinterval = 1,
|
||||
)
|
||||
Mod('chan2',
|
||||
'frappy_demo.acquisition.Channel',
|
||||
'simple channel demo',
|
||||
pollinterval = 1,
|
||||
)
|
||||
Mod('chan3',
|
||||
'frappy_demo.acquisition.Channel',
|
||||
'simple channel demo',
|
||||
pollinterval = 1,
|
||||
)
|
||||
Mod('single',
|
||||
'frappy_demo.acquisition.SimpleAcquisition',
|
||||
'Acquisition demo',
|
||||
pollinterval = 1,
|
||||
goal = 20,
|
||||
goal_enable=True,
|
||||
acquisition_key='single',
|
||||
)
|
||||
Mod('ng',
|
||||
'frappy_demo.acquisition.NoGoalAcquisition',
|
||||
'Acquisition demo',
|
||||
pollinterval = 5,
|
||||
)
|
||||
@@ -3,20 +3,16 @@ Node('ah2700.frappy.psi.ch',
|
||||
)
|
||||
|
||||
Mod('cap_io',
|
||||
'frappy_psi.ah2700.Ah2700IO',
|
||||
'',
|
||||
uri='linse-976d-ts:3006',
|
||||
'frappy_psi.ahcapbridge.IO', '',
|
||||
uri='linse-leiden-ts:3002'
|
||||
)
|
||||
|
||||
Mod('cap',
|
||||
'frappy_psi.ah2700.Capacitance',
|
||||
'frappy_psi.ahcapbridge.AH2700',
|
||||
'capacitance',
|
||||
io = 'cap_io',
|
||||
io='cap_io',
|
||||
loss_module = 'loss',
|
||||
freq_module = 'freq',
|
||||
)
|
||||
|
||||
Mod('loss',
|
||||
'frappy_psi.parmod.Par',
|
||||
'loss parameter',
|
||||
read='cap.loss',
|
||||
unit='deg',
|
||||
)
|
||||
|
||||
|
||||
20
cfg/addons/ah2700leiden_cfg.py
Normal file
20
cfg/addons/ah2700leiden_cfg.py
Normal file
@@ -0,0 +1,20 @@
|
||||
Node('ah2700.frappy.psi.ch',
|
||||
'Andeen Hagerlin 2700 Capacitance Bridge',
|
||||
)
|
||||
|
||||
Mod('cap_io',
|
||||
'frappy_psi.ah2700.Ah2700IO',
|
||||
'',
|
||||
uri='linse-leiden-ts:3002',
|
||||
timeout=60,
|
||||
)
|
||||
|
||||
# this creates also cap_freq and cap_loss
|
||||
Mod('cap',
|
||||
'frappy_psi.ah2700.Capacitance',
|
||||
'capacitance',
|
||||
io = 'cap_io',
|
||||
loss_name='loss',
|
||||
freq_name='freq',
|
||||
)
|
||||
|
||||
@@ -16,7 +16,7 @@ Mod('ah',
|
||||
'frappy_psi.sea.SeaReadable', '',
|
||||
io='sea_addons',
|
||||
sea_object='cap',
|
||||
extra_modules = ['cap', 'loss']
|
||||
extra_modules = ['cap', 'loss', 'freq']
|
||||
)
|
||||
|
||||
Mod('cap',
|
||||
@@ -32,6 +32,12 @@ Mod('loss',
|
||||
single_module='ah.loss',
|
||||
)
|
||||
|
||||
Mod('freq',
|
||||
'frappy_psi.sea.SeaWritable', '',
|
||||
io='sea_addons',
|
||||
single_module='ah.freq',
|
||||
)
|
||||
|
||||
Mod('capslope',
|
||||
'frappy_psi.sea.SeaReadable', '',
|
||||
io='sea_addons',
|
||||
|
||||
31
cfg/addons/ahtwo_cfg.py
Normal file
31
cfg/addons/ahtwo_cfg.py
Normal file
@@ -0,0 +1,31 @@
|
||||
Node('ahtwo.frappy.psi.ch',
|
||||
'Andeen Hagerlin 2700 and 2550 Capacitance Bridges',
|
||||
)
|
||||
|
||||
# TODO: adapt names (cap, cap2) to your experiment
|
||||
|
||||
Mod('cap_io',
|
||||
'frappy_psi.ahcapbridge.IO', '',
|
||||
uri='linse-leiden-ts:3002'
|
||||
)
|
||||
|
||||
Mod('cap',
|
||||
'frappy_psi.ahcapbridge.AH2700',
|
||||
'capacitance',
|
||||
io='cap_io',
|
||||
loss_module = 'loss',
|
||||
freq_module = 'freq',
|
||||
)
|
||||
|
||||
Mod('cap2_io',
|
||||
'frappy_psi.ahcapbridge.IO', '',
|
||||
uri='linse-leiden-ts:3001'
|
||||
)
|
||||
|
||||
Mod('cap2',
|
||||
'frappy_psi.ahcapbridge.AH2550',
|
||||
'capacitance',
|
||||
io='cap2_io',
|
||||
loss_module = 'loss2',
|
||||
)
|
||||
|
||||
15
cfg/addons/haake_add_cfg.py
Normal file
15
cfg/addons/haake_add_cfg.py
Normal file
@@ -0,0 +1,15 @@
|
||||
Node('haake.frappy.psi.ch',
|
||||
'additional haake waterbath',
|
||||
)
|
||||
|
||||
Mod('haake_io',
|
||||
'frappy_psi.haake.HaakeIO',
|
||||
'',
|
||||
uri='sans-sample-ts:3006',
|
||||
)
|
||||
|
||||
Mod('T2',
|
||||
'frappy_psi.haake.TemperatureLoop',
|
||||
'second haake',
|
||||
io = 'haake_io',
|
||||
)
|
||||
@@ -3,8 +3,15 @@ Node('AH2700Test.psi.ch',
|
||||
'tcp://5000',
|
||||
)
|
||||
|
||||
Mod('cap',
|
||||
'frappy_psi.ah2700.Capacitance',
|
||||
'capacitance',
|
||||
uri='ldmse3-ts:3015',
|
||||
Mod('io',
|
||||
'frappy_psi.ahcapbridge.IO', '',
|
||||
uri='linse-leiden-ts:3002'
|
||||
)
|
||||
|
||||
Mod('cap',
|
||||
'frappy_psi.ahcapbridge.AH2700',
|
||||
'capacitance',
|
||||
io='io',
|
||||
loss_module = 'loss',
|
||||
freq_module = 'freq',
|
||||
)
|
||||
|
||||
327
cfg/dil5_cfg.py
327
cfg/dil5_cfg.py
@@ -1,219 +1,119 @@
|
||||
# by ID (independent of plug location)
|
||||
# by id (independent of plug location, but may not neccessarly be unique)
|
||||
# to verify just do:
|
||||
# ls /dev/serial/by-id
|
||||
turbo_uri = '/dev/serial/by-id/usb-FTDI_FT232R_USB_UART_A601PCGF-if00-port0'
|
||||
press_uri = '/dev/serial/by-id/usb-FTDI_FT232R_USB_UART_AH07445U-if00-port0'
|
||||
itc_uri = '/dev/serial/by-id/usb-Prolific_Technology_Inc._USB-Serial_Controller_D-if00-port0'
|
||||
lsc_uri = '192.168.1.2:7777'
|
||||
# by plug location:
|
||||
#turbo_uri='/dev/serial/by-path/platform-fd500000.pcie-pci-0000:01:00.0-usb-0:1.1:1.0-port0'
|
||||
#press_uri = '/dev/serial/by-path/platform-fd500000.pcie-pci-0000:01:00.0-usb-0:1.2:1.0-port0'
|
||||
#itc_uri = '/dev/serial/by-path/platform-fd500000.pcie-pci-0000:01:00.0-usb-0:1.3:1.0-port0'
|
||||
# over USB (does not work anymore)
|
||||
#lsc_uri='serial:///dev/ttyACM1?baudrate=57600+parity=odd+bytesize=7+stopbits=1',
|
||||
logo_ip = '192.168.0.3'
|
||||
# by plug location would also be possible (/dev/serial/by-path)
|
||||
|
||||
|
||||
Node('dil5.psi.ch',
|
||||
'dil5 with state machine for condensing and removing',
|
||||
'dil5 on linse-dil5',
|
||||
interface='tcp://5000',
|
||||
secondary = ['ws://8010']
|
||||
)
|
||||
|
||||
Mod('io',
|
||||
Mod('logo',
|
||||
'frappy_psi.logo.IO',
|
||||
'',
|
||||
ip_address = "192.168.0.3",
|
||||
ip_address = logo_ip,
|
||||
tcap_client = 0x3000,
|
||||
tsap_server = 0x2000
|
||||
)
|
||||
|
||||
Mod('V1',
|
||||
'frappy_psi.logo.Valve',
|
||||
'frappy_psi.logo.DigitalActuator',
|
||||
'Valves',
|
||||
io = 'io',
|
||||
vm_address_input ="V1025.0",
|
||||
vm_address_output ="V1064.3"
|
||||
io = 'logo',
|
||||
feedback_addr ="V1025.0",
|
||||
output_addr ="V1064.3"
|
||||
)
|
||||
|
||||
Mod('V2',
|
||||
'frappy_psi.logo.Valve',
|
||||
'Valves',
|
||||
io = 'io',
|
||||
vm_address_input ="V1024.2",
|
||||
vm_address_output ="V1064.0",
|
||||
'frappy_psi.logo.DigitalActuator',
|
||||
'dil bypass',
|
||||
io = 'logo',
|
||||
feedback_addr ="V1024.2",
|
||||
output_addr ="V1064.0",
|
||||
)
|
||||
|
||||
Mod('V4',
|
||||
'frappy_psi.logo.Valve',
|
||||
'Valves',
|
||||
io = 'io',
|
||||
vm_address_input ="V1024.5",
|
||||
vm_address_output ="V1064.7",
|
||||
'frappy_psi.logo.DigitalActuator',
|
||||
'compressor to dump',
|
||||
io = 'logo',
|
||||
# feedback seems not to work
|
||||
output_addr ="V1064.7",
|
||||
target_addr ="V404.1",
|
||||
)
|
||||
|
||||
Mod('V5',
|
||||
'frappy_psi.logo.Valve',
|
||||
'Valves',
|
||||
io = 'io',
|
||||
vm_address_input ="V1024.4",
|
||||
vm_address_output ="V1064.2"
|
||||
'frappy_psi.logo.DigitalActuator',
|
||||
'compressor input',
|
||||
io = 'logo',
|
||||
feedback_addr ="V1024.4",
|
||||
output_addr ="V1064.2",
|
||||
)
|
||||
|
||||
Mod('V9',
|
||||
'frappy_psi.logo.Valve',
|
||||
'Valves',
|
||||
io = 'io',
|
||||
vm_address_input ="V1024.3",
|
||||
vm_address_output ="V404.1",
|
||||
'frappy_psi.logo.DelayedActuator',
|
||||
'dump output',
|
||||
io = 'logo',
|
||||
delay_addr = 'VW24',
|
||||
feedback_addr ="V1024.3",
|
||||
output_addr ="V1064.5",
|
||||
target_addr ="V404.3",
|
||||
)
|
||||
|
||||
Mod('pump',
|
||||
'frappy_psi.logo.FluidMachines',
|
||||
'Pump',
|
||||
io = 'io',
|
||||
vm_address_output ="V414.1"
|
||||
Mod('forepump',
|
||||
'frappy_psi.logo.DigitalActuator',
|
||||
'forepump',
|
||||
io = 'logo',
|
||||
output_addr ="V1064.6",
|
||||
target_addr ="V404.4",
|
||||
)
|
||||
|
||||
Mod('compressor',
|
||||
'frappy_psi.logo.FluidMachines',
|
||||
'Compressor',
|
||||
io = 'io',
|
||||
vm_address_output ="V400.1"
|
||||
'frappy_psi.logo.DigitalActuator',
|
||||
'',
|
||||
io = 'logo',
|
||||
output_addr ="V1064.4",
|
||||
target_addr ="V404.2",
|
||||
)
|
||||
|
||||
Mod('p2',
|
||||
'frappy_psi.logo.Pressure',
|
||||
'Pressure in mBar',
|
||||
io = 'io',
|
||||
vm_address ="VW0",
|
||||
)
|
||||
'pressure after compressor',
|
||||
io = 'logo',
|
||||
addr ="VW0",
|
||||
pollinterval=0.5,
|
||||
)
|
||||
|
||||
Mod('p1',
|
||||
'frappy_psi.logo.Pressure',
|
||||
'Pressure in mBar',
|
||||
io = 'io',
|
||||
vm_address ="VW2",
|
||||
)
|
||||
'dump pressure',
|
||||
io = 'logo',
|
||||
addr ="VW28",
|
||||
pollinterval=0.5,
|
||||
)
|
||||
|
||||
Mod('p5',
|
||||
'frappy_psi.logo.Pressure',
|
||||
'Pressure in mBar',
|
||||
io = 'io',
|
||||
vm_address ="VW4",
|
||||
)
|
||||
|
||||
Mod('Druckluft',
|
||||
'frappy_psi.logo.Airpressure',
|
||||
'Airpressure state',
|
||||
io = 'io',
|
||||
vm_address ="VW6",
|
||||
)
|
||||
|
||||
|
||||
|
||||
Mod('SF1',
|
||||
'frappy_psi.logo.safetyfeatureState',
|
||||
'Safety Feature',
|
||||
io = 'io',
|
||||
vm_address ="V410.1",
|
||||
)
|
||||
|
||||
Mod('SF2',
|
||||
'frappy_psi.logo.safetyfeatureState',
|
||||
'Safety Feature',
|
||||
io = 'io',
|
||||
vm_address ="V406.1",
|
||||
)
|
||||
|
||||
Mod('SF3',
|
||||
'frappy_psi.logo.safetyfeatureState',
|
||||
'Safety Feature',
|
||||
io = 'io',
|
||||
vm_address ="V408.1",
|
||||
)
|
||||
|
||||
Mod('SF4',
|
||||
'frappy_psi.logo.safetyfeatureState',
|
||||
'Safety Feature',
|
||||
io = 'io',
|
||||
vm_address ="V412.1",
|
||||
)
|
||||
|
||||
Mod('p2max',
|
||||
'frappy_psi.logo.safetyfeatureParam',
|
||||
'Safety Feature Param',
|
||||
io = 'io',
|
||||
target = 2000,
|
||||
vm_address ="VW8",
|
||||
)
|
||||
|
||||
Mod('pcond',
|
||||
'frappy_psi.logo.safetyfeatureParam',
|
||||
'Safety Feature Param',
|
||||
io = 'io',
|
||||
target = 1800,
|
||||
vm_address ="VW10",
|
||||
)
|
||||
|
||||
Mod('p5min',
|
||||
'frappy_psi.logo.safetyfeatureParam',
|
||||
'Safety Feature Param',
|
||||
io = 'io',
|
||||
target = 0,
|
||||
vm_address ="VW12",
|
||||
)
|
||||
|
||||
Mod('p5max',
|
||||
'frappy_psi.logo.safetyfeatureParam',
|
||||
'Safety Feature Param',
|
||||
io = 'io',
|
||||
target = 900,
|
||||
vm_address ="VW14",
|
||||
)
|
||||
|
||||
|
||||
Mod('io_ls273',
|
||||
'frappy_psi.ls372.StringIO',
|
||||
'io for Ls372',
|
||||
uri=lsc_uri,
|
||||
'pressure after forepump',
|
||||
io = 'logo',
|
||||
addr ="VW4",
|
||||
pollinterval = 0.5,
|
||||
)
|
||||
Mod('sw',
|
||||
'frappy_psi.ls372.Switcher',
|
||||
'channel switcher',
|
||||
io = 'io_ls273',
|
||||
)
|
||||
Mod('T_mix',
|
||||
'frappy_psi.ls372.TemperatureLoop',
|
||||
'mix temperature chan 5',
|
||||
channel = 5,
|
||||
switcher = 'sw',
|
||||
)
|
||||
|
||||
Mod('T_ivc',
|
||||
'frappy_psi.ls372.TemperatureLoop',
|
||||
'mix temperature chan 2',
|
||||
channel = 2,
|
||||
switcher = 'sw',
|
||||
)
|
||||
|
||||
Mod('T_still',
|
||||
'frappy_psi.ls372.TemperatureLoop',
|
||||
'mix temperature chan 3',
|
||||
channel = 3,
|
||||
switcher = 'sw',
|
||||
)
|
||||
|
||||
Mod('T_sorb',
|
||||
'frappy_psi.ls372.TemperatureLoop',
|
||||
'mix temperature chan 1',
|
||||
channel = 1,
|
||||
switcher = 'sw',
|
||||
)
|
||||
|
||||
Mod('T_cp',
|
||||
'frappy_psi.ls372.TemperatureLoop',
|
||||
'mix temperature chan 4',
|
||||
channel = 4,
|
||||
switcher = 'sw',
|
||||
)
|
||||
Mod('airpressure',
|
||||
'frappy_psi.logo.Comparator',
|
||||
'Airpressure state',
|
||||
io = 'logo',
|
||||
addr ="V1024.7",
|
||||
threshold = 500,
|
||||
pollinterval = 0.5,
|
||||
)
|
||||
|
||||
Mod('io_pfeiffer',
|
||||
'frappy_psi.pfeiffer_new.PfeifferProtocol',
|
||||
@@ -361,41 +261,80 @@ Mod('T_cond',
|
||||
io='itc',
|
||||
)
|
||||
|
||||
Mod('stateMachine',
|
||||
'frappy_psi.dilution_statemachine.DIL5',
|
||||
'Statemachine',
|
||||
|
||||
Mod('safety',
|
||||
'frappy_psi.dilution.Interlock',
|
||||
'interlock mechanism',
|
||||
io='logo',
|
||||
dil='dil',
|
||||
)
|
||||
|
||||
Mod('dil',
|
||||
'frappy_psi.dilution.DIL5',
|
||||
'dilution state machine and parameters',
|
||||
|
||||
condenseline_pressure = "p2",
|
||||
condense_valve = "V9",
|
||||
dump_valve = "V4",
|
||||
circulate_pump = "pump",
|
||||
forepump = "forepump",
|
||||
compressor = "compressor",
|
||||
|
||||
turbopump = "turbopump",
|
||||
condenseline_valve = "V1",
|
||||
circuitshort_valve = "V2",
|
||||
still_pressure = "p3",
|
||||
still_pressure = "p4",
|
||||
still_pressure_turbo = "p3",
|
||||
#ls372 = "res1",
|
||||
V5 = "V5",
|
||||
p1 = "p1",
|
||||
|
||||
MV10 = 'MV10',
|
||||
MV13 ='MV13',
|
||||
MV8 = 'MV8',
|
||||
MVB = 'MVB',
|
||||
MV2 = 'MV2',
|
||||
|
||||
MV1 = 'MV1',
|
||||
MV3a = 'MV3a',
|
||||
MV3b = 'MV3b',
|
||||
GV1 = 'GV1',
|
||||
MV14 = 'MV14',
|
||||
MV12 = 'MV12',
|
||||
MV11 = 'MV11',
|
||||
MV9 = 'MV9',
|
||||
GV2 = 'GV2',
|
||||
condensing_p_low = 150,
|
||||
condensing_p_high = 250
|
||||
dump_pressure = "p1",
|
||||
condensing_p_low = 1200,
|
||||
condensing_p_high = 1500,
|
||||
)
|
||||
|
||||
## Dilution lakeshore Temperature controller
|
||||
|
||||
Mod('io_ls273',
|
||||
'frappy_psi.ls372.StringIO',
|
||||
'io for Ls372',
|
||||
uri=lsc_uri,
|
||||
)
|
||||
|
||||
Mod('sw',
|
||||
'frappy_psi.ls372.Switcher',
|
||||
'channel switcher',
|
||||
io = 'io_ls273',
|
||||
)
|
||||
|
||||
Mod('T_ivc',
|
||||
'frappy_psi.ls372.TemperatureChannel',
|
||||
'mix temperature chan 2',
|
||||
channel = 2,
|
||||
switcher = 'sw',
|
||||
)
|
||||
|
||||
Mod('T_still',
|
||||
'frappy_psi.ls372.TemperatureChannel',
|
||||
'mix temperature chan 3',
|
||||
channel = 3,
|
||||
switcher = 'sw',
|
||||
)
|
||||
|
||||
Mod('T_sorb',
|
||||
'frappy_psi.ls372.TemperatureChannel',
|
||||
'mix temperature chan 1',
|
||||
channel = 1,
|
||||
switcher = 'sw',
|
||||
)
|
||||
|
||||
Mod('T_cp',
|
||||
'frappy_psi.ls372.TemperatureChannel',
|
||||
'mix temperature chan 4',
|
||||
channel = 4,
|
||||
switcher = 'sw',
|
||||
)
|
||||
|
||||
Mod('T_mix',
|
||||
'frappy_psi.ls372.TemperatureLoop',
|
||||
'mix temperature chan 5',
|
||||
channel = 5,
|
||||
htrrng = '1mA',
|
||||
switcher = 'sw',
|
||||
)
|
||||
|
||||
16
cfg/dilhtr_cfg.py
Normal file
16
cfg/dilhtr_cfg.py
Normal file
@@ -0,0 +1,16 @@
|
||||
Node('dilhtrtest.psi.ch',
|
||||
'dilhtr test',
|
||||
'tcp://5000',
|
||||
)
|
||||
|
||||
Mod('io',
|
||||
'frappy_psi.dilhtr.IO',
|
||||
'dilhtr communication',
|
||||
uri='serial:///dev/tty.usbserial-21440?baudrate=9600',
|
||||
)
|
||||
|
||||
Mod('heater',
|
||||
'frappy_psi.dilhtr.Heater',
|
||||
'dilhtr box',
|
||||
io='io',
|
||||
)
|
||||
@@ -45,17 +45,16 @@ Mod('T4',
|
||||
)
|
||||
|
||||
Mod('T',
|
||||
'frappy_psi.picontrol.PI',
|
||||
'controlled Temperature',
|
||||
input_module='T_main',
|
||||
output_module='htr',
|
||||
'frappy_psi.furnace.PIctrl',
|
||||
'controlled temperature ',
|
||||
value = Param(unit='degC'),
|
||||
input_module = 'T_htr',
|
||||
output_module = 't_out',
|
||||
output_min = 0,
|
||||
output_max = 100,
|
||||
# relais='relais',
|
||||
p=0.1,
|
||||
i=0.01,
|
||||
)
|
||||
p = 1,
|
||||
i = 0.01,
|
||||
)
|
||||
|
||||
Mod('htr_io',
|
||||
'frappy_psi.tdkpower.IO',
|
||||
@@ -84,7 +83,7 @@ Mod('flowswitch',
|
||||
true_level='low',
|
||||
)
|
||||
|
||||
Mod('interlocks',
|
||||
Mod('interlock',
|
||||
'frappy_psi.furnace.Interlocks',
|
||||
'interlock parameters',
|
||||
main_T='T_main',
|
||||
@@ -97,7 +96,7 @@ Mod('interlocks',
|
||||
wall_limit=50,
|
||||
main_T_limit = 1400,
|
||||
extra_T_limit = 1400,
|
||||
vacuum_limit=0.01,
|
||||
vacuum_limit=0.001,
|
||||
)
|
||||
|
||||
Mod('p',
|
||||
|
||||
@@ -4,63 +4,62 @@ Node('fs.psi.ch',
|
||||
)
|
||||
|
||||
Mod('T',
|
||||
'frappy_psi.picontrol.PI2',
|
||||
'frappy_psi.furnace.PI2',
|
||||
'controlled Temperature on sample (2nd loop)',
|
||||
input = 'T_sample',
|
||||
output = 'T_reg',
|
||||
relais = 'relais',
|
||||
value = Param(unit='degC'),
|
||||
meaning = ['temperature', 30],
|
||||
input_module = 'T_sam',
|
||||
output_module = 'T_reg',
|
||||
p = 1.2,
|
||||
i = 0.005,
|
||||
)
|
||||
|
||||
Mod('T_reg',
|
||||
'frappy_psi.picontrol.PI',
|
||||
'frappy_psi.furnace.PIctrl',
|
||||
'controlled Temperature on heater',
|
||||
input = 'T_htr',
|
||||
output = 't_out',
|
||||
relais = 'relais',
|
||||
value = Param(unit='degC'),
|
||||
input_module = 'T_htr',
|
||||
output_module = 't_out',
|
||||
output_min = 0,
|
||||
output_max = 100,
|
||||
p = 1,
|
||||
i = 0.003,
|
||||
)
|
||||
|
||||
Mod('p_reg',
|
||||
'frappy_psi.picontrol.PI',
|
||||
'controlled pressure',
|
||||
input = 'p',
|
||||
output = 'p_out',
|
||||
relais = 'relais',
|
||||
p = 1,
|
||||
i = 0.005,
|
||||
)
|
||||
#Mod('p_reg',
|
||||
# 'frappy_psi.furnace.PI',
|
||||
# 'controlled pressure',
|
||||
# input_module = 'p',
|
||||
# output_module = 't_out',
|
||||
# p = 1,
|
||||
# i = 0.005,
|
||||
# )
|
||||
|
||||
Mod('T_htr',
|
||||
'frappy_psi.ionopimax.CurrentInput',
|
||||
'frappy_psi.furnace.PRtransmitter',
|
||||
'heater temperature',
|
||||
addr = 'ai4',
|
||||
valuerange = (0, 1372),
|
||||
value = Param(unit='degC'),
|
||||
|
||||
)
|
||||
|
||||
|
||||
Mod('T_sample',
|
||||
'frappy_psi.ionopimax.CurrentInput',
|
||||
Mod('T_sam',
|
||||
'frappy_psi.furnace.PRtransmitter',
|
||||
'sample temperature',
|
||||
addr = 'ai3',
|
||||
valuerange = (0, 1372),
|
||||
value = Param(unit='degC'),
|
||||
|
||||
)
|
||||
|
||||
Mod('T_extra',
|
||||
'frappy_psi.ionopimax.CurrentInput',
|
||||
'extra temperature',
|
||||
addr = 'ai2',
|
||||
valuerange = (0, 1372),
|
||||
value = Param(unit='degC'),
|
||||
|
||||
)
|
||||
|
||||
Mod('T_extra',
|
||||
'frappy_psi.furnace.PRtransmitter',
|
||||
'extra temperature',
|
||||
addr = 'ai3',
|
||||
valuerange = (0, 1372),
|
||||
value = Param(unit='degC'),
|
||||
)
|
||||
|
||||
Mod('T_wall',
|
||||
'frappy_psi.ionopimax.VoltageInput',
|
||||
@@ -86,35 +85,38 @@ Mod('htr',
|
||||
Mod('t_out',
|
||||
'frappy_psi.bkpower.Output',
|
||||
'heater output',
|
||||
p_value = 'p_out',
|
||||
# p_value = 'p_out',
|
||||
io = 'htr_io',
|
||||
maxvolt = 50,
|
||||
maxcurrent = 2,
|
||||
)
|
||||
|
||||
Mod('relais',
|
||||
Mod('relay',
|
||||
'frappy_psi.ionopimax.DigitalOutput',
|
||||
'relais for power output',
|
||||
addr = 'o2',
|
||||
)
|
||||
|
||||
Mod('interlocks',
|
||||
Mod('interlock',
|
||||
'frappy_psi.furnace.Interlocks',
|
||||
'interlock parameters',
|
||||
input = 'T_htr',
|
||||
wall_T = 'T_wall',
|
||||
htr_T = 'T_htr',
|
||||
main_T = 'T_sample',
|
||||
main_T = 'T_sam',
|
||||
reg_T = 'T_reg',
|
||||
extra_T = 'T_extra',
|
||||
htr = 't_out',
|
||||
vacuum = 'p',
|
||||
relais = 'relais',
|
||||
relay = 'relay',
|
||||
control = 'T',
|
||||
wall_limit = 100,
|
||||
vacuum_limit = 0.1,
|
||||
wall_limit = 60,
|
||||
vacuum_limit = 0.001,
|
||||
disabled_checks = 'T_extra',
|
||||
)
|
||||
|
||||
Mod('p',
|
||||
'frappy_psi.ionopimax.LogVoltageInput',
|
||||
'frappy_psi.furnace.PKRgauge',
|
||||
'pressure reading',
|
||||
addr = 'av1',
|
||||
rawrange = (1.82, 8.6),
|
||||
|
||||
94
cfg/gas10ka_cfg.py
Normal file
94
cfg/gas10ka_cfg.py
Normal file
@@ -0,0 +1,94 @@
|
||||
Node('gas10ka.psi.ch',
|
||||
'10kBar Gas pressure stick',
|
||||
interface='tcp://5010',
|
||||
)
|
||||
|
||||
Mod('io',
|
||||
'frappy_psi.logo.IO',
|
||||
'',
|
||||
ip_address = "192.168.1.1",
|
||||
tcap_client = 0x3000,
|
||||
tsap_server = 0x2000
|
||||
)
|
||||
|
||||
Mod('R_pt10k',
|
||||
'frappy_psi.logo.Resistor',
|
||||
'raw sensor value of T_p10k',
|
||||
io = 'io',
|
||||
addr = "VW0",
|
||||
)
|
||||
|
||||
Mod('T_pt10k',
|
||||
'frappy_psi.softcal.Sensor',
|
||||
'temperature close to sample',
|
||||
value=Param(unit='K'),
|
||||
rawsensor='R_pt10k',
|
||||
calcurve='pt10000e',
|
||||
)
|
||||
|
||||
Mod('R_top',
|
||||
'frappy_psi.logo.Resistor',
|
||||
'raw sensor value of T_top',
|
||||
io = 'io',
|
||||
addr = "VW2",
|
||||
)
|
||||
|
||||
Mod('T_top',
|
||||
'frappy_psi.softcal.Sensor',
|
||||
'capillary temperature at highest position',
|
||||
value=Param(unit='K'),
|
||||
rawsensor='R_top',
|
||||
calcurve='pt1000e',
|
||||
)
|
||||
|
||||
Mod('R_mid',
|
||||
'frappy_psi.logo.Resistor',
|
||||
'raw sensor value of T_mid',
|
||||
io = 'io',
|
||||
addr = "VW6",
|
||||
)
|
||||
|
||||
Mod('T_mid',
|
||||
'frappy_psi.softcal.Sensor',
|
||||
'capillary temperature at mid position',
|
||||
value=Param(unit='K'),
|
||||
rawsensor='R_mid',
|
||||
calcurve='pt1000e',
|
||||
)
|
||||
|
||||
Mod('R_bot',
|
||||
'frappy_psi.logo.Resistor',
|
||||
'raw sensor value of T_bot',
|
||||
io = 'io',
|
||||
addr = "VW4",
|
||||
)
|
||||
|
||||
Mod('T_bot',
|
||||
'frappy_psi.softcal.Sensor',
|
||||
'capillary temperature at lower position',
|
||||
value=Param(unit='K'),
|
||||
rawsensor='R_bot',
|
||||
calcurve='pt1000e',
|
||||
)
|
||||
|
||||
|
||||
Mod('R_sam_cx',
|
||||
'frappy_psi.logo.Resistor',
|
||||
'sensor',
|
||||
io = 'io',
|
||||
addr = "VW16",
|
||||
)
|
||||
|
||||
Mod('T_sam_cx',
|
||||
'frappy_psi.softcal.Sensor',
|
||||
'?',
|
||||
value=Param(unit='K'),
|
||||
rawsensor='R_sam_cx',
|
||||
calcurve='X174785',
|
||||
)
|
||||
|
||||
Mod('heater',
|
||||
'frappy_psi.capillary_heater.Heater',
|
||||
'the capillary heater',
|
||||
io = 'io',
|
||||
)
|
||||
@@ -10,7 +10,6 @@ Mod('sea_main',
|
||||
Mod('te',
|
||||
'frappy_psi.sea.SeaDrivable', '',
|
||||
io = 'sea_main',
|
||||
meaning=['temperature', 20],
|
||||
sea_object = 'te',
|
||||
meaning=('temperature', 11),
|
||||
)
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
Node('haake.config.sea.psi.ch',
|
||||
'Haake thermostat',
|
||||
Node('haake.frappy.psi.ch',
|
||||
'additional haake waterbath',
|
||||
)
|
||||
Mod('sea_main',
|
||||
'frappy_psi.sea.SeaClient',
|
||||
'main sea connection for haakeuro.config',
|
||||
config = 'haake.config',
|
||||
service = 'main',
|
||||
|
||||
Mod('haake_io',
|
||||
'frappy_psi.haake.HaakeIO',
|
||||
'',
|
||||
uri='sans-sample-ts:3006',
|
||||
)
|
||||
Mod('th',
|
||||
'frappy_psi.sea.SeaDrivable', '',
|
||||
meaning = ('temperature', 10),
|
||||
io = 'sea_main',
|
||||
sea_object = 'th',
|
||||
extra_modules=['t2'],
|
||||
value=Param(unit='degC'),
|
||||
|
||||
Mod('T2',
|
||||
'frappy_psi.haake.TemperatureLoop',
|
||||
'second haake',
|
||||
io = 'haake_io',
|
||||
)
|
||||
|
||||
@@ -10,11 +10,12 @@ Mod('sea_main',
|
||||
)
|
||||
|
||||
Mod('tt',
|
||||
'frappy_psi.sea.SeaDrivable', '',
|
||||
'frappy_psi.sea.LscDrivable', '',
|
||||
io='sea_main',
|
||||
meaning=['temperature_regulation', 27],
|
||||
sea_object='tt',
|
||||
rel_paths=['tm', '.', 'set', 'dblctrl'],
|
||||
sensor_path='tm',
|
||||
set_path='set',
|
||||
)
|
||||
|
||||
Mod('cc',
|
||||
|
||||
@@ -10,11 +10,12 @@ Mod('sea_main',
|
||||
)
|
||||
|
||||
Mod('tt',
|
||||
'frappy_psi.sea.SeaDrivable', '',
|
||||
'frappy_psi.sea.LscDrivable', '',
|
||||
io='sea_main',
|
||||
meaning=['temperature_regulation', 27],
|
||||
sea_object='tt',
|
||||
rel_paths=['tm', '.', 'set', 'dblctrl'],
|
||||
sensor_path='tm',
|
||||
set_path='set',
|
||||
)
|
||||
|
||||
Mod('cc',
|
||||
|
||||
@@ -10,11 +10,12 @@ Mod('sea_main',
|
||||
)
|
||||
|
||||
Mod('tt',
|
||||
'frappy_psi.sea.SeaDrivable', '',
|
||||
'frappy_psi.sea.LscDrivable', '',
|
||||
io='sea_main',
|
||||
meaning=['temperature_regulation', 27],
|
||||
sea_object='tt',
|
||||
rel_paths=['tm', '.', 'set', 'dblctrl'],
|
||||
sensor_path='tm',
|
||||
set_path='set',
|
||||
)
|
||||
|
||||
Mod('cc',
|
||||
|
||||
@@ -10,11 +10,12 @@ Mod('sea_main',
|
||||
)
|
||||
|
||||
Mod('tt',
|
||||
'frappy_psi.sea.SeaDrivable', '',
|
||||
'frappy_psi.sea.LscDrivable', '',
|
||||
io='sea_main',
|
||||
meaning=['temperature_regulation', 27],
|
||||
sea_object='tt',
|
||||
rel_paths=['tm', '.', 'set', 'dblctrl'],
|
||||
sensor_path='tm',
|
||||
set_path='set',
|
||||
)
|
||||
|
||||
Mod('cc',
|
||||
|
||||
@@ -10,11 +10,12 @@ Mod('sea_main',
|
||||
)
|
||||
|
||||
Mod('tt',
|
||||
'frappy_psi.sea.SeaDrivable', '',
|
||||
'frappy_psi.sea.LscDrivable', '',
|
||||
io='sea_main',
|
||||
meaning=['temperature_regulation', 27],
|
||||
sea_object='tt',
|
||||
rel_paths=['tm', '.', 'set', 'dblctrl'],
|
||||
sensor_path='tm',
|
||||
set_path='set',
|
||||
)
|
||||
|
||||
Mod('cc',
|
||||
|
||||
@@ -10,11 +10,12 @@ Mod('sea_main',
|
||||
)
|
||||
|
||||
Mod('tt',
|
||||
'frappy_psi.sea.SeaDrivable', '',
|
||||
'frappy_psi.sea.LscDrivable', '',
|
||||
io='sea_main',
|
||||
meaning=['temperature_regulation', 27],
|
||||
sea_object='tt',
|
||||
rel_paths=['tm', '.', 'set', 'dblctrl'],
|
||||
sensor_path='tm',
|
||||
set_path='set',
|
||||
)
|
||||
|
||||
Mod('pauto',
|
||||
|
||||
@@ -14,7 +14,7 @@ Mod('tt',
|
||||
io='sea_main',
|
||||
meaning=['temperature_regulation', 27],
|
||||
sea_object='tt',
|
||||
rel_paths=['tt', 'set'],
|
||||
rel_paths=['main', '.', 'set'],
|
||||
value=Param(unit='K'),
|
||||
)
|
||||
|
||||
|
||||
224
cfg/main/leiden_cfg.py
Normal file
224
cfg/main/leiden_cfg.py
Normal file
@@ -0,0 +1,224 @@
|
||||
Node('leiden.psi.ch',
|
||||
'''Leiden Dilution''',
|
||||
)
|
||||
|
||||
ah2700_uri = 'linse-leiden-ts:3002' # used in cfg/addons/ahtwo_cfg.pt
|
||||
ls370_uri = 'linse-leiden-ts:3004' # used in ~/sea/tcl/leiden.config
|
||||
tcs_uri = 'linse-leiden-ts:3005'
|
||||
#nanov_uri = 'linse-leiden-ts:3006' # used in ~/sea/tcl/leiden.config
|
||||
k2601b_uri = 'linse-leiden-ts:3006' # used for HC experiment as heater
|
||||
dilhtr_uri = 'linse-leiden-ts:3007'
|
||||
srbridge_uri = 'linse-leiden-ts:3008'
|
||||
|
||||
Mod('sea_main',
|
||||
'frappy_psi.sea.SeaClient',
|
||||
'main sea connection for leiden.config',
|
||||
config = 'leiden.config',
|
||||
service = 'main',
|
||||
)
|
||||
|
||||
for name in ['T3K', 'Tstill', 'T50mK', 'Tmxlow', 'Tmxhigh', 'Tmxcx', 'Tblueo',
|
||||
'Tpt50', 'Tpt3high', 'Tpt3low', 'Twhite', 'Tgreen']:
|
||||
mname = name.replace('T','T_')
|
||||
Mod(mname,
|
||||
'frappy_psi.sea.SeaReadable', '',
|
||||
io='sea_main',
|
||||
sea_object='tt',
|
||||
rel_paths=[name],
|
||||
value=Param(unit='K'),
|
||||
extra_modules = ['raw'],
|
||||
)
|
||||
Mod(name.replace('T', 'R_'),
|
||||
'frappy_psi.sea.SeaReadable', '',
|
||||
io='sea_main',
|
||||
value=Param(unit='Ohm'),
|
||||
single_module=f'{mname}.raw'
|
||||
)
|
||||
|
||||
#Mod('cmn',
|
||||
# 'frappy_psi.sea.SeaReadable', '',
|
||||
# io = 'sea_main',
|
||||
# sea_object = 'cmn',
|
||||
# extra_modules = ['u1', 'u2', 'temp'],
|
||||
#)
|
||||
|
||||
#Mod('T_cmn',
|
||||
# 'frappy_psi.sea.SeaReadable', '',
|
||||
# io='sea_main',
|
||||
# value=Param(unit='K'),
|
||||
# single_module='cmn.temp',
|
||||
#)
|
||||
|
||||
#Mod('V_fixp',
|
||||
# 'frappy_psi.sea.SeaReadable', '',
|
||||
# io='sea_main',
|
||||
# value=Param(unit='V'),
|
||||
# single_module='cmn.u2',
|
||||
#)
|
||||
|
||||
#Mod('V_cmn',
|
||||
# 'frappy_psi.sea.SeaReadable', '',
|
||||
# io='sea_main',
|
||||
# value=Param(unit='V'),
|
||||
# single_module='cmn.u1',
|
||||
#)
|
||||
|
||||
|
||||
Mod('tcs_io',
|
||||
'frappy_psi.tcs.IO',
|
||||
'tcs communication',
|
||||
uri=tcs_uri,
|
||||
)
|
||||
|
||||
Mod('still_htr',
|
||||
'frappy_psi.tcs.Heater',
|
||||
'still heater',
|
||||
io='tcs_io',
|
||||
channel=2,
|
||||
)
|
||||
|
||||
Mod('mix_io',
|
||||
'frappy_psi.dilhtr.IO',
|
||||
'dilhtr communication',
|
||||
uri=dilhtr_uri,
|
||||
)
|
||||
|
||||
Mod('mix_htr',
|
||||
'frappy_psi.dilhtr.WrappedHeater',
|
||||
'mixing chamber heater',
|
||||
io='mix_io',
|
||||
)
|
||||
|
||||
Mod('drive_mix',
|
||||
'frappy_psi.picontrol.PIctrl',
|
||||
'controlled mix ch. temperature',
|
||||
input_module = 'T_mxlow',
|
||||
output_module = 'mix_htr',
|
||||
output_min = 0,
|
||||
output_max = 0.02,
|
||||
p = 5,
|
||||
itime = 60,
|
||||
)
|
||||
|
||||
#Mod('drive_cmn',
|
||||
# 'frappy_psi.picontrol.PIctrl',
|
||||
# 'controlled cmn temperature',
|
||||
# input_module = 'T_cmn',
|
||||
# output_module = 'mix_htr',
|
||||
# output_min = 0,
|
||||
# output_max = 3e-2,
|
||||
# p = 2,
|
||||
# itime = 120,
|
||||
# )
|
||||
|
||||
#Mod('drive_fixp',
|
||||
# 'frappy_psi.picontrol.PI',
|
||||
# 'controlled fixpoint voltage',
|
||||
# value=Param(unit='V'),
|
||||
# input_module = 'V_fixp',
|
||||
# output_module = 'drive_mix',
|
||||
# output_min = 0.0,
|
||||
# output_max = 0.01,
|
||||
# p = 1,
|
||||
# itime = 120,
|
||||
# )
|
||||
|
||||
Mod('simio',
|
||||
'frappy_psi.bridge.BridgeIO',
|
||||
'communication to sim900',
|
||||
uri=srbridge_uri,
|
||||
)
|
||||
|
||||
Mod('res1',
|
||||
'frappy_psi.bridge.Resistance',
|
||||
'please add description',
|
||||
io='simio',
|
||||
port=1,
|
||||
)
|
||||
|
||||
Mod('res2',
|
||||
'frappy_psi.bridge.Resistance',
|
||||
'please add description',
|
||||
io='simio',
|
||||
port=3,
|
||||
)
|
||||
|
||||
Mod('phase1',
|
||||
'frappy_psi.bridge.Phase',
|
||||
'please add description',
|
||||
resistance='res1',
|
||||
)
|
||||
|
||||
Mod('phase2',
|
||||
'frappy_psi.bridge.Phase',
|
||||
'please add description',
|
||||
resistance='res2',
|
||||
)
|
||||
|
||||
|
||||
Mod('dev1',
|
||||
'frappy_psi.bridge.Deviation',
|
||||
'please add description',
|
||||
resistance='res1',
|
||||
)
|
||||
|
||||
Mod('dev2',
|
||||
'frappy_psi.bridge.Deviation',
|
||||
'please add description',
|
||||
resistance='res2',
|
||||
)
|
||||
|
||||
|
||||
Mod('vsource_io',
|
||||
'frappy_psi.k2601b.K2601bIO',
|
||||
'source meter',
|
||||
# uri = '129.129.156.90:5025',
|
||||
uri = k2601b_uri,
|
||||
)
|
||||
|
||||
|
||||
Mod('source',
|
||||
'frappy_psi.k2601b.SourceMeter'
|
||||
'',
|
||||
description = "keithley sourcemeter",
|
||||
mode = 2,
|
||||
vlimit = 0.5,
|
||||
ilimit = .0005,
|
||||
io = 'vsource_io',
|
||||
)
|
||||
|
||||
Mod('hvolt',
|
||||
'frappy_psi.k2601b.Voltage'
|
||||
'',
|
||||
description = "Heater Voltage",
|
||||
active = False,
|
||||
limit = 1.0,
|
||||
target = 0.0,
|
||||
sourcemeter = 'source',
|
||||
io = 'vsource_io',
|
||||
)
|
||||
|
||||
Mod('hcur',
|
||||
'frappy_psi.k2601b.Current'
|
||||
'',
|
||||
description = "Heater Current Source",
|
||||
active = True,
|
||||
limit = 0.0001,
|
||||
target = 0.0,
|
||||
sourcemeter = 'source',
|
||||
io = 'vsource_io',
|
||||
)
|
||||
|
||||
Mod('hres',
|
||||
'frappy_psi.k2601b.Resistivity'
|
||||
'',
|
||||
description = "Heater Resistance",
|
||||
io = 'vsource_io',
|
||||
)
|
||||
|
||||
Mod('hpow',
|
||||
'frappy_psi.k2601b.Power'
|
||||
'',
|
||||
description = "Heater Power",
|
||||
io = 'vsource_io',
|
||||
)
|
||||
@@ -10,11 +10,12 @@ Mod('sea_main',
|
||||
)
|
||||
|
||||
Mod('tt',
|
||||
'frappy_psi.sea.SeaDrivable', '',
|
||||
'frappy_psi.sea.LscDrivable', '',
|
||||
io='sea_main',
|
||||
meaning=['temperature_regulation', 27],
|
||||
sea_object='tt',
|
||||
rel_paths=['tm', '.', 'set', 'dblctrl'],
|
||||
sensor_path='tm',
|
||||
set_path='set',
|
||||
)
|
||||
|
||||
Mod('cc',
|
||||
|
||||
@@ -10,11 +10,12 @@ Mod('sea_main',
|
||||
)
|
||||
|
||||
Mod('tt',
|
||||
'frappy_psi.sea.SeaDrivable', '',
|
||||
'frappy_psi.sea.LscDrivable', '',
|
||||
io='sea_main',
|
||||
meaning=['temperature_regulation', 27],
|
||||
sea_object='tt',
|
||||
rel_paths=['tm', '.', 'set', 'dblctrl'],
|
||||
sensor_path='tm',
|
||||
set_path='set',
|
||||
)
|
||||
|
||||
Mod('cc',
|
||||
|
||||
@@ -10,11 +10,12 @@ Mod('sea_main',
|
||||
)
|
||||
|
||||
Mod('tt',
|
||||
'frappy_psi.sea.SeaDrivable', '',
|
||||
'frappy_psi.sea.LscDrivable', '',
|
||||
io='sea_main',
|
||||
meaning=['temperature_regulation', 27],
|
||||
sea_object='tt',
|
||||
rel_paths=['tm', '.', 'set', 'dblctrl'],
|
||||
sensor_path='tm',
|
||||
set_path='set',
|
||||
)
|
||||
|
||||
Mod('cc',
|
||||
|
||||
@@ -8,11 +8,12 @@ Mod('sea_main',
|
||||
service = 'main',
|
||||
)
|
||||
Mod('tt',
|
||||
'frappy_psi.sea.SeaDrivable', '',
|
||||
io = 'sea_main',
|
||||
'frappy_psi.sea.LscDrivable', '',
|
||||
io='sea_main',
|
||||
meaning=['temperature_regulation', 27],
|
||||
sea_object = 'tt',
|
||||
rel_paths=['tm', '.', 'set', 'dblctrl'],
|
||||
sea_object='tt',
|
||||
sensor_path='tm',
|
||||
set_path='set',
|
||||
)
|
||||
Mod('cc',
|
||||
'frappy_psi.sea.SeaReadable', '',
|
||||
|
||||
@@ -10,11 +10,12 @@ Mod('sea_main',
|
||||
)
|
||||
|
||||
Mod('tt',
|
||||
'frappy_psi.sea.SeaDrivable', '',
|
||||
'frappy_psi.sea.LscDrivable', '',
|
||||
io='sea_main',
|
||||
meaning=['temperature_regulation', 27],
|
||||
sea_object='tt',
|
||||
rel_paths=['tm', '.', 'set', 'dblctrl'],
|
||||
sensor_path='tm',
|
||||
set_path='set',
|
||||
)
|
||||
|
||||
Mod('cc',
|
||||
|
||||
@@ -10,11 +10,12 @@ Mod('sea_main',
|
||||
)
|
||||
|
||||
Mod('tt',
|
||||
'frappy_psi.sea.SeaDrivable', '',
|
||||
'frappy_psi.sea.LscDrivable', '',
|
||||
io='sea_main',
|
||||
meaning=['temperature_regulation', 27],
|
||||
sea_object='tt',
|
||||
rel_paths=['tm', '.', 'set', 'dblctrl'],
|
||||
sensor_path='tm',
|
||||
set_path='set',
|
||||
)
|
||||
|
||||
Mod('th',
|
||||
|
||||
@@ -10,12 +10,13 @@ Mod('sea_main',
|
||||
)
|
||||
|
||||
Mod('tt',
|
||||
'frappy_psi.sea.SeaDrivable', '',
|
||||
'frappy_psi.sea.LscDrivable', '',
|
||||
io='sea_main',
|
||||
meaning=['temperature_regulation', 27],
|
||||
sea_object='tt',
|
||||
rel_paths=['tm', '.', 'set', 'dblctrl'],
|
||||
)
|
||||
sensor_path='tm',
|
||||
set_path='set',
|
||||
)
|
||||
|
||||
Mod('th',
|
||||
'frappy_psi.sea.SeaReadable',
|
||||
|
||||
@@ -15,11 +15,12 @@ Mod('sea_main',
|
||||
#)
|
||||
|
||||
Mod('tt',
|
||||
'frappy_psi.sea.SeaDrivable', '',
|
||||
meaning=['temperature_regulation', 27],
|
||||
'frappy_psi.sea.LscDrivable', '',
|
||||
io='sea_main',
|
||||
meaning=['temperature_regulation', 27],
|
||||
sea_object='tt',
|
||||
rel_paths=['tm', '.', 'set', 'dblctrl'],
|
||||
sensor_path='tm',
|
||||
set_path='set',
|
||||
)
|
||||
|
||||
Mod('th',
|
||||
|
||||
@@ -10,11 +10,12 @@ Mod('sea_main',
|
||||
)
|
||||
|
||||
Mod('tt',
|
||||
'frappy_psi.sea.SeaDrivable', '',
|
||||
'frappy_psi.sea.LscDrivable', '',
|
||||
io='sea_main',
|
||||
meaning=['temperature_regulation', 27],
|
||||
sea_object='tt',
|
||||
rel_paths=['tm', '.', 'set', 'dblctrl'],
|
||||
sensor_path='tm',
|
||||
set_path='set',
|
||||
)
|
||||
|
||||
Mod('cc',
|
||||
|
||||
@@ -2,8 +2,6 @@ Node('mb11.psi.ch',
|
||||
'MB11 11 Tesla - 100 mm cryomagnet',
|
||||
)
|
||||
|
||||
sea_cfg = 'mb11.config'
|
||||
|
||||
Mod('itc1',
|
||||
'frappy_psi.mercury.IO',
|
||||
'ITC for heat exchanger and pressures',
|
||||
|
||||
@@ -1,228 +0,0 @@
|
||||
Node('mb11.psi.ch',
|
||||
'MB11 11 Tesla - 100 mm cryomagnet',
|
||||
)
|
||||
|
||||
Mod('itc1',
|
||||
'frappy_psi.mercury.IO',
|
||||
'ITC for heat exchanger and pressures',
|
||||
uri='mb11-ts:3001',
|
||||
)
|
||||
|
||||
Mod('itc2',
|
||||
'frappy_psi.mercury.IO',
|
||||
'ITC for neck and nv heaters',
|
||||
uri='mb11-ts:3002',
|
||||
)
|
||||
|
||||
Mod('ips',
|
||||
'frappy_psi.mercury.IO',
|
||||
'IPS for magnet and levels',
|
||||
uri='mb11-ts:3003',
|
||||
)
|
||||
|
||||
Mod('T_stat',
|
||||
'frappy_psi.mercury.TemperatureAutoFlow',
|
||||
'static heat exchanger temperature',
|
||||
meaning=['temperature_regulation', 27],
|
||||
output_module='htr_stat',
|
||||
needle_valve='p_stat',
|
||||
slot='DB6.T1',
|
||||
io='itc1',
|
||||
tolerance=0.1,
|
||||
flowpars=((1,5), (2, 20)),
|
||||
)
|
||||
|
||||
Mod('htr_stat',
|
||||
'frappy_psi.mercury.HeaterOutput',
|
||||
'static heat exchanger heater',
|
||||
slot='DB1.H1',
|
||||
io='itc1',
|
||||
)
|
||||
|
||||
Mod('ts',
|
||||
'frappy_psi.mercury.TemperatureLoop',
|
||||
'sample temperature',
|
||||
output_module='htr_sample',
|
||||
slot='MB1.T1',
|
||||
io='itc1',
|
||||
tolerance=1.0,
|
||||
visibility='expert',
|
||||
)
|
||||
|
||||
Mod('htr_sample',
|
||||
'frappy_psi.mercury.HeaterOutput',
|
||||
'sample stick heater power',
|
||||
slot='MB0.H1',
|
||||
io='itc1',
|
||||
)
|
||||
|
||||
Mod('p_stat',
|
||||
'frappy_psi.mercury.PressureLoop',
|
||||
'static needle valve pressure',
|
||||
output_module='pos_stat',
|
||||
settling_time=60.0,
|
||||
slot='DB5.P1',
|
||||
io='itc1',
|
||||
tolerance=1.0,
|
||||
value=Param(
|
||||
unit='mbar_flow',
|
||||
),
|
||||
)
|
||||
|
||||
Mod('pos_stat',
|
||||
'frappy_psi.mercury.ValvePos',
|
||||
'static needle valve position',
|
||||
slot='DB5.P1,DB3.G1',
|
||||
io='itc1',
|
||||
)
|
||||
|
||||
Mod('T_dyn',
|
||||
'frappy_psi.mercury.TemperatureAutoFlow',
|
||||
'dynamic heat exchanger temperature',
|
||||
output_module='htr_dyn',
|
||||
needle_valve='p_dyn',
|
||||
slot='DB7.T1',
|
||||
io='itc1',
|
||||
tolerance=0.1,
|
||||
)
|
||||
|
||||
Mod('htr_dyn',
|
||||
'frappy_psi.mercury.HeaterOutput',
|
||||
'dynamic heat exchanger heater',
|
||||
slot='DB2.H1',
|
||||
io='itc1',
|
||||
)
|
||||
|
||||
Mod('p_dyn',
|
||||
'frappy_psi.mercury.PressureLoop',
|
||||
'dynamic needle valve pressure',
|
||||
output_module='pos_dyn',
|
||||
settling_time=60.0,
|
||||
slot='DB8.P1',
|
||||
io='itc1',
|
||||
tolerance=1.0,
|
||||
value=Param(
|
||||
unit='mbar_flow',
|
||||
),
|
||||
)
|
||||
|
||||
Mod('pos_dyn',
|
||||
'frappy_psi.mercury.ValvePos',
|
||||
'dynamic needle valve position',
|
||||
slot='DB8.P1,DB4.G1',
|
||||
io='itc1',
|
||||
)
|
||||
|
||||
Mod('mf',
|
||||
'frappy_psi.ips_mercury.Field',
|
||||
'magnetic field',
|
||||
slot='GRPZ',
|
||||
io='ips',
|
||||
tolerance=0.001,
|
||||
wait_stable_field=60.0,
|
||||
target=Param(
|
||||
max=11.0,
|
||||
),
|
||||
persistent_limit=11.1,
|
||||
)
|
||||
|
||||
Mod('lev',
|
||||
'frappy_psi.mercury.HeLevel',
|
||||
'LHe level',
|
||||
slot='DB1.L1',
|
||||
io='ips',
|
||||
)
|
||||
|
||||
Mod('n2lev',
|
||||
'frappy_psi.mercury.N2Level',
|
||||
'LN2 level',
|
||||
slot='DB1.L1',
|
||||
io='ips',
|
||||
)
|
||||
|
||||
Mod('T_neck1',
|
||||
'frappy_psi.mercury.TemperatureLoop',
|
||||
'neck heater 1 temperature',
|
||||
output_module='htr_neck1',
|
||||
slot='MB1.T1',
|
||||
io='itc2',
|
||||
tolerance=1.0,
|
||||
)
|
||||
|
||||
Mod('htr_neck1',
|
||||
'frappy_psi.mercury.HeaterOutput',
|
||||
'neck heater 1 power',
|
||||
slot='MB0.H1',
|
||||
io='itc2',
|
||||
)
|
||||
|
||||
Mod('T_neck2',
|
||||
'frappy_psi.mercury.TemperatureLoop',
|
||||
'neck heater 2 temperature',
|
||||
output_module='htr_neck2',
|
||||
slot='DB6.T1',
|
||||
io='itc2',
|
||||
tolerance=1.0,
|
||||
)
|
||||
|
||||
Mod('htr_neck2',
|
||||
'frappy_psi.mercury.HeaterOutput',
|
||||
'neck heater 2 power',
|
||||
slot='DB1.H1',
|
||||
io='itc2',
|
||||
)
|
||||
|
||||
Mod('T_nvs',
|
||||
'frappy_psi.mercury.TemperatureLoop',
|
||||
'static needle valve temperature',
|
||||
output_module='htr_nvs',
|
||||
slot='DB7.T1',
|
||||
io='itc2',
|
||||
tolerance=0.1,
|
||||
)
|
||||
|
||||
Mod('htr_nvs',
|
||||
'frappy_psi.mercury.HeaterOutput',
|
||||
'static needle valve heater power',
|
||||
slot='DB2.H1',
|
||||
io='itc2',
|
||||
)
|
||||
|
||||
Mod('T_nvd',
|
||||
'frappy_psi.mercury.TemperatureLoop',
|
||||
'dynamic needle valve heater temperature',
|
||||
output_module='htr_nvd',
|
||||
slot='DB8.T1',
|
||||
io='itc2',
|
||||
tolerance=0.1,
|
||||
)
|
||||
|
||||
Mod('htr_nvd',
|
||||
'frappy_psi.mercury.HeaterOutput',
|
||||
'dynamic needle valve heater power',
|
||||
slot='DB3.H1',
|
||||
io='itc2',
|
||||
)
|
||||
|
||||
Mod('T_coil',
|
||||
'frappy_psi.mercury.TemperatureSensor',
|
||||
'coil temperature',
|
||||
slot='MB1.T1',
|
||||
io='ips',
|
||||
)
|
||||
|
||||
Mod('om_io',
|
||||
'frappy_psi.phytron.PhytronIO',
|
||||
'dom motor IO',
|
||||
uri='mb11-ts.psi.ch:3004',
|
||||
)
|
||||
|
||||
Mod('om',
|
||||
'frappy_psi.phytron.Motor',
|
||||
'stick rotation, typically used for omega',
|
||||
io='om_io',
|
||||
target_min=-360,
|
||||
target_max=360,
|
||||
encoder_mode='NO',
|
||||
target=Param(min=-360, max=360),
|
||||
)
|
||||
@@ -10,11 +10,12 @@ Mod('sea_main',
|
||||
)
|
||||
|
||||
Mod('tt',
|
||||
'frappy_psi.sea.SeaDrivable', '',
|
||||
'frappy_psi.sea.LscDrivable', '',
|
||||
io='sea_main',
|
||||
meaning=['temperature_regulation', 27],
|
||||
sea_object='tt',
|
||||
rel_paths=['tm', '.', 'set', 'dblctrl'],
|
||||
sensor_path='tm',
|
||||
set_path='set',
|
||||
)
|
||||
|
||||
Mod('cc',
|
||||
|
||||
@@ -10,11 +10,12 @@ Mod('sea_main',
|
||||
)
|
||||
|
||||
Mod('tt',
|
||||
'frappy_psi.sea.SeaDrivable', '',
|
||||
'frappy_psi.sea.LscDrivable', '',
|
||||
io='sea_main',
|
||||
meaning=['temperature_regulation', 27],
|
||||
sea_object='tt',
|
||||
rel_paths=['tm', '.', 'set', 'dblctrl'],
|
||||
sensor_path='tm',
|
||||
set_path='set',
|
||||
)
|
||||
|
||||
Mod('cc',
|
||||
|
||||
@@ -10,11 +10,12 @@ Mod('sea_main',
|
||||
)
|
||||
|
||||
Mod('tt',
|
||||
'frappy_psi.sea.SeaDrivable', '',
|
||||
'frappy_psi.sea.LscDrivable', '',
|
||||
io='sea_main',
|
||||
meaning=['temperature_regulation', 27],
|
||||
sea_object='tt',
|
||||
rel_paths=['.', 'tm', 'set', 'dblctrl'],
|
||||
sensor_path='tm',
|
||||
set_path='set',
|
||||
)
|
||||
|
||||
Mod('cc',
|
||||
|
||||
@@ -10,11 +10,12 @@ Mod('sea_main',
|
||||
)
|
||||
|
||||
Mod('tt',
|
||||
'frappy_psi.sea.SeaDrivable', '',
|
||||
'frappy_psi.sea.LscDrivable', '',
|
||||
io='sea_main',
|
||||
meaning=['temperature_regulation', 27],
|
||||
sea_object='tt',
|
||||
rel_paths=['tm', '.', 'set', 'dblctrl'],
|
||||
sensor_path='tm',
|
||||
set_path='set',
|
||||
)
|
||||
|
||||
Mod('cc',
|
||||
|
||||
@@ -10,11 +10,12 @@ Mod('sea_main',
|
||||
)
|
||||
|
||||
Mod('tt',
|
||||
'frappy_psi.sea.SeaDrivable', '',
|
||||
io = 'sea_main',
|
||||
'frappy_psi.sea.LscDrivable', '',
|
||||
io='sea_main',
|
||||
meaning=['temperature_regulation', 27],
|
||||
sea_object = 'tt',
|
||||
rel_paths=['tm', '.', 'set', 'dblctrl'],
|
||||
sea_object='tt',
|
||||
sensor_path='tm',
|
||||
set_path='set',
|
||||
)
|
||||
|
||||
Mod('cc',
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
from frappy_psi.ccracks import Rack
|
||||
|
||||
Node('ori7test.psi.ch',
|
||||
'ORI7 test',
|
||||
'tcp://5000'
|
||||
)
|
||||
|
||||
rack = Rack(Mod)
|
||||
|
||||
rack.lakeshore()
|
||||
rack.sensor('Ts', channel='C', calcurve='x186350')
|
||||
rack.loop('T', channel='B', calcurve='x174786', output_module='htr', target=10)
|
||||
rack.heater('htr', output_no=1, max_heater='100W', resistance=25)
|
||||
|
||||
rack.he()
|
||||
rack.n2()
|
||||
rack.flow(min_open_pulse=0.03)
|
||||
20
cfg/main/tfa_cfg.py
Normal file
20
cfg/main/tfa_cfg.py
Normal file
@@ -0,0 +1,20 @@
|
||||
Node('TFA10.psi.ch',
|
||||
'thermofisher water bath',
|
||||
'tcp://5000',
|
||||
)
|
||||
|
||||
Mod('io',
|
||||
'frappy_psi.thermofisher.ThermFishIO',
|
||||
'connection for ThermoFisher A10',
|
||||
uri='tcp://ldm-fi-ts:3002',
|
||||
)
|
||||
|
||||
Mod('T',
|
||||
'frappy_psi.thermofisher.TemperatureLoopA10',
|
||||
'holder temperature',
|
||||
io='io',
|
||||
meaning=['temperature', 20],
|
||||
target=Param(max=100),
|
||||
tolerance=0.5,
|
||||
settling_time=20,
|
||||
)
|
||||
@@ -10,11 +10,12 @@ Mod('sea_main',
|
||||
)
|
||||
|
||||
Mod('tt',
|
||||
'frappy_psi.sea.SeaDrivable', '',
|
||||
'frappy_psi.sea.LscDrivable', '',
|
||||
io='sea_main',
|
||||
meaning=['temperature_regulation', 27],
|
||||
sea_object='tt',
|
||||
rel_paths=['tm', '.', 'set', 'dblctrl'],
|
||||
sensor_path='tm',
|
||||
set_path='set',
|
||||
)
|
||||
|
||||
Mod('cc',
|
||||
|
||||
100
cfg/muwaba_cfg.py
Normal file
100
cfg/muwaba_cfg.py
Normal file
@@ -0,0 +1,100 @@
|
||||
Node('muwaba.psi.ch',
|
||||
'multi waterbath',
|
||||
'tcp://5000',
|
||||
)
|
||||
|
||||
Mod('wio_1',
|
||||
'frappy_psi.thermofisher.ThermFishIO',
|
||||
'connection for water bath',
|
||||
uri='serial:///dev/ttyUSB0?baudrate=19200', # 3001 = Port 1, 3002 = Port 2 ...
|
||||
)
|
||||
|
||||
Mod('wio_2',
|
||||
'frappy_psi.thermofisher.ThermFishIO',
|
||||
'connection for water bath',
|
||||
uri='serial:///dev/ttyUSB1?baudrate=19200', # 3001 = Port 1, 3002 = Port 2 ...
|
||||
)
|
||||
|
||||
Mod('wio_3',
|
||||
'frappy_psi.thermofisher.ThermFishIO',
|
||||
'connection for water bath',
|
||||
uri='serial:///dev/ttyUSB2?baudrate=19200', # 3001 = Port 1, 3002 = Port 2 ...
|
||||
)
|
||||
|
||||
Mod('Tbath_1',
|
||||
'frappy_psi.thermofisher.TemperatureLoopA10',
|
||||
'water_bath_1',
|
||||
io='wio_1',
|
||||
control_active=0,
|
||||
target=25,
|
||||
tolerance=0.1,
|
||||
settling_time=20,
|
||||
)
|
||||
|
||||
Mod('Tbath_2',
|
||||
'frappy_psi.thermofisher.TemperatureLoopA10',
|
||||
'water_bath_2',
|
||||
io='wio_2',
|
||||
control_active=0,
|
||||
target=25,
|
||||
tolerance=0.1,
|
||||
settling_time=20,
|
||||
)
|
||||
|
||||
Mod('Tbath_3',
|
||||
'frappy_psi.thermofisher.TemperatureLoopA10',
|
||||
'water_bath_3',
|
||||
io='wio_3',
|
||||
control_active=0,
|
||||
target=25,
|
||||
tolerance=0.1,
|
||||
settling_time=20,
|
||||
)
|
||||
|
||||
Mod('valve_1',
|
||||
'frappy_psi.ionopimax.DigitalOutput',
|
||||
'valve_for_fast_water_temperature_changing',
|
||||
addr = 'o1',
|
||||
target = 0,
|
||||
)
|
||||
|
||||
Mod('valve_2',
|
||||
'frappy_psi.ionopimax.DigitalOutput',
|
||||
'valve_for_fast_water_temperature_changing',
|
||||
addr = 'o2',
|
||||
target = 0,
|
||||
)
|
||||
|
||||
Mod('valve_3',
|
||||
'frappy_psi.ionopimax.DigitalOutput',
|
||||
'valve_for_fast_water_temperature_changing',
|
||||
addr = 'o3',
|
||||
target = 0,
|
||||
)
|
||||
|
||||
Mod('temp_sensor_tc',
|
||||
'frappy_psi.ionopimax.SimpleVoltageInput',
|
||||
'temperatur_sensor_sample',
|
||||
rawrange = (0.0, 10.0),
|
||||
valuerange = (5.0, 90.0),
|
||||
addr = 'ai1_mv',
|
||||
meaning = ['temperature', 20],
|
||||
value = Param(unit='degC'),
|
||||
)
|
||||
|
||||
Mod('temp_sensor_pt1000',
|
||||
'frappy_psi.ionopimax.SimpleVoltageInput',
|
||||
'temperatur_sensor_sample',
|
||||
rawrange = (0.0, 10.0),
|
||||
valuerange = (5.0, 90.0),
|
||||
value = Param(unit='degC'),
|
||||
addr = 'ai2_mv',
|
||||
)
|
||||
|
||||
Mod('switcher',
|
||||
'frappy_psi.muwaba.Switcher',
|
||||
'waterbath switcher',
|
||||
valve1 = 'valve_1',
|
||||
valve2 = 'valve_2',
|
||||
valve3 = 'valve_3',
|
||||
)
|
||||
@@ -13,9 +13,11 @@ Mod('th',
|
||||
io = 'sea_main',
|
||||
sea_object = 'th',
|
||||
extra_modules=['t2'],
|
||||
value=Param(unit='degC'),
|
||||
)
|
||||
Mod('ts',
|
||||
'frappy_psi.sea.SeaReadable', '',
|
||||
io='sea_main',
|
||||
single_module='th.t2',
|
||||
value=Param(unit='degC'),
|
||||
)
|
||||
17
cfg/obsolete_sea_cfg/haake_cfg.py
Normal file
17
cfg/obsolete_sea_cfg/haake_cfg.py
Normal file
@@ -0,0 +1,17 @@
|
||||
Node('haake.config.sea.psi.ch',
|
||||
'Haake thermostat',
|
||||
)
|
||||
Mod('sea_main',
|
||||
'frappy_psi.sea.SeaClient',
|
||||
'main sea connection for haakeuro.config',
|
||||
config = 'haake.config',
|
||||
service = 'main',
|
||||
)
|
||||
Mod('th',
|
||||
'frappy_psi.sea.SeaDrivable', '',
|
||||
meaning = ('temperature', 10),
|
||||
io = 'sea_main',
|
||||
sea_object = 'th',
|
||||
extra_modules=['t2'],
|
||||
value=Param(unit='degC'),
|
||||
)
|
||||
@@ -1,14 +1,21 @@
|
||||
{"cap": {"base": "/cap", "params": [{"path": "", "type": "none", "kids": 8},
|
||||
{"path": "send", "type": "text", "readonly": false, "cmd": "cap send", "visibility": 3},
|
||||
{"capff": {"base": "/capff", "params": [
|
||||
{"path": "", "type": "none", "kids": 7},
|
||||
{"path": "send", "type": "text", "readonly": false, "cmd": "capff send", "visibility": 3},
|
||||
{"path": "status", "type": "text", "visibility": 3},
|
||||
{"path": "cap", "type": "float"},
|
||||
{"path": "loss", "type": "float"},
|
||||
{"path": "period", "type": "float", "readonly": false, "cmd": "cap period"},
|
||||
{"path": "V", "type": "float", "readonly": false, "cmd": "cap V"},
|
||||
{"path": "average", "type": "int", "readonly": false, "cmd": "cap average"}]}, "capslope": {"base": "/capslope", "params": [{"path": "", "type": "float", "kids": 6},
|
||||
{"path": "send", "type": "text", "readonly": false, "cmd": "capslope send", "visibility": 3},
|
||||
{"path": "period", "type": "float", "readonly": false, "cmd": "capff period"},
|
||||
{"path": "V", "type": "float", "readonly": false, "cmd": "capff V"},
|
||||
{"path": "average", "type": "int", "readonly": false, "cmd": "capff average"}]},
|
||||
|
||||
"capslopeff": {"base": "/capslopeff", "params": [
|
||||
{"path": "", "type": "float", "kids": 6},
|
||||
{"path": "send", "type": "text", "readonly": false, "cmd": "capslopeff send", "visibility": 3},
|
||||
{"path": "status", "type": "text", "visibility": 3},
|
||||
{"path": "node", "type": "text", "readonly": false, "cmd": "capslope node"},
|
||||
{"path": "unit", "type": "float", "readonly": false, "cmd": "capslope unit", "description": "unit=60: mainunits/minutes, unit=1: mainunits/sec"},
|
||||
{"path": "ref", "type": "float", "readonly": false, "cmd": "capslope ref"},
|
||||
{"path": "buffersize", "type": "float", "readonly": false, "cmd": "capslope buffersize"}]}}
|
||||
{"path": "node", "type": "text", "readonly": false, "cmd": "capslopeff node"},
|
||||
{"path": "unit", "type": "float", "readonly": false, "cmd": "capslopeff unit", "description": "unit=60: mainunits/minutes, unit=1: mainunits/sec"},
|
||||
{"path": "ref", "type": "float", "readonly": false, "cmd": "capslopeff ref"},
|
||||
{"path": "bufperiod", "type": "float", "readonly": false, "cmd": "capslopeff bufperiod"}]},
|
||||
|
||||
"addonlock_ah2550": {"base": "/addonlock_ah2550", "params": [
|
||||
{"path": "", "type": "text", "readonly": false, "cmd": "addonlock_ah2550 = "}]}}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{"cap": {"base": "/cap", "params": [{"path": "", "type": "none", "kids": 8},
|
||||
{"cap": {"base": "/cap", "params": [
|
||||
{"path": "", "type": "none", "kids": 8},
|
||||
{"path": "send", "type": "text", "readonly": false, "cmd": "cap send", "visibility": 3},
|
||||
{"path": "status", "type": "text", "visibility": 3},
|
||||
{"path": "cap", "type": "float"},
|
||||
@@ -6,10 +7,16 @@
|
||||
{"path": "period", "type": "float", "readonly": false, "cmd": "cap period"},
|
||||
{"path": "freq", "type": "float", "readonly": false, "cmd": "cap freq"},
|
||||
{"path": "V", "type": "float", "readonly": false, "cmd": "cap V"},
|
||||
{"path": "average", "type": "int", "readonly": false, "cmd": "cap average"}]}, "capslope": {"base": "/capslope", "params": [{"path": "", "type": "float", "kids": 6},
|
||||
{"path": "average", "type": "int", "readonly": false, "cmd": "cap average"}]},
|
||||
|
||||
"capslope": {"base": "/capslope", "params": [
|
||||
{"path": "", "type": "float", "kids": 6},
|
||||
{"path": "send", "type": "text", "readonly": false, "cmd": "capslope send", "visibility": 3},
|
||||
{"path": "status", "type": "text", "visibility": 3},
|
||||
{"path": "node", "type": "text", "readonly": false, "cmd": "capslope node"},
|
||||
{"path": "unit", "type": "float", "readonly": false, "cmd": "capslope unit", "description": "unit=60: mainunits/minutes, unit=1: mainunits/sec"},
|
||||
{"path": "ref", "type": "float", "readonly": false, "cmd": "capslope ref"},
|
||||
{"path": "buffersize", "type": "float", "readonly": false, "cmd": "capslope buffersize"}]}}
|
||||
{"path": "bufperiod", "type": "float", "readonly": false, "cmd": "capslope bufperiod"}]},
|
||||
|
||||
"addonlock_ah2700": {"base": "/addonlock_ah2700", "params": [
|
||||
{"path": "", "type": "text", "readonly": false, "cmd": "addonlock_ah2700 = "}]}}
|
||||
|
||||
29
cfg/sea/cp1000.addon.json
Normal file
29
cfg/sea/cp1000.addon.json
Normal file
@@ -0,0 +1,29 @@
|
||||
{"cp2800": {"base": "/cp2800", "params": [
|
||||
{"path": "", "type": "bool", "readonly": false, "cmd": "cp2800", "kids": 27},
|
||||
{"path": "send", "type": "text", "readonly": false, "cmd": "cp2800 send", "visibility": 3},
|
||||
{"path": "status", "type": "text", "visibility": 3},
|
||||
{"path": "comp_running_hrs", "type": "float"},
|
||||
{"path": "cpu_t", "type": "float"},
|
||||
{"path": "motor_current_a", "type": "float"},
|
||||
{"path": "inp_water_t", "type": "float"},
|
||||
{"path": "inp_water_t_min", "type": "float"},
|
||||
{"path": "inp_water_t_max", "type": "float"},
|
||||
{"path": "out_water_t", "type": "float"},
|
||||
{"path": "out_water_t_min", "type": "float"},
|
||||
{"path": "out_water_t_max", "type": "float"},
|
||||
{"path": "helium_t", "type": "float"},
|
||||
{"path": "helium_t_min", "type": "float"},
|
||||
{"path": "helium_t_max", "type": "float"},
|
||||
{"path": "oil_t", "type": "float"},
|
||||
{"path": "oil_t_min", "type": "float"},
|
||||
{"path": "oil_t_max", "type": "float"},
|
||||
{"path": "high_side_p", "type": "float"},
|
||||
{"path": "high_side_p_min", "type": "float"},
|
||||
{"path": "high_side_p_max", "type": "float"},
|
||||
{"path": "high_side_p_avg", "type": "float"},
|
||||
{"path": "low_side_p", "type": "float"},
|
||||
{"path": "low_side_p_min", "type": "float"},
|
||||
{"path": "low_side_p_max", "type": "float"},
|
||||
{"path": "low_side_p_avg", "type": "float"},
|
||||
{"path": "high_side_delta_p_avg", "type": "float"},
|
||||
{"path": "high_side_bounce", "type": "float"}]}}
|
||||
14
cfg/sea/cp1000_cfg.py
Normal file
14
cfg/sea/cp1000_cfg.py
Normal file
@@ -0,0 +1,14 @@
|
||||
Node('cp1000.addon.sea.psi.ch',
|
||||
'''dry system''',
|
||||
)
|
||||
Mod('sea_addons',
|
||||
'frappy_psi.sea.SeaClient',
|
||||
'addons sea connection for cp1000.addon',
|
||||
config = 'cp1000.addon',
|
||||
service = 'addons',
|
||||
)
|
||||
Mod('cp2800',
|
||||
'frappy_psi.sea.SeaWritable', '',
|
||||
io = 'sea_addons',
|
||||
sea_object = 'cp2800',
|
||||
)
|
||||
@@ -18,7 +18,7 @@
|
||||
{"path": "heaterselect", "type": "enum", "enum": {"sample": 0, "mix": 1, "mix(temporarely)": 2}, "readonly": false, "cmd": "ts heaterselect"},
|
||||
{"path": "control", "type": "enum", "enum": {"off": 0, "sample": 6, "mix": 5, "samplehtr": 8}, "readonly": false, "cmd": "ts control", "description": "click off to reload list"},
|
||||
{"path": "heatermode", "type": "enum", "enum": {"disabled": -1, "off": 0, "on": 1}, "readonly": false, "cmd": "ts heatermode"},
|
||||
{"path": "heaterrange", "type": "enum", "enum": {"2uW": 1, "20uW": 2, "200uW": 3, "2mW": 4, "20mW": 5}, "readonly": false, "cmd": "ts heaterrange"},
|
||||
{"path": "heaterrange", "type": "enum", "enum": {"off": 0, "2uW": 1, "20uW": 2, "200uW": 3, "2mW": 4, "20mW": 5}, "readonly": false, "cmd": "ts heaterrange"},
|
||||
{"path": "autoheater", "type": "bool", "readonly": false, "cmd": "ts autoheater", "description": "automatic heater range", "kids": 12},
|
||||
{"path": "autoheater/wlp0", "type": "float", "readonly": false, "cmd": "ts autoheater/wlp0", "description": "weak link base temperature (used for auto heater)"},
|
||||
{"path": "autoheater/wlp1", "type": "float", "readonly": false, "cmd": "ts autoheater/wlp1", "description": "weak link temperature at 1 uW (used for auto heater)"},
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
{"path": "heaterselect", "type": "enum", "enum": {"sample": 0, "mix": 1, "mix(temporarely)": 2}, "readonly": false, "cmd": "ts heaterselect"},
|
||||
{"path": "control", "type": "enum", "enum": {"off": 0, "sample": 6, "mix": 5, "samplehtr": 8}, "readonly": false, "cmd": "ts control", "description": "click off to reload list"},
|
||||
{"path": "heatermode", "type": "enum", "enum": {"disabled": -1, "off": 0, "on": 1}, "readonly": false, "cmd": "ts heatermode"},
|
||||
{"path": "heaterrange", "type": "enum", "enum": {"2uW": 1, "20uW": 2, "200uW": 3, "2mW": 4, "20mW": 5}, "readonly": false, "cmd": "ts heaterrange"},
|
||||
{"path": "heaterrange", "type": "enum", "enum": {"off": 0, "2uW": 1, "20uW": 2, "200uW": 3, "2mW": 4, "20mW": 5}, "readonly": false, "cmd": "ts heaterrange"},
|
||||
{"path": "autoheater", "type": "bool", "readonly": false, "cmd": "ts autoheater", "description": "automatic heater range", "kids": 12},
|
||||
{"path": "autoheater/wlp0", "type": "float", "readonly": false, "cmd": "ts autoheater/wlp0", "description": "weak link base temperature (used for auto heater)"},
|
||||
{"path": "autoheater/wlp1", "type": "float", "readonly": false, "cmd": "ts autoheater/wlp1", "description": "weak link temperature at 1 uW (used for auto heater)"},
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
{"path": "heaterselect", "type": "enum", "enum": {"sample": 0, "mix": 1, "mix(temporarely)": 2}, "readonly": false, "cmd": "ts heaterselect"},
|
||||
{"path": "control", "type": "enum", "enum": {"off": 0, "sample": 6, "mix": 5, "samplehtr": 8}, "readonly": false, "cmd": "ts control", "description": "click off to reload list"},
|
||||
{"path": "heatermode", "type": "enum", "enum": {"disabled": -1, "off": 0, "on": 1}, "readonly": false, "cmd": "ts heatermode"},
|
||||
{"path": "heaterrange", "type": "enum", "enum": {"2uW": 1, "20uW": 2, "200uW": 3, "2mW": 4, "20mW": 5}, "readonly": false, "cmd": "ts heaterrange"},
|
||||
{"path": "heaterrange", "type": "enum", "enum": {"off": 0, "2uW": 1, "20uW": 2, "200uW": 3, "2mW": 4, "20mW": 5}, "readonly": false, "cmd": "ts heaterrange"},
|
||||
{"path": "autoheater", "type": "bool", "readonly": false, "cmd": "ts autoheater", "description": "automatic heater range", "kids": 12},
|
||||
{"path": "autoheater/wlp0", "type": "float", "readonly": false, "cmd": "ts autoheater/wlp0", "description": "weak link base temperature (used for auto heater)"},
|
||||
{"path": "autoheater/wlp1", "type": "float", "readonly": false, "cmd": "ts autoheater/wlp1", "description": "weak link temperature at 1 uW (used for auto heater)"},
|
||||
|
||||
213
cfg/sea/leiden.config.json
Normal file
213
cfg/sea/leiden.config.json
Normal file
@@ -0,0 +1,213 @@
|
||||
{"tt": {"base": "/tt", "params": [
|
||||
{"path": "", "type": "int", "kids": 18},
|
||||
{"path": "send", "type": "text", "readonly": false, "cmd": "tt send", "visibility": 3},
|
||||
{"path": "status", "type": "text", "visibility": 3},
|
||||
{"path": "autoscan", "type": "bool", "readonly": false, "cmd": "tt autoscan", "kids": 4},
|
||||
{"path": "autoscan/synchronized", "type": "bool", "readonly": false, "cmd": "tt autoscan/synchronized"},
|
||||
{"path": "autoscan/interval", "type": "text", "readonly": false, "cmd": "tt autoscan/interval"},
|
||||
{"path": "autoscan/pause", "type": "text", "readonly": false, "cmd": "tt autoscan/pause"},
|
||||
{"path": "autoscan/dwell", "type": "text", "readonly": false, "cmd": "tt autoscan/dwell"},
|
||||
{"path": "T3K", "type": "float", "kids": 14},
|
||||
{"path": "T3K/active", "type": "enum", "enum": {"inactive": 0, "active": 1}, "readonly": false, "cmd": "tt T3K/active"},
|
||||
{"path": "T3K/autorange", "type": "bool", "readonly": false, "cmd": "tt T3K/autorange", "description": "autorange (common for all channels)"},
|
||||
{"path": "T3K/range", "type": "text", "readonly": false, "cmd": "tt T3K/range", "description": "resistance range in Ohm"},
|
||||
{"path": "T3K/range_num", "type": "int"},
|
||||
{"path": "T3K/excitation", "type": "text", "readonly": false, "cmd": "tt T3K/excitation", "description": "excitation with unit, i.e. 2uV or 3pA"},
|
||||
{"path": "T3K/excitation_num", "type": "int"},
|
||||
{"path": "T3K/excitation_mode", "type": "enum", "enum": {"voltage": 0, "current": 1, "off": 2}},
|
||||
{"path": "T3K/pause", "type": "int", "readonly": false, "cmd": "tt T3K/pause", "description": "pause time [sec] after channel change"},
|
||||
{"path": "T3K/filter", "type": "int", "readonly": false, "cmd": "tt T3K/filter", "description": "filter average time [sec]"},
|
||||
{"path": "T3K/dwell", "type": "int", "readonly": false, "cmd": "tt T3K/dwell", "description": "dwell time [sec]. Total time per channel: pause + filter + dwell"},
|
||||
{"path": "T3K/status", "type": "text"},
|
||||
{"path": "T3K/curve", "type": "text", "readonly": false, "cmd": "tt T3K/curve", "kids": 1},
|
||||
{"path": "T3K/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tt T3K/curve/points", "visibility": 3},
|
||||
{"path": "T3K/alarm", "type": "float", "readonly": false, "cmd": "tt T3K/alarm"},
|
||||
{"path": "T3K/raw", "type": "float"},
|
||||
{"path": "Tstill", "type": "float", "kids": 14},
|
||||
{"path": "Tstill/active", "type": "enum", "enum": {"inactive": 0, "active": 1}, "readonly": false, "cmd": "tt Tstill/active"},
|
||||
{"path": "Tstill/autorange", "type": "bool", "readonly": false, "cmd": "tt Tstill/autorange", "description": "autorange (common for all channels)"},
|
||||
{"path": "Tstill/range", "type": "text", "readonly": false, "cmd": "tt Tstill/range", "description": "resistance range in Ohm"},
|
||||
{"path": "Tstill/range_num", "type": "int"},
|
||||
{"path": "Tstill/excitation", "type": "text", "readonly": false, "cmd": "tt Tstill/excitation", "description": "excitation with unit, i.e. 2uV or 3pA"},
|
||||
{"path": "Tstill/excitation_num", "type": "int"},
|
||||
{"path": "Tstill/excitation_mode", "type": "enum", "enum": {"voltage": 0, "current": 1, "off": 2}},
|
||||
{"path": "Tstill/pause", "type": "int", "readonly": false, "cmd": "tt Tstill/pause", "description": "pause time [sec] after channel change"},
|
||||
{"path": "Tstill/filter", "type": "int", "readonly": false, "cmd": "tt Tstill/filter", "description": "filter average time [sec]"},
|
||||
{"path": "Tstill/dwell", "type": "int", "readonly": false, "cmd": "tt Tstill/dwell", "description": "dwell time [sec]. Total time per channel: pause + filter + dwell"},
|
||||
{"path": "Tstill/status", "type": "text"},
|
||||
{"path": "Tstill/curve", "type": "text", "readonly": false, "cmd": "tt Tstill/curve", "kids": 1},
|
||||
{"path": "Tstill/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tt Tstill/curve/points", "visibility": 3},
|
||||
{"path": "Tstill/alarm", "type": "float", "readonly": false, "cmd": "tt Tstill/alarm"},
|
||||
{"path": "Tstill/raw", "type": "float"},
|
||||
{"path": "T50mK", "type": "float", "kids": 14},
|
||||
{"path": "T50mK/active", "type": "enum", "enum": {"inactive": 0, "active": 1}, "readonly": false, "cmd": "tt T50mK/active"},
|
||||
{"path": "T50mK/autorange", "type": "bool", "readonly": false, "cmd": "tt T50mK/autorange", "description": "autorange (common for all channels)"},
|
||||
{"path": "T50mK/range", "type": "text", "readonly": false, "cmd": "tt T50mK/range", "description": "resistance range in Ohm"},
|
||||
{"path": "T50mK/range_num", "type": "int"},
|
||||
{"path": "T50mK/excitation", "type": "text", "readonly": false, "cmd": "tt T50mK/excitation", "description": "excitation with unit, i.e. 2uV or 3pA"},
|
||||
{"path": "T50mK/excitation_num", "type": "int"},
|
||||
{"path": "T50mK/excitation_mode", "type": "enum", "enum": {"voltage": 0, "current": 1, "off": 2}},
|
||||
{"path": "T50mK/pause", "type": "int", "readonly": false, "cmd": "tt T50mK/pause", "description": "pause time [sec] after channel change"},
|
||||
{"path": "T50mK/filter", "type": "int", "readonly": false, "cmd": "tt T50mK/filter", "description": "filter average time [sec]"},
|
||||
{"path": "T50mK/dwell", "type": "int", "readonly": false, "cmd": "tt T50mK/dwell", "description": "dwell time [sec]. Total time per channel: pause + filter + dwell"},
|
||||
{"path": "T50mK/status", "type": "text"},
|
||||
{"path": "T50mK/curve", "type": "text", "readonly": false, "cmd": "tt T50mK/curve", "kids": 1},
|
||||
{"path": "T50mK/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tt T50mK/curve/points", "visibility": 3},
|
||||
{"path": "T50mK/alarm", "type": "float", "readonly": false, "cmd": "tt T50mK/alarm"},
|
||||
{"path": "T50mK/raw", "type": "float"},
|
||||
{"path": "Tmxlow", "type": "float", "kids": 14},
|
||||
{"path": "Tmxlow/active", "type": "enum", "enum": {"inactive": 0, "active": 1}, "readonly": false, "cmd": "tt Tmxlow/active"},
|
||||
{"path": "Tmxlow/autorange", "type": "bool", "readonly": false, "cmd": "tt Tmxlow/autorange", "description": "autorange (common for all channels)"},
|
||||
{"path": "Tmxlow/range", "type": "text", "readonly": false, "cmd": "tt Tmxlow/range", "description": "resistance range in Ohm"},
|
||||
{"path": "Tmxlow/range_num", "type": "int"},
|
||||
{"path": "Tmxlow/excitation", "type": "text", "readonly": false, "cmd": "tt Tmxlow/excitation", "description": "excitation with unit, i.e. 2uV or 3pA"},
|
||||
{"path": "Tmxlow/excitation_num", "type": "int"},
|
||||
{"path": "Tmxlow/excitation_mode", "type": "enum", "enum": {"voltage": 0, "current": 1, "off": 2}},
|
||||
{"path": "Tmxlow/pause", "type": "int", "readonly": false, "cmd": "tt Tmxlow/pause", "description": "pause time [sec] after channel change"},
|
||||
{"path": "Tmxlow/filter", "type": "int", "readonly": false, "cmd": "tt Tmxlow/filter", "description": "filter average time [sec]"},
|
||||
{"path": "Tmxlow/dwell", "type": "int", "readonly": false, "cmd": "tt Tmxlow/dwell", "description": "dwell time [sec]. Total time per channel: pause + filter + dwell"},
|
||||
{"path": "Tmxlow/status", "type": "text"},
|
||||
{"path": "Tmxlow/curve", "type": "text", "readonly": false, "cmd": "tt Tmxlow/curve", "kids": 1},
|
||||
{"path": "Tmxlow/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tt Tmxlow/curve/points", "visibility": 3},
|
||||
{"path": "Tmxlow/alarm", "type": "float", "readonly": false, "cmd": "tt Tmxlow/alarm"},
|
||||
{"path": "Tmxlow/raw", "type": "float"},
|
||||
{"path": "Tmxhigh", "type": "float", "kids": 14},
|
||||
{"path": "Tmxhigh/active", "type": "enum", "enum": {"inactive": 0, "active": 1}, "readonly": false, "cmd": "tt Tmxhigh/active"},
|
||||
{"path": "Tmxhigh/autorange", "type": "bool", "readonly": false, "cmd": "tt Tmxhigh/autorange", "description": "autorange (common for all channels)"},
|
||||
{"path": "Tmxhigh/range", "type": "text", "readonly": false, "cmd": "tt Tmxhigh/range", "description": "resistance range in Ohm"},
|
||||
{"path": "Tmxhigh/range_num", "type": "int"},
|
||||
{"path": "Tmxhigh/excitation", "type": "text", "readonly": false, "cmd": "tt Tmxhigh/excitation", "description": "excitation with unit, i.e. 2uV or 3pA"},
|
||||
{"path": "Tmxhigh/excitation_num", "type": "int"},
|
||||
{"path": "Tmxhigh/excitation_mode", "type": "enum", "enum": {"voltage": 0, "current": 1, "off": 2}},
|
||||
{"path": "Tmxhigh/pause", "type": "int", "readonly": false, "cmd": "tt Tmxhigh/pause", "description": "pause time [sec] after channel change"},
|
||||
{"path": "Tmxhigh/filter", "type": "int", "readonly": false, "cmd": "tt Tmxhigh/filter", "description": "filter average time [sec]"},
|
||||
{"path": "Tmxhigh/dwell", "type": "int", "readonly": false, "cmd": "tt Tmxhigh/dwell", "description": "dwell time [sec]. Total time per channel: pause + filter + dwell"},
|
||||
{"path": "Tmxhigh/status", "type": "text"},
|
||||
{"path": "Tmxhigh/curve", "type": "text", "readonly": false, "cmd": "tt Tmxhigh/curve", "kids": 1},
|
||||
{"path": "Tmxhigh/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tt Tmxhigh/curve/points", "visibility": 3},
|
||||
{"path": "Tmxhigh/alarm", "type": "float", "readonly": false, "cmd": "tt Tmxhigh/alarm"},
|
||||
{"path": "Tmxhigh/raw", "type": "float"},
|
||||
{"path": "Tmxcx", "type": "float", "kids": 14},
|
||||
{"path": "Tmxcx/active", "type": "enum", "enum": {"inactive": 0, "active": 1}, "readonly": false, "cmd": "tt Tmxcx/active"},
|
||||
{"path": "Tmxcx/autorange", "type": "bool", "readonly": false, "cmd": "tt Tmxcx/autorange", "description": "autorange (common for all channels)"},
|
||||
{"path": "Tmxcx/range", "type": "text", "readonly": false, "cmd": "tt Tmxcx/range", "description": "resistance range in Ohm"},
|
||||
{"path": "Tmxcx/range_num", "type": "int"},
|
||||
{"path": "Tmxcx/excitation", "type": "text", "readonly": false, "cmd": "tt Tmxcx/excitation", "description": "excitation with unit, i.e. 2uV or 3pA"},
|
||||
{"path": "Tmxcx/excitation_num", "type": "int"},
|
||||
{"path": "Tmxcx/excitation_mode", "type": "enum", "enum": {"voltage": 0, "current": 1, "off": 2}},
|
||||
{"path": "Tmxcx/pause", "type": "int", "readonly": false, "cmd": "tt Tmxcx/pause", "description": "pause time [sec] after channel change"},
|
||||
{"path": "Tmxcx/filter", "type": "int", "readonly": false, "cmd": "tt Tmxcx/filter", "description": "filter average time [sec]"},
|
||||
{"path": "Tmxcx/dwell", "type": "int", "readonly": false, "cmd": "tt Tmxcx/dwell", "description": "dwell time [sec]. Total time per channel: pause + filter + dwell"},
|
||||
{"path": "Tmxcx/status", "type": "text"},
|
||||
{"path": "Tmxcx/curve", "type": "text", "readonly": false, "cmd": "tt Tmxcx/curve", "kids": 1},
|
||||
{"path": "Tmxcx/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tt Tmxcx/curve/points", "visibility": 3},
|
||||
{"path": "Tmxcx/alarm", "type": "float", "readonly": false, "cmd": "tt Tmxcx/alarm"},
|
||||
{"path": "Tmxcx/raw", "type": "float"},
|
||||
{"path": "Tblueo", "type": "float", "kids": 14},
|
||||
{"path": "Tblueo/active", "type": "enum", "enum": {"inactive": 0, "active": 1}, "readonly": false, "cmd": "tt Tblueo/active"},
|
||||
{"path": "Tblueo/autorange", "type": "bool", "readonly": false, "cmd": "tt Tblueo/autorange", "description": "autorange (common for all channels)"},
|
||||
{"path": "Tblueo/range", "type": "text", "readonly": false, "cmd": "tt Tblueo/range", "description": "resistance range in Ohm"},
|
||||
{"path": "Tblueo/range_num", "type": "int"},
|
||||
{"path": "Tblueo/excitation", "type": "text", "readonly": false, "cmd": "tt Tblueo/excitation", "description": "excitation with unit, i.e. 2uV or 3pA"},
|
||||
{"path": "Tblueo/excitation_num", "type": "int"},
|
||||
{"path": "Tblueo/excitation_mode", "type": "enum", "enum": {"voltage": 0, "current": 1, "off": 2}},
|
||||
{"path": "Tblueo/pause", "type": "int", "readonly": false, "cmd": "tt Tblueo/pause", "description": "pause time [sec] after channel change"},
|
||||
{"path": "Tblueo/filter", "type": "int", "readonly": false, "cmd": "tt Tblueo/filter", "description": "filter average time [sec]"},
|
||||
{"path": "Tblueo/dwell", "type": "int", "readonly": false, "cmd": "tt Tblueo/dwell", "description": "dwell time [sec]. Total time per channel: pause + filter + dwell"},
|
||||
{"path": "Tblueo/status", "type": "text"},
|
||||
{"path": "Tblueo/curve", "type": "text", "readonly": false, "cmd": "tt Tblueo/curve", "kids": 1},
|
||||
{"path": "Tblueo/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tt Tblueo/curve/points", "visibility": 3},
|
||||
{"path": "Tblueo/alarm", "type": "float", "readonly": false, "cmd": "tt Tblueo/alarm"},
|
||||
{"path": "Tblueo/raw", "type": "float"},
|
||||
{"path": "Tpt50", "type": "float", "kids": 14},
|
||||
{"path": "Tpt50/active", "type": "enum", "enum": {"inactive": 0, "active": 1}, "readonly": false, "cmd": "tt Tpt50/active"},
|
||||
{"path": "Tpt50/autorange", "type": "bool", "readonly": false, "cmd": "tt Tpt50/autorange", "description": "autorange (common for all channels)"},
|
||||
{"path": "Tpt50/range", "type": "text", "readonly": false, "cmd": "tt Tpt50/range", "description": "resistance range in Ohm"},
|
||||
{"path": "Tpt50/range_num", "type": "int"},
|
||||
{"path": "Tpt50/excitation", "type": "text", "readonly": false, "cmd": "tt Tpt50/excitation", "description": "excitation with unit, i.e. 2uV or 3pA"},
|
||||
{"path": "Tpt50/excitation_num", "type": "int"},
|
||||
{"path": "Tpt50/excitation_mode", "type": "enum", "enum": {"voltage": 0, "current": 1, "off": 2}},
|
||||
{"path": "Tpt50/pause", "type": "int", "readonly": false, "cmd": "tt Tpt50/pause", "description": "pause time [sec] after channel change"},
|
||||
{"path": "Tpt50/filter", "type": "int", "readonly": false, "cmd": "tt Tpt50/filter", "description": "filter average time [sec]"},
|
||||
{"path": "Tpt50/dwell", "type": "int", "readonly": false, "cmd": "tt Tpt50/dwell", "description": "dwell time [sec]. Total time per channel: pause + filter + dwell"},
|
||||
{"path": "Tpt50/status", "type": "text"},
|
||||
{"path": "Tpt50/curve", "type": "text", "readonly": false, "cmd": "tt Tpt50/curve", "kids": 1},
|
||||
{"path": "Tpt50/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tt Tpt50/curve/points", "visibility": 3},
|
||||
{"path": "Tpt50/alarm", "type": "float", "readonly": false, "cmd": "tt Tpt50/alarm"},
|
||||
{"path": "Tpt50/raw", "type": "float"},
|
||||
{"path": "Tpt3high", "type": "float", "kids": 14},
|
||||
{"path": "Tpt3high/active", "type": "enum", "enum": {"inactive": 0, "active": 1}, "readonly": false, "cmd": "tt Tpt3high/active"},
|
||||
{"path": "Tpt3high/autorange", "type": "bool", "readonly": false, "cmd": "tt Tpt3high/autorange", "description": "autorange (common for all channels)"},
|
||||
{"path": "Tpt3high/range", "type": "text", "readonly": false, "cmd": "tt Tpt3high/range", "description": "resistance range in Ohm"},
|
||||
{"path": "Tpt3high/range_num", "type": "int"},
|
||||
{"path": "Tpt3high/excitation", "type": "text", "readonly": false, "cmd": "tt Tpt3high/excitation", "description": "excitation with unit, i.e. 2uV or 3pA"},
|
||||
{"path": "Tpt3high/excitation_num", "type": "int"},
|
||||
{"path": "Tpt3high/excitation_mode", "type": "enum", "enum": {"voltage": 0, "current": 1, "off": 2}},
|
||||
{"path": "Tpt3high/pause", "type": "int", "readonly": false, "cmd": "tt Tpt3high/pause", "description": "pause time [sec] after channel change"},
|
||||
{"path": "Tpt3high/filter", "type": "int", "readonly": false, "cmd": "tt Tpt3high/filter", "description": "filter average time [sec]"},
|
||||
{"path": "Tpt3high/dwell", "type": "int", "readonly": false, "cmd": "tt Tpt3high/dwell", "description": "dwell time [sec]. Total time per channel: pause + filter + dwell"},
|
||||
{"path": "Tpt3high/status", "type": "text"},
|
||||
{"path": "Tpt3high/curve", "type": "text", "readonly": false, "cmd": "tt Tpt3high/curve", "kids": 1},
|
||||
{"path": "Tpt3high/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tt Tpt3high/curve/points", "visibility": 3},
|
||||
{"path": "Tpt3high/alarm", "type": "float", "readonly": false, "cmd": "tt Tpt3high/alarm"},
|
||||
{"path": "Tpt3high/raw", "type": "float"},
|
||||
{"path": "Tpt3low", "type": "float", "kids": 14},
|
||||
{"path": "Tpt3low/active", "type": "enum", "enum": {"inactive": 0, "active": 1}, "readonly": false, "cmd": "tt Tpt3low/active"},
|
||||
{"path": "Tpt3low/autorange", "type": "bool", "readonly": false, "cmd": "tt Tpt3low/autorange", "description": "autorange (common for all channels)"},
|
||||
{"path": "Tpt3low/range", "type": "text", "readonly": false, "cmd": "tt Tpt3low/range", "description": "resistance range in Ohm"},
|
||||
{"path": "Tpt3low/range_num", "type": "int"},
|
||||
{"path": "Tpt3low/excitation", "type": "text", "readonly": false, "cmd": "tt Tpt3low/excitation", "description": "excitation with unit, i.e. 2uV or 3pA"},
|
||||
{"path": "Tpt3low/excitation_num", "type": "int"},
|
||||
{"path": "Tpt3low/excitation_mode", "type": "enum", "enum": {"voltage": 0, "current": 1, "off": 2}},
|
||||
{"path": "Tpt3low/pause", "type": "int", "readonly": false, "cmd": "tt Tpt3low/pause", "description": "pause time [sec] after channel change"},
|
||||
{"path": "Tpt3low/filter", "type": "int", "readonly": false, "cmd": "tt Tpt3low/filter", "description": "filter average time [sec]"},
|
||||
{"path": "Tpt3low/dwell", "type": "int", "readonly": false, "cmd": "tt Tpt3low/dwell", "description": "dwell time [sec]. Total time per channel: pause + filter + dwell"},
|
||||
{"path": "Tpt3low/status", "type": "text"},
|
||||
{"path": "Tpt3low/curve", "type": "text", "readonly": false, "cmd": "tt Tpt3low/curve", "kids": 1},
|
||||
{"path": "Tpt3low/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tt Tpt3low/curve/points", "visibility": 3},
|
||||
{"path": "Tpt3low/alarm", "type": "float", "readonly": false, "cmd": "tt Tpt3low/alarm"},
|
||||
{"path": "Tpt3low/raw", "type": "float"},
|
||||
{"path": "Twhite", "type": "float", "kids": 14},
|
||||
{"path": "Twhite/active", "type": "enum", "enum": {"inactive": 0, "active": 1}, "readonly": false, "cmd": "tt Twhite/active"},
|
||||
{"path": "Twhite/autorange", "type": "bool", "readonly": false, "cmd": "tt Twhite/autorange", "description": "autorange (common for all channels)"},
|
||||
{"path": "Twhite/range", "type": "text", "readonly": false, "cmd": "tt Twhite/range", "description": "resistance range in Ohm"},
|
||||
{"path": "Twhite/range_num", "type": "int"},
|
||||
{"path": "Twhite/excitation", "type": "text", "readonly": false, "cmd": "tt Twhite/excitation", "description": "excitation with unit, i.e. 2uV or 3pA"},
|
||||
{"path": "Twhite/excitation_num", "type": "int"},
|
||||
{"path": "Twhite/excitation_mode", "type": "enum", "enum": {"voltage": 0, "current": 1, "off": 2}},
|
||||
{"path": "Twhite/pause", "type": "int", "readonly": false, "cmd": "tt Twhite/pause", "description": "pause time [sec] after channel change"},
|
||||
{"path": "Twhite/filter", "type": "int", "readonly": false, "cmd": "tt Twhite/filter", "description": "filter average time [sec]"},
|
||||
{"path": "Twhite/dwell", "type": "int", "readonly": false, "cmd": "tt Twhite/dwell", "description": "dwell time [sec]. Total time per channel: pause + filter + dwell"},
|
||||
{"path": "Twhite/status", "type": "text"},
|
||||
{"path": "Twhite/curve", "type": "text", "readonly": false, "cmd": "tt Twhite/curve", "kids": 1},
|
||||
{"path": "Twhite/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tt Twhite/curve/points", "visibility": 3},
|
||||
{"path": "Twhite/alarm", "type": "float", "readonly": false, "cmd": "tt Twhite/alarm"},
|
||||
{"path": "Twhite/raw", "type": "float"},
|
||||
{"path": "Tgreen", "type": "float", "kids": 14},
|
||||
{"path": "Tgreen/active", "type": "enum", "enum": {"inactive": 0, "active": 1}, "readonly": false, "cmd": "tt Tgreen/active"},
|
||||
{"path": "Tgreen/autorange", "type": "bool", "readonly": false, "cmd": "tt Tgreen/autorange", "description": "autorange (common for all channels)"},
|
||||
{"path": "Tgreen/range", "type": "text", "readonly": false, "cmd": "tt Tgreen/range", "description": "resistance range in Ohm"},
|
||||
{"path": "Tgreen/range_num", "type": "int"},
|
||||
{"path": "Tgreen/excitation", "type": "text", "readonly": false, "cmd": "tt Tgreen/excitation", "description": "excitation with unit, i.e. 2uV or 3pA"},
|
||||
{"path": "Tgreen/excitation_num", "type": "int"},
|
||||
{"path": "Tgreen/excitation_mode", "type": "enum", "enum": {"voltage": 0, "current": 1, "off": 2}},
|
||||
{"path": "Tgreen/pause", "type": "int", "readonly": false, "cmd": "tt Tgreen/pause", "description": "pause time [sec] after channel change"},
|
||||
{"path": "Tgreen/filter", "type": "int", "readonly": false, "cmd": "tt Tgreen/filter", "description": "filter average time [sec]"},
|
||||
{"path": "Tgreen/dwell", "type": "int", "readonly": false, "cmd": "tt Tgreen/dwell", "description": "dwell time [sec]. Total time per channel: pause + filter + dwell"},
|
||||
{"path": "Tgreen/status", "type": "text"},
|
||||
{"path": "Tgreen/curve", "type": "text", "readonly": false, "cmd": "tt Tgreen/curve", "kids": 1},
|
||||
{"path": "Tgreen/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tt Tgreen/curve/points", "visibility": 3},
|
||||
{"path": "Tgreen/alarm", "type": "float", "readonly": false, "cmd": "tt Tgreen/alarm"},
|
||||
{"path": "Tgreen/raw", "type": "float"},
|
||||
{"path": "analog2", "type": "float", "readonly": false, "cmd": "tt analog2"},
|
||||
{"path": "remote", "type": "bool"},
|
||||
{"path": "display", "type": "text", "readonly": false, "cmd": "tt display"}]},
|
||||
|
||||
"cmn": {"base": "/cmn", "params": [
|
||||
{"path": "", "type": "none", "kids": 6},
|
||||
{"path": "send", "type": "text", "readonly": false, "cmd": "cmn send", "visibility": 3},
|
||||
{"path": "status", "type": "text", "visibility": 3},
|
||||
{"path": "u1", "type": "float"},
|
||||
{"path": "temp", "type": "float"},
|
||||
{"path": "u2", "type": "float"},
|
||||
{"path": "chan", "type": "enum", "enum": {"auto": 0, "chan1": 1, "chan2": 2}, "readonly": false, "cmd": "cmn chan"}]}}
|
||||
213
cfg/sea/leiden370.config.json
Normal file
213
cfg/sea/leiden370.config.json
Normal file
@@ -0,0 +1,213 @@
|
||||
{"tt": {"base": "/tt", "params": [
|
||||
{"path": "", "type": "int", "kids": 18},
|
||||
{"path": "send", "type": "text", "readonly": false, "cmd": "tt send", "visibility": 3},
|
||||
{"path": "status", "type": "text", "visibility": 3},
|
||||
{"path": "autoscan", "type": "bool", "readonly": false, "cmd": "tt autoscan", "kids": 4},
|
||||
{"path": "autoscan/synchronized", "type": "bool", "readonly": false, "cmd": "tt autoscan/synchronized"},
|
||||
{"path": "autoscan/interval", "type": "text", "readonly": false, "cmd": "tt autoscan/interval"},
|
||||
{"path": "autoscan/pause", "type": "text", "readonly": false, "cmd": "tt autoscan/pause"},
|
||||
{"path": "autoscan/dwell", "type": "text", "readonly": false, "cmd": "tt autoscan/dwell"},
|
||||
{"path": "T3K", "type": "float", "kids": 14},
|
||||
{"path": "T3K/active", "type": "enum", "enum": {"inactive": 0, "active": 1}, "readonly": false, "cmd": "tt T3K/active"},
|
||||
{"path": "T3K/autorange", "type": "bool", "readonly": false, "cmd": "tt T3K/autorange", "description": "autorange (common for all channels)"},
|
||||
{"path": "T3K/range", "type": "text", "readonly": false, "cmd": "tt T3K/range", "description": "resistance range in Ohm"},
|
||||
{"path": "T3K/range_num", "type": "int"},
|
||||
{"path": "T3K/excitation", "type": "text", "readonly": false, "cmd": "tt T3K/excitation", "description": "excitation with unit, i.e. 2uV or 3pA"},
|
||||
{"path": "T3K/excitation_num", "type": "int"},
|
||||
{"path": "T3K/excitation_mode", "type": "enum", "enum": {"voltage": 0, "current": 1, "off": 2}},
|
||||
{"path": "T3K/pause", "type": "int", "readonly": false, "cmd": "tt T3K/pause", "description": "pause time [sec] after channel change"},
|
||||
{"path": "T3K/filter", "type": "int", "readonly": false, "cmd": "tt T3K/filter", "description": "filter average time [sec]"},
|
||||
{"path": "T3K/dwell", "type": "int", "readonly": false, "cmd": "tt T3K/dwell", "description": "dwell time [sec]. Total time per channel: pause + filter + dwell"},
|
||||
{"path": "T3K/status", "type": "text"},
|
||||
{"path": "T3K/curve", "type": "text", "readonly": false, "cmd": "tt T3K/curve", "kids": 1},
|
||||
{"path": "T3K/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tt T3K/curve/points", "visibility": 3},
|
||||
{"path": "T3K/alarm", "type": "float", "readonly": false, "cmd": "tt T3K/alarm"},
|
||||
{"path": "T3K/raw", "type": "float"},
|
||||
{"path": "Tstill", "type": "float", "kids": 14},
|
||||
{"path": "Tstill/active", "type": "enum", "enum": {"inactive": 0, "active": 1}, "readonly": false, "cmd": "tt Tstill/active"},
|
||||
{"path": "Tstill/autorange", "type": "bool", "readonly": false, "cmd": "tt Tstill/autorange", "description": "autorange (common for all channels)"},
|
||||
{"path": "Tstill/range", "type": "text", "readonly": false, "cmd": "tt Tstill/range", "description": "resistance range in Ohm"},
|
||||
{"path": "Tstill/range_num", "type": "int"},
|
||||
{"path": "Tstill/excitation", "type": "text", "readonly": false, "cmd": "tt Tstill/excitation", "description": "excitation with unit, i.e. 2uV or 3pA"},
|
||||
{"path": "Tstill/excitation_num", "type": "int"},
|
||||
{"path": "Tstill/excitation_mode", "type": "enum", "enum": {"voltage": 0, "current": 1, "off": 2}},
|
||||
{"path": "Tstill/pause", "type": "int", "readonly": false, "cmd": "tt Tstill/pause", "description": "pause time [sec] after channel change"},
|
||||
{"path": "Tstill/filter", "type": "int", "readonly": false, "cmd": "tt Tstill/filter", "description": "filter average time [sec]"},
|
||||
{"path": "Tstill/dwell", "type": "int", "readonly": false, "cmd": "tt Tstill/dwell", "description": "dwell time [sec]. Total time per channel: pause + filter + dwell"},
|
||||
{"path": "Tstill/status", "type": "text"},
|
||||
{"path": "Tstill/curve", "type": "text", "readonly": false, "cmd": "tt Tstill/curve", "kids": 1},
|
||||
{"path": "Tstill/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tt Tstill/curve/points", "visibility": 3},
|
||||
{"path": "Tstill/alarm", "type": "float", "readonly": false, "cmd": "tt Tstill/alarm"},
|
||||
{"path": "Tstill/raw", "type": "float"},
|
||||
{"path": "T50mK", "type": "float", "kids": 14},
|
||||
{"path": "T50mK/active", "type": "enum", "enum": {"inactive": 0, "active": 1}, "readonly": false, "cmd": "tt T50mK/active"},
|
||||
{"path": "T50mK/autorange", "type": "bool", "readonly": false, "cmd": "tt T50mK/autorange", "description": "autorange (common for all channels)"},
|
||||
{"path": "T50mK/range", "type": "text", "readonly": false, "cmd": "tt T50mK/range", "description": "resistance range in Ohm"},
|
||||
{"path": "T50mK/range_num", "type": "int"},
|
||||
{"path": "T50mK/excitation", "type": "text", "readonly": false, "cmd": "tt T50mK/excitation", "description": "excitation with unit, i.e. 2uV or 3pA"},
|
||||
{"path": "T50mK/excitation_num", "type": "int"},
|
||||
{"path": "T50mK/excitation_mode", "type": "enum", "enum": {"voltage": 0, "current": 1, "off": 2}},
|
||||
{"path": "T50mK/pause", "type": "int", "readonly": false, "cmd": "tt T50mK/pause", "description": "pause time [sec] after channel change"},
|
||||
{"path": "T50mK/filter", "type": "int", "readonly": false, "cmd": "tt T50mK/filter", "description": "filter average time [sec]"},
|
||||
{"path": "T50mK/dwell", "type": "int", "readonly": false, "cmd": "tt T50mK/dwell", "description": "dwell time [sec]. Total time per channel: pause + filter + dwell"},
|
||||
{"path": "T50mK/status", "type": "text"},
|
||||
{"path": "T50mK/curve", "type": "text", "readonly": false, "cmd": "tt T50mK/curve", "kids": 1},
|
||||
{"path": "T50mK/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tt T50mK/curve/points", "visibility": 3},
|
||||
{"path": "T50mK/alarm", "type": "float", "readonly": false, "cmd": "tt T50mK/alarm"},
|
||||
{"path": "T50mK/raw", "type": "float"},
|
||||
{"path": "Tmxlow", "type": "float", "kids": 14},
|
||||
{"path": "Tmxlow/active", "type": "enum", "enum": {"inactive": 0, "active": 1}, "readonly": false, "cmd": "tt Tmxlow/active"},
|
||||
{"path": "Tmxlow/autorange", "type": "bool", "readonly": false, "cmd": "tt Tmxlow/autorange", "description": "autorange (common for all channels)"},
|
||||
{"path": "Tmxlow/range", "type": "text", "readonly": false, "cmd": "tt Tmxlow/range", "description": "resistance range in Ohm"},
|
||||
{"path": "Tmxlow/range_num", "type": "int"},
|
||||
{"path": "Tmxlow/excitation", "type": "text", "readonly": false, "cmd": "tt Tmxlow/excitation", "description": "excitation with unit, i.e. 2uV or 3pA"},
|
||||
{"path": "Tmxlow/excitation_num", "type": "int"},
|
||||
{"path": "Tmxlow/excitation_mode", "type": "enum", "enum": {"voltage": 0, "current": 1, "off": 2}},
|
||||
{"path": "Tmxlow/pause", "type": "int", "readonly": false, "cmd": "tt Tmxlow/pause", "description": "pause time [sec] after channel change"},
|
||||
{"path": "Tmxlow/filter", "type": "int", "readonly": false, "cmd": "tt Tmxlow/filter", "description": "filter average time [sec]"},
|
||||
{"path": "Tmxlow/dwell", "type": "int", "readonly": false, "cmd": "tt Tmxlow/dwell", "description": "dwell time [sec]. Total time per channel: pause + filter + dwell"},
|
||||
{"path": "Tmxlow/status", "type": "text"},
|
||||
{"path": "Tmxlow/curve", "type": "text", "readonly": false, "cmd": "tt Tmxlow/curve", "kids": 1},
|
||||
{"path": "Tmxlow/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tt Tmxlow/curve/points", "visibility": 3},
|
||||
{"path": "Tmxlow/alarm", "type": "float", "readonly": false, "cmd": "tt Tmxlow/alarm"},
|
||||
{"path": "Tmxlow/raw", "type": "float"},
|
||||
{"path": "Tmxhigh", "type": "float", "kids": 14},
|
||||
{"path": "Tmxhigh/active", "type": "enum", "enum": {"inactive": 0, "active": 1}, "readonly": false, "cmd": "tt Tmxhigh/active"},
|
||||
{"path": "Tmxhigh/autorange", "type": "bool", "readonly": false, "cmd": "tt Tmxhigh/autorange", "description": "autorange (common for all channels)"},
|
||||
{"path": "Tmxhigh/range", "type": "text", "readonly": false, "cmd": "tt Tmxhigh/range", "description": "resistance range in Ohm"},
|
||||
{"path": "Tmxhigh/range_num", "type": "int"},
|
||||
{"path": "Tmxhigh/excitation", "type": "text", "readonly": false, "cmd": "tt Tmxhigh/excitation", "description": "excitation with unit, i.e. 2uV or 3pA"},
|
||||
{"path": "Tmxhigh/excitation_num", "type": "int"},
|
||||
{"path": "Tmxhigh/excitation_mode", "type": "enum", "enum": {"voltage": 0, "current": 1, "off": 2}},
|
||||
{"path": "Tmxhigh/pause", "type": "int", "readonly": false, "cmd": "tt Tmxhigh/pause", "description": "pause time [sec] after channel change"},
|
||||
{"path": "Tmxhigh/filter", "type": "int", "readonly": false, "cmd": "tt Tmxhigh/filter", "description": "filter average time [sec]"},
|
||||
{"path": "Tmxhigh/dwell", "type": "int", "readonly": false, "cmd": "tt Tmxhigh/dwell", "description": "dwell time [sec]. Total time per channel: pause + filter + dwell"},
|
||||
{"path": "Tmxhigh/status", "type": "text"},
|
||||
{"path": "Tmxhigh/curve", "type": "text", "readonly": false, "cmd": "tt Tmxhigh/curve", "kids": 1},
|
||||
{"path": "Tmxhigh/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tt Tmxhigh/curve/points", "visibility": 3},
|
||||
{"path": "Tmxhigh/alarm", "type": "float", "readonly": false, "cmd": "tt Tmxhigh/alarm"},
|
||||
{"path": "Tmxhigh/raw", "type": "float"},
|
||||
{"path": "Tmxcx", "type": "float", "kids": 14},
|
||||
{"path": "Tmxcx/active", "type": "enum", "enum": {"inactive": 0, "active": 1}, "readonly": false, "cmd": "tt Tmxcx/active"},
|
||||
{"path": "Tmxcx/autorange", "type": "bool", "readonly": false, "cmd": "tt Tmxcx/autorange", "description": "autorange (common for all channels)"},
|
||||
{"path": "Tmxcx/range", "type": "text", "readonly": false, "cmd": "tt Tmxcx/range", "description": "resistance range in Ohm"},
|
||||
{"path": "Tmxcx/range_num", "type": "int"},
|
||||
{"path": "Tmxcx/excitation", "type": "text", "readonly": false, "cmd": "tt Tmxcx/excitation", "description": "excitation with unit, i.e. 2uV or 3pA"},
|
||||
{"path": "Tmxcx/excitation_num", "type": "int"},
|
||||
{"path": "Tmxcx/excitation_mode", "type": "enum", "enum": {"voltage": 0, "current": 1, "off": 2}},
|
||||
{"path": "Tmxcx/pause", "type": "int", "readonly": false, "cmd": "tt Tmxcx/pause", "description": "pause time [sec] after channel change"},
|
||||
{"path": "Tmxcx/filter", "type": "int", "readonly": false, "cmd": "tt Tmxcx/filter", "description": "filter average time [sec]"},
|
||||
{"path": "Tmxcx/dwell", "type": "int", "readonly": false, "cmd": "tt Tmxcx/dwell", "description": "dwell time [sec]. Total time per channel: pause + filter + dwell"},
|
||||
{"path": "Tmxcx/status", "type": "text"},
|
||||
{"path": "Tmxcx/curve", "type": "text", "readonly": false, "cmd": "tt Tmxcx/curve", "kids": 1},
|
||||
{"path": "Tmxcx/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tt Tmxcx/curve/points", "visibility": 3},
|
||||
{"path": "Tmxcx/alarm", "type": "float", "readonly": false, "cmd": "tt Tmxcx/alarm"},
|
||||
{"path": "Tmxcx/raw", "type": "float"},
|
||||
{"path": "Tblueo", "type": "float", "kids": 14},
|
||||
{"path": "Tblueo/active", "type": "enum", "enum": {"inactive": 0, "active": 1}, "readonly": false, "cmd": "tt Tblueo/active"},
|
||||
{"path": "Tblueo/autorange", "type": "bool", "readonly": false, "cmd": "tt Tblueo/autorange", "description": "autorange (common for all channels)"},
|
||||
{"path": "Tblueo/range", "type": "text", "readonly": false, "cmd": "tt Tblueo/range", "description": "resistance range in Ohm"},
|
||||
{"path": "Tblueo/range_num", "type": "int"},
|
||||
{"path": "Tblueo/excitation", "type": "text", "readonly": false, "cmd": "tt Tblueo/excitation", "description": "excitation with unit, i.e. 2uV or 3pA"},
|
||||
{"path": "Tblueo/excitation_num", "type": "int"},
|
||||
{"path": "Tblueo/excitation_mode", "type": "enum", "enum": {"voltage": 0, "current": 1, "off": 2}},
|
||||
{"path": "Tblueo/pause", "type": "int", "readonly": false, "cmd": "tt Tblueo/pause", "description": "pause time [sec] after channel change"},
|
||||
{"path": "Tblueo/filter", "type": "int", "readonly": false, "cmd": "tt Tblueo/filter", "description": "filter average time [sec]"},
|
||||
{"path": "Tblueo/dwell", "type": "int", "readonly": false, "cmd": "tt Tblueo/dwell", "description": "dwell time [sec]. Total time per channel: pause + filter + dwell"},
|
||||
{"path": "Tblueo/status", "type": "text"},
|
||||
{"path": "Tblueo/curve", "type": "text", "readonly": false, "cmd": "tt Tblueo/curve", "kids": 1},
|
||||
{"path": "Tblueo/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tt Tblueo/curve/points", "visibility": 3},
|
||||
{"path": "Tblueo/alarm", "type": "float", "readonly": false, "cmd": "tt Tblueo/alarm"},
|
||||
{"path": "Tblueo/raw", "type": "float"},
|
||||
{"path": "Tpt50", "type": "float", "kids": 14},
|
||||
{"path": "Tpt50/active", "type": "enum", "enum": {"inactive": 0, "active": 1}, "readonly": false, "cmd": "tt Tpt50/active"},
|
||||
{"path": "Tpt50/autorange", "type": "bool", "readonly": false, "cmd": "tt Tpt50/autorange", "description": "autorange (common for all channels)"},
|
||||
{"path": "Tpt50/range", "type": "text", "readonly": false, "cmd": "tt Tpt50/range", "description": "resistance range in Ohm"},
|
||||
{"path": "Tpt50/range_num", "type": "int"},
|
||||
{"path": "Tpt50/excitation", "type": "text", "readonly": false, "cmd": "tt Tpt50/excitation", "description": "excitation with unit, i.e. 2uV or 3pA"},
|
||||
{"path": "Tpt50/excitation_num", "type": "int"},
|
||||
{"path": "Tpt50/excitation_mode", "type": "enum", "enum": {"voltage": 0, "current": 1, "off": 2}},
|
||||
{"path": "Tpt50/pause", "type": "int", "readonly": false, "cmd": "tt Tpt50/pause", "description": "pause time [sec] after channel change"},
|
||||
{"path": "Tpt50/filter", "type": "int", "readonly": false, "cmd": "tt Tpt50/filter", "description": "filter average time [sec]"},
|
||||
{"path": "Tpt50/dwell", "type": "int", "readonly": false, "cmd": "tt Tpt50/dwell", "description": "dwell time [sec]. Total time per channel: pause + filter + dwell"},
|
||||
{"path": "Tpt50/status", "type": "text"},
|
||||
{"path": "Tpt50/curve", "type": "text", "readonly": false, "cmd": "tt Tpt50/curve", "kids": 1},
|
||||
{"path": "Tpt50/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tt Tpt50/curve/points", "visibility": 3},
|
||||
{"path": "Tpt50/alarm", "type": "float", "readonly": false, "cmd": "tt Tpt50/alarm"},
|
||||
{"path": "Tpt50/raw", "type": "float"},
|
||||
{"path": "Tpt3high", "type": "float", "kids": 14},
|
||||
{"path": "Tpt3high/active", "type": "enum", "enum": {"inactive": 0, "active": 1}, "readonly": false, "cmd": "tt Tpt3high/active"},
|
||||
{"path": "Tpt3high/autorange", "type": "bool", "readonly": false, "cmd": "tt Tpt3high/autorange", "description": "autorange (common for all channels)"},
|
||||
{"path": "Tpt3high/range", "type": "text", "readonly": false, "cmd": "tt Tpt3high/range", "description": "resistance range in Ohm"},
|
||||
{"path": "Tpt3high/range_num", "type": "int"},
|
||||
{"path": "Tpt3high/excitation", "type": "text", "readonly": false, "cmd": "tt Tpt3high/excitation", "description": "excitation with unit, i.e. 2uV or 3pA"},
|
||||
{"path": "Tpt3high/excitation_num", "type": "int"},
|
||||
{"path": "Tpt3high/excitation_mode", "type": "enum", "enum": {"voltage": 0, "current": 1, "off": 2}},
|
||||
{"path": "Tpt3high/pause", "type": "int", "readonly": false, "cmd": "tt Tpt3high/pause", "description": "pause time [sec] after channel change"},
|
||||
{"path": "Tpt3high/filter", "type": "int", "readonly": false, "cmd": "tt Tpt3high/filter", "description": "filter average time [sec]"},
|
||||
{"path": "Tpt3high/dwell", "type": "int", "readonly": false, "cmd": "tt Tpt3high/dwell", "description": "dwell time [sec]. Total time per channel: pause + filter + dwell"},
|
||||
{"path": "Tpt3high/status", "type": "text"},
|
||||
{"path": "Tpt3high/curve", "type": "text", "readonly": false, "cmd": "tt Tpt3high/curve", "kids": 1},
|
||||
{"path": "Tpt3high/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tt Tpt3high/curve/points", "visibility": 3},
|
||||
{"path": "Tpt3high/alarm", "type": "float", "readonly": false, "cmd": "tt Tpt3high/alarm"},
|
||||
{"path": "Tpt3high/raw", "type": "float"},
|
||||
{"path": "Tpt3low", "type": "float", "kids": 14},
|
||||
{"path": "Tpt3low/active", "type": "enum", "enum": {"inactive": 0, "active": 1}, "readonly": false, "cmd": "tt Tpt3low/active"},
|
||||
{"path": "Tpt3low/autorange", "type": "bool", "readonly": false, "cmd": "tt Tpt3low/autorange", "description": "autorange (common for all channels)"},
|
||||
{"path": "Tpt3low/range", "type": "text", "readonly": false, "cmd": "tt Tpt3low/range", "description": "resistance range in Ohm"},
|
||||
{"path": "Tpt3low/range_num", "type": "int"},
|
||||
{"path": "Tpt3low/excitation", "type": "text", "readonly": false, "cmd": "tt Tpt3low/excitation", "description": "excitation with unit, i.e. 2uV or 3pA"},
|
||||
{"path": "Tpt3low/excitation_num", "type": "int"},
|
||||
{"path": "Tpt3low/excitation_mode", "type": "enum", "enum": {"voltage": 0, "current": 1, "off": 2}},
|
||||
{"path": "Tpt3low/pause", "type": "int", "readonly": false, "cmd": "tt Tpt3low/pause", "description": "pause time [sec] after channel change"},
|
||||
{"path": "Tpt3low/filter", "type": "int", "readonly": false, "cmd": "tt Tpt3low/filter", "description": "filter average time [sec]"},
|
||||
{"path": "Tpt3low/dwell", "type": "int", "readonly": false, "cmd": "tt Tpt3low/dwell", "description": "dwell time [sec]. Total time per channel: pause + filter + dwell"},
|
||||
{"path": "Tpt3low/status", "type": "text"},
|
||||
{"path": "Tpt3low/curve", "type": "text", "readonly": false, "cmd": "tt Tpt3low/curve", "kids": 1},
|
||||
{"path": "Tpt3low/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tt Tpt3low/curve/points", "visibility": 3},
|
||||
{"path": "Tpt3low/alarm", "type": "float", "readonly": false, "cmd": "tt Tpt3low/alarm"},
|
||||
{"path": "Tpt3low/raw", "type": "float"},
|
||||
{"path": "Twhite", "type": "float", "kids": 14},
|
||||
{"path": "Twhite/active", "type": "enum", "enum": {"inactive": 0, "active": 1}, "readonly": false, "cmd": "tt Twhite/active"},
|
||||
{"path": "Twhite/autorange", "type": "bool", "readonly": false, "cmd": "tt Twhite/autorange", "description": "autorange (common for all channels)"},
|
||||
{"path": "Twhite/range", "type": "text", "readonly": false, "cmd": "tt Twhite/range", "description": "resistance range in Ohm"},
|
||||
{"path": "Twhite/range_num", "type": "int"},
|
||||
{"path": "Twhite/excitation", "type": "text", "readonly": false, "cmd": "tt Twhite/excitation", "description": "excitation with unit, i.e. 2uV or 3pA"},
|
||||
{"path": "Twhite/excitation_num", "type": "int"},
|
||||
{"path": "Twhite/excitation_mode", "type": "enum", "enum": {"voltage": 0, "current": 1, "off": 2}},
|
||||
{"path": "Twhite/pause", "type": "int", "readonly": false, "cmd": "tt Twhite/pause", "description": "pause time [sec] after channel change"},
|
||||
{"path": "Twhite/filter", "type": "int", "readonly": false, "cmd": "tt Twhite/filter", "description": "filter average time [sec]"},
|
||||
{"path": "Twhite/dwell", "type": "int", "readonly": false, "cmd": "tt Twhite/dwell", "description": "dwell time [sec]. Total time per channel: pause + filter + dwell"},
|
||||
{"path": "Twhite/status", "type": "text"},
|
||||
{"path": "Twhite/curve", "type": "text", "readonly": false, "cmd": "tt Twhite/curve", "kids": 1},
|
||||
{"path": "Twhite/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tt Twhite/curve/points", "visibility": 3},
|
||||
{"path": "Twhite/alarm", "type": "float", "readonly": false, "cmd": "tt Twhite/alarm"},
|
||||
{"path": "Twhite/raw", "type": "float"},
|
||||
{"path": "Tgreen", "type": "float", "kids": 14},
|
||||
{"path": "Tgreen/active", "type": "enum", "enum": {"inactive": 0, "active": 1}, "readonly": false, "cmd": "tt Tgreen/active"},
|
||||
{"path": "Tgreen/autorange", "type": "bool", "readonly": false, "cmd": "tt Tgreen/autorange", "description": "autorange (common for all channels)"},
|
||||
{"path": "Tgreen/range", "type": "text", "readonly": false, "cmd": "tt Tgreen/range", "description": "resistance range in Ohm"},
|
||||
{"path": "Tgreen/range_num", "type": "int"},
|
||||
{"path": "Tgreen/excitation", "type": "text", "readonly": false, "cmd": "tt Tgreen/excitation", "description": "excitation with unit, i.e. 2uV or 3pA"},
|
||||
{"path": "Tgreen/excitation_num", "type": "int"},
|
||||
{"path": "Tgreen/excitation_mode", "type": "enum", "enum": {"voltage": 0, "current": 1, "off": 2}},
|
||||
{"path": "Tgreen/pause", "type": "int", "readonly": false, "cmd": "tt Tgreen/pause", "description": "pause time [sec] after channel change"},
|
||||
{"path": "Tgreen/filter", "type": "int", "readonly": false, "cmd": "tt Tgreen/filter", "description": "filter average time [sec]"},
|
||||
{"path": "Tgreen/dwell", "type": "int", "readonly": false, "cmd": "tt Tgreen/dwell", "description": "dwell time [sec]. Total time per channel: pause + filter + dwell"},
|
||||
{"path": "Tgreen/status", "type": "text"},
|
||||
{"path": "Tgreen/curve", "type": "text", "readonly": false, "cmd": "tt Tgreen/curve", "kids": 1},
|
||||
{"path": "Tgreen/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tt Tgreen/curve/points", "visibility": 3},
|
||||
{"path": "Tgreen/alarm", "type": "float", "readonly": false, "cmd": "tt Tgreen/alarm"},
|
||||
{"path": "Tgreen/raw", "type": "float"},
|
||||
{"path": "analog2", "type": "float", "readonly": false, "cmd": "tt analog2"},
|
||||
{"path": "remote", "type": "bool"},
|
||||
{"path": "display", "type": "text", "readonly": false, "cmd": "tt display"}]},
|
||||
|
||||
"cmn": {"base": "/cmn", "params": [
|
||||
{"path": "", "type": "none", "kids": 6},
|
||||
{"path": "send", "type": "text", "readonly": false, "cmd": "cmn send", "visibility": 3},
|
||||
{"path": "status", "type": "text", "visibility": 3},
|
||||
{"path": "u1", "type": "float"},
|
||||
{"path": "temp", "type": "float"},
|
||||
{"path": "u2", "type": "float"},
|
||||
{"path": "chan", "type": "enum", "enum": {"auto": 0, "chan1": 1, "chan2": 2}, "readonly": false, "cmd": "cmn chan"}]}}
|
||||
@@ -284,8 +284,8 @@
|
||||
{"path": "eeprom", "type": "enum", "enum": {"ok": 0, "dirty": 1, "save": 2, "load": 3}, "readonly": false, "cmd": "hemot eeprom"},
|
||||
{"path": "customadr", "type": "text", "readonly": false, "cmd": "hemot customadr"},
|
||||
{"path": "custompar", "type": "float", "readonly": false, "cmd": "hemot custompar"}]},
|
||||
"
|
||||
ln2fill": {"base": "/ln2fill", "params": [
|
||||
|
||||
"ln2fill": {"base": "/ln2fill", "params": [
|
||||
{"path": "", "type": "enum", "enum": {"watching": 0, "fill": 1, "inactive": 2}, "readonly": false, "cmd": "ln2fill", "kids": 14},
|
||||
{"path": "send", "type": "text", "readonly": false, "cmd": "ln2fill send", "visibility": 3},
|
||||
{"path": "status", "type": "text", "visibility": 3},
|
||||
|
||||
@@ -1,50 +1,50 @@
|
||||
{"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", "readonly": false, "cmd": "run tt", "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", "readonly": false, "cmd": "run tt"},
|
||||
{"path": "running", "type": "int", "readonly": false, "cmd": "run tt"},
|
||||
{"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", "readonly": false, "cmd": "run tt", "visibility": 3},
|
||||
{"path": "log/m2", "type": "float", "readonly": false, "cmd": "run tt", "visibility": 3},
|
||||
{"path": "log/stddev", "type": "float", "readonly": false, "cmd": "run tt", "visibility": 3},
|
||||
{"path": "log/n", "type": "float", "readonly": false, "cmd": "run tt", "visibility": 3},
|
||||
{"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", "readonly": false, "cmd": "run tt"},
|
||||
{"path": "dblctrl/shift_lo", "type": "float", "readonly": false, "cmd": "run tt"},
|
||||
{"path": "dblctrl/t_min", "type": "float", "readonly": false, "cmd": "run tt"},
|
||||
{"path": "dblctrl/t_max", "type": "float", "readonly": false, "cmd": "run tt"},
|
||||
{"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", "readonly": false, "cmd": "run tt", "kids": 4},
|
||||
{"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", "readonly": false, "cmd": "run tt"},
|
||||
{"path": "tm/raw", "type": "float", "readonly": false, "cmd": "run tt"},
|
||||
{"path": "ts", "type": "float", "readonly": false, "cmd": "run tt", "kids": 4},
|
||||
{"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", "readonly": false, "cmd": "run tt"},
|
||||
{"path": "ts/raw", "type": "float", "readonly": false, "cmd": "run tt"},
|
||||
{"path": "ts_2", "type": "float", "readonly": false, "cmd": "run tt", "kids": 4},
|
||||
{"path": "ts_2/curve", "type": "text", "readonly": false, "cmd": "tt ts_2/curve", "kids": 1},
|
||||
{"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"},
|
||||
{"path": "ts_2/stddev", "type": "float", "readonly": false, "cmd": "run tt"},
|
||||
{"path": "ts_2/raw", "type": "float", "readonly": false, "cmd": "run tt"},
|
||||
{"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", "readonly": false, "cmd": "run tt"},
|
||||
{"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)"},
|
||||
@@ -53,17 +53,17 @@
|
||||
{"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", "readonly": false, "cmd": "run tt", "description": "the maximum power limit (before any booster or converter)"},
|
||||
{"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", "readonly": false, "cmd": "run tt", "description": "the maximum current before any booster or converter"},
|
||||
{"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", "readonly": false, "cmd": "run tt"},
|
||||
{"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", "readonly": false, "cmd": "run tt"},
|
||||
{"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)"},
|
||||
@@ -72,16 +72,16 @@
|
||||
{"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", "readonly": false, "cmd": "run tt", "description": "the maximum power limit (before any booster or converter)"},
|
||||
{"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", "readonly": false, "cmd": "run tt", "description": "the maximum current before any booster or converter"},
|
||||
{"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", "readonly": false, "cmd": "run tt"},
|
||||
{"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", "readonly": false, "cmd": "run tt"}]},
|
||||
{"path": "remote", "type": "bool"}]},
|
||||
|
||||
"cc": {"base": "/cc", "params": [
|
||||
{"path": "", "type": "bool", "kids": 96},
|
||||
@@ -108,7 +108,7 @@
|
||||
{"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": "enum", "type": "enum", "enum": {"none": 0, "int": 1, "ext": 2}, "readonly": false, "cmd": "cc hav"},
|
||||
{"path": "hav", "type": "enum", "enum": {"none": 0, "int": 1, "ext": 2}, "readonly": false, "cmd": "cc hav"},
|
||||
{"path": "h", "type": "float"},
|
||||
{"path": "hr", "type": "float"},
|
||||
{"path": "hc", "type": "float"},
|
||||
@@ -132,26 +132,26 @@
|
||||
{"path": "hms", "type": "float"},
|
||||
{"path": "hit", "type": "float", "readonly": false, "cmd": "cc hit"},
|
||||
{"path": "hft", "type": "int", "readonly": false, "cmd": "cc hft"},
|
||||
{"path": "hea", "type": "enum", "enum": {"0": 0, "1": 1, "6": 2}, "readonly": false, "cmd": "cc hea"},
|
||||
{"path": "hch", "type": "int", "readonly": false, "cmd": "cc hch", "visibility": 3},
|
||||
{"path": "hwr0", "type": "float", "readonly": false, "cmd": "cc hwr0", "visibility": 3},
|
||||
{"path": "hem0", "type": "float", "readonly": false, "cmd": "cc hem0", "description": "sensor length in mm from top to empty pos.", "visibility": 3},
|
||||
{"path": "hfu0", "type": "float", "readonly": false, "cmd": "cc hfu0", "description": "sensor length in mm from top to full pos.", "visibility": 3},
|
||||
{"path": "hd0", "type": "float", "readonly": false, "cmd": "cc hd0", "description": "external sensor drive current (mA)", "visibility": 3},
|
||||
{"path": "h0", "type": "float", "visibility": 3},
|
||||
{"path": "hs0", "type": "enum", "enum": {"sens_ok": 0, "sens_warm": 1, "no_sens": 2, "timeout": 3, "not_yet_read": 4, "disabled": 5}, "visibility": 3},
|
||||
{"path": "h1", "type": "float", "visibility": 3},
|
||||
{"path": "hs1", "type": "enum", "enum": {"sens_ok": 0, "sens_warm": 1, "no_sens": 2, "timeout": 3, "not_yet_read": 4, "disabled": 5}, "visibility": 3},
|
||||
{"path": "h2", "type": "float", "visibility": 3},
|
||||
{"path": "hs2", "type": "enum", "enum": {"sens_ok": 0, "sens_warm": 1, "no_sens": 2, "timeout": 3, "not_yet_read": 4, "disabled": 5}, "visibility": 3},
|
||||
{"path": "h3", "type": "float", "visibility": 3},
|
||||
{"path": "hs3", "type": "enum", "enum": {"sens_ok": 0, "sens_warm": 1, "no_sens": 2, "timeout": 3, "not_yet_read": 4, "disabled": 5}, "visibility": 3},
|
||||
{"path": "h4", "type": "float", "visibility": 3},
|
||||
{"path": "hs4", "type": "enum", "enum": {"sens_ok": 0, "sens_warm": 1, "no_sens": 2, "timeout": 3, "not_yet_read": 4, "disabled": 5}, "visibility": 3},
|
||||
{"path": "h5", "type": "float", "visibility": 3},
|
||||
{"path": "hs5", "type": "enum", "enum": {"sens_ok": 0, "sens_warm": 1, "no_sens": 2, "timeout": 3, "not_yet_read": 4, "disabled": 5}, "visibility": 3},
|
||||
{"path": "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": "enum", "type": "enum", "enum": {"none": 0, "int": 1, "ext": 2}, "readonly": false, "cmd": "cc nav"},
|
||||
{"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"},
|
||||
@@ -183,15 +183,16 @@
|
||||
{"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": "", "type": "enum", "enum": {"fixed": 0, "controlled": 1, "automatic": 2, "close": 3, "open": 4}, "readonly": false, "cmd": "nv", "kids": 12},
|
||||
{"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": "flowp", "type": "float", "description": "flow calculated from pressure before pump"},
|
||||
{"path": "span", "type": "float"},
|
||||
{"path": "use_pressure", "type": "bool", "readonly": false, "cmd": "nv use_pressure", "description": "use pressure instead of flow meter for control"},
|
||||
{"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"},
|
||||
@@ -235,15 +236,34 @@
|
||||
{"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": "readpath", "type": "text", "readonly": false, "cmd": "hefill readpath", "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": "eco", "type": "bool", "readonly": false, "cmd": "hepump eco", "visibility": 3},
|
||||
{"path": "auto", "type": "bool", "readonly": false, "cmd": "hepump auto", "visibility": 3},
|
||||
{"path": "valve", "type": "enum", "enum": {"closed": 0, "closing": 1, "opening": 2, "opened": 3, "undefined": 4}, "readonly": false, "cmd": "hepump valve"},
|
||||
{"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": "eco_t_lim", "type": "float", "readonly": false, "cmd": "hepump eco_t_lim", "description": "switch off eco mode when T_set < eco_t_lim and T < eco_t_lim * 2", "visibility": 3},
|
||||
{"path": "calib", "type": "float", "readonly": false, "cmd": "hepump calib", "visibility": 3},
|
||||
{"path": "health", "type": "float"}]},
|
||||
|
||||
@@ -291,11 +311,11 @@
|
||||
{"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, "fill": 1, "inactive": 2}, "readonly": false, "cmd": "ln2fill", "kids": 14},
|
||||
{"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": "readpath", "type": "text", "readonly": false, "cmd": "ln2fill readpath", "visibility": 3},
|
||||
{"path": "lowlevel", "type": "float", "readonly": false, "cmd": "ln2fill lowlevel"},
|
||||
{"path": "highlevel", "type": "float", "readonly": false, "cmd": "ln2fill highlevel"},
|
||||
{"path": "smooth", "type": "float"},
|
||||
@@ -307,52 +327,33 @@
|
||||
{"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, "fill": 1, "inactive": 2}, "readonly": false, "cmd": "hefill", "kids": 16},
|
||||
{"path": "send", "type": "text", "readonly": false, "cmd": "hefill send", "visibility": 3},
|
||||
{"path": "status", "type": "text", "visibility": 3},
|
||||
{"path": "state", "type": "text"},
|
||||
{"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"}]},
|
||||
|
||||
"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", "readonly": false, "cmd": "run mf"},
|
||||
{"path": "perswitch", "type": "int"},
|
||||
{"path": "nowait", "type": "int", "readonly": false, "cmd": "mf nowait"},
|
||||
{"path": "maxlimit", "type": "float", "readonly": false, "cmd": "run mf", "visibility": 3},
|
||||
{"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", "readonly": false, "cmd": "run mf"},
|
||||
{"path": "measured", "type": "float", "readonly": false, "cmd": "run mf"},
|
||||
{"path": "voltage", "type": "float", "readonly": false, "cmd": "run mf"},
|
||||
{"path": "lastfield", "type": "float", "readonly": false, "cmd": "run mf", "visibility": 3},
|
||||
{"path": "ampRamp", "type": "float", "readonly": false, "cmd": "run mf", "visibility": 3},
|
||||
{"path": "inductance", "type": "float", "readonly": false, "cmd": "run mf", "visibility": 3},
|
||||
{"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", "readonly": false, "cmd": "run mf"},
|
||||
{"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": "run mf", "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", "readonly": false, "cmd": "run mf", "visibility": 3},
|
||||
{"path": "creationCmd", "type": "text", "readonly": false, "cmd": "run mf", "visibility": 3},
|
||||
{"path": "targetValue", "type": "float", "readonly": false, "cmd": "run mf"},
|
||||
{"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": [
|
||||
@@ -362,7 +363,22 @@
|
||||
{"path": "mode", "type": "enum", "enum": {"slow": 0, "fast (switches to slow automatically after filling)": 1}, "readonly": false, "cmd": "lev mode"},
|
||||
{"path": "n2", "type": "float"}]},
|
||||
|
||||
"prep0": {"base": "/prep0", "params": [
|
||||
{"path": "", "type": "text", "readonly": false, "cmd": "prep0", "kids": 2},
|
||||
{"path": "send", "type": "text", "readonly": false, "cmd": "prep0 send", "visibility": 3},
|
||||
{"path": "status", "type": "text", "visibility": 3}]}}
|
||||
"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 ..."}]}}
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
# pylint: skip-file
|
||||
Node('ccr12',
|
||||
'[sim] CCR12 box of MLZ Sample environment group'
|
||||
''
|
||||
'Contains a Lakeshore 336 and an PLC controlling the compressor'
|
||||
'and some valves.'
|
||||
''
|
||||
'This is an improved version, how we think it should be.',
|
||||
'[sim] CCR12 box of MLZ Sample environment group\n'
|
||||
'\n'
|
||||
'Contains a Lakeshore 336 and an PLC controlling the compressor\n'
|
||||
'and some valves.\n'
|
||||
'\n'
|
||||
'This is an improved version, how we think it should be.\n',
|
||||
'tcp://10767',
|
||||
)
|
||||
|
||||
Mod('T_ccr12',
|
||||
'frappy.simulation.SimDrivable',
|
||||
'Main temperature control node of CCR12.'
|
||||
''
|
||||
'Switches between regulation on stick and regulation on tube depending on temperature requested.'
|
||||
'May also pump gas for higher temperatures, if configured.'
|
||||
'Main temperature control node of CCR12.\n'
|
||||
'\n'
|
||||
'Switches between regulation on stick and regulation on tube depending on temperature requested.\n'
|
||||
'May also pump gas for higher temperatures, if configured.\n'
|
||||
'Manual switching of the regulation node is supported via the regulationmode parameter.',
|
||||
value = Param(default=300,
|
||||
datatype={"type":"double", "min":0, "max":600, "unit":"K"}),
|
||||
|
||||
@@ -54,7 +54,7 @@ Mod('T',
|
||||
'frappy_psi.softcal.Sensor',
|
||||
'temperature sensor, soft calibration',
|
||||
rawsensor='res',
|
||||
calib='X132254',
|
||||
calcurve='X132254',
|
||||
value=Param(
|
||||
unit='K',
|
||||
),
|
||||
|
||||
@@ -16,5 +16,5 @@ Mod('T2',
|
||||
'',
|
||||
value = Param(unit = 'K'),
|
||||
rawsensor = 'r2',
|
||||
calib = 'X131346',
|
||||
calcurve = 'X131346',
|
||||
)
|
||||
|
||||
@@ -43,5 +43,5 @@ Mod('ts',
|
||||
'calibrated value for ts',
|
||||
value = Param(unit = 'K'),
|
||||
rawsensor = 'tsraw',
|
||||
calib = 'X133834',
|
||||
calcurve = 'X133834',
|
||||
)
|
||||
|
||||
@@ -38,6 +38,6 @@ Mod('T_sample',
|
||||
output_module='htr_sample',
|
||||
p=1,
|
||||
i=0.01,
|
||||
calib='X161269',
|
||||
calcurve='X161269',
|
||||
value=Param(unit='K'),
|
||||
)
|
||||
|
||||
@@ -9,10 +9,23 @@ Mod('sea_stick',
|
||||
service='stick',
|
||||
)
|
||||
|
||||
Mod('ts',
|
||||
'frappy_psi.sea.SeaReadable', '',
|
||||
meaning=['temperature', 30],
|
||||
Mod('ts_sea',
|
||||
'frappy_psi.sea.SeaReadable',
|
||||
'readable sample stick T',
|
||||
io='sea_stick',
|
||||
sea_path='tt/ts',
|
||||
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',
|
||||
read='ts_sea.value',
|
||||
write='ts_sea.setsamp',
|
||||
meaning=['temperature', 20],
|
||||
settling_time=20,
|
||||
tolerance=1,
|
||||
)
|
||||
|
||||
|
||||
@@ -1,3 +1,33 @@
|
||||
import os
|
||||
|
||||
Node('mb11.stick.sea.psi.ch',
|
||||
'MB11 standard sample stick (do not use)',
|
||||
)
|
||||
|
||||
frappy_main_port = os.environ.get('FRAPPY_MAIN_PORT', 0)
|
||||
|
||||
Mod('itc1_',
|
||||
'frappy.core.Proxy',
|
||||
'itc1 on main frappy server',
|
||||
remote_class = 'frappy_psi.mercury.IO',
|
||||
uri = f'tcp://localhost:{frappy_main_port}',
|
||||
module='itc1',
|
||||
# export = False,
|
||||
)
|
||||
|
||||
|
||||
Mod('T_sample',
|
||||
'frappy_psi.mercury.TemperatureLoop',
|
||||
'T at sample stick sensor',
|
||||
meaning=['temperature', 30],
|
||||
io='itc1_',
|
||||
slot='MB1.T1',
|
||||
)
|
||||
|
||||
Mod('htr_sample',
|
||||
'frappy_psi.mercury.HeaterOutput',
|
||||
'sample stick heater power',
|
||||
slot='MB0.H1',
|
||||
io='itc1_',
|
||||
)
|
||||
|
||||
|
||||
34
cfg/stick/msparestick_cfg.py
Normal file
34
cfg/stick/msparestick_cfg.py
Normal file
@@ -0,0 +1,34 @@
|
||||
Node('mspare.stick.sea.psi.ch',
|
||||
'MA generic sample stick',
|
||||
)
|
||||
|
||||
Mod('sea_stick',
|
||||
'frappy_psi.sea.SeaClient',
|
||||
'SEA stick connection',
|
||||
config='mspare.stick',
|
||||
service='stick',
|
||||
)
|
||||
|
||||
Mod('ts',
|
||||
'frappy_psi.sea.SeaReadable',
|
||||
'sample stick temperature',
|
||||
io='sea_stick',
|
||||
json_file='ma6.config.json',
|
||||
sea_object='tt',
|
||||
rel_paths=['ts', 'setsamp'],
|
||||
meaning=['temperature', 30],
|
||||
)
|
||||
|
||||
|
||||
"""
|
||||
Mod('ts',
|
||||
'frappy_psi.parmod.Converging',
|
||||
'drivable stick T using setsamp',
|
||||
meaning=['temperature', 25],
|
||||
unit='K',
|
||||
read='tsam.value',
|
||||
write='tsam.setsamp',
|
||||
settling_time=20,
|
||||
tolerance=1,
|
||||
)
|
||||
"""
|
||||
24
cfg/tcs_cfg.py
Normal file
24
cfg/tcs_cfg.py
Normal file
@@ -0,0 +1,24 @@
|
||||
Node('tcstest.psi.ch',
|
||||
'heater tcs test',
|
||||
'tcp://5000',
|
||||
)
|
||||
|
||||
Mod('io',
|
||||
'frappy_psi.tcs.IO',
|
||||
'tcs communication',
|
||||
uri='linse-leiden-ts:3005',
|
||||
)
|
||||
|
||||
Mod('still_htr',
|
||||
'frappy_psi.tcs.Heater',
|
||||
'still heater',
|
||||
io='io',
|
||||
channel=2,
|
||||
)
|
||||
|
||||
Mod('mix_htr',
|
||||
'frappy_psi.tcs.Heater',
|
||||
'mixing chamber heater',
|
||||
io='io',
|
||||
channel=3,
|
||||
)
|
||||
15
cfg/test_function_cfg.py
Normal file
15
cfg/test_function_cfg.py
Normal file
@@ -0,0 +1,15 @@
|
||||
Node('softcal.function.test',
|
||||
'test the function class',
|
||||
'tcp://5000',
|
||||
)
|
||||
|
||||
Mod('sim_writable',
|
||||
'frappy_demo.test.SimpleWritable',
|
||||
'simulation of a writable for function test',
|
||||
)
|
||||
|
||||
Mod('function',
|
||||
'frappy_psi.softcal.Function',
|
||||
'function test',
|
||||
rawsensor = 'sim_writable',
|
||||
)
|
||||
81
cfg/thermofischer_cfg.py
Normal file
81
cfg/thermofischer_cfg.py
Normal file
@@ -0,0 +1,81 @@
|
||||
Node('thermofischer.psi.ch',
|
||||
'thermofischer_waterbath',
|
||||
'tcp://5000',
|
||||
)
|
||||
|
||||
Mod('wio_1',
|
||||
'frappy_psi.thermofisher.ThermFishIO',
|
||||
'connection for water bath',
|
||||
uri='serial:///dev/ttyUSB0?baudrate=19200', # 3001 = Port 1, 3002 = Port 2 ...
|
||||
)
|
||||
|
||||
Mod('wio_2',
|
||||
'frappy_psi.thermofisher.ThermFishIO',
|
||||
'connection for water bath',
|
||||
uri='serial:///dev/ttyUSB1?baudrate=19200', # 3001 = Port 1, 3002 = Port 2 ...
|
||||
)
|
||||
|
||||
Mod('wio_3',
|
||||
'frappy_psi.thermofisher.ThermFishIO',
|
||||
'connection for water bath',
|
||||
uri='serial:///dev/ttyUSB2?baudrate=19200', # 3001 = Port 1, 3002 = Port 2 ...
|
||||
)
|
||||
|
||||
Mod('Tbath_1',
|
||||
'frappy_psi.thermofisher.TemperatureLoopA10',
|
||||
'water_bath_1',
|
||||
io='wio_1',
|
||||
control_active=0,
|
||||
target=25,
|
||||
tolerance=0.1,
|
||||
settling_time=20,
|
||||
)
|
||||
|
||||
Mod('Tbath_2',
|
||||
'frappy_psi.thermofisher.TemperatureLoopA10',
|
||||
'water_bath_2',
|
||||
io='wio_2',
|
||||
control_active=0,
|
||||
target=25,
|
||||
tolerance=0.1,
|
||||
settling_time=20,
|
||||
)
|
||||
|
||||
Mod('Tbath_3',
|
||||
'frappy_psi.thermofisher.TemperatureLoopA10',
|
||||
'water_bath_3',
|
||||
io='wio_3',
|
||||
control_active=0,
|
||||
target=25,
|
||||
tolerance=0.1,
|
||||
settling_time=20,
|
||||
)
|
||||
|
||||
Mod('valve_1',
|
||||
'frappy_psi.ionopimax.DigitalOutput',
|
||||
'valve_for_fast_water_temperature_changing',
|
||||
addr = 'o1',
|
||||
target = 0,
|
||||
)
|
||||
|
||||
Mod('valve_2',
|
||||
'frappy_psi.ionopimax.DigitalOutput',
|
||||
'valve_for_fast_water_temperature_changing',
|
||||
addr = 'o2',
|
||||
target = 0,
|
||||
)
|
||||
|
||||
Mod('valve_3',
|
||||
'frappy_psi.ionopimax.DigitalOutput',
|
||||
'valve_for_fast_water_temperature_changing',
|
||||
addr = 'o3',
|
||||
target = 0,
|
||||
)
|
||||
|
||||
Mod('temp_sensor_1',
|
||||
'frappy_psi.ionopimax.SimpleVoltageInput',
|
||||
'temperatur_sensor_sample',
|
||||
rawrange = (0.0, 10.0),
|
||||
valuerange = (-40.0, 150.0),
|
||||
addr = 'ai1_mv',
|
||||
)
|
||||
@@ -52,7 +52,7 @@ Mod('T',
|
||||
'frappy_psi.softcal.Sensor',
|
||||
'sample T',
|
||||
rawsensor='res',
|
||||
calib='X132254',
|
||||
calcurve='X132254',
|
||||
value=Param(
|
||||
unit='K',
|
||||
),
|
||||
|
||||
17
debian/changelog
vendored
17
debian/changelog
vendored
@@ -1,3 +1,20 @@
|
||||
frappy-core (0.20.7) stable; urgency=medium
|
||||
|
||||
* fix debian install
|
||||
|
||||
-- Georg Brandl <jenkins@frm2.tum.de> Fri, 25 Jul 2025 13:22:54 +0200
|
||||
|
||||
frappy-core (0.20.6) stable; urgency=medium
|
||||
|
||||
[ Markus Zolliker ]
|
||||
* config: add 'include' and 'override'
|
||||
* frappy.client.interactive: no pathlib needed here
|
||||
|
||||
[ Georg Brandl ]
|
||||
* install systemd units to /usr/lib
|
||||
|
||||
-- Markus Zolliker <jenkins@frm2.tum.de> Thu, 24 Jul 2025 22:26:02 +0200
|
||||
|
||||
frappy-core (0.20.5) stable; urgency=medium
|
||||
|
||||
[ Markus Zolliker ]
|
||||
|
||||
1
debian/control
vendored
1
debian/control
vendored
@@ -9,7 +9,6 @@ Build-Depends: debhelper-compat (= 13),
|
||||
python3-setuptools,
|
||||
python3-docutils,
|
||||
python3-sphinx,
|
||||
python3-sip-dev,
|
||||
python3-pyqt5,
|
||||
python3-mlzlog,
|
||||
python3-numpy,
|
||||
|
||||
4
debian/frappy-core.install
vendored
4
debian/frappy-core.install
vendored
@@ -10,6 +10,6 @@ usr/lib/python3.*/dist-packages/frappy/protocol
|
||||
usr/lib/python3.*/dist-packages/frappy_core-*
|
||||
usr/lib/python3.*/dist-packages/frappy/RELEASE-VERSION
|
||||
usr/lib/python3.*/dist-packages/frappy_demo
|
||||
lib/systemd
|
||||
usr/lib/systemd
|
||||
var/log/frappy
|
||||
etc/frappy/generalConfig.cfg
|
||||
etc/generalConfig.cfg etc/frappy
|
||||
|
||||
16
debian/rules
vendored
16
debian/rules
vendored
@@ -1,19 +1,13 @@
|
||||
#!/usr/bin/make -f
|
||||
# -*- makefile -*-
|
||||
|
||||
# Uncomment this to turn on verbose mode.
|
||||
#export DH_VERBOSE=1
|
||||
|
||||
export PYBUILD_NAME=frappy
|
||||
export PYBUILD_TEST_PYTEST=1
|
||||
|
||||
override_dh_install:
|
||||
rmdir debian/tmp
|
||||
mv debian/python3-frappy debian/tmp
|
||||
|
||||
install -m644 -Dt debian/tmp/etc/frappy etc/generalConfig.cfg
|
||||
dh_install -i -O--buildsystem=pybuild
|
||||
dh_missing --fail-missing
|
||||
# needed for bookworm compatibility!
|
||||
override_dh_installsystemd:
|
||||
ln -s usr/lib debian/frappy-core/lib
|
||||
dh_installsystemd
|
||||
rm debian/frappy-core/lib
|
||||
|
||||
%:
|
||||
dh $@ --with python3 --buildsystem=pybuild
|
||||
|
||||
@@ -35,7 +35,7 @@ def main():
|
||||
generalConfig.init()
|
||||
config_dir = generalConfig['confdir']
|
||||
|
||||
frappy_unit = '/lib/systemd/system/frappy@.service'
|
||||
frappy_unit = '/usr/lib/systemd/system/frappy@.service'
|
||||
wants_dir = normal_dir + '/frappy.target.wants'
|
||||
|
||||
all_servers = [base[:-4] if base.endswith('_cfg') else base for (base, ext) in
|
||||
|
||||
75
frappy/addrparam.py
Normal file
75
frappy/addrparam.py
Normal file
@@ -0,0 +1,75 @@
|
||||
# *****************************************************************************
|
||||
#
|
||||
# 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>
|
||||
#
|
||||
# *****************************************************************************
|
||||
|
||||
from frappy.core import Parameter, Property
|
||||
from frappy.datatypes import ValueType
|
||||
|
||||
|
||||
class AddrParam(Parameter):
|
||||
"""parameter with an address field
|
||||
|
||||
instead of implementing read_<param> and write_<param>, just implement
|
||||
addressed_read and addressed_write.
|
||||
"""
|
||||
addr = Property('address', ValueType())
|
||||
|
||||
|
||||
class AddrMixin:
|
||||
"""mixin for addressed parameters
|
||||
|
||||
in case a read_<param> and/or write_<param> are not implemented,
|
||||
they are created with a call to addressed_read and/or addressed_write
|
||||
"""
|
||||
def __init_subclass__(cls):
|
||||
for aname, aobj in list(cls.__dict__.items()):
|
||||
if isinstance(aobj, AddrParam):
|
||||
methodname = f'read_{aname}'
|
||||
|
||||
if not hasattr(cls, methodname):
|
||||
def rfunc(self, pname=aname):
|
||||
return self.addressed_read(self.accessibles[pname])
|
||||
|
||||
setattr(cls, methodname, rfunc)
|
||||
|
||||
if not aobj.readonly:
|
||||
methodname = f'write_{aname}'
|
||||
if not hasattr(cls, methodname):
|
||||
def wfunc(self, value, pname=aname):
|
||||
return self.addressed_write(self.accessibles[pname], value)
|
||||
|
||||
setattr(cls, methodname, wfunc)
|
||||
super().__init_subclass__()
|
||||
|
||||
def addressed_read(self, pobj):
|
||||
"""addressed read
|
||||
|
||||
:param pobj: the AddrParam
|
||||
:return: the value read
|
||||
"""
|
||||
return getattr(self, pobj.name)
|
||||
|
||||
def addressed_write(self, pobj, value):
|
||||
"""addressed write
|
||||
|
||||
:param pobj: the AddrParam
|
||||
:param value: the value to be written
|
||||
:return: the value written or None
|
||||
"""
|
||||
131
frappy/attached.py
Normal file
131
frappy/attached.py
Normal file
@@ -0,0 +1,131 @@
|
||||
# *****************************************************************************
|
||||
#
|
||||
# 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>
|
||||
#
|
||||
# *****************************************************************************
|
||||
|
||||
from frappy.errors import ConfigError
|
||||
from frappy.modulebase import Module
|
||||
from frappy.datatypes import StringType, ValueType
|
||||
from frappy.properties import Property
|
||||
|
||||
|
||||
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
|
||||
super().__init__(description, StringType(), mandatory=mandatory)
|
||||
|
||||
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 not isinstance(modobj, self.basecls):
|
||||
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
|
||||
|
||||
def copy(self):
|
||||
return Attached(self.basecls, self.description, self.mandatory)
|
||||
|
||||
|
||||
class DictWithFlag(dict):
|
||||
flag = False
|
||||
|
||||
|
||||
class AttachDictType(ValueType):
|
||||
"""a custom datatype for a dict <key> of names or modules"""
|
||||
def __init__(self):
|
||||
super().__init__(DictWithFlag)
|
||||
|
||||
def copy(self):
|
||||
return AttachDictType()
|
||||
|
||||
def export_value(self, value):
|
||||
"""export either names or the name attribute
|
||||
|
||||
to treat bare names and modules the same
|
||||
"""
|
||||
return {k: getattr(v, 'name', v) for k, v in value.items()}
|
||||
|
||||
|
||||
class AttachedDict(Property):
|
||||
def __init__(self, description='attached modules', elements=None, optional=None, basecls=None,
|
||||
**kwds):
|
||||
"""a mapping of attached modules
|
||||
|
||||
:param elements: None or a dict <key> of <basecls> for mandatory elements
|
||||
:param optional: None or a dict <key> of <basecls> for optional elements
|
||||
:param basecls: None or a base class for arbitrary keys
|
||||
if not given, only keys given in parameters 'elements' and 'optional' are allowed
|
||||
:param description: the property description
|
||||
|
||||
<key> might also be a number or any other immutable
|
||||
"""
|
||||
self.elements = elements or {}
|
||||
self.basecls = basecls
|
||||
self.baseclasses = {**self.elements, **(optional or {})}
|
||||
super().__init__(description, AttachDictType(), default={}, **kwds)
|
||||
|
||||
def __get__(self, obj, owner):
|
||||
if obj is None:
|
||||
return self
|
||||
attach_dict = super().__get__(obj, owner) or DictWithFlag({})
|
||||
if attach_dict.flag:
|
||||
return attach_dict
|
||||
|
||||
for key, modulename in attach_dict.items():
|
||||
basecls = self.baseclasses.get(key, self.basecls)
|
||||
if basecls is None:
|
||||
raise ConfigError(f'unknown key {key!r} for attached modules {self.name}')
|
||||
modobj = obj.secNode.get_module(modulename)
|
||||
if modobj is None:
|
||||
raise ConfigError(f'attached modules {self.name}: '
|
||||
f'{key}={modulename!r} does not exist')
|
||||
if not isinstance(modobj, basecls):
|
||||
raise ConfigError(f'attached modules {self.name}: '
|
||||
f'module {key}={modulename!r} must inherit '
|
||||
f'from {basecls.__qualname__!r}')
|
||||
obj.attachedModules[self.name, key] = attach_dict[key] = modobj
|
||||
missing_keys = set(self.elements) - set(attach_dict)
|
||||
if missing_keys:
|
||||
raise ConfigError(f'attached modules {self.name}: '
|
||||
f"missing {', '.join(missing_keys)} ")
|
||||
attach_dict.flag = True
|
||||
return attach_dict
|
||||
|
||||
def copy(self):
|
||||
return AttachedDict(self.elements, self.baseclasses, self.basecls, self.description)
|
||||
@@ -29,7 +29,7 @@ import os
|
||||
import traceback
|
||||
import threading
|
||||
import logging
|
||||
from os.path import expanduser
|
||||
from pathlib import Path
|
||||
from frappy.lib import delayed_import
|
||||
from frappy.client import SecopClient, UnregisterCallback
|
||||
from frappy.errors import SECoPError
|
||||
@@ -64,6 +64,8 @@ LOG_LEVELS = {
|
||||
'off': logging.ERROR+1}
|
||||
CLR = '\r\x1b[K' # code to move to the left and clear current line
|
||||
|
||||
UNDEF = object()
|
||||
|
||||
|
||||
class Handler(logging.StreamHandler):
|
||||
def emit(self, record):
|
||||
@@ -213,8 +215,8 @@ class Module:
|
||||
clientenv.raise_with_short_traceback(error)
|
||||
return value
|
||||
|
||||
def __call__(self, target=None):
|
||||
if target is None:
|
||||
def __call__(self, target=UNDEF):
|
||||
if target is UNDEF:
|
||||
return self.read()
|
||||
watch_params = ['value', 'status']
|
||||
for pname in watch_params:
|
||||
@@ -222,7 +224,15 @@ class Module:
|
||||
updateEvent=self._watch_parameter,
|
||||
callimmediately=False)
|
||||
|
||||
self.target = target # this sets self._is_driving
|
||||
if 'go' in self._commands:
|
||||
if 'goal' in self._parameters and target is not None:
|
||||
self.goal_enable = True
|
||||
self.goal = target
|
||||
if 'target' in self._parameters:
|
||||
self.target = target
|
||||
self.go()
|
||||
elif 'target' in self._parameters:
|
||||
self.target = target # this sets self._is_driving
|
||||
|
||||
def loop():
|
||||
while self._is_driving:
|
||||
@@ -230,9 +240,12 @@ class Module:
|
||||
self._driving_event.clear()
|
||||
try:
|
||||
loop()
|
||||
except KeyboardInterrupt as e:
|
||||
except KeyboardInterrupt:
|
||||
self._secnode.log.info('-- interrupted --')
|
||||
self.stop()
|
||||
try:
|
||||
self.stop()
|
||||
except Exception as e:
|
||||
print(f'while stopping: {e!r}')
|
||||
try:
|
||||
loop() # wait for stopping to be finished
|
||||
except KeyboardInterrupt:
|
||||
@@ -242,8 +255,8 @@ class Module:
|
||||
finally:
|
||||
self._secnode.readParameter(self._name, 'value')
|
||||
for pname in watch_params:
|
||||
self._secnode.unregister_callback((self._name, pname),
|
||||
updateEvent=self._watch_parameter)
|
||||
self._secnode.unregister_callback(
|
||||
(self._name, pname), updateEvent=self._watch_parameter)
|
||||
return self.value
|
||||
|
||||
def __repr__(self):
|
||||
@@ -297,6 +310,8 @@ class Param:
|
||||
|
||||
|
||||
class Command:
|
||||
_obj = None
|
||||
|
||||
def __init__(self, name, modname, secnode):
|
||||
self.name = name
|
||||
self.modname = modname
|
||||
@@ -311,11 +326,14 @@ class Command:
|
||||
result, _ = self.exec(self.modname, self.name, *args)
|
||||
else:
|
||||
result, _ = self.exec(self.modname, self.name, args or None)
|
||||
if self.name == 'go' and self._obj:
|
||||
self._obj._is_driving = self._obj._isBusy()
|
||||
return result
|
||||
|
||||
def __get__(self, obj, owner=None):
|
||||
if obj is None:
|
||||
return self
|
||||
self._obj = obj
|
||||
return self.call
|
||||
|
||||
|
||||
@@ -497,7 +515,7 @@ class Console(code.InteractiveConsole):
|
||||
history = None
|
||||
if readline:
|
||||
try:
|
||||
history = expanduser(f'~/.config/frappy/{name}-history')
|
||||
history = Path(f'~/.local/state/frappy-{name}-history').expanduser()
|
||||
readline.read_history_file(history)
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
@@ -505,6 +523,7 @@ class Console(code.InteractiveConsole):
|
||||
self.interact('', '')
|
||||
finally:
|
||||
if history:
|
||||
history.parent.mkdir(mode=0o700, parents=True, exist_ok=True)
|
||||
readline.write_history_file(history)
|
||||
|
||||
def raw_input(self, prompt=""):
|
||||
|
||||
@@ -29,8 +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
|
||||
from frappy.modules import Communicator, Drivable, Readable, Writable
|
||||
from frappy.attached import Attached, AttachedDict
|
||||
from frappy.params import Command, Parameter, Limit
|
||||
from frappy.properties import Property
|
||||
from frappy.proxy import Proxy, SecNode, proxy_class
|
||||
|
||||
214
frappy/ctrlby.py
Normal file
214
frappy/ctrlby.py
Normal file
@@ -0,0 +1,214 @@
|
||||
# *****************************************************************************
|
||||
#
|
||||
# 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>
|
||||
#
|
||||
# *****************************************************************************
|
||||
|
||||
from frappy.datatypes import BoolType, EnumType, Enum
|
||||
from frappy.core import Parameter, Attached
|
||||
|
||||
|
||||
class WrapControlledBy:
|
||||
"""mixin to add controlled_by to writable modules
|
||||
|
||||
Create a wrapper class inheriting from this mixin
|
||||
to add controlled_by to a Writable module
|
||||
|
||||
Usage:
|
||||
|
||||
class Enhanced(WrapControlledBy, BaseWritable):
|
||||
pass
|
||||
|
||||
# typically nothing else has to be implemented
|
||||
|
||||
from a module with output (inheriting from HasOutput), the
|
||||
method update_target must be called for internal updates
|
||||
"""
|
||||
|
||||
controlled_by = Parameter('source of target value', EnumType(members={'self': 0}), default=0)
|
||||
target = Parameter() # make sure target is a parameter
|
||||
inputCallbacks = ()
|
||||
|
||||
def register_input(self, name, deactivate_control):
|
||||
"""register input
|
||||
|
||||
:param name: the name of the module (for controlled_by enum)
|
||||
:param deactivate_control: a method on the input module to switch off control
|
||||
|
||||
called by <controller module>.initModule
|
||||
"""
|
||||
if not self.inputCallbacks:
|
||||
self.inputCallbacks = {}
|
||||
self.inputCallbacks[name] = deactivate_control
|
||||
prev_enum = self.parameters['controlled_by'].datatype.export_datatype()['members']
|
||||
# add enum member, using autoincrement feature of Enum
|
||||
self.parameters['controlled_by'].datatype = EnumType(Enum(prev_enum, **{name: None}))
|
||||
self.log.info('enumtype %r', self.parameters['controlled_by'].datatype)
|
||||
|
||||
def write_controlled_by(self, modulename):
|
||||
result = modulename
|
||||
if modulename in ('self', self.name):
|
||||
# inform the deactivate_control methods, that we have already switched
|
||||
self.controlled_by = result = 'self'
|
||||
for name, deactivate_control in self.inputCallbacks.items():
|
||||
if name != modulename:
|
||||
deactivate_control(modulename)
|
||||
return result
|
||||
|
||||
def self_controlled(self):
|
||||
"""method to change controlled_by to self
|
||||
|
||||
to be called from the write_target method
|
||||
"""
|
||||
if self.controlled_by != 0:
|
||||
self.write_controlled_by('self')
|
||||
|
||||
def set_off(self):
|
||||
"""to be overridden if the off state should be different from the default
|
||||
|
||||
on a FloatRange() the default value is 0
|
||||
"""
|
||||
zero = self.parameters['target'].datatype.default
|
||||
try:
|
||||
self.internal_set_target(zero)
|
||||
except Exception as e:
|
||||
self.target = zero
|
||||
|
||||
def update_target(self, module, value):
|
||||
"""update internal target value
|
||||
|
||||
as write_target would switch to manual mode, the controlling module
|
||||
has to use this method to update the value
|
||||
|
||||
override and super call, if other actions are needed
|
||||
"""
|
||||
if self.controlled_by != module:
|
||||
deactivate_control = self.inputCallbacks.get(self.controlled_by)
|
||||
if deactivate_control:
|
||||
deactivate_control(module)
|
||||
self.controlled_by = module
|
||||
target = self.internal_set_target(value)
|
||||
self.target = value if target is None else target
|
||||
|
||||
def write_target(self, target):
|
||||
self.self_controlled()
|
||||
return self.internal_set_target(target)
|
||||
|
||||
def internal_set_target(self, target):
|
||||
# we need this additional indirection:
|
||||
# super().write_target must refer to an inherited base class
|
||||
# which is after WrapControlledBy in the method resolution order
|
||||
return super().write_target(target)
|
||||
|
||||
|
||||
class HasControlledBy(WrapControlledBy):
|
||||
"""mixin for controlled_by functionality
|
||||
|
||||
Create a wrapper class inheriting from this mixin
|
||||
to add controlled_by to a Writable module
|
||||
|
||||
Usage:
|
||||
|
||||
class Enhanced(HasControlledBy, BaseWritable):
|
||||
def set_target(self, value):
|
||||
# implement here hardware access for setting target
|
||||
|
||||
# do not override write_target!
|
||||
|
||||
from a module with output (inheriting from HasOutput), the
|
||||
method update_target must be called for internal updates
|
||||
"""
|
||||
|
||||
def set_target(self, value):
|
||||
"""to be overridden for setting target of HW"""
|
||||
raise NotImplementedError
|
||||
|
||||
def internal_set_target(self, value):
|
||||
# we need this additional indirection:
|
||||
# self.write_target must refer to a base class which
|
||||
# is before HasControlledBy in the method resolution order
|
||||
return self.set_target(value)
|
||||
|
||||
def set_off(self):
|
||||
"""typically needs to be overridden"""
|
||||
|
||||
|
||||
class HasOutputModule:
|
||||
"""mixin for modules having an output module
|
||||
|
||||
this module will call the update_target method of an output module
|
||||
"""
|
||||
# mandatory=False: it should be possible to configure a module with fixed control
|
||||
output_module = Attached(WrapControlledBy, mandatory=False)
|
||||
control_active = Parameter('control mode', BoolType(), default=False)
|
||||
target = Parameter() # make sure target is a parameter
|
||||
|
||||
def initModule(self):
|
||||
super().initModule()
|
||||
if self.output_module:
|
||||
self.output_module.register_input(self.name, self.deactivate_control)
|
||||
|
||||
def write_control_active(self, value):
|
||||
"""override with supercall if needed
|
||||
|
||||
control_active is readonly by default, as specified in the SECoP standard.
|
||||
This method is meant to be called internally.
|
||||
|
||||
However, it is possible to override control_active with readonly=False
|
||||
and this is quite useful IMHO in some situations
|
||||
"""
|
||||
out = self.output_module
|
||||
if out:
|
||||
if value:
|
||||
if out.controlled_by != self.name:
|
||||
# deactivate control an all modules controlling our output_module
|
||||
out.write_controlled_by(self.name)
|
||||
else:
|
||||
if out.controlled_by == self.name:
|
||||
out.set_off() # this sets out.controlled_by to 0 (=self)
|
||||
|
||||
def set_control_active(self, active):
|
||||
"""to be overridden for switching hw control
|
||||
|
||||
TODO: remove this legacy method (replaced by write_control_active)
|
||||
"""
|
||||
self.control_active = active
|
||||
|
||||
def activate_control(self):
|
||||
"""method to switch control_active on
|
||||
|
||||
TODO: remove this legacy method (replaced by write_control_active)
|
||||
"""
|
||||
self.write_control_active(True)
|
||||
|
||||
def deactivate_control(self, source=None):
|
||||
"""called when another module takes over control
|
||||
|
||||
registered to be called from the controlled module(s)
|
||||
"""
|
||||
if self.control_active:
|
||||
self.write_control_active(False)
|
||||
self.log.warning(f'switched to manual mode by {source or self.name}')
|
||||
|
||||
def write_target(self, target):
|
||||
self.write_control_active(True)
|
||||
return self.set_target(target)
|
||||
|
||||
def set_target(self, target):
|
||||
"""to be overridden"""
|
||||
raise NotImplementedError
|
||||
@@ -53,13 +53,9 @@ def shortrepr(value):
|
||||
return r
|
||||
|
||||
|
||||
# base class for all DataTypes
|
||||
class DataType(HasProperties):
|
||||
"""base class for all data types"""
|
||||
IS_COMMAND = False
|
||||
unit = ''
|
||||
class SimpleDataType(HasProperties):
|
||||
"""base class for simple datatypes, used in properties only"""
|
||||
default = None
|
||||
client = False # used on the client side
|
||||
|
||||
def __call__(self, value):
|
||||
"""convert given value to our datatype and validate
|
||||
@@ -105,38 +101,10 @@ class DataType(HasProperties):
|
||||
"""
|
||||
return self.format_value(value, False)
|
||||
|
||||
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."
|
||||
)
|
||||
|
||||
def export_value(self, value):
|
||||
"""if needed, reformat value for transport"""
|
||||
return value
|
||||
|
||||
def import_value(self, value):
|
||||
"""opposite of export_value, reformat from transport to internal repr
|
||||
|
||||
note: for importing from gui/configfile/commandline use :meth:`from_string`
|
||||
instead.
|
||||
"""
|
||||
return self(value)
|
||||
|
||||
def format_value(self, value, unit=True):
|
||||
"""format a value of this type into a string
|
||||
|
||||
This is intended for 'nice' formatting for humans and is NOT
|
||||
the opposite of :meth:`from_string`
|
||||
|
||||
possible values of unit:
|
||||
- True: use the string of the datatype
|
||||
- False: return a value interpretable by ast.literal_eval (internal use only)
|
||||
- any other string: use as unit (internal use only)
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def set_properties(self, **kwds):
|
||||
"""init datatype properties"""
|
||||
try:
|
||||
@@ -161,6 +129,34 @@ class DataType(HasProperties):
|
||||
# looks like the simplest way to make a deep copy
|
||||
return get_datatype(self.export_datatype())
|
||||
|
||||
|
||||
class DataType(SimpleDataType):
|
||||
"""base class for data types used in parameters and commands"""
|
||||
IS_COMMAND = False
|
||||
unit = ''
|
||||
client = False # used on the client side
|
||||
|
||||
def import_value(self, value):
|
||||
"""opposite of export_value, reformat from transport to internal repr
|
||||
|
||||
note: for importing from gui/configfile/commandline use :meth:`from_string`
|
||||
instead.
|
||||
"""
|
||||
return self(value)
|
||||
|
||||
def format_value(self, value, unit=True):
|
||||
"""format a value of this type into a string
|
||||
|
||||
This is intended for 'nice' formatting for humans and is NOT
|
||||
the opposite of :meth:`from_string`
|
||||
|
||||
possible values of unit:
|
||||
- True: use the string of the datatype
|
||||
- False: return a value interpretable by ast.literal_eval (internal use only)
|
||||
- any other string: use as unit (internal use only)
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def compatible(self, other):
|
||||
"""check other for compatibility
|
||||
|
||||
@@ -169,6 +165,10 @@ class DataType(HasProperties):
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def export_datatype(self):
|
||||
"""return a python object which after jsonifying identifies this datatype"""
|
||||
raise NotImplementedError
|
||||
|
||||
def set_main_unit(self, unit):
|
||||
"""replace $ in unit by argument"""
|
||||
|
||||
@@ -238,7 +238,7 @@ class FloatRange(HasUnit, DataType):
|
||||
self.default = 0 if self.min <= 0 <= self.max else self.min
|
||||
super().checkProperties()
|
||||
if '%' not in self.fmtstr:
|
||||
raise ConfigError('Invalid fmtstr!')
|
||||
raise ConfigError('Invalid fmtstr')
|
||||
|
||||
def export_datatype(self):
|
||||
return self.get_info(type='double')
|
||||
@@ -411,7 +411,7 @@ class ScaledInteger(HasUnit, DataType):
|
||||
|
||||
# check values
|
||||
if '%' not in self.fmtstr:
|
||||
raise ConfigError('Invalid fmtstr!')
|
||||
raise ConfigError('Invalid fmtstr')
|
||||
# Remark: Datatype.copy() will round min, max to a multiple of self.scale
|
||||
# this should be o.k.
|
||||
|
||||
@@ -557,9 +557,9 @@ class BLOBType(DataType):
|
||||
internally treated as bytes
|
||||
"""
|
||||
|
||||
minbytes = Property('minimum number of bytes', IntRange(0), extname='minbytes',
|
||||
minbytes = Property('minimum number of bytes', IntRange(0, UNLIMITED), extname='minbytes',
|
||||
default=0)
|
||||
maxbytes = Property('maximum number of bytes', IntRange(0), extname='maxbytes',
|
||||
maxbytes = Property('maximum number of bytes', IntRange(0, UNLIMITED), extname='maxbytes',
|
||||
mandatory=True)
|
||||
|
||||
def __init__(self, minbytes=0, maxbytes=None):
|
||||
@@ -587,10 +587,10 @@ class BLOBType(DataType):
|
||||
size = len(value)
|
||||
if size < self.minbytes:
|
||||
raise RangeError(
|
||||
f'{value!r} must be at least {self.minbytes} bytes long!')
|
||||
f'blob {shortrepr(value)!r} must be at least {self.minbytes} bytes long (got {size})')
|
||||
if size > self.maxbytes:
|
||||
raise RangeError(
|
||||
f'{value!r} must be at most {self.maxbytes} bytes long!')
|
||||
f'blob {shortrepr(value)!r} must be at most {self.maxbytes} bytes long (got {size})')
|
||||
return value
|
||||
|
||||
def export_value(self, value):
|
||||
@@ -646,22 +646,22 @@ class StringType(DataType):
|
||||
def __call__(self, value):
|
||||
"""accepts strings only"""
|
||||
if not isinstance(value, str):
|
||||
raise WrongTypeError(f'{shortrepr(value)} has the wrong type!')
|
||||
raise WrongTypeError(f'{shortrepr(value)} has the wrong type')
|
||||
if not self.isUTF8:
|
||||
try:
|
||||
value.encode('ascii')
|
||||
except UnicodeEncodeError:
|
||||
raise RangeError(f'{shortrepr(value)} contains non-ascii character!') from None
|
||||
raise RangeError(f'{shortrepr(value)} contains non-ascii character') from None
|
||||
size = len(value)
|
||||
if size < self.minchars:
|
||||
raise RangeError(
|
||||
f'{shortrepr(value)} must be at least {self.minchars} chars long!')
|
||||
f'string {shortrepr(value)} must be at least {self.minchars} chars long (got {size})')
|
||||
if size > self.maxchars:
|
||||
raise RangeError(
|
||||
f'{shortrepr(value)} must be at most {self.maxchars} chars long!')
|
||||
f'string {shortrepr(value)} must be at most {self.maxchars} chars long (got {size})')
|
||||
if '\0' in value:
|
||||
raise RangeError(
|
||||
'Strings are not allowed to embed a \\0! Use a Blob instead!')
|
||||
'strings are not allowed to embed a null byte, Use a Blob instead')
|
||||
return value
|
||||
|
||||
def export_value(self, value):
|
||||
@@ -724,12 +724,12 @@ class BoolType(DataType):
|
||||
return False
|
||||
if value in ['1', 'True', 'true', 'yes', 'on']:
|
||||
return True
|
||||
raise WrongTypeError(f'{shortrepr(value)} is not a boolean value!')
|
||||
raise WrongTypeError(f'{shortrepr(value)} is not a boolean value')
|
||||
|
||||
def __call__(self, value):
|
||||
if value in (0, 1):
|
||||
return bool(value)
|
||||
raise WrongTypeError(f'{shortrepr(value)} is not a boolean value!')
|
||||
raise WrongTypeError(f'{shortrepr(value)} is not a boolean value')
|
||||
|
||||
def export_value(self, value):
|
||||
"""returns a python object fit for serialisation"""
|
||||
@@ -755,16 +755,16 @@ class ArrayOf(DataType):
|
||||
|
||||
:param members: the datatype of the elements
|
||||
"""
|
||||
minlen = Property('minimum number of elements', IntRange(0), extname='minlen',
|
||||
minlen = Property('minimum number of elements', IntRange(0, UNLIMITED), extname='minlen',
|
||||
default=0)
|
||||
maxlen = Property('maximum number of elements', IntRange(0), extname='maxlen',
|
||||
maxlen = Property('maximum number of elements', IntRange(0, UNLIMITED), extname='maxlen',
|
||||
mandatory=True)
|
||||
|
||||
def __init__(self, members, minlen=0, maxlen=None):
|
||||
super().__init__()
|
||||
if not isinstance(members, DataType):
|
||||
raise ProgrammingError(
|
||||
'ArrayOf only works with a DataType as first argument!')
|
||||
'ArrayOf only works with a DataType as first argument')
|
||||
# one argument -> exactly that size
|
||||
# argument default to 100
|
||||
if maxlen is None:
|
||||
@@ -807,15 +807,16 @@ class ArrayOf(DataType):
|
||||
|
||||
def check_type(self, value):
|
||||
try:
|
||||
size = len(value)
|
||||
# check number of elements
|
||||
if self.minlen is not None and len(value) < self.minlen:
|
||||
if self.minlen is not None and size < self.minlen:
|
||||
raise RangeError(
|
||||
f'array too small, needs at least {self.minlen} elements!')
|
||||
if self.maxlen is not None and len(value) > self.maxlen:
|
||||
f'array must have at least {self.minlen} elements (has {size})')
|
||||
if self.maxlen is not None and size > self.maxlen:
|
||||
raise RangeError(
|
||||
f'array too big, holds at most {self.maxlen} elements!')
|
||||
f'array must have at most {self.maxlen} elements (has {size})')
|
||||
except TypeError:
|
||||
raise WrongTypeError(f'{type(value).__name__} can not be converted to ArrayOf DataType!') from None
|
||||
raise WrongTypeError(f'{type(value).__name__} can not be converted to ArrayOf DataType') from None
|
||||
|
||||
def __call__(self, value):
|
||||
"""accepts any sequence, converts to tuple (immutable!)"""
|
||||
@@ -881,11 +882,11 @@ class TupleOf(DataType):
|
||||
def __init__(self, *members):
|
||||
super().__init__()
|
||||
if not members:
|
||||
raise ProgrammingError('Empty tuples are not allowed!')
|
||||
raise ProgrammingError('Empty tuples are not allowed')
|
||||
for subtype in members:
|
||||
if not isinstance(subtype, DataType):
|
||||
raise ProgrammingError(
|
||||
'TupleOf only works with DataType objs as arguments!')
|
||||
'TupleOf only works with DataType objs as arguments')
|
||||
self.members = members
|
||||
self.default = tuple(el.default for el in members)
|
||||
|
||||
@@ -904,7 +905,7 @@ class TupleOf(DataType):
|
||||
if len(value) == len(self.members):
|
||||
return
|
||||
except TypeError:
|
||||
raise WrongTypeError(f'{type(value).__name__} can not be converted to TupleOf DataType!') from None
|
||||
raise WrongTypeError(f'{type(value).__name__} can not be converted to TupleOf DataType') from None
|
||||
raise WrongTypeError(f'tuple needs {len(self.members)} elements')
|
||||
|
||||
def __call__(self, value):
|
||||
@@ -969,16 +970,16 @@ class StructOf(DataType):
|
||||
super().__init__()
|
||||
self.members = members
|
||||
if not members:
|
||||
raise ProgrammingError('Empty structs are not allowed!')
|
||||
raise ProgrammingError('Empty structs are not allowed')
|
||||
self.optional = list(members if optional is None else optional)
|
||||
for name, subtype in list(members.items()):
|
||||
if not isinstance(subtype, DataType):
|
||||
raise ProgrammingError(
|
||||
'StructOf only works with named DataType objs as keyworded arguments!')
|
||||
'StructOf only works with named DataType objs as keyworded arguments')
|
||||
for name in self.optional:
|
||||
if name not in members:
|
||||
raise ProgrammingError(
|
||||
'Only members of StructOf may be declared as optional!')
|
||||
'Only members of StructOf may be declared as optional')
|
||||
self.default = dict((k, el.default) for k, el in members.items())
|
||||
|
||||
def copy(self):
|
||||
@@ -1082,10 +1083,10 @@ class CommandType(DataType):
|
||||
super().__init__()
|
||||
if argument is not None:
|
||||
if not isinstance(argument, DataType):
|
||||
raise ProgrammingError('CommandType: Argument type must be a DataType!')
|
||||
raise ProgrammingError('CommandType: Argument type must be a DataType')
|
||||
if result is not None:
|
||||
if not isinstance(result, DataType):
|
||||
raise ProgrammingError('CommandType: Result type must be a DataType!')
|
||||
raise ProgrammingError('CommandType: Result type must be a DataType')
|
||||
self.argument = argument
|
||||
self.result = result
|
||||
|
||||
@@ -1107,10 +1108,10 @@ class CommandType(DataType):
|
||||
raise ProgrammingError('commands can not be converted to a value')
|
||||
|
||||
def export_value(self, value):
|
||||
raise ProgrammingError('values of type command can not be transported!')
|
||||
raise ProgrammingError('values of type command can not be transported')
|
||||
|
||||
def import_value(self, value):
|
||||
raise ProgrammingError('values of type command can not be transported!')
|
||||
raise ProgrammingError('values of type command can not be transported')
|
||||
|
||||
def from_string(self, text):
|
||||
raise ProgrammingError('a string can not be converted to a command')
|
||||
@@ -1131,10 +1132,23 @@ class CommandType(DataType):
|
||||
|
||||
# internally used datatypes (i.e. only for programming the SEC-node)
|
||||
|
||||
class DataTypeType(DataType):
|
||||
class DefaultType(DataType):
|
||||
"""datatype used as default for parameters
|
||||
|
||||
needs some minimal interface to avoid errors when
|
||||
the datatype of a parameter is not yet defined
|
||||
"""
|
||||
def __call__(self, value):
|
||||
return value
|
||||
|
||||
def setProperty(self, key, value):
|
||||
"""silently ignored"""
|
||||
|
||||
|
||||
class DataTypeType(SimpleDataType):
|
||||
def __call__(self, value):
|
||||
"""accepts a datatype"""
|
||||
if isinstance(value, DataType):
|
||||
if isinstance(value, SimpleDataType):
|
||||
return value
|
||||
#TODO: not needed anymore?
|
||||
try:
|
||||
@@ -1155,7 +1169,7 @@ class DataTypeType(DataType):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class ValueType(DataType):
|
||||
class ValueType(SimpleDataType):
|
||||
"""Can take any python value.
|
||||
|
||||
The optional (callable) validator can be used to restrict values to a
|
||||
@@ -1178,7 +1192,7 @@ class ValueType(DataType):
|
||||
try:
|
||||
return self.validator(value)
|
||||
except Exception as e:
|
||||
raise ConfigError(f'Validator {self.validator} raised {e!r} for value {value}') from e
|
||||
raise ConfigError(f'Validator {self.validator} raised {e!r} for value {shortrepr(value)}') from e
|
||||
return value
|
||||
|
||||
def copy(self):
|
||||
@@ -1188,23 +1202,8 @@ class ValueType(DataType):
|
||||
"""if needed, reformat value for transport"""
|
||||
return value
|
||||
|
||||
def import_value(self, value):
|
||||
"""opposite of export_value, reformat from transport to internal repr
|
||||
|
||||
note: for importing from gui/configfile/commandline use :meth:`from_string`
|
||||
instead.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def setProperty(self, key, value):
|
||||
"""silently ignored
|
||||
|
||||
as ValueType is used for the datatype default, this makes code
|
||||
shorter for cases, where the datatype may not yet be defined
|
||||
"""
|
||||
|
||||
|
||||
class NoneOr(DataType):
|
||||
class NoneOr(SimpleDataType):
|
||||
"""validates a None or smth. else"""
|
||||
default = None
|
||||
|
||||
@@ -1222,7 +1221,7 @@ class NoneOr(DataType):
|
||||
return self.other.export_value(value)
|
||||
|
||||
|
||||
class OrType(DataType):
|
||||
class OrType(SimpleDataType):
|
||||
def __init__(self, *types):
|
||||
super().__init__()
|
||||
self.types = types
|
||||
|
||||
@@ -33,7 +33,6 @@ class SECoPError(RuntimeError):
|
||||
clsname2class = {} # needed to convert error reports back to classes
|
||||
name = 'InternalError'
|
||||
name2class = {}
|
||||
report_error = True
|
||||
raising_methods = None
|
||||
|
||||
def __init_subclass__(cls):
|
||||
@@ -76,7 +75,7 @@ class SECoPError(RuntimeError):
|
||||
if mlist and stripped:
|
||||
mlist = mlist[:-1] # do not pop, as this would change self.raising_methods
|
||||
prefix = '' if self.name2class.get(self.name) == type(self) else type(self).__name__
|
||||
prefix += ''.join(' in ' + m for m in mlist).strip()
|
||||
prefix = (prefix + ''.join(' in ' + m for m in mlist)).strip()
|
||||
if prefix:
|
||||
return f'{prefix}: {super().__str__()}'
|
||||
return super().__str__()
|
||||
|
||||
101
frappy/io.py
101
frappy/io.py
@@ -30,7 +30,7 @@ import time
|
||||
from frappy.datatypes import ArrayOf, BLOBType, BoolType, FloatRange, \
|
||||
IntRange, StringType, StructOf, TupleOf, ValueType
|
||||
from frappy.errors import CommunicationFailedError, ConfigError, \
|
||||
ProgrammingError, SilentCommunicationFailedError as SilentError
|
||||
ProgrammingError, SECoPError, SilentCommunicationFailedError as SilentError
|
||||
from frappy.lib import generalConfig
|
||||
from frappy.lib.asynconn import AsynConn, ConnectionClosed
|
||||
from frappy.modules import Attached, Command, Communicator, Module, \
|
||||
@@ -125,7 +125,7 @@ class IOBase(Communicator):
|
||||
|
||||
_reconnectCallbacks = None
|
||||
_conn = None
|
||||
_last_error = None
|
||||
_last_error = None # this is None only until the first connection success
|
||||
_lock = None
|
||||
_last_connect_attempt = 0
|
||||
|
||||
@@ -167,14 +167,17 @@ class IOBase(Communicator):
|
||||
try:
|
||||
self.connectStart()
|
||||
if self._last_error:
|
||||
# we do not get here before the first connect success
|
||||
self.log.info('connected')
|
||||
self._last_error = 'connected'
|
||||
self.callCallbacks()
|
||||
return self.is_connected
|
||||
self._last_error = 'connected'
|
||||
except Exception as e:
|
||||
if repr(e) != self._last_error:
|
||||
self._last_error = repr(e)
|
||||
self.log.error(self._last_error)
|
||||
if not isinstance(e, CommunicationFailedError):
|
||||
# when this happens on startup, assume it is not worth to continue
|
||||
self.secNode.error_count += 1
|
||||
raise SilentError(repr(e)) from e
|
||||
return self.is_connected
|
||||
|
||||
@@ -193,7 +196,7 @@ class IOBase(Communicator):
|
||||
now = time.time()
|
||||
if now >= self._last_connect_attempt + self.pollinterval:
|
||||
# we do not try to reconnect more often than pollinterval
|
||||
_last_connect_attempt = now
|
||||
self._last_connect_attempt = now
|
||||
if self.read_is_connected():
|
||||
return
|
||||
raise SilentError('disconnected') from None
|
||||
@@ -218,13 +221,23 @@ class IOBase(Communicator):
|
||||
def communicate(self, command):
|
||||
return NotImplementedError
|
||||
|
||||
@Command
|
||||
def reconnect(self):
|
||||
"""close and open connection
|
||||
|
||||
sometimes a reconnect helps to heal a broken connection
|
||||
"""
|
||||
self.closeConnection()
|
||||
self.read_is_connected() # this always tries to reconnect
|
||||
|
||||
|
||||
class StringIO(IOBase):
|
||||
"""line oriented communicator
|
||||
|
||||
self healing is assured by polling the parameter 'is_connected'
|
||||
self-healing is assured by polling the parameter 'is_connected'
|
||||
"""
|
||||
end_of_line = Property('end_of_line character', datatype=ValueType(),
|
||||
end_of_line = Property('end_of_line character or tuple(eol_read, eol_write)',
|
||||
datatype=ValueType(),
|
||||
default='\n', settable=True)
|
||||
encoding = Property('used encoding', datatype=StringType(),
|
||||
default='ascii', settable=True)
|
||||
@@ -297,6 +310,7 @@ class StringIO(IOBase):
|
||||
"""
|
||||
command = command.encode(self.encoding)
|
||||
self.check_connection()
|
||||
new_error = 'no error' # in case of success (must not be None)
|
||||
try:
|
||||
with self._lock:
|
||||
# read garbage and wait before send
|
||||
@@ -304,12 +318,14 @@ class StringIO(IOBase):
|
||||
cmds = command.split(self._eol_write)
|
||||
else:
|
||||
cmds = [command]
|
||||
garbage = None
|
||||
# do not skip garbage when no reply is expected
|
||||
skip_garbage = not noreply
|
||||
try:
|
||||
for cmd in cmds:
|
||||
if self.wait_before:
|
||||
time.sleep(self.wait_before)
|
||||
if garbage is None: # read garbage only once
|
||||
if skip_garbage:
|
||||
skip_garbage = False # read garbage only once
|
||||
garbage = self._conn.flush_recv()
|
||||
if garbage:
|
||||
self.comLog('garbage: %r', garbage)
|
||||
@@ -325,12 +341,19 @@ class StringIO(IOBase):
|
||||
self.comLog('< %s', reply)
|
||||
return reply
|
||||
except Exception as e:
|
||||
if self._conn is None:
|
||||
raise SilentError('disconnected') from None
|
||||
if repr(e) != self._last_error:
|
||||
self._last_error = repr(e)
|
||||
self.log.error(self._last_error)
|
||||
raise SilentError(repr(e)) from e
|
||||
new_error = 'disconnected' if self._conn is None else repr(e)
|
||||
if new_error != self._last_error:
|
||||
# suppress subsequent equal error messages
|
||||
# this is in addition to the mechanism in Module.callPollFunc
|
||||
# as the same error would appear potentially in a lot of
|
||||
# methods
|
||||
if isinstance(e, SECoPError):
|
||||
self.log.error(new_error)
|
||||
else:
|
||||
self.log.exception(new_error)
|
||||
raise SilentError(new_error) from e
|
||||
finally:
|
||||
self._last_error = new_error
|
||||
|
||||
@Command(StringType())
|
||||
def writeline(self, command):
|
||||
@@ -397,6 +420,34 @@ class StringIO(IOBase):
|
||||
time.sleep(delay)
|
||||
return replies
|
||||
|
||||
@Command(result=StringType())
|
||||
def readline(self):
|
||||
"""read a line, if available within self.timeout
|
||||
|
||||
remark: the call might return earlier, when an other
|
||||
thread consumed the data in parallel
|
||||
"""
|
||||
self.check_connection()
|
||||
try:
|
||||
if self._conn.read_ready(self.timeout):
|
||||
with self._lock: # important: lock only after waiting
|
||||
reply = self._conn.readline(0)
|
||||
if reply:
|
||||
reply = reply.decode(self.encoding)
|
||||
self.comLog('< %s', reply)
|
||||
return reply
|
||||
return ''
|
||||
except ConnectionClosed:
|
||||
self.closeConnection()
|
||||
raise CommunicationFailedError('disconnected') from None
|
||||
except Exception as e:
|
||||
if self._conn is None:
|
||||
raise SilentError('disconnected') from None
|
||||
if repr(e) != self._last_error:
|
||||
self._last_error = repr(e)
|
||||
self.log.error(self._last_error)
|
||||
raise SilentError(repr(e)) from e
|
||||
|
||||
|
||||
def make_regexp(string):
|
||||
"""create a bytes regexp pattern from a string describing a bytes pattern
|
||||
@@ -460,6 +511,7 @@ class BytesIO(IOBase):
|
||||
def communicate(self, request, replylen): # pylint: disable=arguments-differ
|
||||
"""send a request and receive (at least) <replylen> bytes as reply"""
|
||||
self.check_connection()
|
||||
new_error = 'no error' # in case of success (must not be None)
|
||||
try:
|
||||
with self._lock:
|
||||
# read garbage and wait before send
|
||||
@@ -478,12 +530,19 @@ class BytesIO(IOBase):
|
||||
self.comLog('< %s', hexify(reply))
|
||||
return self.getFullReply(request, reply)
|
||||
except Exception as e:
|
||||
if self._conn is None:
|
||||
raise SilentError('disconnected') from None
|
||||
if repr(e) != self._last_error:
|
||||
self._last_error = str(e)
|
||||
self.log.error(self._last_error)
|
||||
raise SilentError(repr(e)) from e
|
||||
new_error = 'disconnected' if self._conn is None else repr(e)
|
||||
if new_error != self._last_error:
|
||||
# suppress subsequent equal error messages
|
||||
# this is in addition to the mechanism in Module.callPollFunc
|
||||
# as the same error would appear potentially in a lot of
|
||||
# methods
|
||||
if isinstance(e, SECoPError):
|
||||
self.log.error(new_error)
|
||||
else:
|
||||
self.log.exception(new_error)
|
||||
raise SilentError(new_error) from e
|
||||
finally:
|
||||
self._last_error = new_error
|
||||
|
||||
@Command(StructOf(requests=ArrayOf(TupleOf(BLOBType(), IntRange(0), FloatRange(0, unit='s')))),
|
||||
result=ArrayOf(BLOBType()))
|
||||
|
||||
@@ -28,10 +28,10 @@ synchronous IO (see frappy.io)
|
||||
"""
|
||||
|
||||
import ast
|
||||
import select
|
||||
import socket
|
||||
import time
|
||||
import re
|
||||
from select import select
|
||||
|
||||
from frappy.errors import CommunicationFailedError, ConfigError
|
||||
from frappy.lib import closeSocket, parse_host_port, SECoP_DEFAULT_PORT
|
||||
@@ -50,8 +50,7 @@ class AsynConn:
|
||||
timeout = 1 # inter byte timeout
|
||||
scheme = None
|
||||
SCHEME_MAP = {}
|
||||
connection = None # is not None, if connected
|
||||
HOSTNAMEPAT = re.compile(r'[a-z0-9_.-]+$', re.IGNORECASE) # roughly checking if it is a valid hostname
|
||||
_connection = None # None means disconnected
|
||||
|
||||
def __new__(cls, uri, end_of_line=b'\n', default_settings=None):
|
||||
scheme = uri.split('://')[0]
|
||||
@@ -85,6 +84,12 @@ class AsynConn:
|
||||
if cls.scheme:
|
||||
cls.SCHEME_MAP[cls.scheme] = cls
|
||||
|
||||
@property
|
||||
def connection(self):
|
||||
if self._connection is None:
|
||||
raise ConnectionClosed()
|
||||
return self._connection
|
||||
|
||||
def shutdown(self):
|
||||
"""prepare connection for disconnect, can be empty"""
|
||||
|
||||
@@ -106,25 +111,34 @@ class AsynConn:
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def recv_nowait(self):
|
||||
"""return bytes in buffer without waiting"""
|
||||
raise NotImplementedError
|
||||
|
||||
def flush_recv(self):
|
||||
"""flush all available bytes (return them)"""
|
||||
raise NotImplementedError
|
||||
result = self._rxbuffer + self.recv_nowait()
|
||||
self._rxbuffer = b''
|
||||
return result
|
||||
|
||||
def readline(self, timeout=None):
|
||||
"""read one line
|
||||
|
||||
return either a complete line or None if no data available within 1 sec (self.timeout)
|
||||
if a non-zero timeout is given, a timeout error is raised instead of returning None
|
||||
the timeout effectively used will not be lower than self.timeout (1 sec)
|
||||
Return either a complete line or None if not enough is available
|
||||
within 1 sec (self.timeout).
|
||||
With timeout=0 no waiting happens at all.
|
||||
If a non-zero timeout is given, a timeout error is raised instead
|
||||
of returning None.
|
||||
The timeout resolution is self.timeout (1 sec by default)
|
||||
"""
|
||||
if timeout:
|
||||
end = time.time() + timeout
|
||||
end = time.time() + timeout if timeout else 0
|
||||
recv = self.recv_nowait if timeout == 0 else self.recv
|
||||
while True:
|
||||
splitted = self._rxbuffer.split(self.end_of_line, 1)
|
||||
if len(splitted) == 2:
|
||||
line, self._rxbuffer = splitted
|
||||
return line
|
||||
data = self.recv()
|
||||
data = recv()
|
||||
if not data:
|
||||
if timeout:
|
||||
if time.time() < end:
|
||||
@@ -136,14 +150,17 @@ class AsynConn:
|
||||
def readbytes(self, nbytes, timeout=None):
|
||||
"""read a fixed number of bytes
|
||||
|
||||
return either <nbytes> bytes or None if not enough data available within 1 sec (self.timeout)
|
||||
if a non-zero timeout is given, a timeout error is raised instead of returning None
|
||||
the timeout effectively used will not be lower than self.timeout (1 sec)
|
||||
Return either <nbytes> bytes or None if not enough data is available
|
||||
within 1 sec (self.timeout).
|
||||
With timeout=0 no waiting happens at all.
|
||||
If a non-zero timeout is given, a timeout error is raised instead
|
||||
of returning None
|
||||
The timeout resolution is self.timeout (1 sec by default)
|
||||
"""
|
||||
if timeout:
|
||||
end = time.time() + timeout
|
||||
end = time.time() + timeout if timeout else 0
|
||||
recv = self.recv_nowait if timeout == 0 else self.recv
|
||||
while len(self._rxbuffer) < nbytes:
|
||||
data = self.recv()
|
||||
data = recv()
|
||||
if not data:
|
||||
if timeout:
|
||||
if time.time() < end:
|
||||
@@ -158,6 +175,9 @@ class AsynConn:
|
||||
def writeline(self, line):
|
||||
self.send(line + self.end_of_line)
|
||||
|
||||
def read_ready(self, timeout=1):
|
||||
return bool(select([self.connection], [], [], timeout)[0])
|
||||
|
||||
|
||||
class AsynTcp(AsynConn):
|
||||
"""a tcp/ip connection
|
||||
@@ -174,45 +194,38 @@ class AsynTcp(AsynConn):
|
||||
if uri.startswith('tcp://'):
|
||||
uri = uri[6:]
|
||||
try:
|
||||
|
||||
host, port = parse_host_port(uri, self.default_settings.get('port', SECoP_DEFAULT_PORT))
|
||||
self.connection = socket.create_connection((host, port), timeout=self.timeout)
|
||||
host, port = parse_host_port(
|
||||
uri, self.default_settings.get('port', SECoP_DEFAULT_PORT))
|
||||
self._connection = socket.create_connection(
|
||||
(host, port), timeout=self.timeout)
|
||||
except (ConnectionRefusedError, socket.gaierror, socket.timeout) as e:
|
||||
# indicate that retrying might make sense
|
||||
raise CommunicationFailedError(f'can not connect to {host}:{port}, {e}') from None
|
||||
|
||||
def shutdown(self):
|
||||
if self.connection:
|
||||
if self._connection:
|
||||
try:
|
||||
self.connection.shutdown(socket.SHUT_RDWR)
|
||||
except OSError:
|
||||
pass # in case socket is already disconnected
|
||||
|
||||
def disconnect(self):
|
||||
if self.connection:
|
||||
if self._connection:
|
||||
closeSocket(self.connection)
|
||||
self.connection = None
|
||||
self._connection = None
|
||||
|
||||
def send(self, data):
|
||||
"""send data (bytes!)"""
|
||||
# remark: will raise socket.timeout when output buffer is full and blocked for 1 sec
|
||||
# remark: will raise socket.timeout when output buffer is full and blocked for self.timeout
|
||||
self.connection.sendall(data)
|
||||
|
||||
def flush_recv(self):
|
||||
"""flush recv buffer"""
|
||||
data = [self._rxbuffer]
|
||||
while select.select([self.connection], [], [], 0)[0]:
|
||||
data.append(self.recv())
|
||||
self._rxbuffer = b''
|
||||
return b''.join(data)
|
||||
|
||||
def recv(self):
|
||||
"""return bytes in the recv buffer
|
||||
|
||||
or bytes received within 1 sec
|
||||
or bytes received within self.timeout
|
||||
"""
|
||||
try:
|
||||
data = self.connection.recv(8192)
|
||||
data = self.connection.recv(1024*1024)
|
||||
if data:
|
||||
return data
|
||||
except (socket.timeout, TimeoutError):
|
||||
@@ -225,6 +238,12 @@ class AsynTcp(AsynConn):
|
||||
# help in this case.
|
||||
raise ConnectionClosed() # marks end of connection
|
||||
|
||||
def recv_nowait(self):
|
||||
"""return bytes in the recv buffer"""
|
||||
if select([self.connection], [], [], 0)[0]:
|
||||
return self.recv()
|
||||
return b''
|
||||
|
||||
|
||||
class AsynSerial(AsynConn):
|
||||
"""a serial connection using pyserial
|
||||
@@ -279,31 +298,41 @@ class AsynSerial(AsynConn):
|
||||
if 'timeout' not in options:
|
||||
options['timeout'] = self.timeout
|
||||
try:
|
||||
self.connection = Serial(dev, **options)
|
||||
self._connection = Serial(dev, **options)
|
||||
except ValueError as e:
|
||||
raise ConfigError(e) from None
|
||||
# TODO: turn exceptions into ConnectionFailedError, where a retry makes sense
|
||||
|
||||
def disconnect(self):
|
||||
if self.connection:
|
||||
if self._connection:
|
||||
self.connection.close()
|
||||
self.connection = None
|
||||
self._connection = None
|
||||
|
||||
def send(self, data):
|
||||
"""send data (bytes!)"""
|
||||
self.connection.write(data)
|
||||
|
||||
def flush_recv(self):
|
||||
result = self._rxbuffer + self.connection.read(self.connection.in_waiting)
|
||||
self._rxbuffer = b''
|
||||
return result
|
||||
|
||||
def recv(self):
|
||||
"""return bytes received within 1 sec"""
|
||||
if not self.connection: # disconnect() might have been called in between
|
||||
raise ConnectionClosed()
|
||||
"""return bytes received within self.timeout"""
|
||||
n = self.connection.in_waiting
|
||||
if n:
|
||||
return self.connection.read(n)
|
||||
data = self.connection.read(1)
|
||||
return data + self.connection.read(self.connection.in_waiting)
|
||||
|
||||
def recv_nowait(self):
|
||||
n = self.connection.in_waiting
|
||||
return self.connection.read(n) if n else b''
|
||||
|
||||
if not hasattr(Serial, 'fileno'):
|
||||
# select is not supported for serial objects (Windows)
|
||||
# create a less efficient workaround
|
||||
def read_ready(self, timeout=1):
|
||||
if self.connection.in_waiting:
|
||||
return True
|
||||
deadline = time.time() + timeout
|
||||
while time.time() < deadline:
|
||||
if self.connection.in_waiting:
|
||||
return True
|
||||
time.sleep(0.05)
|
||||
return False
|
||||
|
||||
90
frappy/lib/mathparser.py
Normal file
90
frappy/lib/mathparser.py
Normal file
@@ -0,0 +1,90 @@
|
||||
# *****************************************************************************
|
||||
#
|
||||
# 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>
|
||||
# Anik Stark <anik.stark@psi.ch>
|
||||
# https://stackoverflow.com/questions/43836866/safely-evaluate-simple-string-equation
|
||||
#
|
||||
# *****************************************************************************
|
||||
|
||||
import math
|
||||
import ast
|
||||
import operator as op
|
||||
|
||||
class MathParser:
|
||||
_operators2method = {
|
||||
ast.Add: op.add,
|
||||
ast.Sub: op.sub,
|
||||
ast.BitXor: op.xor,
|
||||
ast.Or: op.or_,
|
||||
ast.And: op.and_,
|
||||
ast.Mod: op.mod,
|
||||
ast.Mult: op.mul,
|
||||
ast.Div: op.truediv,
|
||||
ast.Pow: op.pow,
|
||||
ast.FloorDiv: op.floordiv,
|
||||
ast.USub: op.neg,
|
||||
ast.UAdd: lambda a:a}
|
||||
|
||||
def __init__(self, math=True, **kwargs):
|
||||
self._vars = kwargs
|
||||
if not math:
|
||||
self._alt_name = self._no_alt_name
|
||||
|
||||
def _Name(self, name):
|
||||
try:
|
||||
return self._vars[name] # look up in user-provided dict
|
||||
except KeyError:
|
||||
return self._alt_name(name) # fall back to math functions
|
||||
|
||||
@staticmethod
|
||||
def _alt_name(name):
|
||||
if name.startswith("_"): # prevent access to hidden names
|
||||
raise NameError(f"{name!r}")
|
||||
try:
|
||||
return getattr(math, name)
|
||||
except AttributeError:
|
||||
raise NameError(f"{name!r}")
|
||||
|
||||
@staticmethod
|
||||
def _no_alt_name(name):
|
||||
raise NameError(f"{name!r}")
|
||||
|
||||
def eval_(self, node):
|
||||
if isinstance(node, ast.Expression):
|
||||
return self.eval_(node.body)
|
||||
if isinstance(node, ast.Constant): # return the number
|
||||
return node.value
|
||||
if isinstance(node, ast.Name): # return variable or math function
|
||||
return self._Name(node.id)
|
||||
if isinstance(node, ast.BinOp): # evaluate binary operations
|
||||
method = self._operators2method[type(node.op)]
|
||||
return method( self.eval_(node.left), self.eval_(node.right))
|
||||
if isinstance(node, ast.UnaryOp): # handle operators
|
||||
method = self._operators2method[type(node.op)]
|
||||
return method( self.eval_(node.operand) )
|
||||
if isinstance(node, ast.Attribute): # handle attributes (e.g. math.cos)
|
||||
return getattr(self.eval_(node.value), node.attr)
|
||||
if isinstance(node, ast.Call): # evaluate the function and its arguments, calls function
|
||||
return self.eval_(node.func)(
|
||||
*(self.eval_(a) for a in node.args),
|
||||
**{k.arg:self.eval_(k.value) for k in node.keywords})
|
||||
raise TypeError(node)
|
||||
|
||||
def calculate(self, expr, **kwargs):
|
||||
self._vars.update(kwargs)
|
||||
return self.eval_(ast.parse(expr, mode='eval'))
|
||||
@@ -32,15 +32,11 @@ from frappy.datatypes import ArrayOf, BoolType, EnumType, FloatRange, \
|
||||
NoneOr
|
||||
from frappy.errors import BadValueError, CommunicationFailedError, ConfigError, \
|
||||
ProgrammingError, SECoPError, secop_error, RangeError
|
||||
from frappy.lib import formatException, mkthread, UniqueObject
|
||||
from frappy.lib import formatException, mkthread, UniqueObject, generalConfig
|
||||
from frappy.params import Accessible, Command, Parameter, Limit, PREDEFINED_ACCESSIBLES
|
||||
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']
|
||||
PREDEF_ORDER = list(PREDEFINED_ACCESSIBLES)
|
||||
|
||||
Done = UniqueObject('Done')
|
||||
@@ -248,7 +244,7 @@ class PollInfo:
|
||||
self.interval = pollinterval
|
||||
self.last_main = 0
|
||||
self.last_slow = 0
|
||||
self.pending_errors = set()
|
||||
self.pending_errors = {}
|
||||
self.polled_parameters = []
|
||||
self.fast_flag = False
|
||||
self.trigger_event = trigger_event
|
||||
@@ -310,8 +306,8 @@ class Module(HasAccessibles):
|
||||
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')
|
||||
interface_classes = Property('offical interface-classes of the module', ArrayOf(StringType()),
|
||||
extname='interface_classes', default=[])
|
||||
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)
|
||||
@@ -324,6 +320,9 @@ class Module(HasAccessibles):
|
||||
pollInfo = None
|
||||
triggerPoll = None # trigger event for polls. used on io modules and modules without io
|
||||
__poller = None # the poller thread, if used
|
||||
SECoP_CLASS = None
|
||||
SECoP_BASE_CLASSES = [] # predefined SECoP base classes
|
||||
SECoP_CLASSES = [] # all predefined SECoP interface classes
|
||||
|
||||
def __init__(self, name, logger, cfgdict, srv):
|
||||
# remember the secnode for interacting with other modules and the
|
||||
@@ -340,8 +339,8 @@ class Module(HasAccessibles):
|
||||
self.updateLock = threading.RLock() # for announceUpdate
|
||||
self.polledModules = [] # modules polled by thread started in self.startModules
|
||||
self.attachedModules = {}
|
||||
self.errors = []
|
||||
self._isinitialized = False
|
||||
self._initfailed = False
|
||||
self.updateCallback = srv.dispatcher.announce_update
|
||||
|
||||
# handle module properties
|
||||
@@ -367,17 +366,13 @@ class Module(HasAccessibles):
|
||||
else:
|
||||
self.setProperty(key, value)
|
||||
except BadValueError:
|
||||
self.errors.append(f'{key}: value {value!r} does not match {self.propertyDict[key].datatype!r}!')
|
||||
self.logError(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__]
|
||||
|
||||
@@ -398,7 +393,7 @@ class Module(HasAccessibles):
|
||||
|
||||
# 3) complain about names not found as accessible or property names
|
||||
if cfgdict:
|
||||
self.errors.append(
|
||||
self.logError(
|
||||
f"{', '.join(cfgdict.keys())} does not exist (use one of"
|
||||
f" {', '.join(list(self.accessibles) + list(self.propertyDict))})")
|
||||
|
||||
@@ -414,18 +409,17 @@ class Module(HasAccessibles):
|
||||
self.applyMainUnit(mainunit)
|
||||
|
||||
# 6) check complete configuration of * properties
|
||||
if not self.errors:
|
||||
try:
|
||||
self.checkProperties()
|
||||
except ProgrammingError:
|
||||
raise
|
||||
except SECoPError as e:
|
||||
self.logError(str(e))
|
||||
for aname, aobj in self.accessibles.items():
|
||||
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)
|
||||
aobj.checkProperties()
|
||||
except SECoPError as e:
|
||||
self.logError(f'{aname}: {e}')
|
||||
|
||||
# helper cfg-editor
|
||||
def __iter__(self):
|
||||
@@ -453,15 +447,19 @@ class Module(HasAccessibles):
|
||||
self.commands[name] = accessible
|
||||
if cfg is not None:
|
||||
try:
|
||||
# apply datatype first
|
||||
datatype = cfg.pop('datatype', None)
|
||||
if datatype is not None:
|
||||
accessible.setProperty('datatype', datatype)
|
||||
for propname, propvalue in cfg.items():
|
||||
if propname in {'value', 'default', 'constant'}:
|
||||
# these properties have ValueType(), but should be checked for datatype
|
||||
accessible.datatype(cfg[propname])
|
||||
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)}')
|
||||
self.logError(f"'{name}' has no property '{propname}'")
|
||||
except SECoPError as e:
|
||||
self.logError(type(e)(f'{name}.{propname}: {e}'))
|
||||
if isinstance(accessible, Parameter):
|
||||
self._handle_writes(name, accessible)
|
||||
|
||||
@@ -475,17 +473,17 @@ class Module(HasAccessibles):
|
||||
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}')
|
||||
self.logError(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')
|
||||
self.logError(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!')
|
||||
self.logError(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
|
||||
@@ -533,7 +531,6 @@ class Module(HasAccessibles):
|
||||
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
|
||||
@@ -610,8 +607,6 @@ class Module(HasAccessibles):
|
||||
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:
|
||||
self.__poller = mkthread(self.__pollThread, self.polledModules, start_events.get_trigger())
|
||||
self.startModuleDone = True
|
||||
@@ -670,29 +665,31 @@ class Module(HasAccessibles):
|
||||
self.pollInfo.interval = fast_interval if flag else self.pollinterval
|
||||
self.pollInfo.trigger()
|
||||
|
||||
def callPollFunc(self, rfunc, raise_com_failed=False):
|
||||
def callPollFunc(self, rfunc, pollname=None, raise_com_failed=False):
|
||||
"""call read method with proper error handling"""
|
||||
try:
|
||||
name = pollname or rfunc.__name__
|
||||
rfunc()
|
||||
if rfunc.__name__ in self.pollInfo.pending_errors:
|
||||
self.log.info('%s: o.k.', rfunc.__name__)
|
||||
self.pollInfo.pending_errors.discard(rfunc.__name__)
|
||||
if self.pollInfo.pending_errors.pop(name, None):
|
||||
self.log.info('%s: o.k.', 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
|
||||
prev = self.pollInfo.pending_errors.get(name)
|
||||
if isinstance(e, SECoPError):
|
||||
if pollname:
|
||||
e.raising_methods.append(pollname)
|
||||
self.log.debug('%s failed with %r', pollname, e)
|
||||
if raise_com_failed and isinstance(e, CommunicationFailedError):
|
||||
raise
|
||||
efmt = None if e.silent else e.format(False)
|
||||
if efmt != prev:
|
||||
self.log.error('%s', efmt)
|
||||
else:
|
||||
# not a SECoPError: this is proabably a programming error
|
||||
efmt = repr(e)
|
||||
if efmt != prev:
|
||||
# we want to log the traceback
|
||||
self.log.error('%s', formatException())
|
||||
self.log.exception('%s', efmt)
|
||||
self.pollInfo.pending_errors[name] = efmt
|
||||
|
||||
def __pollThread(self, modules, started_callback):
|
||||
"""poll thread body
|
||||
@@ -723,35 +720,42 @@ class Module(HasAccessibles):
|
||||
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
|
||||
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`
|
||||
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
|
||||
if started_callback:
|
||||
started_callback()
|
||||
if not polled_modules: # no polls needed - exit thread
|
||||
return
|
||||
to_poll = ()
|
||||
report_day = time.localtime().tm_min
|
||||
while modules: # modules will be cleared on shutdown
|
||||
now = time.time()
|
||||
today = time.localtime().tm_min
|
||||
if today != report_day:
|
||||
report_day = today
|
||||
for mobj in modules:
|
||||
pending = mobj.pollInfo.pending_errors
|
||||
if pending:
|
||||
self.log.info('%d pending errors', len(pending))
|
||||
# this will trigger again logging these errors
|
||||
# or logging o.k. on success
|
||||
pending.update((k, 'x') for k in pending)
|
||||
wait_time = 999
|
||||
for mobj in modules:
|
||||
pinfo = mobj.pollInfo
|
||||
@@ -771,7 +775,7 @@ class Module(HasAccessibles):
|
||||
pinfo.last_main = (now // pinfo.interval) * pinfo.interval
|
||||
except ZeroDivisionError:
|
||||
pinfo.last_main = now
|
||||
mobj.callPollFunc(mobj.doPoll)
|
||||
mobj.callPollFunc(mobj.doPoll, f'{mobj.name}.doPoll')
|
||||
now = time.time()
|
||||
# find ONE due slow poll and call it
|
||||
loop = True
|
||||
@@ -867,3 +871,15 @@ class Module(HasAccessibles):
|
||||
raise RangeError(f'{pname} below {pname}_min')
|
||||
if value > max_:
|
||||
raise RangeError(f'{pname} above {pname}_max')
|
||||
|
||||
def logError(self, error):
|
||||
"""log error or raise, depending on generalConfig settings
|
||||
|
||||
:param error: an exception or a str (considered as ConfigError)
|
||||
|
||||
to be used during startup
|
||||
"""
|
||||
if generalConfig.raise_config_errors:
|
||||
raise ConfigError(error) if isinstance(error, str) else error
|
||||
self.log.error(str(error))
|
||||
self.secNode.error_count += 1
|
||||
|
||||
@@ -22,20 +22,24 @@
|
||||
# *****************************************************************************
|
||||
"""Define base classes for real Modules implemented in the server"""
|
||||
|
||||
|
||||
from frappy.datatypes import FloatRange, \
|
||||
StatusType, StringType
|
||||
from frappy.datatypes import BoolType, 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
|
||||
from frappy.params import Command, Parameter
|
||||
|
||||
from .modulebase import Module
|
||||
from .attached import AttachedDict
|
||||
|
||||
# import compatibility:
|
||||
# pylint: disable=unused-import
|
||||
from .properties import Property
|
||||
from .attached import Attached
|
||||
|
||||
|
||||
class Readable(Module):
|
||||
"""basic readable module"""
|
||||
interface_classes = ['Readable']
|
||||
# pylint: disable=invalid-name
|
||||
Status = Enum('Status',
|
||||
IDLE=StatusType.IDLE,
|
||||
@@ -55,6 +59,7 @@ class Readable(Module):
|
||||
|
||||
class Writable(Readable):
|
||||
"""basic writable module"""
|
||||
interface_classes = ['Writable']
|
||||
target = Parameter('target value of the module',
|
||||
default=0, readonly=False, datatype=FloatRange(unit='$'))
|
||||
|
||||
@@ -74,7 +79,7 @@ class Writable(Readable):
|
||||
|
||||
class Drivable(Writable):
|
||||
"""basic drivable module"""
|
||||
|
||||
interface_classes = ['Drivable']
|
||||
status = Parameter(datatype=StatusType(Readable, 'BUSY')) # extend Readable.status
|
||||
|
||||
def isBusy(self, status=None):
|
||||
@@ -96,8 +101,80 @@ class Drivable(Writable):
|
||||
"""not implemented - this is a no-op"""
|
||||
|
||||
|
||||
class AcquisitionChannel(Readable):
|
||||
"""A Readable which is part of a data acquisition."""
|
||||
interface_classes = ['AcquisitionChannel', 'Readable']
|
||||
# copy Readable.status and extend it with BUSY
|
||||
status = Parameter(datatype=StatusType(Readable, 'BUSY'))
|
||||
goal = Parameter('stops the data acquisition when it is reached',
|
||||
FloatRange(), default=0, readonly=False, optional=True)
|
||||
goal_enable = Parameter('enable goal', BoolType(), readonly=False,
|
||||
default=False, optional=True)
|
||||
|
||||
# clear is no longer part of the proposed spec, so it does not appear
|
||||
# as optional command here. however, a subclass may still implement it
|
||||
|
||||
|
||||
class AcquisitionController(Module):
|
||||
"""Controls other modules.
|
||||
|
||||
Controls the data acquisition from AcquisitionChannels.
|
||||
"""
|
||||
interface_classes = ['AcquisitionController']
|
||||
# channels might be configured to an arbitrary number of channels with arbitrary roles
|
||||
# - to forbid the use fo arbitrary roles, override base=None
|
||||
# - to restrict roles and base classes override elements={<key>: <basecls>}
|
||||
# and/or optional={<key>: <basecls>}
|
||||
channels = AttachedDict('mapping of role to module name for attached channels',
|
||||
elements=None, optional=None,
|
||||
basecls=AcquisitionChannel,
|
||||
extname='acquisition_channels')
|
||||
status = Drivable.status
|
||||
isBusy = Drivable.isBusy
|
||||
# add pollinterval parameter to enable faster polling of the status
|
||||
pollinterval = Readable.pollinterval
|
||||
|
||||
def doPoll(self):
|
||||
self.read_status()
|
||||
|
||||
@Command()
|
||||
def go(self):
|
||||
"""Start the acquisition. No-op if the controller is already Busy."""
|
||||
raise NotImplementedError()
|
||||
|
||||
@Command(optional=True)
|
||||
def prepare(self):
|
||||
"""Prepare the hardware so 'go' can trigger immediately."""
|
||||
|
||||
@Command(optional=True)
|
||||
def hold(self):
|
||||
"""Pause the operation.
|
||||
|
||||
The next go will continue without clearing any channels or resetting hardware."""
|
||||
|
||||
@Command(optional=True)
|
||||
def stop(self):
|
||||
"""Stop the data acquisition or operation."""
|
||||
|
||||
|
||||
class Acquisition(AcquisitionController, AcquisitionChannel): # pylint: disable=abstract-method
|
||||
"""Combines AcquisitionController and AcquisitionChannel into one Module
|
||||
|
||||
for the special case where there is only one channel.
|
||||
remark: when using multiple inheritance, Acquisition must appear
|
||||
before any base class inheriting from AcquisitionController
|
||||
"""
|
||||
interface_classes = ['Acquisition', 'Readable']
|
||||
channels = None # remove property
|
||||
acquisition_key = Property('acquisition role (equivalent to NICOS preset name)',
|
||||
StringType(), export=True, default='')
|
||||
|
||||
doPoll = Readable.doPoll
|
||||
|
||||
|
||||
class Communicator(HasComlog, Module):
|
||||
"""basic abstract communication module"""
|
||||
interface_classes = ['Communicator']
|
||||
|
||||
@Command(StringType(), result=StringType())
|
||||
def communicate(self, command):
|
||||
@@ -107,41 +184,3 @@ class Communicator(HasComlog, Module):
|
||||
:return: the reply
|
||||
"""
|
||||
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
|
||||
super().__init__(description, StringType(), mandatory=mandatory)
|
||||
|
||||
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 not isinstance(modobj, self.basecls):
|
||||
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
|
||||
|
||||
def copy(self):
|
||||
return Attached(self.basecls, self.description, self.mandatory)
|
||||
|
||||
@@ -23,10 +23,9 @@
|
||||
|
||||
|
||||
import inspect
|
||||
|
||||
from frappy.datatypes import ArrayOf, BoolType, CommandType, DataType, \
|
||||
DataTypeType, EnumType, FloatRange, NoneOr, OrType, StringType, StructOf, \
|
||||
TextType, TupleOf, ValueType
|
||||
DataTypeType, DefaultType, EnumType, FloatRange, NoneOr, OrType, StringType, \
|
||||
StructOf, TextType, TupleOf, ValueType
|
||||
from frappy.errors import BadValueError, ProgrammingError, WrongTypeError
|
||||
from frappy.lib import generalConfig
|
||||
from frappy.properties import HasProperties, Property
|
||||
@@ -144,7 +143,7 @@ class Parameter(Accessible):
|
||||
extname='description', mandatory=True, export='always')
|
||||
datatype = Property(
|
||||
'datatype of the Parameter (SECoP datainfo)', DataTypeType(),
|
||||
extname='datainfo', mandatory=True, export='always', default=ValueType())
|
||||
extname='datainfo', mandatory=True, export='always', default=DefaultType())
|
||||
readonly = Property(
|
||||
'not changeable via SECoP (default True)', BoolType(),
|
||||
extname='readonly', default=True, export='always')
|
||||
@@ -233,13 +232,13 @@ class Parameter(Accessible):
|
||||
try:
|
||||
return instance.parameters[self.name].value
|
||||
except KeyError:
|
||||
raise ProgrammingError(f'optional parameter {self.name} it is not implemented') from None
|
||||
raise ProgrammingError(f'optional parameter {self.name} is not implemented') from None
|
||||
|
||||
def __set__(self, obj, value):
|
||||
try:
|
||||
obj.announceUpdate(self.name, value)
|
||||
except KeyError:
|
||||
raise ProgrammingError(f'optional parameter {self.name} it is not implemented') from None
|
||||
raise ProgrammingError(f'optional parameter {self.name} is not implemented') from None
|
||||
|
||||
def __set_name__(self, owner, name):
|
||||
self.name = name
|
||||
@@ -342,7 +341,9 @@ class Parameter(Accessible):
|
||||
try:
|
||||
self.datatype.setProperty(key, value)
|
||||
except KeyError:
|
||||
raise ProgrammingError(f'cannot set {key} on parameter with datatype {type(self.datatype).__name__}') from None
|
||||
raise ProgrammingError(
|
||||
f'cannot set {key} on parameter with datatype'
|
||||
f' {type(self.datatype).__name__}') from None
|
||||
except BadValueError as e:
|
||||
raise ProgrammingError(f'property {key}: {str(e)}') from None
|
||||
|
||||
|
||||
@@ -94,6 +94,7 @@ logger = MainLogger()
|
||||
|
||||
class Playground(Server):
|
||||
def __init__(self, **kwds): # pylint: disable=super-init-not-called
|
||||
self.name = 'playground'
|
||||
for modname, cfg in kwds.items():
|
||||
cfg.setdefault('description', modname)
|
||||
self.log = logger.log
|
||||
|
||||
@@ -141,6 +141,10 @@ class HasProperties(HasDescriptors):
|
||||
for pn, po in list(properties.items()):
|
||||
value = getattr(cls, pn, po)
|
||||
if not isinstance(value, Property): # attribute may be a bare value
|
||||
if value is None:
|
||||
# this allows to remove a property defined in a base class
|
||||
cls.propertyDict.pop(pn)
|
||||
continue
|
||||
po = po.copy()
|
||||
try:
|
||||
# try to apply bare value to Property
|
||||
@@ -155,7 +159,7 @@ class HasProperties(HasDescriptors):
|
||||
def checkProperties(self):
|
||||
"""validates properties and checks for min... <= max..."""
|
||||
for pn, po in self.propertyDict.items():
|
||||
if po.mandatory:
|
||||
if po.mandatory or pn in self.propertyValues:
|
||||
try:
|
||||
self.propertyValues[pn] = po.datatype.validate(self.propertyValues[pn])
|
||||
except (KeyError, BadValueError):
|
||||
|
||||
@@ -23,6 +23,9 @@
|
||||
import os
|
||||
import json
|
||||
import socket
|
||||
import select
|
||||
from time import monotonic
|
||||
from collections import namedtuple
|
||||
|
||||
from frappy.lib import closeSocket
|
||||
from frappy.protocol.interface.tcp import format_address
|
||||
@@ -32,6 +35,79 @@ UDP_PORT = 10767
|
||||
MAX_MESSAGE_LEN = 508
|
||||
|
||||
|
||||
Answer = namedtuple('Answer',
|
||||
'address, hostname, port, equipment_id, firmware, description')
|
||||
|
||||
|
||||
def decode(msg, addr):
|
||||
msg = msg.decode('utf-8')
|
||||
try:
|
||||
data = json.loads(msg)
|
||||
except Exception:
|
||||
return None
|
||||
if not isinstance(data, dict):
|
||||
return None
|
||||
if data.get('SECoP') != 'node':
|
||||
return None
|
||||
try:
|
||||
eq_id = data['equipment_id']
|
||||
fw = data['firmware']
|
||||
desc = data['description']
|
||||
port = data['port']
|
||||
except KeyError:
|
||||
return None
|
||||
try:
|
||||
hostname = socket.gethostbyaddr(addr[0])[0]
|
||||
except Exception:
|
||||
hostname = addr[0]
|
||||
return Answer(addr[0], hostname, port, eq_id, fw, desc)
|
||||
|
||||
|
||||
def scan(max_wait=1.0):
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
|
||||
# send a general broadcast
|
||||
try:
|
||||
s.sendto(json.dumps(dict(SECoP='discover')).encode('utf-8'),
|
||||
('255.255.255.255', UDP_PORT))
|
||||
except OSError as e:
|
||||
print('could not send the broadcast:', e)
|
||||
# we still keep listening for self-announcements
|
||||
seen = set()
|
||||
start = monotonic()
|
||||
while monotonic() < start + max_wait:
|
||||
res = select.select([s], [], [], 0.1)
|
||||
if res[0]:
|
||||
try:
|
||||
msg, addr = s.recvfrom(1024)
|
||||
except socket.error: # pragma: no cover
|
||||
continue
|
||||
answer = decode(msg, addr)
|
||||
if answer is None:
|
||||
continue
|
||||
if (answer.address, answer.equipment_id, answer.port) in seen:
|
||||
continue
|
||||
seen.add((answer.address, answer.equipment_id, answer.port))
|
||||
yield answer
|
||||
|
||||
|
||||
def listen():
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
if os.name == 'nt':
|
||||
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
else:
|
||||
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
|
||||
s.bind(('0.0.0.0', UDP_PORT))
|
||||
while True:
|
||||
try:
|
||||
msg, addr = s.recvfrom(1024)
|
||||
except KeyboardInterrupt:
|
||||
break
|
||||
answer = decode(msg, addr)
|
||||
if answer:
|
||||
yield answer
|
||||
|
||||
|
||||
class UDPListener:
|
||||
def __init__(self, equipment_id, description, ifaces, logger, *,
|
||||
startup_broadcast=True):
|
||||
|
||||
@@ -20,12 +20,12 @@
|
||||
# *****************************************************************************
|
||||
|
||||
import time
|
||||
import traceback
|
||||
from collections import OrderedDict
|
||||
|
||||
from frappy.dynamic import Pinata
|
||||
from frappy.errors import ConfigError, NoSuchModuleError, NoSuchParameterError
|
||||
from frappy.lib import get_class
|
||||
from frappy.errors import NoSuchModuleError, NoSuchParameterError, SECoPError, \
|
||||
ConfigError, ProgrammingError
|
||||
from frappy.lib import get_class, generalConfig
|
||||
from frappy.version import get_version
|
||||
from frappy.modules import Module
|
||||
|
||||
@@ -38,6 +38,7 @@ class SecNode:
|
||||
- get_module(modulename) returns the requested module or None if there is
|
||||
no suitable configuration on the server
|
||||
"""
|
||||
raise_config_errors = False # collect catchable errors instead of raising
|
||||
|
||||
def __init__(self, name, logger, options, srv):
|
||||
self.equipment_id = options.pop('equipment_id', name)
|
||||
@@ -46,11 +47,7 @@ class SecNode:
|
||||
self.modules = {}
|
||||
self.log = logger
|
||||
self.srv = srv
|
||||
# set of modules that failed creation
|
||||
self.failed_modules = set()
|
||||
# list of errors that occured during initialization
|
||||
self.errors = []
|
||||
self.traceback_counter = 0
|
||||
self.error_count = 0 # count catchable errors during initialization
|
||||
self.name = name
|
||||
|
||||
def add_secnode_property(self, prop, value):
|
||||
@@ -58,6 +55,18 @@ class SecNode:
|
||||
in the description."""
|
||||
self.nodeprops[prop] = value
|
||||
|
||||
def logError(self, error):
|
||||
"""log error or raise, depending on generalConfig settings
|
||||
|
||||
:param error: an exception or a str (considered as ConfigError)
|
||||
|
||||
to be used during startup
|
||||
"""
|
||||
if generalConfig.raise_config_errors:
|
||||
raise ConfigError(error) if isinstance(error, str) else error
|
||||
self.log.error(str(error))
|
||||
self.error_count += 1
|
||||
|
||||
def get_secnode_property(self, prop):
|
||||
"""Get SECNode property.
|
||||
|
||||
@@ -76,20 +85,18 @@ class SecNode:
|
||||
|
||||
# also call earlyInit on the modules
|
||||
self.log.debug('initializing module %r', modulename)
|
||||
try:
|
||||
modobj.earlyInit()
|
||||
if not modobj.earlyInitDone:
|
||||
self.errors.append(f'{modobj.earlyInit.__qualname__} was not '
|
||||
f'called, probably missing super call')
|
||||
modobj.initModule()
|
||||
if not modobj.initModuleDone:
|
||||
self.errors.append(f'{modobj.initModule.__qualname__} was not '
|
||||
f'called, probably missing super call')
|
||||
except Exception as e:
|
||||
if self.traceback_counter == 0:
|
||||
self.log.exception(traceback.format_exc())
|
||||
self.traceback_counter += 1
|
||||
self.errors.append(f'error initializing {modulename}: {e!r}')
|
||||
modobj.earlyInit()
|
||||
if not modobj.earlyInitDone:
|
||||
self.logError(ProgrammingError(
|
||||
f'module {modulename}: '
|
||||
'Module.earlyInit was not called, probably missing super call'))
|
||||
modobj.earlyInitDone = True
|
||||
modobj.initModule()
|
||||
if not modobj.initModuleDone:
|
||||
self.logError(ProgrammingError(
|
||||
f'module {modulename}: '
|
||||
'Module.initModule was not called, probably missing super call'))
|
||||
modobj.initModuleDone = True
|
||||
modobj._isinitialized = True
|
||||
self.log.debug('initialized module %r', modulename)
|
||||
return modobj
|
||||
@@ -115,51 +122,22 @@ class SecNode:
|
||||
raise NoSuchModuleError(f'Module {modulename!r} does not exist on '
|
||||
f'this SEC-Node!')
|
||||
opts = dict(opts)
|
||||
pymodule = None
|
||||
try: # pylint: disable=no-else-return
|
||||
classname = opts.pop('cls')
|
||||
classname = opts.pop('cls')
|
||||
try:
|
||||
if isinstance(classname, str):
|
||||
pymodule = classname.rpartition('.')[0]
|
||||
if pymodule in self.failed_modules:
|
||||
# creation has failed already once, do not try again
|
||||
return None
|
||||
cls = get_class(classname)
|
||||
else:
|
||||
pymodule = classname.__module__
|
||||
if pymodule in self.failed_modules:
|
||||
# creation has failed already once, do not try again
|
||||
return None
|
||||
cls = classname
|
||||
if not issubclass(cls, Module):
|
||||
self.errors.append(f'{cls.__name__} is not a Module')
|
||||
self.logError(f'{cls.__name__} is not a Module')
|
||||
return None
|
||||
except Exception as e:
|
||||
except AttributeError as e:
|
||||
if str(e) == 'no such class':
|
||||
self.errors.append(f'{classname} not found')
|
||||
else:
|
||||
self.failed_modules.add(pymodule)
|
||||
if self.traceback_counter == 0:
|
||||
self.log.exception(traceback.format_exc())
|
||||
self.traceback_counter += 1
|
||||
self.errors.append(f'error importing {classname}')
|
||||
return None
|
||||
else:
|
||||
try:
|
||||
modobj = cls(modulename, self.log.parent.getChild(modulename),
|
||||
opts, self.srv)
|
||||
except ConfigError as e:
|
||||
self.errors.append(f'error creating module {modulename}:')
|
||||
for errtxt in e.args[0] if isinstance(e.args[0], list) else [e.args[0]]:
|
||||
self.errors.append(' ' + errtxt)
|
||||
modobj = None
|
||||
except Exception as e:
|
||||
if self.traceback_counter == 0:
|
||||
self.log.exception(traceback.format_exc())
|
||||
self.traceback_counter += 1
|
||||
self.errors.append(f'error creating {modulename}')
|
||||
modobj = None
|
||||
if modobj:
|
||||
self.add_module(modobj, modulename)
|
||||
self.logError(f'{classname} not found')
|
||||
return None
|
||||
raise
|
||||
modobj = cls(modulename, self.log.parent.getChild(modulename),
|
||||
opts, self.srv)
|
||||
return modobj
|
||||
|
||||
def create_modules(self):
|
||||
@@ -190,6 +168,19 @@ class SecNode:
|
||||
self.log.info('Pinata %s found %d modules',
|
||||
modname, len(pinata_modules))
|
||||
todos.extend(pinata_modules)
|
||||
# initialize all modules
|
||||
for modname in self.modules:
|
||||
modobj = self.get_module(modname)
|
||||
# check attached modules for existence
|
||||
# normal properties are retrieved too, but this does not harm
|
||||
for prop in modobj.propertyDict:
|
||||
try:
|
||||
getattr(modobj, prop)
|
||||
except SECoPError as e:
|
||||
if self.raise_config_errors:
|
||||
raise
|
||||
self.error_count += 1
|
||||
modobj.logError(e)
|
||||
|
||||
def export_accessibles(self, modobj):
|
||||
self.log.debug('export_accessibles(%r)', modobj.name)
|
||||
@@ -267,7 +258,7 @@ class SecNode:
|
||||
now = time.time()
|
||||
deadline = now + 0.5 # should be long enough for most read functions to finish
|
||||
for mod in self.modules.values():
|
||||
mod.joinPollThread(max(0, deadline - now))
|
||||
mod.joinPollThread(max(0.0, deadline - now))
|
||||
now = time.time()
|
||||
for name in self._getSortedModules():
|
||||
self.modules[name].shutdownModule()
|
||||
|
||||
@@ -31,7 +31,7 @@ import time
|
||||
import mlzlog
|
||||
|
||||
from frappy.config import load_config
|
||||
from frappy.errors import ConfigError
|
||||
from frappy.errors import ConfigError, ProgrammingError
|
||||
from frappy.lib import formatException, generalConfig, get_class, mkthread
|
||||
from frappy.lib.multievent import MultiEvent
|
||||
from frappy.logging import init_remote_logging
|
||||
@@ -39,6 +39,8 @@ from frappy.params import PREDEFINED_ACCESSIBLES
|
||||
from frappy.secnode import SecNode
|
||||
from frappy.protocol.discovery import UDPListener
|
||||
|
||||
generalConfig.set_default('raise_config_errors', False)
|
||||
|
||||
try:
|
||||
from daemon import DaemonContext
|
||||
try:
|
||||
@@ -299,33 +301,35 @@ class Server:
|
||||
for k in list(opts):
|
||||
self.secnode.add_secnode_property(k, opts.pop(k))
|
||||
|
||||
self.secnode.create_modules()
|
||||
# initialize modules by calling self.secnode.get_module for all of them
|
||||
# this is done in build_descriptive_data even for unexported modules
|
||||
self.secnode.build_descriptive_data()
|
||||
# =========== All modules are initialized ===========
|
||||
try:
|
||||
self.secnode.create_modules()
|
||||
# initialize modules by calling self.secnode.get_module for all of them
|
||||
# this is done in build_descriptive_data even for unexported modules
|
||||
self.secnode.build_descriptive_data()
|
||||
# =========== All modules are initialized ===========
|
||||
|
||||
# all errors from initialization process
|
||||
errors = self.secnode.errors
|
||||
|
||||
if not self._testonly:
|
||||
start_events = MultiEvent(default_timeout=30)
|
||||
for modname, modobj in self.secnode.modules.items():
|
||||
# startModule must return either a timeout value or None (default 30 sec)
|
||||
start_events.name = f'module {modname}'
|
||||
modobj.startModule(start_events)
|
||||
if not modobj.startModuleDone:
|
||||
errors.append(f'{modobj.startModule.__qualname__} was not called, probably missing super call')
|
||||
|
||||
if errors:
|
||||
for errtxt in errors:
|
||||
for line in errtxt.split('\n'):
|
||||
self.log.error(line)
|
||||
# print a list of config errors to stderr
|
||||
sys.stderr.write('\n'.join(errors))
|
||||
sys.stderr.write('\n')
|
||||
if not self._testonly:
|
||||
start_events = MultiEvent(default_timeout=30)
|
||||
for modname, modobj in self.secnode.modules.items():
|
||||
# startModule must return either a timeout value or None (default 30 sec)
|
||||
start_events.name = f'module {modname}'
|
||||
if self.secnode.error_count:
|
||||
# do not start poll thread. check for startModuleDone only
|
||||
modobj.polledModules = []
|
||||
modobj.startModule(start_events)
|
||||
if not modobj.startModuleDone:
|
||||
self.secnode.log_error(ProgrammingError(
|
||||
f'module {modname}: '
|
||||
'Module.startModule was not called, probably missing super call'))
|
||||
except Exception as e:
|
||||
if self.secnode.error_count:
|
||||
raise type(e)(
|
||||
f'{e.args[0]} - see also {self.secnode.error_count}'
|
||||
' errors logged above') from e
|
||||
raise
|
||||
if self.secnode.error_count:
|
||||
self.log.error('%d errors during initialisation', self.secnode.error_count)
|
||||
sys.exit(1)
|
||||
|
||||
if self._testonly:
|
||||
return
|
||||
self.log.info('waiting for modules being started')
|
||||
@@ -334,6 +338,9 @@ class Server:
|
||||
# some timeout happened
|
||||
for name in start_events.waiting_for():
|
||||
self.log.warning('timeout when starting %s', name)
|
||||
if self.secnode.error_count:
|
||||
self.log.error('%d errors during startup', self.secnode.error_count)
|
||||
sys.exit(1)
|
||||
self.log.info('all modules started')
|
||||
history_path = os.environ.get('FRAPPY_HISTORY')
|
||||
if history_path:
|
||||
|
||||
241
frappy_demo/acquisition.py
Normal file
241
frappy_demo/acquisition.py
Normal file
@@ -0,0 +1,241 @@
|
||||
# *****************************************************************************
|
||||
#
|
||||
# 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:
|
||||
# Alexander Zaft <a.zaft@fz-juelich.de>
|
||||
# Markus Zolliker <markus.zolliker@psi.ch>
|
||||
#
|
||||
# *****************************************************************************
|
||||
import time
|
||||
import random
|
||||
import threading
|
||||
from frappy.lib import clamp, mkthread
|
||||
from frappy.core import IntRange, Parameter, ArrayOf, TupleOf, FloatRange, \
|
||||
IDLE, ERROR, BUSY
|
||||
from frappy.modules import AcquisitionController, AcquisitionChannel, Acquisition
|
||||
from frappy.params import Command
|
||||
|
||||
|
||||
class AcquisitionSimulation:
|
||||
def __init__(self, keys):
|
||||
self.values = {k: 0 for k in keys}
|
||||
self.err = None
|
||||
self._stopflag = threading.Event()
|
||||
self.run_acquisition = threading.Event()
|
||||
self.lock = threading.Lock()
|
||||
self.need_reset = False
|
||||
self._thread = None
|
||||
self.start()
|
||||
|
||||
def start(self):
|
||||
if self.need_reset:
|
||||
self.reset()
|
||||
if self._thread is None:
|
||||
self._thread = mkthread(self.threadfun)
|
||||
|
||||
def threadfun(self):
|
||||
self.sim_interval = 1
|
||||
self.err = None
|
||||
try:
|
||||
self.__sim()
|
||||
except Exception as e:
|
||||
self.err = str(e)
|
||||
# the thread stops here, but will be restarted with the go command
|
||||
self._thread = None
|
||||
|
||||
def __sim(self):
|
||||
timestamp = time.time()
|
||||
delay = 0
|
||||
while not self._stopflag.wait(delay):
|
||||
self.run_acquisition.wait()
|
||||
t = time.time()
|
||||
diff = t - timestamp
|
||||
if diff < self.sim_interval:
|
||||
delay = clamp(0.1, self.sim_interval, 10)
|
||||
continue
|
||||
delay = 0
|
||||
with self.lock:
|
||||
self.values = {k: v + max(0., random.normalvariate(4., 1.))
|
||||
for k, v in self.values.items()}
|
||||
timestamp = t
|
||||
|
||||
def reset(self):
|
||||
with self.lock:
|
||||
for key in self.values:
|
||||
self.values[key] = 0
|
||||
self.need_reset = False
|
||||
|
||||
def shutdown(self):
|
||||
# unblock thread:
|
||||
self._stopflag.set()
|
||||
self.run_acquisition.set()
|
||||
if self._thread and self._thread.is_alive():
|
||||
self._thread.join()
|
||||
|
||||
|
||||
class Controller(AcquisitionController):
|
||||
_status = None # for sticky status values
|
||||
|
||||
def init_ac(self):
|
||||
self.ac = AcquisitionSimulation(m.name for m in self.channels.values())
|
||||
self.ac.reset()
|
||||
for key, channel in self.channels.items():
|
||||
self.log.debug('register %s: %s', key, channel.name)
|
||||
channel.register_acq(self.ac)
|
||||
|
||||
def initModule(self):
|
||||
super().initModule()
|
||||
self.init_ac()
|
||||
|
||||
def read_status(self):
|
||||
with self.ac.lock:
|
||||
if self.ac.err:
|
||||
status = self.Status.ERROR, self.ac.err
|
||||
elif self.ac.run_acquisition.is_set():
|
||||
status = self.Status.BUSY, 'running acquisition'
|
||||
else:
|
||||
status = self._status or (self.Status.IDLE, '')
|
||||
for chan in self.channels.values():
|
||||
chan.read_status()
|
||||
return status
|
||||
|
||||
def go(self):
|
||||
self.ac.start() # restart sim thread if it failed
|
||||
self.ac.run_acquisition.set()
|
||||
self._status = None
|
||||
self.read_status()
|
||||
|
||||
def hold(self):
|
||||
self.ac.run_acquisition.clear()
|
||||
self._status = IDLE, 'paused'
|
||||
self.read_status()
|
||||
|
||||
def stop(self):
|
||||
self.ac.run_acquisition.clear()
|
||||
self.ac.need_reset = True
|
||||
self._status = IDLE, 'stopped'
|
||||
|
||||
@Command()
|
||||
def clear(self):
|
||||
"""clear all channels"""
|
||||
self.ac.reset()
|
||||
|
||||
def shutdownModule(self):
|
||||
self.ac.shutdown()
|
||||
|
||||
|
||||
class Channel(AcquisitionChannel):
|
||||
_status = None # for sticky status values
|
||||
# activate optional parameters:
|
||||
goal = Parameter()
|
||||
goal_enable = Parameter()
|
||||
|
||||
def register_acq(self, ac):
|
||||
self.ac = ac
|
||||
|
||||
def read_value(self):
|
||||
with self.ac.lock:
|
||||
try:
|
||||
ret = self.ac.values[self.name]
|
||||
except KeyError:
|
||||
return -1
|
||||
if self.goal_enable and self.goal < ret:
|
||||
if self.ac.run_acquisition.is_set():
|
||||
self.ac.run_acquisition.clear()
|
||||
self.ac.need_reset = True
|
||||
self._status = IDLE, 'hit goal'
|
||||
else:
|
||||
self._status = None
|
||||
return ret
|
||||
|
||||
def read_status(self):
|
||||
if self.ac.err:
|
||||
return ERROR, self.ac.err
|
||||
if self.ac.run_acquisition.is_set():
|
||||
return BUSY, 'running acquisition'
|
||||
return self._status or (IDLE, '')
|
||||
|
||||
@Command()
|
||||
def clear(self):
|
||||
"""clear this channel"""
|
||||
with self.ac.lock:
|
||||
try:
|
||||
self.ac.values[self.name] = 0.
|
||||
except KeyError:
|
||||
pass
|
||||
self.read_value()
|
||||
|
||||
|
||||
class SimpleAcquisition(Acquisition, Controller, Channel):
|
||||
def init_ac(self):
|
||||
self.channels = {}
|
||||
self.ac = AcquisitionSimulation([self.name])
|
||||
self.ac.reset()
|
||||
|
||||
|
||||
class NoGoalAcquisition(Acquisition):
|
||||
_value = 0
|
||||
_deadline = 0
|
||||
|
||||
def read_value(self):
|
||||
return self._value
|
||||
|
||||
def read_status(self):
|
||||
if self.status[0] == BUSY:
|
||||
overtime = time.time() - self._deadline
|
||||
if overtime < 0:
|
||||
return BUSY, ''
|
||||
self.setFastPoll(False)
|
||||
self._value = overtime
|
||||
self.read_value()
|
||||
return IDLE, ''
|
||||
|
||||
def go(self):
|
||||
self._value = 0
|
||||
self.status = BUSY, 'started'
|
||||
self.setFastPoll(True, 0.1)
|
||||
self._deadline = time.time() + 1
|
||||
self.read_status()
|
||||
|
||||
|
||||
# TODO
|
||||
class MatrixChannel(AcquisitionChannel):
|
||||
roi = Parameter('region of interest',
|
||||
ArrayOf(TupleOf(IntRange(), IntRange()), 0, 1),
|
||||
default=[], readonly=False)
|
||||
|
||||
def initModule(self):
|
||||
self.data = [0.] * 128
|
||||
|
||||
def read_value(self):
|
||||
# mean of data or roi
|
||||
if self.roi:
|
||||
b, e = self.roi[0]
|
||||
else:
|
||||
b, e = 0, len(self.data) - 1
|
||||
return self.data[b:e] / (e - b)
|
||||
|
||||
def write_roi(self, roi):
|
||||
pass
|
||||
|
||||
@Command(result=ArrayOf(FloatRange()))
|
||||
def get_data(self):
|
||||
return self.data
|
||||
|
||||
# axes
|
||||
# binning
|
||||
def clear(self):
|
||||
raise NotImplementedError()
|
||||
@@ -248,6 +248,10 @@ class SampleTemp(Drivable):
|
||||
# note: setting self.target to the new value is done after this....
|
||||
# note: we may also return the read-back value from the hw here
|
||||
|
||||
def stop(self):
|
||||
"""Stop and keep temperature at current position."""
|
||||
self.target = self.value
|
||||
|
||||
def _thread(self):
|
||||
loopdelay = 1
|
||||
while True:
|
||||
|
||||
@@ -53,6 +53,7 @@ class WithAtt(Readable):
|
||||
def read_value(self):
|
||||
return self.att.read_value()
|
||||
|
||||
|
||||
class LN2(Readable):
|
||||
"""Just a readable.
|
||||
|
||||
|
||||
@@ -1,128 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
# *****************************************************************************
|
||||
# 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>
|
||||
# *****************************************************************************
|
||||
"""Andeen Hagerling capacitance bridge
|
||||
|
||||
two modules: the capacitance itself and the loss angle
|
||||
|
||||
in the configuration file, only the capacitance module needs to be configured,
|
||||
while the loss module will be created automatically.
|
||||
|
||||
the name of the loss module may be configured, or disabled by choosing
|
||||
an empty name
|
||||
"""
|
||||
|
||||
from frappy.core import FloatRange, HasIO, Parameter, Readable, StringIO, nopoll, \
|
||||
Attached, Property, StringType
|
||||
from frappy.dynamic import Pinata
|
||||
|
||||
|
||||
class Ah2700IO(StringIO):
|
||||
end_of_line = '\r\n'
|
||||
timeout = 5
|
||||
|
||||
|
||||
class Capacitance(HasIO, Pinata, Readable):
|
||||
value = Parameter('capacitance', FloatRange(unit='pF'))
|
||||
freq = Parameter('frequency', FloatRange(unit='Hz'), readonly=False, default=0)
|
||||
voltage = Parameter('voltage', FloatRange(unit='V'), readonly=False, default=0)
|
||||
loss_name = Property('''name of loss module (default: <name>_loss)
|
||||
|
||||
configure '' to disable the creation of the loss module
|
||||
''',
|
||||
StringType(), default='$_loss')
|
||||
|
||||
ioClass = Ah2700IO
|
||||
loss = 0 # not a parameter
|
||||
|
||||
def scanModules(self):
|
||||
if self.loss_name:
|
||||
# if loss_name is not empty, we tell the framework to create
|
||||
# a module for the loss with this name, and config below
|
||||
yield self.loss_name.replace('$', self.name), {
|
||||
'cls': Loss,
|
||||
'description': f'loss value of {self.name}',
|
||||
'cap': self.name}
|
||||
|
||||
def parse_reply(self, reply):
|
||||
if reply.startswith('SI'): # this is an echo
|
||||
self.communicate('SERIAL ECHO OFF')
|
||||
reply = self.communicate('SI')
|
||||
if not reply.startswith('F='): # this is probably an error message like "LOSS TOO HIGH"
|
||||
self.status = self.Status.ERROR, reply
|
||||
return self.value
|
||||
self.status = self.Status.IDLE, ''
|
||||
# examples of replies:
|
||||
# 'F= 1000.0 HZ C= 0.000001 PF L> 0.0 DS V= 15.0 V'
|
||||
# 'F= 1000.0 HZ C= 0.0000059 PF L=-0.4 DS V= 15.0 V OVEN'
|
||||
# 'LOSS TOO HIGH'
|
||||
# make sure there is always a space after '=' and '>'
|
||||
# split() ignores multiple white space
|
||||
reply = reply.replace('=', '= ').replace('>', '> ').split()
|
||||
_, freq, _, _, cap, _, _, loss, lossunit, _, volt = reply[:11]
|
||||
self.freq = freq
|
||||
self.voltage = volt
|
||||
if lossunit == 'DS':
|
||||
self.loss = loss
|
||||
else: # the unit was wrong, we want DS = tan(delta), not NS = nanoSiemens
|
||||
reply = self.communicate('UN DS').split() # UN DS returns a reply similar to SI
|
||||
try:
|
||||
self.loss = reply[7]
|
||||
except IndexError:
|
||||
pass # don't worry, loss will be updated next time
|
||||
return cap
|
||||
|
||||
def read_value(self):
|
||||
return self.parse_reply(self.communicate('SI')) # SI = single trigger
|
||||
|
||||
@nopoll
|
||||
def read_freq(self):
|
||||
self.read_value()
|
||||
return self.freq
|
||||
|
||||
@nopoll
|
||||
def read_voltage(self):
|
||||
self.read_value()
|
||||
return self.voltage
|
||||
|
||||
def write_freq(self, value):
|
||||
self.value = self.parse_reply(self.communicate(f'FR {value:g};SI'))
|
||||
return self.freq
|
||||
|
||||
def write_voltage(self, value):
|
||||
self.value = self.parse_reply(self.communicate(f'V {value:g};SI'))
|
||||
return self.voltage
|
||||
|
||||
|
||||
class Loss(Readable):
|
||||
cap = Attached()
|
||||
value = Parameter('loss', FloatRange(unit='deg'), default=0)
|
||||
|
||||
def initModule(self):
|
||||
super().initModule()
|
||||
self.cap.registerCallbacks(self, ['status']) # auto update status
|
||||
|
||||
def update_value(self, _):
|
||||
# value is always changed shortly after loss
|
||||
self.value = self.cap.loss
|
||||
|
||||
@nopoll
|
||||
def read_value(self):
|
||||
self.cap.read_value()
|
||||
return self.cap.loss
|
||||
450
frappy_psi/ahcapbridge.py
Normal file
450
frappy_psi/ahcapbridge.py
Normal file
@@ -0,0 +1,450 @@
|
||||
# *****************************************************************************
|
||||
# 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>
|
||||
# *****************************************************************************
|
||||
"""Andeen Hagerling capacitance bridge
|
||||
|
||||
The speciality of this capacitance bridge is, that a measurement might take
|
||||
between factions of seconds up to more than half an hour.
|
||||
|
||||
creates up to two additional modules for 'loss' and 'freq'
|
||||
|
||||
in the configuration file, only the capacitance module needs to be configured,
|
||||
while the loss module will be created automatically.
|
||||
|
||||
the name of the loss (and freq) module may be configured, or disabled by
|
||||
choosing an empty name
|
||||
"""
|
||||
|
||||
import re
|
||||
import time
|
||||
import threading
|
||||
from frappy.core import HasIO, Parameter, Readable, StringIO, \
|
||||
Attached, Property, Command, Writable, BUSY, IDLE, WARN
|
||||
from frappy.datatypes import FloatRange, IntRange, StringType, TupleOf
|
||||
from frappy.modules import Acquisition
|
||||
from frappy.dynamic import Pinata
|
||||
from frappy.errors import IsBusyError, CommunicationFailedError, HardwareError
|
||||
|
||||
|
||||
CONTINUOUS = 0
|
||||
STARTING = 1
|
||||
RUNNING = 2
|
||||
FINISHED = 3
|
||||
|
||||
|
||||
class IO(StringIO):
|
||||
end_of_line = ('\r\n', '\r')
|
||||
timeout = 5
|
||||
sent_command = False # used to detect that communicate was called directly
|
||||
ECHO = re.compile('>|AV |VO |FR |SI |SH ') # this is recognized as an echo
|
||||
MEAS = None # overriden by the module
|
||||
|
||||
@Command(StringType(), result=StringType())
|
||||
def communicate(self, command, noreply=False):
|
||||
"""communicate and remind that a command was sent"""
|
||||
# this is also called by writeline
|
||||
self.sent_command = True
|
||||
for _ in range(3):
|
||||
reply = super().communicate(command, noreply)
|
||||
reply = reply and reply.strip()
|
||||
if self.check_echo_off(reply):
|
||||
return reply
|
||||
raise CommunicationFailedError('detected echo but can not switch off')
|
||||
|
||||
def check_echo_off(self, reply):
|
||||
if self.ECHO.match(reply or ''):
|
||||
super().writeline('\rSERIAL ECHO OFF;UN 2')
|
||||
for _ in range(3):
|
||||
reply = self.readline()
|
||||
if self.MEAS.match(reply or ''):
|
||||
# this is a meas reply
|
||||
break
|
||||
if reply == 'NO DATA FOUND':
|
||||
break
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
class AHBase(HasIO, Pinata, Acquisition):
|
||||
value = Parameter('capacitance', FloatRange(unit='pF'))
|
||||
freq = Parameter('frequency', FloatRange(unit='Hz'), default=1000)
|
||||
voltage = Parameter('upper voltage limit',
|
||||
FloatRange(0, 15, unit='V', fmtstr='%.1f'),
|
||||
readonly=False, default=0)
|
||||
loss = Parameter('loss',
|
||||
FloatRange(unit=''), default=0)
|
||||
averexp = Parameter('average exponent - roughly log2 of number of samples averaged',
|
||||
IntRange(0, 15), readonly=False, default=0)
|
||||
goal = Parameter('value for averexp for the next go()',
|
||||
IntRange(0, 15), readonly=False, default=0)
|
||||
meas_time = Parameter('measured measuring time',
|
||||
FloatRange(unit='s', fmtstr='%.4g'), default=0)
|
||||
calculated_time = Parameter('calculated measuring time',
|
||||
FloatRange(unit='s', fmtstr='%.4g'), default=0)
|
||||
loss_module = Property(
|
||||
'''name of loss module (default: <name>_loss)
|
||||
|
||||
configure '' to disable the creation of the loss module
|
||||
''', StringType(), default='')
|
||||
pollinterval = Parameter('minimum pollinterval - the polling rate is determined by averaging',
|
||||
value=0.1)
|
||||
|
||||
export = True # for a Pinata module, the default is False!
|
||||
ioClass = IO
|
||||
_error = ''
|
||||
_last_start = None
|
||||
_params = None
|
||||
_mode = CONTINUOUS # or RUNNING or FINISHED
|
||||
_cont_deadline = 0 # when to switch back to continuous after finished
|
||||
_averexp_deadline = 0 # to make sure averexp is polled periodically
|
||||
_lossunit = 'undefined'
|
||||
# to be overridden:
|
||||
PATTERN = None # a list of patterns to parse replies
|
||||
MEAS_PAT = None # the pattern to parse the measurement reply
|
||||
UNIT = None # our desired loss unit
|
||||
MODEL_PAT = None
|
||||
MODEL = None
|
||||
|
||||
def scanModules(self):
|
||||
if self.loss_module:
|
||||
# if loss_module is not empty, we tell the framework to create
|
||||
# a module for the loss with this name, and config below
|
||||
yield self.loss_module.replace('$', self.name), {
|
||||
'cls': Loss,
|
||||
'description': f'loss value of {self.name}',
|
||||
'cap': self.name}
|
||||
|
||||
def initModule(self):
|
||||
super().initModule()
|
||||
self._lock = threading.RLock()
|
||||
self.io.MEAS = self.MEAS_PAT
|
||||
self.io.checkHWIdent = self.checkHWIdent
|
||||
|
||||
def checkHWIdent(self):
|
||||
for _ in range(3):
|
||||
if self.MODEL_PAT.match(self.communicate('SH MODEL')):
|
||||
return
|
||||
raise CommunicationFailedError(f'we are not connected to a {self.MODEL}')
|
||||
|
||||
def initialReads(self):
|
||||
# UN 2 does also return the results of the last measurement
|
||||
# (including the frequency for AH2700)
|
||||
self.freq = self.get_param('FR', 'freq')
|
||||
self.set_lossunit()
|
||||
self.verify_averexp()
|
||||
self.goal = self.averexp
|
||||
self.single_meas()
|
||||
|
||||
def communicate(self, command):
|
||||
reply = self.io.communicate(command)
|
||||
self.io.sent_command = False
|
||||
return reply
|
||||
|
||||
def set_lossunit(self):
|
||||
self._lossunit = self.UNIT
|
||||
reply = self.communicate('UN 2')
|
||||
# this should be a measurement reply
|
||||
mdict = self.get_meas_reply(reply)
|
||||
unit = mdict.get('lossunit', 'undefined')
|
||||
if unit == self.UNIT:
|
||||
if self._lossunit != self.UNIT:
|
||||
self.log.warn('changed loss unit from %r to %r', self._lossunit, self.UNIT)
|
||||
else:
|
||||
self.log.warn('bad reply for UN 2: %r', reply)
|
||||
self._lossunit = unit
|
||||
|
||||
def change_param(self, short, value, param):
|
||||
if self._mode == RUNNING:
|
||||
raise IsBusyError('can not change parameters while measuring')
|
||||
with self._lock:
|
||||
for _ in range(3):
|
||||
reply = self.communicate(f'{short} {value};SH {short}')
|
||||
match = self.PATTERN[param].match(reply)
|
||||
if match:
|
||||
result = match.group(1)
|
||||
self.retrigger_meas()
|
||||
return float(result)
|
||||
self.retrigger_meas()
|
||||
raise CommunicationFailedError(f'can not change {param} to {value}')
|
||||
|
||||
def get_param(self, short, param):
|
||||
with self._lock:
|
||||
for _ in range(3):
|
||||
reply = self.communicate(f'SH {short}')
|
||||
match = self.PATTERN[param].match(reply)
|
||||
if match:
|
||||
result = match.group(1)
|
||||
self.retrigger_meas()
|
||||
return float(result)
|
||||
self.retrigger_meas()
|
||||
raise CommunicationFailedError(f'can not get {param}')
|
||||
|
||||
def retrigger_meas(self):
|
||||
if self._mode == CONTINUOUS:
|
||||
self.single_meas()
|
||||
|
||||
def single_meas(self):
|
||||
self._last_start = time.time()
|
||||
self.io.writeline('SI')
|
||||
self.io.sent_command = False
|
||||
|
||||
def get_meas_reply(self, reply):
|
||||
match = self.MEAS_PAT.match(reply)
|
||||
if match:
|
||||
return match.groupdict()
|
||||
return {}
|
||||
|
||||
def doPoll(self):
|
||||
# this typically waits longer than the low pollinterval
|
||||
# -> after returning, doPoll is called again immediately
|
||||
reply = self.io.readline()
|
||||
if reply:
|
||||
meas = self.get_meas_reply(reply)
|
||||
if meas:
|
||||
self.update_meas(**meas)
|
||||
else:
|
||||
self.io.check_echo_off(reply)
|
||||
self.retrigger_meas()
|
||||
elif self._mode == FINISHED and time.time() > self._cont_deadline:
|
||||
self._mode = CONTINUOUS
|
||||
self.status = IDLE, ''
|
||||
self.single_meas()
|
||||
elif self.io.sent_command:
|
||||
# self.io.communicate was called directly
|
||||
# -> we have to retrigger SI again
|
||||
if self._mode == CONTINUOUS:
|
||||
self.single_meas()
|
||||
elif self._mode == RUNNING:
|
||||
self.finish(WARN, 'interrupted')
|
||||
|
||||
def update_freq(self, value):
|
||||
self.freq = value
|
||||
self._calculate_time(self.averexp, value)
|
||||
|
||||
def update_averexp(self, value):
|
||||
self.averexp = value
|
||||
self._averexp_deadline = time.time() + 15
|
||||
self._calculate_time(value, self.freq)
|
||||
|
||||
def update_meas(self, cap, loss, lossunit, voltage, error, freq=None):
|
||||
"""update given arguments from a measurement reply (these are strings!)"""
|
||||
self._error = error
|
||||
if self._error:
|
||||
status = WARN, self._error
|
||||
else:
|
||||
status = IDLE, '' if self._mode == CONTINUOUS else 'finished'
|
||||
now = time.time()
|
||||
if self._mode == RUNNING:
|
||||
self.finish(*status)
|
||||
elif status != self.status:
|
||||
self.status = status
|
||||
if freq:
|
||||
self.freq = float(freq)
|
||||
self._calculate_time(self.averexp, self.freq)
|
||||
self.value = float(cap)
|
||||
self.voltage = float(voltage)
|
||||
if lossunit != self.UNIT:
|
||||
self.set_lossunit()
|
||||
self.retrigger_meas()
|
||||
return
|
||||
self.loss = float(loss)
|
||||
if self._last_start:
|
||||
self.meas_time = now - self._last_start
|
||||
self._last_start = 0
|
||||
if now > self._averexp_deadline and self._mode == CONTINUOUS:
|
||||
self.verify_averexp()
|
||||
else:
|
||||
self.retrigger_meas()
|
||||
|
||||
def read_loss(self):
|
||||
if self._lossunit != self.UNIT:
|
||||
raise HardwareError(f'bad loss unit: {self._lossunit!r}')
|
||||
return self.loss
|
||||
|
||||
def write_voltage(self, value):
|
||||
return round(self.change_param('VO', f'{value:.1f}', 'voltage'), 1)
|
||||
|
||||
def write_averexp(self, value):
|
||||
self.update_averexp(self.change_param('AV', f'{value}', 'averexp'))
|
||||
|
||||
def verify_averexp(self):
|
||||
# we do not want to use read_averexp for this,
|
||||
# as it will stop the measurement when polled
|
||||
self.update_averexp(self.get_param('AV', 'averexp'))
|
||||
|
||||
def _calculate_time(self, averexp, freq):
|
||||
self.calculated_time = self.calculate_time(averexp, freq)
|
||||
|
||||
def go(self):
|
||||
"""start acquisition"""
|
||||
prevmode = self._mode
|
||||
self._mode = STARTING
|
||||
if prevmode != FINISHED or time.time() > self._averexp_deadline:
|
||||
# this also makes sure we catch a previous meas reply
|
||||
self.verify_averexp()
|
||||
if self.averexp != self.goal:
|
||||
self.write_averexp(self.goal)
|
||||
self.status = BUSY, 'started'
|
||||
self.single_meas()
|
||||
self._mode = RUNNING
|
||||
|
||||
def finish(self, statuscode, statustext):
|
||||
self.status = statuscode, statustext
|
||||
self._mode = FINISHED
|
||||
self._cont_deadline = time.time() + 5
|
||||
|
||||
def stop(self):
|
||||
"""stops measurement"""
|
||||
if self._mode == RUNNING:
|
||||
self.verify_averexp()
|
||||
self.finish(WARN, 'stopped')
|
||||
|
||||
def calculate_time(self, averexp, freq):
|
||||
"""estimate measuring time"""
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class Loss(Readable):
|
||||
cap = Attached()
|
||||
value = Parameter('loss', FloatRange(unit=''), default=0)
|
||||
|
||||
def initModule(self):
|
||||
super().initModule()
|
||||
self.cap.addCallback('loss', self.update_loss) # auto update status
|
||||
|
||||
def update_freq(self, freq):
|
||||
self.freq = float(freq)
|
||||
|
||||
def update_loss(self, loss):
|
||||
self.value = float(loss)
|
||||
|
||||
|
||||
class Freq(Writable):
|
||||
cap = Attached()
|
||||
value = Parameter('', FloatRange(unit='Hz'), default=0)
|
||||
|
||||
def initModule(self):
|
||||
super().initModule()
|
||||
self.cap.addCallback('freq', self.update_freq) # auto update status
|
||||
|
||||
def update_freq(self, freq):
|
||||
self.value = freq
|
||||
|
||||
def write_target(self, target):
|
||||
self.cap.write_freq(target)
|
||||
|
||||
|
||||
class AH2550(AHBase):
|
||||
PATTERN = {
|
||||
'averexp': re.compile(r'AVERAGE_AVEREXP *([0-9]*)'),
|
||||
'voltage': re.compile(r'VOLTAGE_HIGHEST *([0-9.E+-]+)'),
|
||||
'freq': re.compile(r'FREQUENCY *([0-9.E+-]+)'),
|
||||
}
|
||||
MEAS_PAT = re.compile(
|
||||
r'C= *(?P<cap>[0-9.E+-]+) *PF,'
|
||||
r'L= *(?P<loss>[0-9.E+-]+) *(?P<lossunit>[A-Z]*),'
|
||||
r'V= *(?P<voltage>[0-9.E+-]+) *V,A,*(?P<error>.*)$'
|
||||
)
|
||||
UNIT = 'DF'
|
||||
MODEL_PAT = re.compile('ILLEGAL WORD: MODEL')
|
||||
MODEL = 'AH2550'
|
||||
|
||||
# empirically determined - may vary with noise
|
||||
# differs drastically from the table in the manual
|
||||
MEAS_TIME_CONST = [0.2, 0.3, 0.4, 1.0, 1.3, 1.6, 2.2, 3.3,
|
||||
5.5, 8.3, 14, 25, 47, 91, 180, 360]
|
||||
|
||||
def _calculate_time(self, averexp, freq):
|
||||
self.calculated_time = self.calculate_time(averexp)
|
||||
|
||||
@Command(TupleOf(IntRange(0, 15)), result=FloatRange())
|
||||
def calculate_time(self, averexp):
|
||||
"""calculate estimated measuring time"""
|
||||
return self.MEAS_TIME_CONST[int(averexp)]
|
||||
|
||||
|
||||
class AH2700(AHBase):
|
||||
freq = Parameter(datatype=FloatRange(50, 20000, unit='Hz', fmtstr='%.1f'),
|
||||
readonly=False)
|
||||
freq_module = Property('''name of freq module
|
||||
|
||||
default: not created
|
||||
''',
|
||||
StringType(), default='')
|
||||
PATTERN = {
|
||||
'averexp': re.compile(r'AVERAGE *AVEREXP=([0-9]*)'),
|
||||
'voltage': re.compile(r'VOLTAGE HIGHEST *([0-9.E+-]+)'),
|
||||
'freq': re.compile(r'FREQUENCY *([0-9.E+-]+)'),
|
||||
}
|
||||
MEAS_PAT = re.compile(
|
||||
r'F= *(?P<freq>[0-9.E+-]+) *HZ '
|
||||
r'C= *(?P<cap>[0-9.E+-]+) *PF '
|
||||
r'L= *(?P<loss>[0-9.E+-]+) *(?P<lossunit>[A-Z]*) '
|
||||
f'V= *(?P<voltage>[0-9.E+-]+) *V *(?P<error>.*)$'
|
||||
)
|
||||
UNIT = 'DS'
|
||||
MODEL_PAT = re.compile('MODEL/OPTIONS *AH2700')
|
||||
MODEL = 'AH2700'
|
||||
|
||||
def scanModules(self):
|
||||
yield from super().scanModules()
|
||||
if self.freq_module:
|
||||
yield self.freq_module.replace('$', self.name), {
|
||||
'cls': Freq,
|
||||
'description': f'freq module of {self.name}',
|
||||
'cap': self.name}
|
||||
|
||||
def write_freq(self, value):
|
||||
self.change_param('FR', f'{value:g}', 'freq')
|
||||
self.update_freq(value)
|
||||
return round(value, 1)
|
||||
|
||||
# empirically determined - may vary with noise
|
||||
# differs drastically from the table in the manual
|
||||
MEAS_TIME_CONST = [
|
||||
# (upper freq limit, meas time @ avrexp=7 )
|
||||
(75, 20.8),
|
||||
(150, 10.8),
|
||||
(270, 6.42),
|
||||
(550, 3.14),
|
||||
(1100, 3.53),
|
||||
(4500, 1.82),
|
||||
(20000, 1.31),
|
||||
]
|
||||
|
||||
@Command(TupleOf(IntRange(0, 15), FloatRange(50, 20000)),
|
||||
result=FloatRange())
|
||||
def calculate_time(self, averexp, freq):
|
||||
"""calculate estimated measuring time
|
||||
|
||||
from time efficiency considerations averexp > 7 is recommended
|
||||
especially for freq < 550 no time is saved with averexp <= 7
|
||||
"""
|
||||
for f, c in self.MEAS_TIME_CONST:
|
||||
if f > freq:
|
||||
const = c
|
||||
break
|
||||
else:
|
||||
const = self.MEAS_TIME_CONST[-1][1]
|
||||
if averexp >= 8:
|
||||
result = 0.8 + (const - 0.8) * (0.5 + 2 ** (averexp - 8))
|
||||
elif freq < 550:
|
||||
result = const
|
||||
else:
|
||||
result = 0.6 + 2 ** (averexp - 7) * (const - 0.8)
|
||||
return round(result, 1)
|
||||
@@ -47,6 +47,7 @@ Mod('out',
|
||||
|
||||
|
||||
from frappy.core import StringIO, Readable, Parameter, FloatRange, Writable, HasIO, BoolType
|
||||
from frappy.ctrlby import HasControlledBy
|
||||
|
||||
|
||||
# define the IO class
|
||||
@@ -65,10 +66,10 @@ class Power(HasIO, Readable):
|
||||
return volt*current
|
||||
|
||||
|
||||
class Output(HasIO, Writable):
|
||||
class Output(HasIO, HasControlledBy, Writable):
|
||||
value = Parameter(datatype=FloatRange(0,100,unit='%'), default=0)
|
||||
target = Parameter(datatype=FloatRange(0,100,unit='%'))
|
||||
p_value = Parameter(datatype=FloatRange(0,100,unit='%'), default=0)
|
||||
p_value = Parameter('?', datatype=FloatRange(0,100,unit='%'), default=0)
|
||||
maxvolt = Parameter('voltage at 100%',datatype=FloatRange(0,60,unit='V'),default=50,readonly=False)
|
||||
maxcurrent = Parameter('current at 100%',datatype=FloatRange(0,5,unit='A'),default=2,readonly=False)
|
||||
output_enable = Parameter('control on/off', BoolType(), readonly=False)
|
||||
@@ -77,7 +78,7 @@ class Output(HasIO, Writable):
|
||||
super().initModule()
|
||||
self.write_output_enable(False)
|
||||
|
||||
def write_target(self, target):
|
||||
def set_target(self, target):
|
||||
self.write_output_enable(target != 0)
|
||||
self.communicate(f'VOLT{round(max(8,(target)**0.5 * self.maxvolt)):03d}')
|
||||
self.communicate(f'CURR{round((target)**0.5* 10 * self.maxcurrent):03d}')
|
||||
|
||||
@@ -84,7 +84,7 @@ class Base(HasIO):
|
||||
|
||||
|
||||
class Resistance(Base, Readable):
|
||||
value = Parameter('resistance', datatype=FloatRange, unit='ohm')
|
||||
value = Parameter('resistance', datatype=FloatRange, unit='Ohm')
|
||||
output_offset = Parameter('resistance deviation', datatype=FloatRange, unit='Ohm', readonly=False)
|
||||
phase_hold = Parameter('phase hold', EnumType('phase hold', off=0, on=1))
|
||||
|
||||
@@ -93,7 +93,7 @@ class Resistance(Base, Readable):
|
||||
irange = Parameter('resistance range index', EnumType('resistance range index',
|
||||
{name: idx for idx, name in enumerate(RES_RANGE)}),
|
||||
readonly=False)
|
||||
range = Parameter('resistance range value', FloatRange(2e-2, 2e7), unit='Om', readonly=False)
|
||||
range = Parameter('resistance range value', FloatRange(2e-2, 2e7), unit='Ohm', readonly=False)
|
||||
|
||||
TIME_CONST = ['0.3s', '1s', '3s', '10s', '30s', '100s', '300s']
|
||||
itc = Parameter('time constant index',
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user