Compare commits
57 Commits
Author | SHA1 | Date | |
---|---|---|---|
6d63c4e0df | |||
98fa19ce3b | |||
7f83f76d38 | |||
0ab849d0cf | |||
8ee49caba5 | |||
b1de9218bd | |||
8eaad86b66 | |||
85400a2777 | |||
dda4afbe5b | |||
9b079ddf4b | |||
898da75b89 | |||
a7a846dfba | |||
6da671df62 | |||
bdb14af4af | |||
e57ad9826e | |||
8775103bf8 | |||
![]() |
5636a76152 | ||
![]() |
745cc69e9e | ||
![]() |
b4c0a827f0 | ||
d57416a73e | |||
![]() |
8dcf6ca658 | ||
bc66a314c4 | |||
6fac63d769 | |||
e41692bf2c | |||
dff3bd2f24 | |||
b67e5a9260 | |||
4815f4e6b4 | |||
e8ec9b415a | |||
5b9e36180e | |||
f1b59e4150 | |||
17070ca732 | |||
![]() |
d618fafe4b | ||
![]() |
dd1dfb3094 | ||
8d6617e288 | |||
![]() |
fdec531c99 | ||
a246584c4a | |||
![]() |
00ef174292 | ||
![]() |
ada66f4851 | ||
![]() |
a9be6475b1 | ||
![]() |
f380289a84 | ||
![]() |
528d80652c | ||
![]() |
7c6df58906 | ||
![]() |
1851c0ac43 | ||
880d472a4a | |||
![]() |
25ff96873b | ||
![]() |
82881049c4 | ||
![]() |
60c9737cfe | ||
![]() |
632db924eb | ||
![]() |
261121297b | ||
![]() |
1bd243f3d2 | ||
![]() |
7c3f9f7196 | ||
9074dfda9d | |||
de32eb09e6 | |||
2e97f0f0ce | |||
0b06acf304 | |||
cc90291358 | |||
03b4604643 |
@ -204,6 +204,9 @@ max-statements=150
|
|||||||
# Maximum number of parents for a class (see R0901).
|
# Maximum number of parents for a class (see R0901).
|
||||||
max-parents=20
|
max-parents=20
|
||||||
|
|
||||||
|
# Maximum number of positional arguments
|
||||||
|
max-positional-arguments=10
|
||||||
|
|
||||||
# Maximum number of attributes for a class (see R0902).
|
# Maximum number of attributes for a class (see R0902).
|
||||||
max-attributes=50
|
max-attributes=50
|
||||||
|
|
||||||
|
@ -23,6 +23,8 @@
|
|||||||
|
|
||||||
import sys
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from frappy.lib import generalConfig
|
||||||
|
from frappy.logging import logger
|
||||||
|
|
||||||
# Add import path for inplace usage
|
# Add import path for inplace usage
|
||||||
sys.path.insert(0, str(Path(__file__).absolute().parents[1]))
|
sys.path.insert(0, str(Path(__file__).absolute().parents[1]))
|
||||||
@ -30,6 +32,8 @@ sys.path.insert(0, str(Path(__file__).absolute().parents[1]))
|
|||||||
from frappy.client.interactive import Console
|
from frappy.client.interactive import Console
|
||||||
from frappy.playground import play, USAGE
|
from frappy.playground import play, USAGE
|
||||||
|
|
||||||
|
generalConfig.init()
|
||||||
|
logger.init()
|
||||||
if len(sys.argv) > 1:
|
if len(sys.argv) > 1:
|
||||||
play(sys.argv[1])
|
play(sys.argv[1])
|
||||||
else:
|
else:
|
||||||
|
128
bin/frappy-scan
Executable file
128
bin/frappy-scan
Executable file
@ -0,0 +1,128 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# *****************************************************************************
|
||||||
|
#
|
||||||
|
# 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>
|
||||||
|
#
|
||||||
|
# *****************************************************************************
|
||||||
|
|
||||||
|
"""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)
|
||||||
|
|
||||||
|
|
||||||
|
def print_answer(answer, *, short=False):
|
||||||
|
if short:
|
||||||
|
# NOTE: keep this easily parseable!
|
||||||
|
print(f'{answer.equipment_id} {answer.address}:{answer.port}')
|
||||||
|
return
|
||||||
|
print(f'Found {answer.equipment_id} at {answer.address}:')
|
||||||
|
print(f' Port: {answer.port}')
|
||||||
|
print(f' Firmware: {answer.firmware}')
|
||||||
|
desc = answer.description.replace('\n', '\n ')
|
||||||
|
print(f' Node description: {desc}')
|
||||||
|
print()
|
||||||
|
|
||||||
|
|
||||||
|
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',
|
||||||
|
help='Print short info. '
|
||||||
|
'Keep listening after the broadcast.')
|
||||||
|
args = parser.parse_args(sys.argv[1:])
|
||||||
|
for answer in scan():
|
||||||
|
print_answer(answer, short=args.listen)
|
||||||
|
if args.listen:
|
||||||
|
listen(short=args.listen)
|
@ -35,7 +35,15 @@ from frappy.server import Server
|
|||||||
|
|
||||||
|
|
||||||
def parseArgv(argv):
|
def parseArgv(argv):
|
||||||
parser = argparse.ArgumentParser(description="Manage a SECoP server")
|
parser = argparse.ArgumentParser(
|
||||||
|
description="Manage a SECoP server",
|
||||||
|
epilog="""The server needs some configuration, by default from the
|
||||||
|
generalConfig.cfg file. the keys confdir, logdir and piddir have to
|
||||||
|
be set.
|
||||||
|
Alternatively, one can set the environment variables FRAPPY_CONFDIR
|
||||||
|
FRAPPY_LOGDIR and FRAPPY_PIDDIR to set the required values.
|
||||||
|
"""
|
||||||
|
)
|
||||||
loggroup = parser.add_mutually_exclusive_group()
|
loggroup = parser.add_mutually_exclusive_group()
|
||||||
loggroup.add_argument("-v", "--verbose",
|
loggroup.add_argument("-v", "--verbose",
|
||||||
help="Output lots of diagnostic information",
|
help="Output lots of diagnostic information",
|
||||||
@ -60,9 +68,9 @@ def parseArgv(argv):
|
|||||||
action='store',
|
action='store',
|
||||||
help="comma separated list of cfg files,\n"
|
help="comma separated list of cfg files,\n"
|
||||||
"defaults to <name_of_the_instance>.\n"
|
"defaults to <name_of_the_instance>.\n"
|
||||||
"cfgfiles given without '.cfg' extension are searched"
|
"If a config file contains a slash, it is treated as a"
|
||||||
" in the configuration directory,"
|
"path, otherwise the file is searched for in the "
|
||||||
" else they are treated as path names",
|
"configuration directory.",
|
||||||
default=None)
|
default=None)
|
||||||
parser.add_argument('-g',
|
parser.add_argument('-g',
|
||||||
'--gencfg',
|
'--gencfg',
|
||||||
@ -96,7 +104,9 @@ def main(argv=None):
|
|||||||
generalConfig.init(args.gencfg)
|
generalConfig.init(args.gencfg)
|
||||||
logger.init(loglevel)
|
logger.init(loglevel)
|
||||||
|
|
||||||
srv = Server(args.name, logger.log, cfgfiles=args.cfgfiles,
|
cfgfiles = [s.strip() for s in args.cfgfiles.split(',')] if args.cfgfiles else None
|
||||||
|
|
||||||
|
srv = Server(args.name, logger.log, cfgfiles=cfgfiles,
|
||||||
interface=args.port, testonly=args.test)
|
interface=args.port, testonly=args.test)
|
||||||
|
|
||||||
if args.daemonize:
|
if args.daemonize:
|
||||||
|
226
bin/sim-server
226
bin/sim-server
@ -22,22 +22,35 @@
|
|||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
|
|
||||||
bin/stringio-server <communciator> <server port>
|
bin/sim-server <communicator class> -p <server port> [-o <option1>=<value> <option2>=<value>]
|
||||||
|
|
||||||
open a server on <server port> to communicate with the string based <communicator> over TCP/IP.
|
open a server on <server port> to communicate with the string based <communicator> over TCP/IP.
|
||||||
|
|
||||||
Use cases, mainly for test purposes:
|
Use cases, mainly for test purposes:
|
||||||
- as a T, if the hardware allows only one connection, and more than one is needed
|
|
||||||
- relay to a communicator not using TCP/IP, if Frappy should run on an other host
|
|
||||||
- relay to a hardware simulation written as a communicator
|
- relay to a hardware simulation written as a communicator
|
||||||
|
|
||||||
|
> bin/sim-server frappy_psi.ls370sim.Ls370Sim
|
||||||
|
|
||||||
|
- relay to a communicator not using TCP/IP, if Frappy should run on an other host
|
||||||
|
|
||||||
|
> bin/sim-server frappy.io.StringIO -o uri=serial:///dev/tty...
|
||||||
|
|
||||||
|
- as a T, if the hardware allows only one connection, and more than one is needed:
|
||||||
|
|
||||||
|
> bin/sim-server frappy.io.StringIO -o uri=tcp://<host>:<port>
|
||||||
|
|
||||||
|
typically using communicator class frappy.io.StringIO
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import argparse
|
import argparse
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import asyncore
|
|
||||||
import socket
|
import socket
|
||||||
import time
|
import time
|
||||||
|
import os
|
||||||
|
from ast import literal_eval
|
||||||
|
from socketserver import BaseRequestHandler, ThreadingTCPServer
|
||||||
|
|
||||||
# Add import path for inplace usage
|
# Add import path for inplace usage
|
||||||
sys.path.insert(0, str(Path(__file__).absolute().parents[1]))
|
sys.path.insert(0, str(Path(__file__).absolute().parents[1]))
|
||||||
@ -45,92 +58,6 @@ sys.path.insert(0, str(Path(__file__).absolute().parents[1]))
|
|||||||
from frappy.lib import get_class, formatException, mkthread
|
from frappy.lib import get_class, formatException, mkthread
|
||||||
|
|
||||||
|
|
||||||
class LineHandler(asyncore.dispatcher_with_send):
|
|
||||||
|
|
||||||
def __init__(self, sock):
|
|
||||||
self.buffer = b""
|
|
||||||
asyncore.dispatcher_with_send.__init__(self, sock)
|
|
||||||
self.crlf = 0
|
|
||||||
|
|
||||||
def handle_line(self, line):
|
|
||||||
raise NotImplementedError
|
|
||||||
|
|
||||||
def handle_read(self):
|
|
||||||
data = self.recv(8192)
|
|
||||||
if data:
|
|
||||||
parts = data.split(b"\n")
|
|
||||||
if len(parts) == 1:
|
|
||||||
self.buffer += data
|
|
||||||
else:
|
|
||||||
self.handle_line((self.buffer + parts[0]).decode('latin_1'))
|
|
||||||
for part in parts[1:-1]:
|
|
||||||
if part[-1] == b"\r":
|
|
||||||
self.crlf = True
|
|
||||||
part = part[:-1]
|
|
||||||
else:
|
|
||||||
self.crlf = False
|
|
||||||
self.handle_line(part.decode('latin_1'))
|
|
||||||
self.buffer = parts[-1]
|
|
||||||
|
|
||||||
def send_line(self, line):
|
|
||||||
self.send((line + ("\r\n" if self.crlf else "\n")).encode('latin_1'))
|
|
||||||
|
|
||||||
|
|
||||||
class LineServer(asyncore.dispatcher):
|
|
||||||
|
|
||||||
def __init__(self, port, line_handler_cls, handler_args):
|
|
||||||
asyncore.dispatcher.__init__(self)
|
|
||||||
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
||||||
self.set_reuse_addr()
|
|
||||||
self.bind(('0.0.0.0', port))
|
|
||||||
self.listen(5)
|
|
||||||
print('accept connections at port', port)
|
|
||||||
self.line_handler_cls = line_handler_cls
|
|
||||||
self.handler_args = handler_args
|
|
||||||
|
|
||||||
def handle_accept(self):
|
|
||||||
pair = self.accept()
|
|
||||||
if pair is not None:
|
|
||||||
sock, addr = pair
|
|
||||||
print("Incoming connection from %s" % repr(addr))
|
|
||||||
self.line_handler_cls(sock, self.handler_args)
|
|
||||||
|
|
||||||
def loop(self):
|
|
||||||
asyncore.loop()
|
|
||||||
|
|
||||||
|
|
||||||
class Server(LineServer):
|
|
||||||
|
|
||||||
class Dispatcher:
|
|
||||||
def announce_update(self, *_):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def announce_update_error(self, *_):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwds):
|
|
||||||
super().__init__(*args, **kwds)
|
|
||||||
self.secnode = None
|
|
||||||
self.dispatcher = self.Dispatcher()
|
|
||||||
|
|
||||||
|
|
||||||
class Handler(LineHandler):
|
|
||||||
def __init__(self, sock, handler_args):
|
|
||||||
super().__init__(sock)
|
|
||||||
self.module = handler_args['module']
|
|
||||||
self.verbose = handler_args['verbose']
|
|
||||||
|
|
||||||
def handle_line(self, line):
|
|
||||||
try:
|
|
||||||
reply = self.module.communicate(line.strip())
|
|
||||||
if self.verbose:
|
|
||||||
print('%-40s | %s' % (line, reply))
|
|
||||||
except Exception:
|
|
||||||
print(formatException(verbose=True))
|
|
||||||
return
|
|
||||||
self.send_line(reply)
|
|
||||||
|
|
||||||
|
|
||||||
class Logger:
|
class Logger:
|
||||||
def debug(self, *args):
|
def debug(self, *args):
|
||||||
pass
|
pass
|
||||||
@ -144,43 +71,126 @@ class Logger:
|
|||||||
exception = error = warn = info
|
exception = error = warn = info
|
||||||
|
|
||||||
|
|
||||||
|
class TcpRequestHandler(BaseRequestHandler):
|
||||||
|
def setup(self):
|
||||||
|
print(f'connection opened from {self.client_address}')
|
||||||
|
self.running = True
|
||||||
|
self.request.settimeout(1)
|
||||||
|
self.data = b''
|
||||||
|
|
||||||
|
def finish(self):
|
||||||
|
"""called when handle() terminates, i.e. the socket closed"""
|
||||||
|
# close socket
|
||||||
|
try:
|
||||||
|
self.request.shutdown(socket.SHUT_RDWR)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
finally:
|
||||||
|
print(f'connection closed from {self.client_address}')
|
||||||
|
self.request.close()
|
||||||
|
|
||||||
|
def poller(self):
|
||||||
|
while True:
|
||||||
|
time.sleep(1.0)
|
||||||
|
self.module.doPoll()
|
||||||
|
|
||||||
|
def handle(self):
|
||||||
|
"""handle a new connection"""
|
||||||
|
# do a copy of the options, as they are consumed
|
||||||
|
self.module = self.server.modulecls(
|
||||||
|
'mod', Logger(), dict(self.server.options), self.server)
|
||||||
|
self.module.earlyInit()
|
||||||
|
|
||||||
|
mkthread(self.poller)
|
||||||
|
while self.running:
|
||||||
|
try:
|
||||||
|
newdata = self.request.recv(1024)
|
||||||
|
if not newdata:
|
||||||
|
return
|
||||||
|
except socket.timeout:
|
||||||
|
# no new data during read, continue
|
||||||
|
continue
|
||||||
|
self.data += newdata
|
||||||
|
while self.running:
|
||||||
|
message, sep, self.data = self.data.partition(b'\n')
|
||||||
|
if not sep:
|
||||||
|
break
|
||||||
|
cmd = message.decode('latin-1')
|
||||||
|
try:
|
||||||
|
reply = self.module.communicate(cmd.strip())
|
||||||
|
if self.server.verbose:
|
||||||
|
print('%-40s | %s' % (cmd, reply))
|
||||||
|
except Exception:
|
||||||
|
print(formatException(verbose=True))
|
||||||
|
return
|
||||||
|
outdata = reply.encode('latin-1') + b'\n'
|
||||||
|
try:
|
||||||
|
self.request.sendall(outdata)
|
||||||
|
except Exception as e:
|
||||||
|
print(repr(e))
|
||||||
|
self.running = False
|
||||||
|
|
||||||
|
|
||||||
|
class Server(ThreadingTCPServer):
|
||||||
|
allow_reuse_address = os.name != 'nt' # False on Windows systems
|
||||||
|
|
||||||
|
class Dispatcher:
|
||||||
|
def announce_update(self, *_):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def announce_update_error(self, *_):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def __init__(self, port, modulecls, options, verbose=False):
|
||||||
|
super().__init__(('', port), TcpRequestHandler,
|
||||||
|
bind_and_activate=True)
|
||||||
|
self.secnode = None
|
||||||
|
self.dispatcher = self.Dispatcher()
|
||||||
|
self.verbose = verbose
|
||||||
|
self.modulecls = get_class(modulecls)
|
||||||
|
self.options = options
|
||||||
|
print(f'started sim-server listening on port {port}')
|
||||||
|
|
||||||
|
|
||||||
def parse_argv(argv):
|
def parse_argv(argv):
|
||||||
parser = argparse.ArgumentParser(description="Simulate HW with a serial interface")
|
parser = argparse.ArgumentParser(description="Relay to a communicator (simulated HW or other)")
|
||||||
parser.add_argument("-v", "--verbose",
|
parser.add_argument("-v", "--verbose",
|
||||||
help="output full communication",
|
help="output full communication",
|
||||||
action='store_true', default=False)
|
action='store_true', default=False)
|
||||||
parser.add_argument("cls",
|
parser.add_argument("cls",
|
||||||
type=str,
|
type=str,
|
||||||
help="simulator class.\n",)
|
help="communicator class.\n",)
|
||||||
parser.add_argument('-p',
|
parser.add_argument('-p',
|
||||||
'--port',
|
'--port',
|
||||||
action='store',
|
action='store',
|
||||||
help='server port or uri',
|
help='server port or uri',
|
||||||
default=2089)
|
default=2089)
|
||||||
|
parser.add_argument('-o',
|
||||||
|
'--options',
|
||||||
|
action='store',
|
||||||
|
nargs='*',
|
||||||
|
help='options in the form key=value',
|
||||||
|
default=None)
|
||||||
return parser.parse_args(argv)
|
return parser.parse_args(argv)
|
||||||
|
|
||||||
|
|
||||||
def poller(pollfunc):
|
|
||||||
while True:
|
|
||||||
time.sleep(1.0)
|
|
||||||
pollfunc()
|
|
||||||
|
|
||||||
|
|
||||||
def main(argv=None):
|
def main(argv=None):
|
||||||
if argv is None:
|
if argv is None:
|
||||||
argv = sys.argv
|
argv = sys.argv
|
||||||
|
|
||||||
args = parse_argv(argv[1:])
|
args = parse_argv(argv[1:])
|
||||||
|
options = {'description': ''}
|
||||||
opts = {'description': 'simulator'}
|
for item in args.options or ():
|
||||||
|
key, eq, value = item.partition('=')
|
||||||
handler_args = {'verbose': args.verbose}
|
if not eq:
|
||||||
srv = Server(int(args.port), Handler, handler_args)
|
raise ValueError(f"missing '=' in {item}")
|
||||||
module = get_class(args.cls)(args.cls, Logger(), opts, srv)
|
try:
|
||||||
handler_args['module'] = module
|
value = literal_eval(value)
|
||||||
module.earlyInit()
|
except Exception:
|
||||||
mkthread(poller, module.doPoll)
|
pass
|
||||||
srv.loop()
|
options[key] = value
|
||||||
|
srv = Server(int(args.port), args.cls, options, args.verbose)
|
||||||
|
srv.serve_forever()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
67
cfg/PEUS.py
Normal file
67
cfg/PEUS.py
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
Node(equipment_id = 'pe_ultrasound.psi.ch',
|
||||||
|
description = 'pulse echo ultra sound setup',
|
||||||
|
interface = 'tcp://5000',
|
||||||
|
)
|
||||||
|
|
||||||
|
Mod('f',
|
||||||
|
cls = 'frappy_psi.ultrasound.Frequency',
|
||||||
|
description = 'ultrasound frequency and acquisition loop',
|
||||||
|
uri = 'serial:///dev/ttyS1',
|
||||||
|
pars = 'pars',
|
||||||
|
pollinterval = 0.1,
|
||||||
|
time = 900, # start time
|
||||||
|
size = 5000,
|
||||||
|
freq = 1.17568e+06,
|
||||||
|
basefreq = 4.14902e+07,
|
||||||
|
control = False,
|
||||||
|
rusmode = False,
|
||||||
|
amp = 5.0,
|
||||||
|
nr = 1000, #500 #300 #100 #50 #30 #10 #5 #3 #1 #1000 #500 #300 #100 #50 #30 #10 #5 #3 #1 #500
|
||||||
|
sr = 32768, #16384
|
||||||
|
plot = True,
|
||||||
|
maxstep = 100000,
|
||||||
|
bw = 10E6, #butter worth filter bandwidth
|
||||||
|
maxy = 0.7, # y scale for plot
|
||||||
|
curves = 'curves', # module to transmit curves:
|
||||||
|
)
|
||||||
|
|
||||||
|
Mod('curves',
|
||||||
|
cls = 'frappy_psi.ultrasound.Curves',
|
||||||
|
description = 't, I, Q and pulse arrays for plot',
|
||||||
|
)
|
||||||
|
|
||||||
|
Mod('delay',
|
||||||
|
cls = 'frappy__psi.dg645.Delay',
|
||||||
|
description = 'delay line with 2 channels',
|
||||||
|
uri = 'serial:///dev/ttyS2',
|
||||||
|
on1 = 1e-9,
|
||||||
|
on2 = 1E-9,
|
||||||
|
off1 = 400e-9,
|
||||||
|
off2 = 600e-9,
|
||||||
|
)
|
||||||
|
|
||||||
|
Mod('pars',
|
||||||
|
cls = 'frappy_psi.ultrasound.Pars',
|
||||||
|
description = 'SEA parameters',
|
||||||
|
)
|
||||||
|
|
||||||
|
def roi(nr, time=None, size=300):
|
||||||
|
Mod(f'roi{nr}',
|
||||||
|
cls = 'frappy_psi.ultrasound.Roi',
|
||||||
|
description = f'I/Q of region {nr}',
|
||||||
|
main = 'f',
|
||||||
|
time=time or 4000,
|
||||||
|
size=size,
|
||||||
|
enable=time is not None,
|
||||||
|
)
|
||||||
|
|
||||||
|
roi(0, 2450) # you may add size as argument if not default
|
||||||
|
roi(1, 5950)
|
||||||
|
roi(2, 9475)
|
||||||
|
roi(3, 12900)
|
||||||
|
roi(4, 16100)
|
||||||
|
roi(5) # disabled
|
||||||
|
roi(6)
|
||||||
|
roi(7)
|
||||||
|
roi(8)
|
||||||
|
roi(9)
|
62
cfg/RUS.py
Normal file
62
cfg/RUS.py
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
Node(equipment_id = 'r_ultrasound.psi.ch',
|
||||||
|
description = 'resonant ultra sound setup',
|
||||||
|
interface = 'tcp://5000',
|
||||||
|
)
|
||||||
|
|
||||||
|
Mod('f',
|
||||||
|
cls = 'frappy_psi.ultrasound.Frequency',
|
||||||
|
description = 'ultrasound frequency and acquisition loop',
|
||||||
|
uri = 'serial:///dev/ttyS1',
|
||||||
|
pars = 'pars',
|
||||||
|
pollinterval = 0.1,
|
||||||
|
time = 900, # start time
|
||||||
|
size = 5000,
|
||||||
|
freq = 1.e+03,
|
||||||
|
basefreq = 1.E+3,
|
||||||
|
control = False,
|
||||||
|
rusmode = False,
|
||||||
|
amp = 2.5,
|
||||||
|
nr = 1, #500 #300 #100 #50 #30 #10 #5 #3 #1 #1000 #500 #300 #100 #50 #30 #10 #5 #3 #1 #500
|
||||||
|
sr = 1E8, #16384
|
||||||
|
plot = True,
|
||||||
|
maxstep = 100000,
|
||||||
|
bw = 10E6, #butter worth filter bandwidth
|
||||||
|
maxy = 0.7, # y scale for plot
|
||||||
|
curves = 'curves', # module to transmit curves:
|
||||||
|
)
|
||||||
|
|
||||||
|
Mod('curves',
|
||||||
|
cls = 'frappy_psi.ultrasound.Curves',
|
||||||
|
description = 't, I, Q and pulse arrays for plot',
|
||||||
|
)
|
||||||
|
|
||||||
|
Mod('roi0',
|
||||||
|
cls = 'frappy_psi.ultrasound.Roi',
|
||||||
|
description = 'I/Q of region in the control loop',
|
||||||
|
time = 300, # this is the center of roi:
|
||||||
|
size = 5000,
|
||||||
|
main = f,
|
||||||
|
)
|
||||||
|
|
||||||
|
Mod('roi1',
|
||||||
|
cls = 'frappy_psi.ultrasound.Roi',
|
||||||
|
description = 'I/Q of region 1',
|
||||||
|
time = 100, # this is the center of roi:
|
||||||
|
size = 300,
|
||||||
|
main = f,
|
||||||
|
)
|
||||||
|
|
||||||
|
Mod('delay',
|
||||||
|
cls = 'frappy__psi.dg645.Delay',
|
||||||
|
description = 'delay line with 2 channels',
|
||||||
|
uri = 'serial:///dev/ttyS2',
|
||||||
|
on1 = 1e-9,
|
||||||
|
on2 = 1E-9,
|
||||||
|
off1 = 400e-9,
|
||||||
|
off2 = 600e-9,
|
||||||
|
)
|
||||||
|
|
||||||
|
Mod('pars',
|
||||||
|
cls = 'frappy_psi.ultrasound.Pars',
|
||||||
|
description = 'SEA parameters',
|
||||||
|
)
|
@ -12,9 +12,9 @@ Mod('sea_main',
|
|||||||
Mod('tt',
|
Mod('tt',
|
||||||
'frappy_psi.sea.SeaDrivable', '',
|
'frappy_psi.sea.SeaDrivable', '',
|
||||||
io='sea_main',
|
io='sea_main',
|
||||||
meaning=['temperature_regulation', 20],
|
meaning=['temperature_regulation', 27],
|
||||||
sea_object='tt',
|
sea_object='tt',
|
||||||
rel_paths=['tm', 'set', 'dblctrl'],
|
rel_paths=['tm', '.', 'set', 'dblctrl'],
|
||||||
)
|
)
|
||||||
|
|
||||||
Mod('cc',
|
Mod('cc',
|
||||||
|
@ -12,9 +12,9 @@ Mod('sea_main',
|
|||||||
Mod('tt',
|
Mod('tt',
|
||||||
'frappy_psi.sea.SeaDrivable', '',
|
'frappy_psi.sea.SeaDrivable', '',
|
||||||
io='sea_main',
|
io='sea_main',
|
||||||
meaning=['temperature_regulation', 20],
|
meaning=['temperature_regulation', 27],
|
||||||
sea_object='tt',
|
sea_object='tt',
|
||||||
rel_paths=['tm', 'set', 'dblctrl'],
|
rel_paths=['tm', '.', 'set', 'dblctrl'],
|
||||||
)
|
)
|
||||||
|
|
||||||
Mod('cc',
|
Mod('cc',
|
||||||
|
@ -12,9 +12,9 @@ Mod('sea_main',
|
|||||||
Mod('tt',
|
Mod('tt',
|
||||||
'frappy_psi.sea.SeaDrivable', '',
|
'frappy_psi.sea.SeaDrivable', '',
|
||||||
io='sea_main',
|
io='sea_main',
|
||||||
meaning=['temperature_regulation', 20],
|
meaning=['temperature_regulation', 27],
|
||||||
sea_object='tt',
|
sea_object='tt',
|
||||||
rel_paths=['tm', 'set', 'dblctrl'],
|
rel_paths=['tm', '.', 'set', 'dblctrl'],
|
||||||
)
|
)
|
||||||
|
|
||||||
Mod('cc',
|
Mod('cc',
|
||||||
|
@ -12,9 +12,9 @@ Mod('sea_main',
|
|||||||
Mod('tt',
|
Mod('tt',
|
||||||
'frappy_psi.sea.SeaDrivable', '',
|
'frappy_psi.sea.SeaDrivable', '',
|
||||||
io='sea_main',
|
io='sea_main',
|
||||||
meaning=['temperature_regulation', 20],
|
meaning=['temperature_regulation', 27],
|
||||||
sea_object='tt',
|
sea_object='tt',
|
||||||
rel_paths=['tm', 'set', 'dblctrl'],
|
rel_paths=['tm', '.', 'set', 'dblctrl'],
|
||||||
)
|
)
|
||||||
|
|
||||||
Mod('cc',
|
Mod('cc',
|
||||||
|
@ -12,9 +12,9 @@ Mod('sea_main',
|
|||||||
Mod('tt',
|
Mod('tt',
|
||||||
'frappy_psi.sea.SeaDrivable', '',
|
'frappy_psi.sea.SeaDrivable', '',
|
||||||
io='sea_main',
|
io='sea_main',
|
||||||
meaning=['temperature_regulation', 20],
|
meaning=['temperature_regulation', 27],
|
||||||
sea_object='tt',
|
sea_object='tt',
|
||||||
rel_paths=['tm', 'set', 'dblctrl'],
|
rel_paths=['tm', '.', 'set', 'dblctrl'],
|
||||||
)
|
)
|
||||||
|
|
||||||
Mod('cc',
|
Mod('cc',
|
||||||
|
@ -12,9 +12,9 @@ Mod('sea_main',
|
|||||||
Mod('tt',
|
Mod('tt',
|
||||||
'frappy_psi.sea.SeaDrivable', '',
|
'frappy_psi.sea.SeaDrivable', '',
|
||||||
io='sea_main',
|
io='sea_main',
|
||||||
meaning=['temperature_regulation', 20],
|
meaning=['temperature_regulation', 27],
|
||||||
sea_object='tt',
|
sea_object='tt',
|
||||||
rel_paths=['tm', 'set', 'dblctrl'],
|
rel_paths=['tm', '.', 'set', 'dblctrl'],
|
||||||
)
|
)
|
||||||
|
|
||||||
Mod('pauto',
|
Mod('pauto',
|
||||||
|
@ -12,7 +12,7 @@ Mod('sea_main',
|
|||||||
Mod('tt',
|
Mod('tt',
|
||||||
'frappy_psi.sea.SeaDrivable', '',
|
'frappy_psi.sea.SeaDrivable', '',
|
||||||
io='sea_main',
|
io='sea_main',
|
||||||
meaning=['temperature_regulation', 20],
|
meaning=['temperature_regulation', 27],
|
||||||
sea_object='tt',
|
sea_object='tt',
|
||||||
rel_paths=['tt', 'set'],
|
rel_paths=['tt', 'set'],
|
||||||
)
|
)
|
||||||
|
@ -12,9 +12,9 @@ Mod('sea_main',
|
|||||||
Mod('tt',
|
Mod('tt',
|
||||||
'frappy_psi.sea.SeaDrivable', '',
|
'frappy_psi.sea.SeaDrivable', '',
|
||||||
io='sea_main',
|
io='sea_main',
|
||||||
meaning=['temperature_regulation', 20],
|
meaning=['temperature_regulation', 27],
|
||||||
sea_object='tt',
|
sea_object='tt',
|
||||||
rel_paths=['tm', 'set', 'dblctrl'],
|
rel_paths=['tm', '.', 'set', 'dblctrl'],
|
||||||
)
|
)
|
||||||
|
|
||||||
Mod('cc',
|
Mod('cc',
|
||||||
|
@ -12,9 +12,9 @@ Mod('sea_main',
|
|||||||
Mod('tt',
|
Mod('tt',
|
||||||
'frappy_psi.sea.SeaDrivable', '',
|
'frappy_psi.sea.SeaDrivable', '',
|
||||||
io='sea_main',
|
io='sea_main',
|
||||||
meaning=['temperature_regulation', 20],
|
meaning=['temperature_regulation', 27],
|
||||||
sea_object='tt',
|
sea_object='tt',
|
||||||
rel_paths=['tm', 'set', 'dblctrl'],
|
rel_paths=['tm', '.', 'set', 'dblctrl'],
|
||||||
)
|
)
|
||||||
|
|
||||||
Mod('cc',
|
Mod('cc',
|
||||||
|
@ -12,7 +12,7 @@ Mod('sea_main',
|
|||||||
Mod('ts',
|
Mod('ts',
|
||||||
'frappy_psi.sea.SeaDrivable', '',
|
'frappy_psi.sea.SeaDrivable', '',
|
||||||
io='sea_main',
|
io='sea_main',
|
||||||
meaning=['temperature_regulation', 20],
|
meaning=['temperature_regulation', 27],
|
||||||
sea_object='tt',
|
sea_object='tt',
|
||||||
rel_paths=['ts', 'set']
|
rel_paths=['ts', 'set']
|
||||||
)
|
)
|
||||||
|
@ -13,7 +13,7 @@ Mod('th',
|
|||||||
'frappy_psi.sea.SeaReadable',
|
'frappy_psi.sea.SeaReadable',
|
||||||
'sample heater temperature',
|
'sample heater temperature',
|
||||||
io='sea_main',
|
io='sea_main',
|
||||||
meaning=['temperature_regulation', 20],
|
meaning=['temperature_regulation', 27],
|
||||||
sea_object='tt',
|
sea_object='tt',
|
||||||
rel_paths=['ts', 'setsamp']
|
rel_paths=['ts', 'setsamp']
|
||||||
)
|
)
|
||||||
@ -22,7 +22,7 @@ Mod('tm',
|
|||||||
'frappy_psi.sea.SeaDrivable', '',
|
'frappy_psi.sea.SeaDrivable', '',
|
||||||
io='sea_main',
|
io='sea_main',
|
||||||
sea_object='tt',
|
sea_object='tt',
|
||||||
rel_paths=['tm', 'set']
|
rel_paths=['tm', '.', 'set']
|
||||||
)
|
)
|
||||||
|
|
||||||
Mod('ts',
|
Mod('ts',
|
||||||
|
@ -12,9 +12,9 @@ Mod('sea_main',
|
|||||||
Mod('tt',
|
Mod('tt',
|
||||||
'frappy_psi.sea.SeaDrivable', '',
|
'frappy_psi.sea.SeaDrivable', '',
|
||||||
io='sea_main',
|
io='sea_main',
|
||||||
meaning=['temperature_regulation', 20],
|
meaning=['temperature_regulation', 27],
|
||||||
sea_object='tt',
|
sea_object='tt',
|
||||||
rel_paths=['tm', 'set', 'dblctrl'],
|
rel_paths=['tm', '.', 'set', 'dblctrl'],
|
||||||
)
|
)
|
||||||
|
|
||||||
Mod('cc',
|
Mod('cc',
|
||||||
|
@ -10,9 +10,9 @@ Mod('sea_main',
|
|||||||
Mod('tt',
|
Mod('tt',
|
||||||
'frappy_psi.sea.SeaDrivable', '',
|
'frappy_psi.sea.SeaDrivable', '',
|
||||||
io = 'sea_main',
|
io = 'sea_main',
|
||||||
meaning=['temperature_regulation', 20],
|
meaning=['temperature_regulation', 27],
|
||||||
sea_object = 'tt',
|
sea_object = 'tt',
|
||||||
rel_paths=['tm', 'set', 'dblctrl'],
|
rel_paths=['tm', '.', 'set', 'dblctrl'],
|
||||||
)
|
)
|
||||||
Mod('cc',
|
Mod('cc',
|
||||||
'frappy_psi.sea.SeaReadable', '',
|
'frappy_psi.sea.SeaReadable', '',
|
||||||
|
@ -12,9 +12,9 @@ Mod('sea_main',
|
|||||||
Mod('tt',
|
Mod('tt',
|
||||||
'frappy_psi.sea.SeaDrivable', '',
|
'frappy_psi.sea.SeaDrivable', '',
|
||||||
io='sea_main',
|
io='sea_main',
|
||||||
meaning=['temperature_regulation', 20],
|
meaning=['temperature_regulation', 27],
|
||||||
sea_object='tt',
|
sea_object='tt',
|
||||||
rel_paths=['tm', 'set', 'dblctrl'],
|
rel_paths=['tm', '.', 'set', 'dblctrl'],
|
||||||
)
|
)
|
||||||
|
|
||||||
Mod('cc',
|
Mod('cc',
|
||||||
|
@ -12,9 +12,9 @@ Mod('sea_main',
|
|||||||
Mod('tt',
|
Mod('tt',
|
||||||
'frappy_psi.sea.SeaDrivable', '',
|
'frappy_psi.sea.SeaDrivable', '',
|
||||||
io='sea_main',
|
io='sea_main',
|
||||||
meaning=['temperature_regulation', 20],
|
meaning=['temperature_regulation', 27],
|
||||||
sea_object='tt',
|
sea_object='tt',
|
||||||
rel_paths=['tm', 'set', 'dblctrl'],
|
rel_paths=['tm', '.', 'set', 'dblctrl'],
|
||||||
)
|
)
|
||||||
|
|
||||||
Mod('th',
|
Mod('th',
|
||||||
|
@ -10,11 +10,12 @@ Mod('sea_main',
|
|||||||
)
|
)
|
||||||
|
|
||||||
Mod('tt',
|
Mod('tt',
|
||||||
'frappy_psi.sea.SeaDrivable', '',
|
'frappy_psi.sea.LscDrivable', '',
|
||||||
io='sea_main',
|
io='sea_main',
|
||||||
meaning=['temperature_regulation', 20],
|
meaning=['temperature_regulation', 27],
|
||||||
sea_object='tt',
|
sea_object='tt',
|
||||||
rel_paths=['tm', 'set', 'dblctrl'],
|
sensor_path='tm',
|
||||||
|
set_path='set',
|
||||||
)
|
)
|
||||||
|
|
||||||
Mod('cc',
|
Mod('cc',
|
||||||
@ -69,15 +70,13 @@ Mod('lev',
|
|||||||
Mod('tcoil1',
|
Mod('tcoil1',
|
||||||
'frappy_psi.sea.SeaReadable', '',
|
'frappy_psi.sea.SeaReadable', '',
|
||||||
io='sea_main',
|
io='sea_main',
|
||||||
sea_object='tcoil',
|
sea_path='tcoil/ta',
|
||||||
rel_paths=['ta'],
|
|
||||||
)
|
)
|
||||||
|
|
||||||
Mod('tcoil2',
|
Mod('tcoil2',
|
||||||
'frappy_psi.sea.SeaReadable', '',
|
'frappy_psi.sea.SeaReadable', '',
|
||||||
io='sea_main',
|
io='sea_main',
|
||||||
sea_object='tcoil',
|
sea_path='tcoil/tb',
|
||||||
rel_paths=['tb'],
|
|
||||||
)
|
)
|
||||||
|
|
||||||
Mod('table',
|
Mod('table',
|
||||||
|
@ -12,9 +12,9 @@ Mod('sea_main',
|
|||||||
Mod('tt',
|
Mod('tt',
|
||||||
'frappy_psi.sea.SeaDrivable', '',
|
'frappy_psi.sea.SeaDrivable', '',
|
||||||
io='sea_main',
|
io='sea_main',
|
||||||
meaning=['temperature_regulation', 20],
|
meaning=['temperature_regulation', 27],
|
||||||
sea_object='tt',
|
sea_object='tt',
|
||||||
rel_paths=['tm', 'set', 'dblctrl', 'voltage'],
|
rel_paths=['tm', '.', 'set', 'dblctrl', 'voltage'],
|
||||||
extra_modules=['manualpower'],
|
extra_modules=['manualpower'],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -12,9 +12,9 @@ Mod('sea_main',
|
|||||||
Mod('tt',
|
Mod('tt',
|
||||||
'frappy_psi.sea.SeaDrivable', '',
|
'frappy_psi.sea.SeaDrivable', '',
|
||||||
io='sea_main',
|
io='sea_main',
|
||||||
meaning=['temperature_regulation', 20],
|
meaning=['temperature_regulation', 27],
|
||||||
sea_object='tt',
|
sea_object='tt',
|
||||||
rel_paths=['tm', 'set', 'dblctrl'],
|
rel_paths=['tm', '.', 'set', 'dblctrl'],
|
||||||
)
|
)
|
||||||
|
|
||||||
Mod('th',
|
Mod('th',
|
||||||
|
@ -16,10 +16,10 @@ Mod('sea_main',
|
|||||||
|
|
||||||
Mod('tt',
|
Mod('tt',
|
||||||
'frappy_psi.sea.SeaDrivable', '',
|
'frappy_psi.sea.SeaDrivable', '',
|
||||||
meaning=['temperature_regulation', 20],
|
meaning=['temperature_regulation', 27],
|
||||||
io='sea_main',
|
io='sea_main',
|
||||||
sea_object='tt',
|
sea_object='tt',
|
||||||
rel_paths=['tm', 'set', 'dblctrl'],
|
rel_paths=['tm', '.', 'set', 'dblctrl'],
|
||||||
)
|
)
|
||||||
|
|
||||||
Mod('th',
|
Mod('th',
|
||||||
|
@ -12,9 +12,9 @@ Mod('sea_main',
|
|||||||
Mod('tt',
|
Mod('tt',
|
||||||
'frappy_psi.sea.SeaDrivable', '',
|
'frappy_psi.sea.SeaDrivable', '',
|
||||||
io='sea_main',
|
io='sea_main',
|
||||||
meaning=['temperature_regulation', 20],
|
meaning=['temperature_regulation', 27],
|
||||||
sea_object='tt',
|
sea_object='tt',
|
||||||
rel_paths=['tm', 'set', 'dblctrl'],
|
rel_paths=['tm', '.', 'set', 'dblctrl'],
|
||||||
)
|
)
|
||||||
|
|
||||||
Mod('cc',
|
Mod('cc',
|
||||||
|
@ -25,7 +25,7 @@ Mod('ips',
|
|||||||
Mod('T_stat',
|
Mod('T_stat',
|
||||||
'frappy_psi.mercury.TemperatureAutoFlow',
|
'frappy_psi.mercury.TemperatureAutoFlow',
|
||||||
'static heat exchanger temperature',
|
'static heat exchanger temperature',
|
||||||
meaning=['temperature_regulation', 20],
|
meaning=['temperature_regulation', 27],
|
||||||
output_module='htr_stat',
|
output_module='htr_stat',
|
||||||
needle_valve='p_stat',
|
needle_valve='p_stat',
|
||||||
slot='DB6.T1',
|
slot='DB6.T1',
|
||||||
|
@ -23,7 +23,7 @@ Mod('ips',
|
|||||||
Mod('T_stat',
|
Mod('T_stat',
|
||||||
'frappy_psi.mercury.TemperatureAutoFlow',
|
'frappy_psi.mercury.TemperatureAutoFlow',
|
||||||
'static heat exchanger temperature',
|
'static heat exchanger temperature',
|
||||||
meaning=['temperature_regulation', 20],
|
meaning=['temperature_regulation', 27],
|
||||||
output_module='htr_stat',
|
output_module='htr_stat',
|
||||||
needle_valve='p_stat',
|
needle_valve='p_stat',
|
||||||
slot='DB6.T1',
|
slot='DB6.T1',
|
||||||
|
73
cfg/main/ori2_cfg.py
Normal file
73
cfg/main/ori2_cfg.py
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
Node('ori3.config.sea.psi.ch',
|
||||||
|
'orange cryostat with 50 mm sample space',
|
||||||
|
)
|
||||||
|
|
||||||
|
Mod('sea_main',
|
||||||
|
'frappy_psi.sea.SeaClient',
|
||||||
|
'main sea connection for ori2.config',
|
||||||
|
config='ori2.config',
|
||||||
|
service='main',
|
||||||
|
)
|
||||||
|
|
||||||
|
Mod('tt',
|
||||||
|
'frappy_psi.sea.SeaDrivable', '',
|
||||||
|
io='sea_main',
|
||||||
|
meaning=['temperature_regulation', 27],
|
||||||
|
sea_object='tt',
|
||||||
|
rel_paths=['tm', '.', 'set', 'dblctrl'],
|
||||||
|
)
|
||||||
|
|
||||||
|
Mod('cc',
|
||||||
|
'frappy_psi.sea.SeaReadable', '',
|
||||||
|
io='sea_main',
|
||||||
|
sea_object='cc',
|
||||||
|
extra_modules=['h'],
|
||||||
|
)
|
||||||
|
|
||||||
|
Mod('lev',
|
||||||
|
'frappy_psi.sea.SeaReadable', '',
|
||||||
|
io='sea_main',
|
||||||
|
single_module='cc.h',
|
||||||
|
)
|
||||||
|
|
||||||
|
Mod('nv',
|
||||||
|
'frappy_psi.sea.SeaWritable', '',
|
||||||
|
io='sea_main',
|
||||||
|
sea_object='nv',
|
||||||
|
)
|
||||||
|
|
||||||
|
Mod('ln2fill',
|
||||||
|
'frappy_psi.sea.SeaWritable', '',
|
||||||
|
io='sea_main',
|
||||||
|
sea_object='ln2fill',
|
||||||
|
)
|
||||||
|
|
||||||
|
Mod('hefill',
|
||||||
|
'frappy_psi.sea.SeaWritable', '',
|
||||||
|
io='sea_main',
|
||||||
|
sea_object='hefill',
|
||||||
|
)
|
||||||
|
|
||||||
|
Mod('hepump',
|
||||||
|
'frappy_psi.sea.SeaWritable', '',
|
||||||
|
io='sea_main',
|
||||||
|
sea_object='hepump',
|
||||||
|
)
|
||||||
|
|
||||||
|
Mod('hemot',
|
||||||
|
'frappy_psi.sea.SeaDrivable', '',
|
||||||
|
io='sea_main',
|
||||||
|
sea_object='hemot',
|
||||||
|
)
|
||||||
|
|
||||||
|
Mod('nvflow',
|
||||||
|
'frappy_psi.sea.SeaReadable', '',
|
||||||
|
io='sea_main',
|
||||||
|
sea_object='nvflow',
|
||||||
|
)
|
||||||
|
|
||||||
|
Mod('table',
|
||||||
|
'frappy_psi.sea.SeaReadable', '',
|
||||||
|
io='sea_main',
|
||||||
|
sea_object='table',
|
||||||
|
)
|
@ -12,9 +12,9 @@ Mod('sea_main',
|
|||||||
Mod('tt',
|
Mod('tt',
|
||||||
'frappy_psi.sea.SeaDrivable', '',
|
'frappy_psi.sea.SeaDrivable', '',
|
||||||
io='sea_main',
|
io='sea_main',
|
||||||
meaning=['temperature_regulation', 20],
|
meaning=['temperature_regulation', 27],
|
||||||
sea_object='tt',
|
sea_object='tt',
|
||||||
rel_paths=['tm', 'set', 'dblctrl'],
|
rel_paths=['tm', '.', 'set', 'dblctrl'],
|
||||||
)
|
)
|
||||||
|
|
||||||
Mod('cc',
|
Mod('cc',
|
||||||
|
@ -12,9 +12,9 @@ Mod('sea_main',
|
|||||||
Mod('tt',
|
Mod('tt',
|
||||||
'frappy_psi.sea.SeaDrivable', '',
|
'frappy_psi.sea.SeaDrivable', '',
|
||||||
io='sea_main',
|
io='sea_main',
|
||||||
meaning=['temperature_regulation', 20],
|
meaning=['temperature_regulation', 27],
|
||||||
sea_object='tt',
|
sea_object='tt',
|
||||||
rel_paths=['tm', 'set', 'dblctrl'],
|
rel_paths=['tm', '.', 'set', 'dblctrl'],
|
||||||
)
|
)
|
||||||
|
|
||||||
Mod('cc',
|
Mod('cc',
|
||||||
|
@ -12,9 +12,9 @@ Mod('sea_main',
|
|||||||
Mod('tt',
|
Mod('tt',
|
||||||
'frappy_psi.sea.SeaDrivable', '',
|
'frappy_psi.sea.SeaDrivable', '',
|
||||||
io='sea_main',
|
io='sea_main',
|
||||||
meaning=['temperature_regulation', 20],
|
meaning=['temperature_regulation', 27],
|
||||||
sea_object='tt',
|
sea_object='tt',
|
||||||
rel_paths=['tm', 'set', 'dblctrl'],
|
rel_paths=['tm', '.', 'set', 'dblctrl'],
|
||||||
)
|
)
|
||||||
|
|
||||||
Mod('cc',
|
Mod('cc',
|
||||||
|
@ -12,9 +12,9 @@ Mod('sea_main',
|
|||||||
Mod('tt',
|
Mod('tt',
|
||||||
'frappy_psi.sea.SeaDrivable', '',
|
'frappy_psi.sea.SeaDrivable', '',
|
||||||
io = 'sea_main',
|
io = 'sea_main',
|
||||||
meaning=['temperature_regulation', 20],
|
meaning=['temperature_regulation', 27],
|
||||||
sea_object = 'tt',
|
sea_object = 'tt',
|
||||||
rel_paths=['tm', 'set', 'dblctrl'],
|
rel_paths=['tm', '.', 'set', 'dblctrl'],
|
||||||
)
|
)
|
||||||
|
|
||||||
Mod('cc',
|
Mod('cc',
|
||||||
|
@ -12,9 +12,9 @@ Mod('sea_main',
|
|||||||
Mod('tt',
|
Mod('tt',
|
||||||
'frappy_psi.sea.SeaDrivable', '',
|
'frappy_psi.sea.SeaDrivable', '',
|
||||||
io='sea_main',
|
io='sea_main',
|
||||||
meaning=['temperature_regulation', 20],
|
meaning=['temperature_regulation', 27],
|
||||||
sea_object='tt',
|
sea_object='tt',
|
||||||
rel_paths=['tm', 'set', 'dblctrl'],
|
rel_paths=['tm', '.', 'set', 'dblctrl'],
|
||||||
)
|
)
|
||||||
|
|
||||||
Mod('cc',
|
Mod('cc',
|
||||||
|
@ -18,7 +18,7 @@ Mod('itc2',
|
|||||||
Mod('T_stat',
|
Mod('T_stat',
|
||||||
'frappy_psi.mercury.TemperatureAutoFlow',
|
'frappy_psi.mercury.TemperatureAutoFlow',
|
||||||
'static heat exchanger temperature',
|
'static heat exchanger temperature',
|
||||||
meaning=['temperature_regulation', 20],
|
meaning=['temperature_regulation', 27],
|
||||||
output_module='htr_stat',
|
output_module='htr_stat',
|
||||||
needle_valve='p_stat',
|
needle_valve='p_stat',
|
||||||
slot='DB6.T1',
|
slot='DB6.T1',
|
||||||
@ -168,6 +168,8 @@ Mod('htr_nvd',
|
|||||||
io='itc2',
|
io='itc2',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Motor controller is not yet available!
|
||||||
|
#
|
||||||
#Mod('om_io',
|
#Mod('om_io',
|
||||||
# 'frappy_psi.phytron.PhytronIO',
|
# 'frappy_psi.phytron.PhytronIO',
|
||||||
# 'dom motor IO',
|
# 'dom motor IO',
|
||||||
|
@ -18,22 +18,22 @@
|
|||||||
{"path": "t1", "type": "float", "readonly": false, "cmd": "run tt", "kids": 3},
|
{"path": "t1", "type": "float", "readonly": false, "cmd": "run tt", "kids": 3},
|
||||||
{"path": "t1/raw", "type": "float", "readonly": false, "cmd": "run tt"},
|
{"path": "t1/raw", "type": "float", "readonly": false, "cmd": "run tt"},
|
||||||
{"path": "t1/curve", "type": "text", "readonly": false, "cmd": "tt t1/curve", "kids": 1},
|
{"path": "t1/curve", "type": "text", "readonly": false, "cmd": "tt t1/curve", "kids": 1},
|
||||||
{"path": "t1/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tt t1/curve/points"},
|
{"path": "t1/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tt t1/curve/points", "visibility": 3},
|
||||||
{"path": "t1/valid", "type": "bool", "readonly": false, "cmd": "run tt"},
|
{"path": "t1/valid", "type": "bool", "readonly": false, "cmd": "run tt"},
|
||||||
{"path": "t2", "type": "float", "readonly": false, "cmd": "run tt", "kids": 3},
|
{"path": "t2", "type": "float", "readonly": false, "cmd": "run tt", "kids": 3},
|
||||||
{"path": "t2/raw", "type": "float", "readonly": false, "cmd": "run tt"},
|
{"path": "t2/raw", "type": "float", "readonly": false, "cmd": "run tt"},
|
||||||
{"path": "t2/curve", "type": "text", "readonly": false, "cmd": "tt t2/curve", "kids": 1},
|
{"path": "t2/curve", "type": "text", "readonly": false, "cmd": "tt t2/curve", "kids": 1},
|
||||||
{"path": "t2/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tt t2/curve/points"},
|
{"path": "t2/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tt t2/curve/points", "visibility": 3},
|
||||||
{"path": "t2/valid", "type": "bool", "readonly": false, "cmd": "run tt"},
|
{"path": "t2/valid", "type": "bool", "readonly": false, "cmd": "run tt"},
|
||||||
{"path": "t3", "type": "float", "readonly": false, "cmd": "run tt", "kids": 3},
|
{"path": "t3", "type": "float", "readonly": false, "cmd": "run tt", "kids": 3},
|
||||||
{"path": "t3/raw", "type": "float", "readonly": false, "cmd": "run tt"},
|
{"path": "t3/raw", "type": "float", "readonly": false, "cmd": "run tt"},
|
||||||
{"path": "t3/curve", "type": "text", "readonly": false, "cmd": "tt t3/curve", "kids": 1},
|
{"path": "t3/curve", "type": "text", "readonly": false, "cmd": "tt t3/curve", "kids": 1},
|
||||||
{"path": "t3/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tt t3/curve/points"},
|
{"path": "t3/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tt t3/curve/points", "visibility": 3},
|
||||||
{"path": "t3/valid", "type": "bool", "readonly": false, "cmd": "run tt"},
|
{"path": "t3/valid", "type": "bool", "readonly": false, "cmd": "run tt"},
|
||||||
{"path": "t4", "type": "float", "readonly": false, "cmd": "run tt", "kids": 3},
|
{"path": "t4", "type": "float", "readonly": false, "cmd": "run tt", "kids": 3},
|
||||||
{"path": "t4/raw", "type": "float", "readonly": false, "cmd": "run tt"},
|
{"path": "t4/raw", "type": "float", "readonly": false, "cmd": "run tt"},
|
||||||
{"path": "t4/curve", "type": "text", "readonly": false, "cmd": "tt t4/curve", "kids": 1},
|
{"path": "t4/curve", "type": "text", "readonly": false, "cmd": "tt t4/curve", "kids": 1},
|
||||||
{"path": "t4/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tt t4/curve/points"},
|
{"path": "t4/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tt t4/curve/points", "visibility": 3},
|
||||||
{"path": "t4/valid", "type": "bool", "readonly": false, "cmd": "run tt"},
|
{"path": "t4/valid", "type": "bool", "readonly": false, "cmd": "run tt"},
|
||||||
{"path": "tref", "type": "float", "readonly": false, "cmd": "run tt"},
|
{"path": "tref", "type": "float", "readonly": false, "cmd": "run tt"},
|
||||||
{"path": "tout", "type": "float", "readonly": false, "cmd": "run tt"},
|
{"path": "tout", "type": "float", "readonly": false, "cmd": "run tt"},
|
||||||
|
@ -269,7 +269,7 @@
|
|||||||
{"path": "custompar", "type": "float", "readonly": false, "cmd": "hemot custompar"}]},
|
{"path": "custompar", "type": "float", "readonly": false, "cmd": "hemot custompar"}]},
|
||||||
|
|
||||||
"mf": {"base": "/mf", "params": [
|
"mf": {"base": "/mf", "params": [
|
||||||
{"path": "", "type": "float", "kids": 26},
|
{"path": "", "type": "float", "cmd": "run mf", "kids": 26},
|
||||||
{"path": "persmode", "type": "int", "readonly": false, "cmd": "mf persmode"},
|
{"path": "persmode", "type": "int", "readonly": false, "cmd": "mf persmode"},
|
||||||
{"path": "perswitch", "type": "int"},
|
{"path": "perswitch", "type": "int"},
|
||||||
{"path": "nowait", "type": "int", "readonly": false, "cmd": "mf nowait"},
|
{"path": "nowait", "type": "int", "readonly": false, "cmd": "mf nowait"},
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
{"tt": {"base": "/tt", "params": [{"path": "", "type": "float", "readonly": false, "cmd": "run tt", "description": "tt", "kids": 18},
|
{"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": "send", "type": "text", "readonly": false, "cmd": "tt send", "visibility": 3},
|
||||||
{"path": "status", "type": "text", "visibility": 3},
|
{"path": "status", "type": "text", "visibility": 3},
|
||||||
{"path": "is_running", "type": "int", "readonly": false, "cmd": "tt is_running", "visibility": 3},
|
{"path": "is_running", "type": "int", "readonly": false, "cmd": "tt is_running", "visibility": 3},
|
||||||
@ -85,7 +86,10 @@
|
|||||||
{"path": "setsamp/integ", "type": "float", "readonly": false, "cmd": "tt setsamp/integ", "description": "bigger means faster"},
|
{"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": "setsamp/deriv", "type": "float", "readonly": false, "cmd": "tt setsamp/deriv"},
|
||||||
{"path": "display", "type": "text", "readonly": false, "cmd": "tt display"},
|
{"path": "display", "type": "text", "readonly": false, "cmd": "tt display"},
|
||||||
{"path": "remote", "type": "bool"}]}, "cc": {"base": "/cc", "params": [{"path": "", "type": "bool", "kids": 96},
|
{"path": "remote", "type": "bool"}]},
|
||||||
|
|
||||||
|
"cc": {"base": "/cc", "params": [
|
||||||
|
{"path": "", "type": "bool", "kids": 96},
|
||||||
{"path": "send", "type": "text", "readonly": false, "cmd": "cc send", "visibility": 3},
|
{"path": "send", "type": "text", "readonly": false, "cmd": "cc send", "visibility": 3},
|
||||||
{"path": "status", "type": "text", "visibility": 3},
|
{"path": "status", "type": "text", "visibility": 3},
|
||||||
{"path": "autodevice", "type": "bool", "readonly": false, "cmd": "cc autodevice"},
|
{"path": "autodevice", "type": "bool", "readonly": false, "cmd": "cc autodevice"},
|
||||||
@ -181,7 +185,10 @@
|
|||||||
{"path": "tm", "type": "float", "visibility": 3},
|
{"path": "tm", "type": "float", "visibility": 3},
|
||||||
{"path": "tv", "type": "float", "visibility": 3},
|
{"path": "tv", "type": "float", "visibility": 3},
|
||||||
{"path": "tq", "type": "float", "visibility": 3},
|
{"path": "tq", "type": "float", "visibility": 3},
|
||||||
{"path": "bdl", "type": "float", "readonly": false, "cmd": "cc bdl"}]}, "nv": {"base": "/nv", "params": [{"path": "", "type": "enum", "enum": {"fixed": 0, "controlled": 1, "automatic": 2, "close": 3, "open": 4}, "readonly": false, "cmd": "nv", "kids": 11},
|
{"path": "bdl", "type": "float", "readonly": false, "cmd": "cc bdl"}]},
|
||||||
|
|
||||||
|
"nv": {"base": "/nv", "params": [
|
||||||
|
{"path": "", "type": "enum", "enum": {"fixed": 0, "controlled": 1, "automatic": 2, "close": 3, "open": 4}, "readonly": false, "cmd": "nv", "kids": 11},
|
||||||
{"path": "send", "type": "text", "readonly": false, "cmd": "nv send", "visibility": 3},
|
{"path": "send", "type": "text", "readonly": false, "cmd": "nv send", "visibility": 3},
|
||||||
{"path": "status", "type": "text", "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": "motstat", "type": "enum", "enum": {"idle": 0, "opening": 1, "closing": 2, "opened": 3, "closed": 4, "no_motor": 5}},
|
||||||
@ -231,7 +238,11 @@
|
|||||||
{"path": "autoflow/flowtarget", "type": "float"},
|
{"path": "autoflow/flowtarget", "type": "float"},
|
||||||
{"path": "calib", "type": "none", "kids": 2},
|
{"path": "calib", "type": "none", "kids": 2},
|
||||||
{"path": "calib/ln_per_min_per_mbar", "type": "float", "readonly": false, "cmd": "nv calib/ln_per_min_per_mbar"},
|
{"path": "calib/ln_per_min_per_mbar", "type": "float", "readonly": false, "cmd": "nv calib/ln_per_min_per_mbar"},
|
||||||
{"path": "calib/mbar_offset", "type": "float", "readonly": false, "cmd": "nv calib/mbar_offset"}]}, "hepump": {"base": "/hepump", "params": [{"path": "", "type": "enum", "enum": {"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": 9},
|
{"path": "calib/mbar_offset", "type": "float", "readonly": false, "cmd": "nv calib/mbar_offset"}]},
|
||||||
|
|
||||||
|
|
||||||
|
"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": 9},
|
||||||
{"path": "send", "type": "text", "readonly": false, "cmd": "hepump send", "visibility": 3},
|
{"path": "send", "type": "text", "readonly": false, "cmd": "hepump send", "visibility": 3},
|
||||||
{"path": "status", "type": "text", "visibility": 3},
|
{"path": "status", "type": "text", "visibility": 3},
|
||||||
{"path": "running", "type": "bool", "readonly": false, "cmd": "hepump running"},
|
{"path": "running", "type": "bool", "readonly": false, "cmd": "hepump running"},
|
||||||
@ -239,7 +250,10 @@
|
|||||||
{"path": "auto", "type": "bool", "readonly": false, "cmd": "hepump auto"},
|
{"path": "auto", "type": "bool", "readonly": false, "cmd": "hepump auto"},
|
||||||
{"path": "valve", "type": "enum", "enum": {"closed": 0, "closing": 1, "opening": 2, "opened": 3, "undefined": 4}, "readonly": false, "cmd": "hepump valve"},
|
{"path": "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"},
|
||||||
{"path": "calib", "type": "float", "readonly": false, "cmd": "hepump calib", "visibility": 3}]}, "hemot": {"base": "/hepump/hemot", "params": [{"path": "", "type": "float", "readonly": false, "cmd": "run hemot", "kids": 30},
|
{"path": "calib", "type": "float", "readonly": false, "cmd": "hepump calib", "visibility": 3}]},
|
||||||
|
|
||||||
|
"hemot": {"base": "/hepump/hemot", "params": [
|
||||||
|
{"path": "", "type": "float", "readonly": false, "cmd": "run hemot", "kids": 30},
|
||||||
{"path": "send", "type": "text", "readonly": false, "cmd": "hemot send", "visibility": 3},
|
{"path": "send", "type": "text", "readonly": false, "cmd": "hemot send", "visibility": 3},
|
||||||
{"path": "status", "type": "text", "visibility": 3},
|
{"path": "status", "type": "text", "visibility": 3},
|
||||||
{"path": "is_running", "type": "int", "readonly": false, "cmd": "hemot is_running", "visibility": 3},
|
{"path": "is_running", "type": "int", "readonly": false, "cmd": "hemot is_running", "visibility": 3},
|
||||||
@ -270,7 +284,8 @@
|
|||||||
{"path": "eeprom", "type": "enum", "enum": {"ok": 0, "dirty": 1, "save": 2, "load": 3}, "readonly": false, "cmd": "hemot eeprom"},
|
{"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": "customadr", "type": "text", "readonly": false, "cmd": "hemot customadr"},
|
||||||
{"path": "custompar", "type": "float", "readonly": false, "cmd": "hemot custompar"}]},
|
{"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": "", "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": "send", "type": "text", "readonly": false, "cmd": "ln2fill send", "visibility": 3},
|
||||||
{"path": "status", "type": "text", "visibility": 3},
|
{"path": "status", "type": "text", "visibility": 3},
|
||||||
@ -285,7 +300,10 @@
|
|||||||
{"path": "maxholdhours", "type": "float", "readonly": false, "cmd": "ln2fill maxholdhours"},
|
{"path": "maxholdhours", "type": "float", "readonly": false, "cmd": "ln2fill maxholdhours"},
|
||||||
{"path": "tolerance", "type": "float", "readonly": false, "cmd": "ln2fill tolerance"},
|
{"path": "tolerance", "type": "float", "readonly": false, "cmd": "ln2fill tolerance"},
|
||||||
{"path": "badreadingminutes", "type": "float", "readonly": false, "cmd": "ln2fill badreadingminutes"},
|
{"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": "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": "send", "type": "text", "readonly": false, "cmd": "hefill send", "visibility": 3},
|
||||||
{"path": "status", "type": "text", "visibility": 3},
|
{"path": "status", "type": "text", "visibility": 3},
|
||||||
{"path": "state", "type": "text"},
|
{"path": "state", "type": "text"},
|
||||||
@ -301,11 +319,17 @@
|
|||||||
{"path": "badreadingminutes", "type": "float", "readonly": false, "cmd": "hefill badreadingminutes"},
|
{"path": "badreadingminutes", "type": "float", "readonly": false, "cmd": "hefill badreadingminutes"},
|
||||||
{"path": "tubecoolingminutes", "type": "float", "readonly": false, "cmd": "hefill tubecoolingminutes"},
|
{"path": "tubecoolingminutes", "type": "float", "readonly": false, "cmd": "hefill tubecoolingminutes"},
|
||||||
{"path": "vessellimit", "type": "float", "readonly": false, "cmd": "hefill vessellimit"},
|
{"path": "vessellimit", "type": "float", "readonly": false, "cmd": "hefill vessellimit"},
|
||||||
{"path": "vext", "type": "float"}]}, "lev": {"base": "/lev", "params": [{"path": "", "type": "float", "kids": 4},
|
{"path": "vext", "type": "float"}]},
|
||||||
|
|
||||||
|
"lev": {"base": "/lev", "params": [
|
||||||
|
{"path": "", "type": "float", "kids": 4},
|
||||||
{"path": "send", "type": "text", "readonly": false, "cmd": "lev send", "visibility": 3},
|
{"path": "send", "type": "text", "readonly": false, "cmd": "lev send", "visibility": 3},
|
||||||
{"path": "status", "type": "text", "visibility": 3},
|
{"path": "status", "type": "text", "visibility": 3},
|
||||||
{"path": "mode", "type": "enum", "enum": {"slow": 0, "fast (switches to slow automatically after filling)": 1}, "readonly": false, "cmd": "lev mode"},
|
{"path": "mode", "type": "enum", "enum": {"slow": 0, "fast (switches to slow automatically after filling)": 1}, "readonly": false, "cmd": "lev mode"},
|
||||||
{"path": "n2", "type": "float"}]}, "mf": {"base": "/mf", "params": [{"path": "", "type": "float", "kids": 26},
|
{"path": "n2", "type": "float"}]},
|
||||||
|
|
||||||
|
"mf": {"base": "/mf", "params": [
|
||||||
|
{"path": "", "type": "float", "cmd": "run mf", "kids": 26},
|
||||||
{"path": "persmode", "type": "int", "readonly": false, "cmd": "mf persmode"},
|
{"path": "persmode", "type": "int", "readonly": false, "cmd": "mf persmode"},
|
||||||
{"path": "perswitch", "type": "int"},
|
{"path": "perswitch", "type": "int"},
|
||||||
{"path": "nowait", "type": "int", "readonly": false, "cmd": "mf nowait"},
|
{"path": "nowait", "type": "int", "readonly": false, "cmd": "mf nowait"},
|
||||||
@ -330,7 +354,10 @@
|
|||||||
{"path": "driver", "type": "text", "visibility": 3},
|
{"path": "driver", "type": "text", "visibility": 3},
|
||||||
{"path": "creationCmd", "type": "text", "visibility": 3},
|
{"path": "creationCmd", "type": "text", "visibility": 3},
|
||||||
{"path": "targetValue", "type": "float"},
|
{"path": "targetValue", "type": "float"},
|
||||||
{"path": "status", "type": "text", "readonly": false, "cmd": "mf status", "visibility": 3}]}, "tcoil": {"base": "/tcoil", "params": [{"path": "", "type": "float", "kids": 11},
|
{"path": "status", "type": "text", "readonly": false, "cmd": "mf status", "visibility": 3}]},
|
||||||
|
|
||||||
|
"tcoil": {"base": "/tcoil", "params": [
|
||||||
|
{"path": "", "type": "float", "kids": 11},
|
||||||
{"path": "send", "type": "text", "readonly": false, "cmd": "tcoil send", "visibility": 3},
|
{"path": "send", "type": "text", "readonly": false, "cmd": "tcoil send", "visibility": 3},
|
||||||
{"path": "status", "type": "text", "visibility": 3},
|
{"path": "status", "type": "text", "visibility": 3},
|
||||||
{"path": "excitation", "type": "float", "readonly": false, "cmd": "tcoil excitation", "visibility": 3},
|
{"path": "excitation", "type": "float", "readonly": false, "cmd": "tcoil excitation", "visibility": 3},
|
||||||
@ -338,40 +365,43 @@
|
|||||||
{"path": "td/enable", "type": "bool", "readonly": false, "cmd": "tcoil td/enable"},
|
{"path": "td/enable", "type": "bool", "readonly": false, "cmd": "tcoil td/enable"},
|
||||||
{"path": "td/r", "type": "float"},
|
{"path": "td/r", "type": "float"},
|
||||||
{"path": "td/curve", "type": "text", "readonly": false, "cmd": "tcoil td/curve", "kids": 3},
|
{"path": "td/curve", "type": "text", "readonly": false, "cmd": "tcoil td/curve", "kids": 3},
|
||||||
{"path": "td/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil td/curve/adjust"},
|
{"path": "td/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil td/curve/adjust", "visibility": 3},
|
||||||
{"path": "td/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil td/curve/points"},
|
{"path": "td/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil td/curve/points", "visibility": 3},
|
||||||
{"path": "td/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil td/curve/cpoints"},
|
{"path": "td/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil td/curve/cpoints", "visibility": 3},
|
||||||
{"path": "tc", "type": "float", "visibility": 3, "kids": 3},
|
{"path": "tc", "type": "float", "visibility": 3, "kids": 3},
|
||||||
{"path": "tc/enable", "type": "bool", "readonly": false, "cmd": "tcoil tc/enable"},
|
{"path": "tc/enable", "type": "bool", "readonly": false, "cmd": "tcoil tc/enable"},
|
||||||
{"path": "tc/r", "type": "float"},
|
{"path": "tc/r", "type": "float"},
|
||||||
{"path": "tc/curve", "type": "text", "readonly": false, "cmd": "tcoil tc/curve", "kids": 3},
|
{"path": "tc/curve", "type": "text", "readonly": false, "cmd": "tcoil tc/curve", "kids": 3},
|
||||||
{"path": "tc/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil tc/curve/adjust"},
|
{"path": "tc/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil tc/curve/adjust", "visibility": 3},
|
||||||
{"path": "tc/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil tc/curve/points"},
|
{"path": "tc/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil tc/curve/points", "visibility": 3},
|
||||||
{"path": "tc/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil tc/curve/cpoints"},
|
{"path": "tc/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil tc/curve/cpoints", "visibility": 3},
|
||||||
{"path": "tb", "type": "float", "visibility": 3, "kids": 3},
|
{"path": "tb", "type": "float", "visibility": 3, "kids": 3},
|
||||||
{"path": "tb/enable", "type": "bool", "readonly": false, "cmd": "tcoil tb/enable"},
|
{"path": "tb/enable", "type": "bool", "readonly": false, "cmd": "tcoil tb/enable"},
|
||||||
{"path": "tb/r", "type": "float"},
|
{"path": "tb/r", "type": "float"},
|
||||||
{"path": "tb/curve", "type": "text", "readonly": false, "cmd": "tcoil tb/curve", "kids": 3},
|
{"path": "tb/curve", "type": "text", "readonly": false, "cmd": "tcoil tb/curve", "kids": 3},
|
||||||
{"path": "tb/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil tb/curve/adjust"},
|
{"path": "tb/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil tb/curve/adjust", "visibility": 3},
|
||||||
{"path": "tb/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil tb/curve/points"},
|
{"path": "tb/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil tb/curve/points", "visibility": 3},
|
||||||
{"path": "tb/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil tb/curve/cpoints"},
|
{"path": "tb/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil tb/curve/cpoints", "visibility": 3},
|
||||||
{"path": "ta", "type": "float", "visibility": 3, "kids": 3},
|
{"path": "ta", "type": "float", "visibility": 3, "kids": 3},
|
||||||
{"path": "ta/enable", "type": "bool", "readonly": false, "cmd": "tcoil ta/enable"},
|
{"path": "ta/enable", "type": "bool", "readonly": false, "cmd": "tcoil ta/enable"},
|
||||||
{"path": "ta/r", "type": "float"},
|
{"path": "ta/r", "type": "float"},
|
||||||
{"path": "ta/curve", "type": "text", "readonly": false, "cmd": "tcoil ta/curve", "kids": 3},
|
{"path": "ta/curve", "type": "text", "readonly": false, "cmd": "tcoil ta/curve", "kids": 3},
|
||||||
{"path": "ta/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil ta/curve/adjust"},
|
{"path": "ta/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil ta/curve/adjust", "visibility": 3},
|
||||||
{"path": "ta/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil ta/curve/points"},
|
{"path": "ta/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil ta/curve/points", "visibility": 3},
|
||||||
{"path": "ta/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil ta/curve/cpoints"},
|
{"path": "ta/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil ta/curve/cpoints", "visibility": 3},
|
||||||
{"path": "ref", "type": "float", "visibility": 3, "kids": 3},
|
{"path": "ref", "type": "float", "visibility": 3, "kids": 3},
|
||||||
{"path": "ref/enable", "type": "bool", "readonly": false, "cmd": "tcoil ref/enable"},
|
{"path": "ref/enable", "type": "bool", "readonly": false, "cmd": "tcoil ref/enable"},
|
||||||
{"path": "ref/r", "type": "float"},
|
{"path": "ref/r", "type": "float"},
|
||||||
{"path": "ref/curve", "type": "text", "readonly": false, "cmd": "tcoil ref/curve", "kids": 3},
|
{"path": "ref/curve", "type": "text", "readonly": false, "cmd": "tcoil ref/curve", "kids": 3},
|
||||||
{"path": "ref/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil ref/curve/adjust"},
|
{"path": "ref/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil ref/curve/adjust", "visibility": 3},
|
||||||
{"path": "ref/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil ref/curve/points"},
|
{"path": "ref/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil ref/curve/points", "visibility": 3},
|
||||||
{"path": "ref/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil ref/curve/cpoints"},
|
{"path": "ref/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil ref/curve/cpoints", "visibility": 3},
|
||||||
{"path": "ext", "type": "float", "visibility": 3},
|
{"path": "ext", "type": "float", "visibility": 3},
|
||||||
{"path": "com", "type": "float", "visibility": 3},
|
{"path": "com", "type": "float", "visibility": 3},
|
||||||
{"path": "gnd", "type": "float", "visibility": 3}]}, "table": {"base": "/table", "params": [{"path": "", "type": "none", "kids": 17},
|
{"path": "gnd", "type": "float", "visibility": 3}]},
|
||||||
|
|
||||||
|
"table": {"base": "/table", "params": [
|
||||||
|
{"path": "", "type": "none", "kids": 17},
|
||||||
{"path": "send", "type": "text", "readonly": false, "cmd": "table send", "visibility": 3},
|
{"path": "send", "type": "text", "readonly": false, "cmd": "table send", "visibility": 3},
|
||||||
{"path": "status", "type": "text", "visibility": 3},
|
{"path": "status", "type": "text", "visibility": 3},
|
||||||
{"path": "fix_tt_set_prop", "type": "bool", "readonly": false, "cmd": "table fix_tt_set_prop"},
|
{"path": "fix_tt_set_prop", "type": "bool", "readonly": false, "cmd": "table fix_tt_set_prop"},
|
||||||
@ -388,8 +418,14 @@
|
|||||||
{"path": "tbl_tt_dblctrl_prop_up", "type": "text", "readonly": false, "cmd": "table tbl_tt_dblctrl_prop_up", "description": "enter value pair separated with colon T1:par1 T2:par2 ..."},
|
{"path": "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": "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": "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 ..."}]}, "ccu2": {"base": "/sics/ccu2", "params": [{"path": "", "type": "text", "readonly": false, "cmd": "ccu2", "kids": 23},
|
{"path": "tbl_tt_dblctrl_prop_lo", "type": "text", "readonly": false, "cmd": "table tbl_tt_dblctrl_prop_lo", "description": "enter value pair separated with colon T1:par1 T2:par2 ..."}]},
|
||||||
{"path": "tasks", "type": "none", "visibility": 3}]}, "lnv": {"base": "/lnv", "params": [{"path": "", "type": "enum", "enum": {"off": 5, "fixed": 0, "controlling": 1, "close": 3, "open": 4}, "readonly": false, "cmd": "lnv", "kids": 12},
|
|
||||||
|
"ccu2": {"base": "/sics/ccu2", "params": [
|
||||||
|
{"path": "", "type": "text", "readonly": false, "cmd": "ccu2", "kids": 23},
|
||||||
|
{"path": "tasks", "type": "none", "visibility": 3}]},
|
||||||
|
|
||||||
|
"lnv": {"base": "/lnv", "params": [
|
||||||
|
{"path": "", "type": "enum", "enum": {"off": 5, "fixed": 0, "controlling": 1, "close": 3, "open": 4}, "readonly": false, "cmd": "lnv", "kids": 12},
|
||||||
{"path": "send", "type": "text", "readonly": false, "cmd": "lnv send", "visibility": 3},
|
{"path": "send", "type": "text", "readonly": false, "cmd": "lnv send", "visibility": 3},
|
||||||
{"path": "status", "type": "text", "visibility": 3},
|
{"path": "status", "type": "text", "visibility": 3},
|
||||||
{"path": "set", "type": "float", "readonly": false, "cmd": "lnv set"},
|
{"path": "set", "type": "float", "readonly": false, "cmd": "lnv set"},
|
||||||
@ -427,7 +463,10 @@
|
|||||||
{"path": "autoflow/difmax", "type": "float"},
|
{"path": "autoflow/difmax", "type": "float"},
|
||||||
{"path": "autoflow/setmin", "type": "float"},
|
{"path": "autoflow/setmin", "type": "float"},
|
||||||
{"path": "autoflow/setmax", "type": "float"},
|
{"path": "autoflow/setmax", "type": "float"},
|
||||||
{"path": "autoflow/flowtarget", "type": "float"}]}, "lpr": {"base": "/lpr", "params": [{"path": "", "type": "float", "readonly": false, "cmd": "run lpr", "description": "lpr", "kids": 28},
|
{"path": "autoflow/flowtarget", "type": "float"}]},
|
||||||
|
|
||||||
|
"lpr": {"base": "/lpr", "params": [
|
||||||
|
{"path": "", "type": "float", "readonly": false, "cmd": "run lpr", "description": "lpr", "kids": 28},
|
||||||
{"path": "send", "type": "text", "readonly": false, "cmd": "lpr send", "visibility": 3},
|
{"path": "send", "type": "text", "readonly": false, "cmd": "lpr send", "visibility": 3},
|
||||||
{"path": "status", "type": "text", "visibility": 3},
|
{"path": "status", "type": "text", "visibility": 3},
|
||||||
{"path": "is_running", "type": "int", "readonly": false, "cmd": "lpr is_running", "visibility": 3},
|
{"path": "is_running", "type": "int", "readonly": false, "cmd": "lpr is_running", "visibility": 3},
|
||||||
@ -455,12 +494,13 @@
|
|||||||
{"path": "running", "type": "int"},
|
{"path": "running", "type": "int"},
|
||||||
{"path": "tolerance", "type": "float", "readonly": false, "cmd": "lpr tolerance"},
|
{"path": "tolerance", "type": "float", "readonly": false, "cmd": "lpr tolerance"},
|
||||||
{"path": "maxwait", "type": "float", "readonly": false, "cmd": "lpr maxwait"},
|
{"path": "maxwait", "type": "float", "readonly": false, "cmd": "lpr maxwait"},
|
||||||
{"path": "settle", "type": "float", "readonly": false, "cmd": "lpr settle"}]}, "lambdawatch": {"base": "/lambdawatch", "params": [{"path": "", "type": "float", "kids": 6},
|
{"path": "settle", "type": "float", "readonly": false, "cmd": "lpr settle"}]},
|
||||||
|
|
||||||
|
"lambdawatch": {"base": "/lambdawatch", "params": [
|
||||||
|
{"path": "", "type": "float", "kids": 6},
|
||||||
{"path": "send", "type": "text", "readonly": false, "cmd": "lambdawatch send", "visibility": 3},
|
{"path": "send", "type": "text", "readonly": false, "cmd": "lambdawatch send", "visibility": 3},
|
||||||
{"path": "status", "type": "text", "visibility": 3},
|
{"path": "status", "type": "text", "visibility": 3},
|
||||||
{"path": "safefield", "type": "float", "readonly": false, "cmd": "lambdawatch safefield"},
|
{"path": "safefield", "type": "float", "readonly": false, "cmd": "lambdawatch safefield"},
|
||||||
{"path": "maxfield", "type": "float", "readonly": false, "cmd": "lambdawatch maxfield"},
|
{"path": "maxfield", "type": "float", "readonly": false, "cmd": "lambdawatch maxfield"},
|
||||||
{"path": "safetemp", "type": "float", "readonly": false, "cmd": "lambdawatch safetemp"},
|
{"path": "safetemp", "type": "float", "readonly": false, "cmd": "lambdawatch safetemp"},
|
||||||
{"path": "coiltemp", "type": "text", "readonly": false, "cmd": "lambdawatch coiltemp"}]}, "prep0": {"base": "/prep0", "params": [{"path": "", "type": "text", "readonly": false, "cmd": "prep0", "kids": 2},
|
{"path": "coiltemp", "type": "text", "readonly": false, "cmd": "lambdawatch coiltemp"}]}}
|
||||||
{"path": "send", "type": "text", "readonly": false, "cmd": "prep0 send", "visibility": 3},
|
|
||||||
{"path": "status", "type": "text", "visibility": 3}]}}
|
|
||||||
|
@ -371,37 +371,37 @@
|
|||||||
{"path": "td/enable", "type": "bool", "readonly": false, "cmd": "tcoil td/enable"},
|
{"path": "td/enable", "type": "bool", "readonly": false, "cmd": "tcoil td/enable"},
|
||||||
{"path": "td/r", "type": "float"},
|
{"path": "td/r", "type": "float"},
|
||||||
{"path": "td/curve", "type": "text", "readonly": false, "cmd": "tcoil td/curve", "kids": 3},
|
{"path": "td/curve", "type": "text", "readonly": false, "cmd": "tcoil td/curve", "kids": 3},
|
||||||
{"path": "td/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil td/curve/adjust"},
|
{"path": "td/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil td/curve/adjust", "visibility": 3},
|
||||||
{"path": "td/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil td/curve/points"},
|
{"path": "td/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil td/curve/points", "visibility": 3},
|
||||||
{"path": "td/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil td/curve/cpoints"},
|
{"path": "td/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil td/curve/cpoints", "visibility": 3},
|
||||||
{"path": "tb", "type": "float", "visibility": 3, "kids": 3},
|
{"path": "tb", "type": "float", "visibility": 3, "kids": 3},
|
||||||
{"path": "tb/enable", "type": "bool", "readonly": false, "cmd": "tcoil tb/enable"},
|
{"path": "tb/enable", "type": "bool", "readonly": false, "cmd": "tcoil tb/enable"},
|
||||||
{"path": "tb/r", "type": "float"},
|
{"path": "tb/r", "type": "float"},
|
||||||
{"path": "tb/curve", "type": "text", "readonly": false, "cmd": "tcoil tb/curve", "kids": 3},
|
{"path": "tb/curve", "type": "text", "readonly": false, "cmd": "tcoil tb/curve", "kids": 3},
|
||||||
{"path": "tb/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil tb/curve/adjust"},
|
{"path": "tb/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil tb/curve/adjust", "visibility": 3},
|
||||||
{"path": "tb/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil tb/curve/points"},
|
{"path": "tb/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil tb/curve/points", "visibility": 3},
|
||||||
{"path": "tb/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil tb/curve/cpoints"},
|
{"path": "tb/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil tb/curve/cpoints", "visibility": 3},
|
||||||
{"path": "tc", "type": "float", "visibility": 3, "kids": 3},
|
{"path": "tc", "type": "float", "visibility": 3, "kids": 3},
|
||||||
{"path": "tc/enable", "type": "bool", "readonly": false, "cmd": "tcoil tc/enable"},
|
{"path": "tc/enable", "type": "bool", "readonly": false, "cmd": "tcoil tc/enable"},
|
||||||
{"path": "tc/r", "type": "float"},
|
{"path": "tc/r", "type": "float"},
|
||||||
{"path": "tc/curve", "type": "text", "readonly": false, "cmd": "tcoil tc/curve", "kids": 3},
|
{"path": "tc/curve", "type": "text", "readonly": false, "cmd": "tcoil tc/curve", "kids": 3},
|
||||||
{"path": "tc/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil tc/curve/adjust"},
|
{"path": "tc/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil tc/curve/adjust", "visibility": 3},
|
||||||
{"path": "tc/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil tc/curve/points"},
|
{"path": "tc/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil tc/curve/points", "visibility": 3},
|
||||||
{"path": "tc/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil tc/curve/cpoints"},
|
{"path": "tc/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil tc/curve/cpoints", "visibility": 3},
|
||||||
{"path": "ta", "type": "float", "visibility": 3, "kids": 3},
|
{"path": "ta", "type": "float", "visibility": 3, "kids": 3},
|
||||||
{"path": "ta/enable", "type": "bool", "readonly": false, "cmd": "tcoil ta/enable"},
|
{"path": "ta/enable", "type": "bool", "readonly": false, "cmd": "tcoil ta/enable"},
|
||||||
{"path": "ta/r", "type": "float"},
|
{"path": "ta/r", "type": "float"},
|
||||||
{"path": "ta/curve", "type": "text", "readonly": false, "cmd": "tcoil ta/curve", "kids": 3},
|
{"path": "ta/curve", "type": "text", "readonly": false, "cmd": "tcoil ta/curve", "kids": 3},
|
||||||
{"path": "ta/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil ta/curve/adjust"},
|
{"path": "ta/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil ta/curve/adjust", "visibility": 3},
|
||||||
{"path": "ta/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil ta/curve/points"},
|
{"path": "ta/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil ta/curve/points", "visibility": 3},
|
||||||
{"path": "ta/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil ta/curve/cpoints"},
|
{"path": "ta/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil ta/curve/cpoints", "visibility": 3},
|
||||||
{"path": "ref", "type": "float", "visibility": 3, "kids": 3},
|
{"path": "ref", "type": "float", "visibility": 3, "kids": 3},
|
||||||
{"path": "ref/enable", "type": "bool", "readonly": false, "cmd": "tcoil ref/enable"},
|
{"path": "ref/enable", "type": "bool", "readonly": false, "cmd": "tcoil ref/enable"},
|
||||||
{"path": "ref/r", "type": "float"},
|
{"path": "ref/r", "type": "float"},
|
||||||
{"path": "ref/curve", "type": "text", "readonly": false, "cmd": "tcoil ref/curve", "kids": 3},
|
{"path": "ref/curve", "type": "text", "readonly": false, "cmd": "tcoil ref/curve", "kids": 3},
|
||||||
{"path": "ref/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil ref/curve/adjust"},
|
{"path": "ref/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil ref/curve/adjust", "visibility": 3},
|
||||||
{"path": "ref/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil ref/curve/points"},
|
{"path": "ref/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil ref/curve/points", "visibility": 3},
|
||||||
{"path": "ref/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil ref/curve/cpoints"},
|
{"path": "ref/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil ref/curve/cpoints", "visibility": 3},
|
||||||
{"path": "ext", "type": "float", "visibility": 3},
|
{"path": "ext", "type": "float", "visibility": 3},
|
||||||
{"path": "com", "type": "float", "visibility": 3},
|
{"path": "com", "type": "float", "visibility": 3},
|
||||||
{"path": "gnd", "type": "float", "visibility": 3}]},
|
{"path": "gnd", "type": "float", "visibility": 3}]},
|
||||||
|
@ -371,37 +371,37 @@
|
|||||||
{"path": "ta/enable", "type": "bool", "readonly": false, "cmd": "tcoil ta/enable"},
|
{"path": "ta/enable", "type": "bool", "readonly": false, "cmd": "tcoil ta/enable"},
|
||||||
{"path": "ta/r", "type": "float"},
|
{"path": "ta/r", "type": "float"},
|
||||||
{"path": "ta/curve", "type": "text", "readonly": false, "cmd": "tcoil ta/curve", "kids": 3},
|
{"path": "ta/curve", "type": "text", "readonly": false, "cmd": "tcoil ta/curve", "kids": 3},
|
||||||
{"path": "ta/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil ta/curve/adjust"},
|
{"path": "ta/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil ta/curve/adjust", "visibility": 3},
|
||||||
{"path": "ta/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil ta/curve/points"},
|
{"path": "ta/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil ta/curve/points", "visibility": 3},
|
||||||
{"path": "ta/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil ta/curve/cpoints"},
|
{"path": "ta/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil ta/curve/cpoints", "visibility": 3},
|
||||||
{"path": "tb", "type": "float", "kids": 3},
|
{"path": "tb", "type": "float", "kids": 3},
|
||||||
{"path": "tb/enable", "type": "bool", "readonly": false, "cmd": "tcoil tb/enable"},
|
{"path": "tb/enable", "type": "bool", "readonly": false, "cmd": "tcoil tb/enable"},
|
||||||
{"path": "tb/r", "type": "float"},
|
{"path": "tb/r", "type": "float"},
|
||||||
{"path": "tb/curve", "type": "text", "readonly": false, "cmd": "tcoil tb/curve", "kids": 3},
|
{"path": "tb/curve", "type": "text", "readonly": false, "cmd": "tcoil tb/curve", "kids": 3},
|
||||||
{"path": "tb/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil tb/curve/adjust"},
|
{"path": "tb/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil tb/curve/adjust", "visibility": 3},
|
||||||
{"path": "tb/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil tb/curve/points"},
|
{"path": "tb/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil tb/curve/points", "visibility": 3},
|
||||||
{"path": "tb/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil tb/curve/cpoints"},
|
{"path": "tb/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil tb/curve/cpoints", "visibility": 3},
|
||||||
{"path": "td", "type": "float", "visibility": 3, "kids": 3},
|
{"path": "td", "type": "float", "visibility": 3, "kids": 3},
|
||||||
{"path": "td/enable", "type": "bool", "readonly": false, "cmd": "tcoil td/enable"},
|
{"path": "td/enable", "type": "bool", "readonly": false, "cmd": "tcoil td/enable"},
|
||||||
{"path": "td/r", "type": "float"},
|
{"path": "td/r", "type": "float"},
|
||||||
{"path": "td/curve", "type": "text", "readonly": false, "cmd": "tcoil td/curve", "kids": 3},
|
{"path": "td/curve", "type": "text", "readonly": false, "cmd": "tcoil td/curve", "kids": 3},
|
||||||
{"path": "td/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil td/curve/adjust"},
|
{"path": "td/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil td/curve/adjust", "visibility": 3},
|
||||||
{"path": "td/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil td/curve/points"},
|
{"path": "td/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil td/curve/points", "visibility": 3},
|
||||||
{"path": "td/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil td/curve/cpoints"},
|
{"path": "td/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil td/curve/cpoints", "visibility": 3},
|
||||||
{"path": "ref", "type": "float", "visibility": 3, "kids": 3},
|
{"path": "ref", "type": "float", "visibility": 3, "kids": 3},
|
||||||
{"path": "ref/enable", "type": "bool", "readonly": false, "cmd": "tcoil ref/enable"},
|
{"path": "ref/enable", "type": "bool", "readonly": false, "cmd": "tcoil ref/enable"},
|
||||||
{"path": "ref/r", "type": "float"},
|
{"path": "ref/r", "type": "float"},
|
||||||
{"path": "ref/curve", "type": "text", "readonly": false, "cmd": "tcoil ref/curve", "kids": 3},
|
{"path": "ref/curve", "type": "text", "readonly": false, "cmd": "tcoil ref/curve", "kids": 3},
|
||||||
{"path": "ref/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil ref/curve/adjust"},
|
{"path": "ref/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil ref/curve/adjust", "visibility": 3},
|
||||||
{"path": "ref/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil ref/curve/points"},
|
{"path": "ref/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil ref/curve/points", "visibility": 3},
|
||||||
{"path": "ref/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil ref/curve/cpoints"},
|
{"path": "ref/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil ref/curve/cpoints", "visibility": 3},
|
||||||
{"path": "tc", "type": "float", "visibility": 3, "kids": 3},
|
{"path": "tc", "type": "float", "visibility": 3, "kids": 3},
|
||||||
{"path": "tc/enable", "type": "bool", "readonly": false, "cmd": "tcoil tc/enable"},
|
{"path": "tc/enable", "type": "bool", "readonly": false, "cmd": "tcoil tc/enable"},
|
||||||
{"path": "tc/r", "type": "float"},
|
{"path": "tc/r", "type": "float"},
|
||||||
{"path": "tc/curve", "type": "text", "readonly": false, "cmd": "tcoil tc/curve", "kids": 3},
|
{"path": "tc/curve", "type": "text", "readonly": false, "cmd": "tcoil tc/curve", "kids": 3},
|
||||||
{"path": "tc/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil tc/curve/adjust"},
|
{"path": "tc/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil tc/curve/adjust", "visibility": 3},
|
||||||
{"path": "tc/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil tc/curve/points"},
|
{"path": "tc/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil tc/curve/points", "visibility": 3},
|
||||||
{"path": "tc/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil tc/curve/cpoints"},
|
{"path": "tc/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil tc/curve/cpoints", "visibility": 3},
|
||||||
{"path": "ext", "type": "float", "visibility": 3},
|
{"path": "ext", "type": "float", "visibility": 3},
|
||||||
{"path": "com", "type": "float", "visibility": 3},
|
{"path": "com", "type": "float", "visibility": 3},
|
||||||
{"path": "gnd", "type": "float", "visibility": 3}]},
|
{"path": "gnd", "type": "float", "visibility": 3}]},
|
||||||
|
@ -370,37 +370,37 @@
|
|||||||
{"path": "ta/enable", "type": "bool", "readonly": false, "cmd": "tcoil ta/enable"},
|
{"path": "ta/enable", "type": "bool", "readonly": false, "cmd": "tcoil ta/enable"},
|
||||||
{"path": "ta/r", "type": "float"},
|
{"path": "ta/r", "type": "float"},
|
||||||
{"path": "ta/curve", "type": "text", "readonly": false, "cmd": "tcoil ta/curve", "kids": 3},
|
{"path": "ta/curve", "type": "text", "readonly": false, "cmd": "tcoil ta/curve", "kids": 3},
|
||||||
{"path": "ta/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil ta/curve/adjust"},
|
{"path": "ta/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil ta/curve/adjust", "visibility": 3},
|
||||||
{"path": "ta/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil ta/curve/points"},
|
{"path": "ta/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil ta/curve/points", "visibility": 3},
|
||||||
{"path": "ta/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil ta/curve/cpoints"},
|
{"path": "ta/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil ta/curve/cpoints", "visibility": 3},
|
||||||
{"path": "tb", "type": "float", "kids": 3},
|
{"path": "tb", "type": "float", "kids": 3},
|
||||||
{"path": "tb/enable", "type": "bool", "readonly": false, "cmd": "tcoil tb/enable"},
|
{"path": "tb/enable", "type": "bool", "readonly": false, "cmd": "tcoil tb/enable"},
|
||||||
{"path": "tb/r", "type": "float"},
|
{"path": "tb/r", "type": "float"},
|
||||||
{"path": "tb/curve", "type": "text", "readonly": false, "cmd": "tcoil tb/curve", "kids": 3},
|
{"path": "tb/curve", "type": "text", "readonly": false, "cmd": "tcoil tb/curve", "kids": 3},
|
||||||
{"path": "tb/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil tb/curve/adjust"},
|
{"path": "tb/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil tb/curve/adjust", "visibility": 3},
|
||||||
{"path": "tb/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil tb/curve/points"},
|
{"path": "tb/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil tb/curve/points", "visibility": 3},
|
||||||
{"path": "tb/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil tb/curve/cpoints"},
|
{"path": "tb/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil tb/curve/cpoints", "visibility": 3},
|
||||||
{"path": "td", "type": "float", "visibility": 3, "kids": 3},
|
{"path": "td", "type": "float", "visibility": 3, "kids": 3},
|
||||||
{"path": "td/enable", "type": "bool", "readonly": false, "cmd": "tcoil td/enable"},
|
{"path": "td/enable", "type": "bool", "readonly": false, "cmd": "tcoil td/enable"},
|
||||||
{"path": "td/r", "type": "float"},
|
{"path": "td/r", "type": "float"},
|
||||||
{"path": "td/curve", "type": "text", "readonly": false, "cmd": "tcoil td/curve", "kids": 3},
|
{"path": "td/curve", "type": "text", "readonly": false, "cmd": "tcoil td/curve", "kids": 3},
|
||||||
{"path": "td/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil td/curve/adjust"},
|
{"path": "td/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil td/curve/adjust", "visibility": 3},
|
||||||
{"path": "td/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil td/curve/points"},
|
{"path": "td/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil td/curve/points", "visibility": 3},
|
||||||
{"path": "td/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil td/curve/cpoints"},
|
{"path": "td/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil td/curve/cpoints", "visibility": 3},
|
||||||
{"path": "ref", "type": "float", "visibility": 3, "kids": 3},
|
{"path": "ref", "type": "float", "visibility": 3, "kids": 3},
|
||||||
{"path": "ref/enable", "type": "bool", "readonly": false, "cmd": "tcoil ref/enable"},
|
{"path": "ref/enable", "type": "bool", "readonly": false, "cmd": "tcoil ref/enable"},
|
||||||
{"path": "ref/r", "type": "float"},
|
{"path": "ref/r", "type": "float"},
|
||||||
{"path": "ref/curve", "type": "text", "readonly": false, "cmd": "tcoil ref/curve", "kids": 3},
|
{"path": "ref/curve", "type": "text", "readonly": false, "cmd": "tcoil ref/curve", "kids": 3},
|
||||||
{"path": "ref/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil ref/curve/adjust"},
|
{"path": "ref/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil ref/curve/adjust", "visibility": 3},
|
||||||
{"path": "ref/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil ref/curve/points"},
|
{"path": "ref/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil ref/curve/points", "visibility": 3},
|
||||||
{"path": "ref/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil ref/curve/cpoints"},
|
{"path": "ref/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil ref/curve/cpoints", "visibility": 3},
|
||||||
{"path": "tc", "type": "float", "visibility": 3, "kids": 3},
|
{"path": "tc", "type": "float", "visibility": 3, "kids": 3},
|
||||||
{"path": "tc/enable", "type": "bool", "readonly": false, "cmd": "tcoil tc/enable"},
|
{"path": "tc/enable", "type": "bool", "readonly": false, "cmd": "tcoil tc/enable"},
|
||||||
{"path": "tc/r", "type": "float"},
|
{"path": "tc/r", "type": "float"},
|
||||||
{"path": "tc/curve", "type": "text", "readonly": false, "cmd": "tcoil tc/curve", "kids": 3},
|
{"path": "tc/curve", "type": "text", "readonly": false, "cmd": "tcoil tc/curve", "kids": 3},
|
||||||
{"path": "tc/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil tc/curve/adjust"},
|
{"path": "tc/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil tc/curve/adjust", "visibility": 3},
|
||||||
{"path": "tc/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil tc/curve/points"},
|
{"path": "tc/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil tc/curve/points", "visibility": 3},
|
||||||
{"path": "tc/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil tc/curve/cpoints"},
|
{"path": "tc/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil tc/curve/cpoints", "visibility": 3},
|
||||||
{"path": "ext", "type": "float", "visibility": 3},
|
{"path": "ext", "type": "float", "visibility": 3},
|
||||||
{"path": "com", "type": "float", "visibility": 3},
|
{"path": "com", "type": "float", "visibility": 3},
|
||||||
{"path": "gnd", "type": "float", "visibility": 3}]},
|
{"path": "gnd", "type": "float", "visibility": 3}]},
|
||||||
|
@ -371,37 +371,37 @@
|
|||||||
{"path": "ta/enable", "type": "bool", "readonly": false, "cmd": "tcoil ta/enable"},
|
{"path": "ta/enable", "type": "bool", "readonly": false, "cmd": "tcoil ta/enable"},
|
||||||
{"path": "ta/r", "type": "float"},
|
{"path": "ta/r", "type": "float"},
|
||||||
{"path": "ta/curve", "type": "text", "readonly": false, "cmd": "tcoil ta/curve", "kids": 3},
|
{"path": "ta/curve", "type": "text", "readonly": false, "cmd": "tcoil ta/curve", "kids": 3},
|
||||||
{"path": "ta/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil ta/curve/adjust"},
|
{"path": "ta/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil ta/curve/adjust", "visibility": 3},
|
||||||
{"path": "ta/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil ta/curve/points"},
|
{"path": "ta/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil ta/curve/points", "visibility": 3},
|
||||||
{"path": "ta/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil ta/curve/cpoints"},
|
{"path": "ta/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil ta/curve/cpoints", "visibility": 3},
|
||||||
{"path": "tb", "type": "float", "kids": 3},
|
{"path": "tb", "type": "float", "kids": 3},
|
||||||
{"path": "tb/enable", "type": "bool", "readonly": false, "cmd": "tcoil tb/enable"},
|
{"path": "tb/enable", "type": "bool", "readonly": false, "cmd": "tcoil tb/enable"},
|
||||||
{"path": "tb/r", "type": "float"},
|
{"path": "tb/r", "type": "float"},
|
||||||
{"path": "tb/curve", "type": "text", "readonly": false, "cmd": "tcoil tb/curve", "kids": 3},
|
{"path": "tb/curve", "type": "text", "readonly": false, "cmd": "tcoil tb/curve", "kids": 3},
|
||||||
{"path": "tb/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil tb/curve/adjust"},
|
{"path": "tb/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil tb/curve/adjust", "visibility": 3},
|
||||||
{"path": "tb/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil tb/curve/points"},
|
{"path": "tb/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil tb/curve/points", "visibility": 3},
|
||||||
{"path": "tb/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil tb/curve/cpoints"},
|
{"path": "tb/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil tb/curve/cpoints", "visibility": 3},
|
||||||
{"path": "td", "type": "float", "visibility": 3, "kids": 3},
|
{"path": "td", "type": "float", "visibility": 3, "kids": 3},
|
||||||
{"path": "td/enable", "type": "bool", "readonly": false, "cmd": "tcoil td/enable"},
|
{"path": "td/enable", "type": "bool", "readonly": false, "cmd": "tcoil td/enable"},
|
||||||
{"path": "td/r", "type": "float"},
|
{"path": "td/r", "type": "float"},
|
||||||
{"path": "td/curve", "type": "text", "readonly": false, "cmd": "tcoil td/curve", "kids": 3},
|
{"path": "td/curve", "type": "text", "readonly": false, "cmd": "tcoil td/curve", "kids": 3},
|
||||||
{"path": "td/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil td/curve/adjust"},
|
{"path": "td/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil td/curve/adjust", "visibility": 3},
|
||||||
{"path": "td/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil td/curve/points"},
|
{"path": "td/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil td/curve/points", "visibility": 3},
|
||||||
{"path": "td/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil td/curve/cpoints"},
|
{"path": "td/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil td/curve/cpoints", "visibility": 3},
|
||||||
{"path": "ref", "type": "float", "visibility": 3, "kids": 3},
|
{"path": "ref", "type": "float", "visibility": 3, "kids": 3},
|
||||||
{"path": "ref/enable", "type": "bool", "readonly": false, "cmd": "tcoil ref/enable"},
|
{"path": "ref/enable", "type": "bool", "readonly": false, "cmd": "tcoil ref/enable"},
|
||||||
{"path": "ref/r", "type": "float"},
|
{"path": "ref/r", "type": "float"},
|
||||||
{"path": "ref/curve", "type": "text", "readonly": false, "cmd": "tcoil ref/curve", "kids": 3},
|
{"path": "ref/curve", "type": "text", "readonly": false, "cmd": "tcoil ref/curve", "kids": 3},
|
||||||
{"path": "ref/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil ref/curve/adjust"},
|
{"path": "ref/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil ref/curve/adjust", "visibility": 3},
|
||||||
{"path": "ref/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil ref/curve/points"},
|
{"path": "ref/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil ref/curve/points", "visibility": 3},
|
||||||
{"path": "ref/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil ref/curve/cpoints"},
|
{"path": "ref/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil ref/curve/cpoints", "visibility": 3},
|
||||||
{"path": "tc", "type": "float", "visibility": 3, "kids": 3},
|
{"path": "tc", "type": "float", "visibility": 3, "kids": 3},
|
||||||
{"path": "tc/enable", "type": "bool", "readonly": false, "cmd": "tcoil tc/enable"},
|
{"path": "tc/enable", "type": "bool", "readonly": false, "cmd": "tcoil tc/enable"},
|
||||||
{"path": "tc/r", "type": "float"},
|
{"path": "tc/r", "type": "float"},
|
||||||
{"path": "tc/curve", "type": "text", "readonly": false, "cmd": "tcoil tc/curve", "kids": 3},
|
{"path": "tc/curve", "type": "text", "readonly": false, "cmd": "tcoil tc/curve", "kids": 3},
|
||||||
{"path": "tc/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil tc/curve/adjust"},
|
{"path": "tc/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil tc/curve/adjust", "visibility": 3},
|
||||||
{"path": "tc/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil tc/curve/points"},
|
{"path": "tc/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil tc/curve/points", "visibility": 3},
|
||||||
{"path": "tc/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil tc/curve/cpoints"},
|
{"path": "tc/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil tc/curve/cpoints", "visibility": 3},
|
||||||
{"path": "ext", "type": "float", "visibility": 3},
|
{"path": "ext", "type": "float", "visibility": 3},
|
||||||
{"path": "com", "type": "float", "visibility": 3},
|
{"path": "com", "type": "float", "visibility": 3},
|
||||||
{"path": "gnd", "type": "float", "visibility": 3}]},
|
{"path": "gnd", "type": "float", "visibility": 3}]},
|
||||||
|
@ -365,37 +365,37 @@
|
|||||||
{"path": "ta/enable", "type": "bool", "readonly": false, "cmd": "tcoil ta/enable"},
|
{"path": "ta/enable", "type": "bool", "readonly": false, "cmd": "tcoil ta/enable"},
|
||||||
{"path": "ta/r", "type": "float"},
|
{"path": "ta/r", "type": "float"},
|
||||||
{"path": "ta/curve", "type": "text", "readonly": false, "cmd": "tcoil ta/curve", "kids": 3},
|
{"path": "ta/curve", "type": "text", "readonly": false, "cmd": "tcoil ta/curve", "kids": 3},
|
||||||
{"path": "ta/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil ta/curve/adjust"},
|
{"path": "ta/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil ta/curve/adjust", "visibility": 3},
|
||||||
{"path": "ta/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil ta/curve/points"},
|
{"path": "ta/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil ta/curve/points", "visibility": 3},
|
||||||
{"path": "ta/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil ta/curve/cpoints"},
|
{"path": "ta/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil ta/curve/cpoints", "visibility": 3},
|
||||||
{"path": "tb", "type": "float", "visibility": 3, "kids": 3},
|
{"path": "tb", "type": "float", "visibility": 3, "kids": 3},
|
||||||
{"path": "tb/enable", "type": "bool", "readonly": false, "cmd": "tcoil tb/enable"},
|
{"path": "tb/enable", "type": "bool", "readonly": false, "cmd": "tcoil tb/enable"},
|
||||||
{"path": "tb/r", "type": "float"},
|
{"path": "tb/r", "type": "float"},
|
||||||
{"path": "tb/curve", "type": "text", "readonly": false, "cmd": "tcoil tb/curve", "kids": 3},
|
{"path": "tb/curve", "type": "text", "readonly": false, "cmd": "tcoil tb/curve", "kids": 3},
|
||||||
{"path": "tb/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil tb/curve/adjust"},
|
{"path": "tb/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil tb/curve/adjust", "visibility": 3},
|
||||||
{"path": "tb/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil tb/curve/points"},
|
{"path": "tb/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil tb/curve/points", "visibility": 3},
|
||||||
{"path": "tb/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil tb/curve/cpoints"},
|
{"path": "tb/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil tb/curve/cpoints", "visibility": 3},
|
||||||
{"path": "td", "type": "float", "visibility": 3, "kids": 3},
|
{"path": "td", "type": "float", "visibility": 3, "kids": 3},
|
||||||
{"path": "td/enable", "type": "bool", "readonly": false, "cmd": "tcoil td/enable"},
|
{"path": "td/enable", "type": "bool", "readonly": false, "cmd": "tcoil td/enable"},
|
||||||
{"path": "td/r", "type": "float"},
|
{"path": "td/r", "type": "float"},
|
||||||
{"path": "td/curve", "type": "text", "readonly": false, "cmd": "tcoil td/curve", "kids": 3},
|
{"path": "td/curve", "type": "text", "readonly": false, "cmd": "tcoil td/curve", "kids": 3},
|
||||||
{"path": "td/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil td/curve/adjust"},
|
{"path": "td/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil td/curve/adjust", "visibility": 3},
|
||||||
{"path": "td/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil td/curve/points"},
|
{"path": "td/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil td/curve/points", "visibility": 3},
|
||||||
{"path": "td/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil td/curve/cpoints"},
|
{"path": "td/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil td/curve/cpoints", "visibility": 3},
|
||||||
{"path": "ref", "type": "float", "visibility": 3, "kids": 3},
|
{"path": "ref", "type": "float", "visibility": 3, "kids": 3},
|
||||||
{"path": "ref/enable", "type": "bool", "readonly": false, "cmd": "tcoil ref/enable"},
|
{"path": "ref/enable", "type": "bool", "readonly": false, "cmd": "tcoil ref/enable"},
|
||||||
{"path": "ref/r", "type": "float"},
|
{"path": "ref/r", "type": "float"},
|
||||||
{"path": "ref/curve", "type": "text", "readonly": false, "cmd": "tcoil ref/curve", "kids": 3},
|
{"path": "ref/curve", "type": "text", "readonly": false, "cmd": "tcoil ref/curve", "kids": 3},
|
||||||
{"path": "ref/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil ref/curve/adjust"},
|
{"path": "ref/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil ref/curve/adjust", "visibility": 3},
|
||||||
{"path": "ref/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil ref/curve/points"},
|
{"path": "ref/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil ref/curve/points", "visibility": 3},
|
||||||
{"path": "ref/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil ref/curve/cpoints"},
|
{"path": "ref/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil ref/curve/cpoints", "visibility": 3},
|
||||||
{"path": "tc", "type": "float", "visibility": 3, "kids": 3},
|
{"path": "tc", "type": "float", "visibility": 3, "kids": 3},
|
||||||
{"path": "tc/enable", "type": "bool", "readonly": false, "cmd": "tcoil tc/enable"},
|
{"path": "tc/enable", "type": "bool", "readonly": false, "cmd": "tcoil tc/enable"},
|
||||||
{"path": "tc/r", "type": "float"},
|
{"path": "tc/r", "type": "float"},
|
||||||
{"path": "tc/curve", "type": "text", "readonly": false, "cmd": "tcoil tc/curve", "kids": 3},
|
{"path": "tc/curve", "type": "text", "readonly": false, "cmd": "tcoil tc/curve", "kids": 3},
|
||||||
{"path": "tc/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil tc/curve/adjust"},
|
{"path": "tc/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil tc/curve/adjust", "visibility": 3},
|
||||||
{"path": "tc/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil tc/curve/points"},
|
{"path": "tc/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil tc/curve/points", "visibility": 3},
|
||||||
{"path": "tc/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil tc/curve/cpoints"},
|
{"path": "tc/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil tc/curve/cpoints", "visibility": 3},
|
||||||
{"path": "ext", "type": "float", "visibility": 3},
|
{"path": "ext", "type": "float", "visibility": 3},
|
||||||
{"path": "com", "type": "float", "visibility": 3},
|
{"path": "com", "type": "float", "visibility": 3},
|
||||||
{"path": "gnd", "type": "float", "visibility": 3}]},
|
{"path": "gnd", "type": "float", "visibility": 3}]},
|
||||||
|
@ -331,37 +331,37 @@
|
|||||||
{"path": "ta/enable", "type": "bool", "readonly": false, "cmd": "tcoil ta/enable"},
|
{"path": "ta/enable", "type": "bool", "readonly": false, "cmd": "tcoil ta/enable"},
|
||||||
{"path": "ta/r", "type": "float"},
|
{"path": "ta/r", "type": "float"},
|
||||||
{"path": "ta/curve", "type": "text", "readonly": false, "cmd": "tcoil ta/curve", "kids": 3},
|
{"path": "ta/curve", "type": "text", "readonly": false, "cmd": "tcoil ta/curve", "kids": 3},
|
||||||
{"path": "ta/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil ta/curve/adjust"},
|
{"path": "ta/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil ta/curve/adjust", "visibility": 3},
|
||||||
{"path": "ta/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil ta/curve/points"},
|
{"path": "ta/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil ta/curve/points", "visibility": 3},
|
||||||
{"path": "ta/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil ta/curve/cpoints"},
|
{"path": "ta/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil ta/curve/cpoints", "visibility": 3},
|
||||||
{"path": "tb", "type": "float", "visibility": 3, "kids": 3},
|
{"path": "tb", "type": "float", "visibility": 3, "kids": 3},
|
||||||
{"path": "tb/enable", "type": "bool", "readonly": false, "cmd": "tcoil tb/enable"},
|
{"path": "tb/enable", "type": "bool", "readonly": false, "cmd": "tcoil tb/enable"},
|
||||||
{"path": "tb/r", "type": "float"},
|
{"path": "tb/r", "type": "float"},
|
||||||
{"path": "tb/curve", "type": "text", "readonly": false, "cmd": "tcoil tb/curve", "kids": 3},
|
{"path": "tb/curve", "type": "text", "readonly": false, "cmd": "tcoil tb/curve", "kids": 3},
|
||||||
{"path": "tb/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil tb/curve/adjust"},
|
{"path": "tb/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil tb/curve/adjust", "visibility": 3},
|
||||||
{"path": "tb/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil tb/curve/points"},
|
{"path": "tb/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil tb/curve/points", "visibility": 3},
|
||||||
{"path": "tb/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil tb/curve/cpoints"},
|
{"path": "tb/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil tb/curve/cpoints", "visibility": 3},
|
||||||
{"path": "td", "type": "float", "visibility": 3, "kids": 3},
|
{"path": "td", "type": "float", "visibility": 3, "kids": 3},
|
||||||
{"path": "td/enable", "type": "bool", "readonly": false, "cmd": "tcoil td/enable"},
|
{"path": "td/enable", "type": "bool", "readonly": false, "cmd": "tcoil td/enable"},
|
||||||
{"path": "td/r", "type": "float"},
|
{"path": "td/r", "type": "float"},
|
||||||
{"path": "td/curve", "type": "text", "readonly": false, "cmd": "tcoil td/curve", "kids": 3},
|
{"path": "td/curve", "type": "text", "readonly": false, "cmd": "tcoil td/curve", "kids": 3},
|
||||||
{"path": "td/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil td/curve/adjust"},
|
{"path": "td/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil td/curve/adjust", "visibility": 3},
|
||||||
{"path": "td/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil td/curve/points"},
|
{"path": "td/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil td/curve/points", "visibility": 3},
|
||||||
{"path": "td/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil td/curve/cpoints"},
|
{"path": "td/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil td/curve/cpoints", "visibility": 3},
|
||||||
{"path": "ref", "type": "float", "visibility": 3, "kids": 3},
|
{"path": "ref", "type": "float", "visibility": 3, "kids": 3},
|
||||||
{"path": "ref/enable", "type": "bool", "readonly": false, "cmd": "tcoil ref/enable"},
|
{"path": "ref/enable", "type": "bool", "readonly": false, "cmd": "tcoil ref/enable"},
|
||||||
{"path": "ref/r", "type": "float"},
|
{"path": "ref/r", "type": "float"},
|
||||||
{"path": "ref/curve", "type": "text", "readonly": false, "cmd": "tcoil ref/curve", "kids": 3},
|
{"path": "ref/curve", "type": "text", "readonly": false, "cmd": "tcoil ref/curve", "kids": 3},
|
||||||
{"path": "ref/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil ref/curve/adjust"},
|
{"path": "ref/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil ref/curve/adjust", "visibility": 3},
|
||||||
{"path": "ref/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil ref/curve/points"},
|
{"path": "ref/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil ref/curve/points", "visibility": 3},
|
||||||
{"path": "ref/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil ref/curve/cpoints"},
|
{"path": "ref/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil ref/curve/cpoints", "visibility": 3},
|
||||||
{"path": "tc", "type": "float", "visibility": 3, "kids": 3},
|
{"path": "tc", "type": "float", "visibility": 3, "kids": 3},
|
||||||
{"path": "tc/enable", "type": "bool", "readonly": false, "cmd": "tcoil tc/enable"},
|
{"path": "tc/enable", "type": "bool", "readonly": false, "cmd": "tcoil tc/enable"},
|
||||||
{"path": "tc/r", "type": "float"},
|
{"path": "tc/r", "type": "float"},
|
||||||
{"path": "tc/curve", "type": "text", "readonly": false, "cmd": "tcoil tc/curve", "kids": 3},
|
{"path": "tc/curve", "type": "text", "readonly": false, "cmd": "tcoil tc/curve", "kids": 3},
|
||||||
{"path": "tc/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil tc/curve/adjust"},
|
{"path": "tc/curve/adjust", "type": "text", "readonly": false, "cmd": "tcoil tc/curve/adjust", "visibility": 3},
|
||||||
{"path": "tc/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil tc/curve/points"},
|
{"path": "tc/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tcoil tc/curve/points", "visibility": 3},
|
||||||
{"path": "tc/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil tc/curve/cpoints"},
|
{"path": "tc/curve/cpoints", "type": "floatvarar", "readonly": false, "cmd": "tcoil tc/curve/cpoints", "visibility": 3},
|
||||||
{"path": "ext", "type": "float", "visibility": 3},
|
{"path": "ext", "type": "float", "visibility": 3},
|
||||||
{"path": "com", "type": "float", "visibility": 3},
|
{"path": "com", "type": "float", "visibility": 3},
|
||||||
{"path": "gnd", "type": "float", "visibility": 3}]},
|
{"path": "gnd", "type": "float", "visibility": 3}]},
|
||||||
|
307
cfg/sea/ori2.config.json
Normal file
307
cfg/sea/ori2.config.json
Normal file
@ -0,0 +1,307 @@
|
|||||||
|
{"tt": {"base": "/tt", "params": [
|
||||||
|
{"path": "", "type": "float", "readonly": false, "cmd": "run tt", "description": "tt", "kids": 19},
|
||||||
|
{"path": "send", "type": "text", "readonly": false, "cmd": "tt send", "visibility": 3},
|
||||||
|
{"path": "status", "type": "text", "visibility": 3},
|
||||||
|
{"path": "is_running", "type": "int", "readonly": false, "cmd": "tt is_running", "visibility": 3},
|
||||||
|
{"path": "mainloop", "type": "text", "readonly": false, "cmd": "tt mainloop", "visibility": 3},
|
||||||
|
{"path": "target", "type": "float"},
|
||||||
|
{"path": "running", "type": "int"},
|
||||||
|
{"path": "tolerance", "type": "float", "readonly": false, "cmd": "tt tolerance"},
|
||||||
|
{"path": "maxwait", "type": "float", "readonly": false, "cmd": "tt maxwait"},
|
||||||
|
{"path": "settle", "type": "float", "readonly": false, "cmd": "tt settle"},
|
||||||
|
{"path": "log", "type": "text", "readonly": false, "cmd": "tt log", "visibility": 3, "kids": 4},
|
||||||
|
{"path": "log/mean", "type": "float", "visibility": 3},
|
||||||
|
{"path": "log/m2", "type": "float", "visibility": 3},
|
||||||
|
{"path": "log/stddev", "type": "float", "visibility": 3},
|
||||||
|
{"path": "log/n", "type": "float", "visibility": 3},
|
||||||
|
{"path": "dblctrl", "type": "bool", "readonly": false, "cmd": "tt dblctrl", "kids": 9},
|
||||||
|
{"path": "dblctrl/tshift", "type": "float", "readonly": false, "cmd": "tt dblctrl/tshift"},
|
||||||
|
{"path": "dblctrl/mode", "type": "enum", "enum": {"disabled": -1, "inactive": 0, "stable": 1, "up": 2, "down": 3}, "readonly": false, "cmd": "tt dblctrl/mode"},
|
||||||
|
{"path": "dblctrl/shift_up", "type": "float"},
|
||||||
|
{"path": "dblctrl/shift_lo", "type": "float"},
|
||||||
|
{"path": "dblctrl/t_min", "type": "float"},
|
||||||
|
{"path": "dblctrl/t_max", "type": "float"},
|
||||||
|
{"path": "dblctrl/int2", "type": "float", "readonly": false, "cmd": "tt dblctrl/int2"},
|
||||||
|
{"path": "dblctrl/prop_up", "type": "float", "readonly": false, "cmd": "tt dblctrl/prop_up"},
|
||||||
|
{"path": "dblctrl/prop_lo", "type": "float", "readonly": false, "cmd": "tt dblctrl/prop_lo"},
|
||||||
|
{"path": "tm", "type": "float", "kids": 4},
|
||||||
|
{"path": "tm/curve", "type": "text", "readonly": false, "cmd": "tt tm/curve", "kids": 1},
|
||||||
|
{"path": "tm/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tt tm/curve/points", "visibility": 3},
|
||||||
|
{"path": "tm/alarm", "type": "float", "readonly": false, "cmd": "tt tm/alarm"},
|
||||||
|
{"path": "tm/stddev", "type": "float"},
|
||||||
|
{"path": "tm/raw", "type": "float"},
|
||||||
|
{"path": "ts", "type": "float", "kids": 4},
|
||||||
|
{"path": "ts/curve", "type": "text", "readonly": false, "cmd": "tt ts/curve", "kids": 1},
|
||||||
|
{"path": "ts/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tt ts/curve/points", "visibility": 3},
|
||||||
|
{"path": "ts/alarm", "type": "float", "readonly": false, "cmd": "tt ts/alarm"},
|
||||||
|
{"path": "ts/stddev", "type": "float"},
|
||||||
|
{"path": "ts/raw", "type": "float"},
|
||||||
|
{"path": "ts_2", "type": "float", "visibility": 3, "kids": 4},
|
||||||
|
{"path": "ts_2/curve", "type": "text", "readonly": false, "cmd": "tt ts_2/curve", "visibility": 3, "kids": 1},
|
||||||
|
{"path": "ts_2/curve/points", "type": "floatvarar", "readonly": false, "cmd": "tt ts_2/curve/points", "visibility": 3},
|
||||||
|
{"path": "ts_2/alarm", "type": "float", "readonly": false, "cmd": "tt ts_2/alarm", "visibility": 3},
|
||||||
|
{"path": "ts_2/stddev", "type": "float", "visibility": 3},
|
||||||
|
{"path": "ts_2/raw", "type": "float", "visibility": 3},
|
||||||
|
{"path": "set", "type": "float", "readonly": false, "cmd": "tt set", "kids": 18},
|
||||||
|
{"path": "set/mode", "type": "enum", "enum": {"disabled": -1, "off": 0, "controlling": 1, "manual": 2}, "readonly": false, "cmd": "tt set/mode"},
|
||||||
|
{"path": "set/reg", "type": "float"},
|
||||||
|
{"path": "set/ramp", "type": "float", "readonly": false, "cmd": "tt set/ramp", "description": "maximum ramp in K/min (0: ramp off)"},
|
||||||
|
{"path": "set/wramp", "type": "float", "readonly": false, "cmd": "tt set/wramp"},
|
||||||
|
{"path": "set/smooth", "type": "float", "readonly": false, "cmd": "tt set/smooth", "description": "smooth time (minutes)"},
|
||||||
|
{"path": "set/channel", "type": "text", "readonly": false, "cmd": "tt set/channel"},
|
||||||
|
{"path": "set/limit", "type": "float", "readonly": false, "cmd": "tt set/limit"},
|
||||||
|
{"path": "set/resist", "type": "float", "readonly": false, "cmd": "tt set/resist"},
|
||||||
|
{"path": "set/maxheater", "type": "text", "readonly": false, "cmd": "tt set/maxheater", "description": "maximum heater limit, units should be given without space: W, mW, A, mA"},
|
||||||
|
{"path": "set/linearpower", "type": "float", "readonly": false, "cmd": "tt set/linearpower", "description": "when not 0, it is the maximum effective power, and the power is linear to the heater output"},
|
||||||
|
{"path": "set/maxpowerlim", "type": "float", "description": "the maximum power limit (before any booster or converter)"},
|
||||||
|
{"path": "set/maxpower", "type": "float", "readonly": false, "cmd": "tt set/maxpower", "description": "maximum power [W]"},
|
||||||
|
{"path": "set/maxcurrent", "type": "float", "description": "the maximum current before any booster or converter"},
|
||||||
|
{"path": "set/manualpower", "type": "float", "readonly": false, "cmd": "tt set/manualpower"},
|
||||||
|
{"path": "set/power", "type": "float"},
|
||||||
|
{"path": "set/prop", "type": "float", "readonly": false, "cmd": "tt set/prop", "description": "bigger means more gain"},
|
||||||
|
{"path": "set/integ", "type": "float", "readonly": false, "cmd": "tt set/integ", "description": "bigger means faster"},
|
||||||
|
{"path": "set/deriv", "type": "float", "readonly": false, "cmd": "tt set/deriv"},
|
||||||
|
{"path": "display", "type": "text", "readonly": false, "cmd": "tt display"},
|
||||||
|
{"path": "remote", "type": "bool"}]},
|
||||||
|
|
||||||
|
"cc": {"base": "/cc", "params": [
|
||||||
|
{"path": "", "type": "bool", "kids": 96},
|
||||||
|
{"path": "send", "type": "text", "readonly": false, "cmd": "cc send", "visibility": 3},
|
||||||
|
{"path": "status", "type": "text", "visibility": 3},
|
||||||
|
{"path": "autodevice", "type": "bool", "readonly": false, "cmd": "cc autodevice"},
|
||||||
|
{"path": "fav", "type": "bool", "readonly": false, "cmd": "cc fav"},
|
||||||
|
{"path": "f", "type": "float"},
|
||||||
|
{"path": "fs", "type": "enum", "enum": {"ok": 0, "no_sens": 1}, "readonly": false, "cmd": "cc fs"},
|
||||||
|
{"path": "mav", "type": "bool", "readonly": false, "cmd": "cc mav"},
|
||||||
|
{"path": "fm", "type": "enum", "enum": {"idle": 0, "opening": 1, "closing": 2, "opened": 3, "closed": 4, "no_motor": 5}},
|
||||||
|
{"path": "fa", "type": "enum", "enum": {"fixed": 0, "controlled": 1, "automatic": 2, "offline": 3}, "readonly": false, "cmd": "cc fa"},
|
||||||
|
{"path": "mp", "type": "float", "readonly": false, "cmd": "cc mp"},
|
||||||
|
{"path": "msp", "type": "float"},
|
||||||
|
{"path": "mmp", "type": "float"},
|
||||||
|
{"path": "mc", "type": "float", "readonly": false, "cmd": "cc mc"},
|
||||||
|
{"path": "mfc", "type": "float", "readonly": false, "cmd": "cc mfc"},
|
||||||
|
{"path": "moc", "type": "float", "readonly": false, "cmd": "cc moc"},
|
||||||
|
{"path": "mtc", "type": "float", "readonly": false, "cmd": "cc mtc"},
|
||||||
|
{"path": "mtl", "type": "float"},
|
||||||
|
{"path": "mft", "type": "float", "readonly": false, "cmd": "cc mft"},
|
||||||
|
{"path": "mt", "type": "float"},
|
||||||
|
{"path": "mo", "type": "float"},
|
||||||
|
{"path": "mcr", "type": "float"},
|
||||||
|
{"path": "mot", "type": "float"},
|
||||||
|
{"path": "mw", "type": "float", "readonly": false, "cmd": "cc mw", "description": "correction pulse after automatic open"},
|
||||||
|
{"path": "hav", "type": "enum", "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"},
|
||||||
|
{"path": "hu", "type": "float"},
|
||||||
|
{"path": "hh", "type": "float", "readonly": false, "cmd": "cc hh"},
|
||||||
|
{"path": "hl", "type": "float", "readonly": false, "cmd": "cc hl"},
|
||||||
|
{"path": "htf", "type": "float", "readonly": false, "cmd": "cc htf", "description": "meas. period in fast mode"},
|
||||||
|
{"path": "hts", "type": "float", "readonly": false, "cmd": "cc hts", "description": "meas. period in slow mode"},
|
||||||
|
{"path": "hd", "type": "float", "readonly": false, "cmd": "cc hd"},
|
||||||
|
{"path": "hwr", "type": "float", "readonly": false, "cmd": "cc hwr"},
|
||||||
|
{"path": "hem", "type": "float", "readonly": false, "cmd": "cc hem", "description": "sensor length in mm from top to empty pos."},
|
||||||
|
{"path": "hfu", "type": "float", "readonly": false, "cmd": "cc hfu", "description": "sensor length in mm from top to full pos."},
|
||||||
|
{"path": "hcd", "type": "enum", "enum": {"stop": 0, "fill": 1, "off": 2, "auto": 3, "manual": 7}, "readonly": false, "cmd": "cc hcd"},
|
||||||
|
{"path": "hv", "type": "enum", "enum": {"fill_valve_off": 0, "filling": 1, "no_fill_valve": 2, "timeout": 3, "timeout1": 4}},
|
||||||
|
{"path": "hsf", "type": "enum", "enum": {"sens_ok": 0, "sens_warm": 1, "no_sens": 2, "timeout": 3, "not_yet_read": 4, "disabled": 5}},
|
||||||
|
{"path": "ha", "type": "bool", "readonly": false, "cmd": "cc ha"},
|
||||||
|
{"path": "hm", "type": "bool"},
|
||||||
|
{"path": "hf", "type": "enum", "enum": {"slow": 0, "fast": 1}, "readonly": false, "cmd": "cc hf"},
|
||||||
|
{"path": "hbe", "type": "bool", "readonly": false, "cmd": "cc hbe"},
|
||||||
|
{"path": "hmf", "type": "float"},
|
||||||
|
{"path": "hms", "type": "float"},
|
||||||
|
{"path": "hit", "type": "float", "readonly": false, "cmd": "cc hit"},
|
||||||
|
{"path": "hft", "type": "int", "readonly": false, "cmd": "cc hft"},
|
||||||
|
{"path": "hea", "type": "enum", "enum": {"0": 0, "1": 1, "6": 2}, "readonly": false, "cmd": "cc hea"},
|
||||||
|
{"path": "hch", "type": "int", "readonly": false, "cmd": "cc hch", "visibility": 3},
|
||||||
|
{"path": "hwr0", "type": "float", "readonly": false, "cmd": "cc hwr0", "visibility": 3},
|
||||||
|
{"path": "hem0", "type": "float", "readonly": false, "cmd": "cc hem0", "description": "sensor length in mm from top to empty pos.", "visibility": 3},
|
||||||
|
{"path": "hfu0", "type": "float", "readonly": false, "cmd": "cc hfu0", "description": "sensor length in mm from top to full pos.", "visibility": 3},
|
||||||
|
{"path": "hd0", "type": "float", "readonly": false, "cmd": "cc hd0", "description": "external sensor drive current (mA)", "visibility": 3},
|
||||||
|
{"path": "h0", "type": "float", "visibility": 3},
|
||||||
|
{"path": "hs0", "type": "enum", "enum": {"sens_ok": 0, "sens_warm": 1, "no_sens": 2, "timeout": 3, "not_yet_read": 4, "disabled": 5}, "visibility": 3},
|
||||||
|
{"path": "h1", "type": "float", "visibility": 3},
|
||||||
|
{"path": "hs1", "type": "enum", "enum": {"sens_ok": 0, "sens_warm": 1, "no_sens": 2, "timeout": 3, "not_yet_read": 4, "disabled": 5}, "visibility": 3},
|
||||||
|
{"path": "h2", "type": "float", "visibility": 3},
|
||||||
|
{"path": "hs2", "type": "enum", "enum": {"sens_ok": 0, "sens_warm": 1, "no_sens": 2, "timeout": 3, "not_yet_read": 4, "disabled": 5}, "visibility": 3},
|
||||||
|
{"path": "h3", "type": "float", "visibility": 3},
|
||||||
|
{"path": "hs3", "type": "enum", "enum": {"sens_ok": 0, "sens_warm": 1, "no_sens": 2, "timeout": 3, "not_yet_read": 4, "disabled": 5}, "visibility": 3},
|
||||||
|
{"path": "h4", "type": "float", "visibility": 3},
|
||||||
|
{"path": "hs4", "type": "enum", "enum": {"sens_ok": 0, "sens_warm": 1, "no_sens": 2, "timeout": 3, "not_yet_read": 4, "disabled": 5}, "visibility": 3},
|
||||||
|
{"path": "h5", "type": "float", "visibility": 3},
|
||||||
|
{"path": "hs5", "type": "enum", "enum": {"sens_ok": 0, "sens_warm": 1, "no_sens": 2, "timeout": 3, "not_yet_read": 4, "disabled": 5}, "visibility": 3},
|
||||||
|
{"path": "hfb", "type": "float"},
|
||||||
|
{"path": "nav", "type": "enum", "type": "enum", "enum": {"none": 0, "int": 1, "ext": 2}, "readonly": false, "cmd": "cc nav"},
|
||||||
|
{"path": "nu", "type": "float"},
|
||||||
|
{"path": "nl", "type": "float"},
|
||||||
|
{"path": "nth", "type": "float", "readonly": false, "cmd": "cc nth"},
|
||||||
|
{"path": "ntc", "type": "float", "readonly": false, "cmd": "cc ntc"},
|
||||||
|
{"path": "ntm", "type": "float", "readonly": false, "cmd": "cc ntm"},
|
||||||
|
{"path": "ns", "type": "enum", "enum": {"sens_ok": 0, "no_sens": 1, "short_circuit": 2, "upside_down": 3, "sens_warm": 4, "empty": 5}},
|
||||||
|
{"path": "na", "type": "bool", "readonly": false, "cmd": "cc na"},
|
||||||
|
{"path": "nv", "type": "enum", "enum": {"fill_valve_off": 0, "filling": 1, "no_fill_valve": 2, "timeout": 3, "timeout1": 4, "boost": 5}},
|
||||||
|
{"path": "nc", "type": "enum", "enum": {"stop": 0, "fill": 1, "off": 2, "auto": 3}, "readonly": false, "cmd": "cc nc"},
|
||||||
|
{"path": "nfb", "type": "float"},
|
||||||
|
{"path": "cda", "type": "float"},
|
||||||
|
{"path": "cdb", "type": "float"},
|
||||||
|
{"path": "cba", "type": "float"},
|
||||||
|
{"path": "cbb", "type": "float"},
|
||||||
|
{"path": "cvs", "type": "int"},
|
||||||
|
{"path": "csp", "type": "int"},
|
||||||
|
{"path": "cdv", "type": "text", "readonly": false, "cmd": "cc cdv"},
|
||||||
|
{"path": "cic", "type": "text", "readonly": false, "cmd": "cc cic"},
|
||||||
|
{"path": "cin", "type": "text"},
|
||||||
|
{"path": "cds", "type": "enum", "enum": {"local": 0, "remote": 1, "loading": 2, "by_code": 3, "by_touch": 4}, "readonly": false, "cmd": "cc cds"},
|
||||||
|
{"path": "timing", "type": "bool", "readonly": false, "cmd": "cc timing"},
|
||||||
|
{"path": "tc", "type": "float", "visibility": 3},
|
||||||
|
{"path": "tn", "type": "float", "visibility": 3},
|
||||||
|
{"path": "th", "type": "float", "visibility": 3},
|
||||||
|
{"path": "tf", "type": "float", "visibility": 3},
|
||||||
|
{"path": "tm", "type": "float", "visibility": 3},
|
||||||
|
{"path": "tv", "type": "float", "visibility": 3},
|
||||||
|
{"path": "tq", "type": "float", "visibility": 3},
|
||||||
|
{"path": "bdl", "type": "float", "readonly": false, "cmd": "cc bdl"}]},
|
||||||
|
|
||||||
|
"nv": {"base": "/nv", "params": [
|
||||||
|
{"path": "", "type": "enum", "enum": {"fixed": 0, "controlled": 1, "automatic": 2, "close": 3, "open": 4}, "readonly": false, "cmd": "nv", "kids": 11},
|
||||||
|
{"path": "send", "type": "text", "readonly": false, "cmd": "nv send", "visibility": 3},
|
||||||
|
{"path": "status", "type": "text", "visibility": 3},
|
||||||
|
{"path": "motstat", "type": "enum", "enum": {"idle": 0, "opening": 1, "closing": 2, "opened": 3, "closed": 4, "no_motor": 5}},
|
||||||
|
{"path": "flow", "type": "float"},
|
||||||
|
{"path": "set", "type": "float", "readonly": false, "cmd": "nv set"},
|
||||||
|
{"path": "flowmax", "type": "float", "readonly": false, "cmd": "nv flowmax"},
|
||||||
|
{"path": "flowp", "type": "float"},
|
||||||
|
{"path": "span", "type": "float"},
|
||||||
|
{"path": "ctrl", "type": "none", "kids": 13},
|
||||||
|
{"path": "ctrl/regtext", "type": "text"},
|
||||||
|
{"path": "ctrl/prop_o", "type": "float", "readonly": false, "cmd": "nv ctrl/prop_o", "description": "prop [sec/mbar] when opening. above 4 mbar a 10 times lower value is used"},
|
||||||
|
{"path": "ctrl/prop_c", "type": "float", "readonly": false, "cmd": "nv ctrl/prop_c", "description": "prop [sec/mbar] when closing. above 4 mbar a 10 times lower value is used"},
|
||||||
|
{"path": "ctrl/deriv_o", "type": "float", "readonly": false, "cmd": "nv ctrl/deriv_o", "description": "convergence target time [sec] when opening"},
|
||||||
|
{"path": "ctrl/deriv_c", "type": "float", "readonly": false, "cmd": "nv ctrl/deriv_c", "description": "convergence target time [sec] when closing"},
|
||||||
|
{"path": "ctrl/minpulse_o", "type": "float", "readonly": false, "cmd": "nv ctrl/minpulse_o", "description": "minimum close pulse [sec]"},
|
||||||
|
{"path": "ctrl/minpulse_c", "type": "float", "readonly": false, "cmd": "nv ctrl/minpulse_c", "description": "standard close pulse [sec]"},
|
||||||
|
{"path": "ctrl/hystpulse_o", "type": "float", "readonly": false, "cmd": "nv ctrl/hystpulse_o", "description": "motor pulse to overcome hysteresis when opening"},
|
||||||
|
{"path": "ctrl/hystpulse_c", "type": "float", "readonly": false, "cmd": "nv ctrl/hystpulse_c", "description": "motor pulse to overcome hysteresis when closing"},
|
||||||
|
{"path": "ctrl/tol", "type": "float", "readonly": false, "cmd": "nv ctrl/tol", "description": "valid below 3 mbar"},
|
||||||
|
{"path": "ctrl/tolhigh", "type": "float", "readonly": false, "cmd": "nv ctrl/tolhigh", "description": "valid above 4 mbar"},
|
||||||
|
{"path": "ctrl/openpulse", "type": "float", "readonly": false, "cmd": "nv ctrl/openpulse", "description": "time to open from completely closed to a significant opening"},
|
||||||
|
{"path": "ctrl/adjust_minpulse", "type": "bool", "readonly": false, "cmd": "nv ctrl/adjust_minpulse", "description": "adjust minpulse automatically"},
|
||||||
|
{"path": "autoflow", "type": "none", "kids": 24},
|
||||||
|
{"path": "autoflow/suspended", "type": "bool", "readonly": false, "cmd": "nv autoflow/suspended"},
|
||||||
|
{"path": "autoflow/prop", "type": "float", "readonly": false, "cmd": "nv autoflow/prop"},
|
||||||
|
{"path": "autoflow/flowstd", "type": "float", "readonly": false, "cmd": "nv autoflow/flowstd"},
|
||||||
|
{"path": "autoflow/flowlim", "type": "float", "readonly": false, "cmd": "nv autoflow/flowlim"},
|
||||||
|
{"path": "autoflow/smooth", "type": "float", "readonly": false, "cmd": "nv autoflow/smooth"},
|
||||||
|
{"path": "autoflow/difSize", "type": "float", "readonly": false, "cmd": "nv autoflow/difSize"},
|
||||||
|
{"path": "autoflow/difRange", "type": "float", "readonly": false, "cmd": "nv autoflow/difRange"},
|
||||||
|
{"path": "autoflow/flowSize", "type": "float", "readonly": false, "cmd": "nv autoflow/flowSize"},
|
||||||
|
{"path": "autoflow/convTime", "type": "float", "readonly": false, "cmd": "nv autoflow/convTime"},
|
||||||
|
{"path": "autoflow/Tmin", "type": "float", "readonly": false, "cmd": "nv autoflow/Tmin"},
|
||||||
|
{"path": "autoflow/script", "type": "text", "readonly": false, "cmd": "nv autoflow/script"},
|
||||||
|
{"path": "autoflow/getTemp", "type": "text", "readonly": false, "cmd": "nv autoflow/getTemp"},
|
||||||
|
{"path": "autoflow/getTset", "type": "text", "readonly": false, "cmd": "nv autoflow/getTset"},
|
||||||
|
{"path": "autoflow/getFlow", "type": "text", "readonly": false, "cmd": "nv autoflow/getFlow"},
|
||||||
|
{"path": "autoflow/difBuf", "type": "text"},
|
||||||
|
{"path": "autoflow/flowBuf", "type": "text"},
|
||||||
|
{"path": "autoflow/flowset", "type": "float"},
|
||||||
|
{"path": "autoflow/flowmin", "type": "float"},
|
||||||
|
{"path": "autoflow/flowmax", "type": "float"},
|
||||||
|
{"path": "autoflow/difmin", "type": "float"},
|
||||||
|
{"path": "autoflow/difmax", "type": "float"},
|
||||||
|
{"path": "autoflow/setmin", "type": "float"},
|
||||||
|
{"path": "autoflow/setmax", "type": "float"},
|
||||||
|
{"path": "autoflow/flowtarget", "type": "float"},
|
||||||
|
{"path": "calib", "type": "none", "kids": 2},
|
||||||
|
{"path": "calib/ln_per_min_per_mbar", "type": "float", "readonly": false, "cmd": "nv calib/ln_per_min_per_mbar"},
|
||||||
|
{"path": "calib/mbar_offset", "type": "float", "readonly": false, "cmd": "nv calib/mbar_offset"}]},
|
||||||
|
|
||||||
|
"ln2fill": {"base": "/ln2fill", "params": [
|
||||||
|
{"path": "", "type": "enum", "enum": {"watching": 0, "fill": 1, "inactive": 2}, "readonly": false, "cmd": "ln2fill", "kids": 3},
|
||||||
|
{"path": "send", "type": "text", "readonly": false, "cmd": "ln2fill send", "visibility": 3},
|
||||||
|
{"path": "status", "type": "text", "visibility": 3},
|
||||||
|
{"path": "state", "type": "text"}]},
|
||||||
|
|
||||||
|
"hefill": {"base": "/hefill", "params": [
|
||||||
|
{"path": "", "type": "enum", "enum": {"watching": 0, "fill": 1, "inactive": 2, "manualfill": 3}, "readonly": false, "cmd": "hefill", "kids": 6},
|
||||||
|
{"path": "send", "type": "text", "readonly": false, "cmd": "hefill send", "visibility": 3},
|
||||||
|
{"path": "status", "type": "text", "visibility": 3},
|
||||||
|
{"path": "fast", "type": "enum", "enum": {"slow": 0, "fast": 1}, "readonly": false, "cmd": "cc hf"},
|
||||||
|
{"path": "state", "type": "text"},
|
||||||
|
{"path": "hefull", "type": "float", "readonly": false, "cmd": "cc hh"},
|
||||||
|
{"path": "helow", "type": "float", "readonly": false, "cmd": "cc hl"}]},
|
||||||
|
|
||||||
|
"hepump": {"base": "/hepump", "params": [
|
||||||
|
{"path": "", "type": "enum", "enum": {"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", "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", "visibility": 3},
|
||||||
|
{"path": "calib", "type": "float", "readonly": false, "cmd": "hepump calib", "visibility": 3},
|
||||||
|
{"path": "health", "type": "float"}]},
|
||||||
|
|
||||||
|
"hemot": {"base": "/hepump/hemot", "params": [
|
||||||
|
{"path": "", "type": "float", "readonly": false, "cmd": "run hemot", "visibility": 3, "kids": 30},
|
||||||
|
{"path": "send", "type": "text", "readonly": false, "cmd": "hemot send", "visibility": 3},
|
||||||
|
{"path": "status", "type": "text", "visibility": 3},
|
||||||
|
{"path": "is_running", "type": "int", "readonly": false, "cmd": "hemot is_running", "visibility": 3},
|
||||||
|
{"path": "pos", "type": "float"},
|
||||||
|
{"path": "encoder", "type": "float"},
|
||||||
|
{"path": "zero", "type": "float", "readonly": false, "cmd": "hemot zero"},
|
||||||
|
{"path": "lowerlimit", "type": "float", "readonly": false, "cmd": "hemot lowerlimit"},
|
||||||
|
{"path": "upperlimit", "type": "float", "readonly": false, "cmd": "hemot upperlimit"},
|
||||||
|
{"path": "disablelimits", "type": "bool", "readonly": false, "cmd": "hemot disablelimits"},
|
||||||
|
{"path": "verbose", "type": "bool", "readonly": false, "cmd": "hemot verbose"},
|
||||||
|
{"path": "target", "type": "float"},
|
||||||
|
{"path": "runstate", "type": "enum", "enum": {"idle": 0, "running": 1, "finished": 2, "error": 3}},
|
||||||
|
{"path": "precision", "type": "float", "readonly": false, "cmd": "hemot precision"},
|
||||||
|
{"path": "maxencdif", "type": "float", "readonly": false, "cmd": "hemot maxencdif"},
|
||||||
|
{"path": "id", "type": "float", "readonly": false, "cmd": "hemot id"},
|
||||||
|
{"path": "pump_number", "type": "float", "readonly": false, "cmd": "hemot pump_number"},
|
||||||
|
{"path": "init", "type": "float", "readonly": false, "cmd": "hemot init"},
|
||||||
|
{"path": "maxspeed", "type": "float", "readonly": false, "cmd": "hemot maxspeed"},
|
||||||
|
{"path": "acceleration", "type": "float", "readonly": false, "cmd": "hemot acceleration"},
|
||||||
|
{"path": "maxcurrent", "type": "float", "readonly": false, "cmd": "hemot maxcurrent"},
|
||||||
|
{"path": "standbycurrent", "type": "float", "readonly": false, "cmd": "hemot standbycurrent"},
|
||||||
|
{"path": "freewheeling", "type": "bool", "readonly": false, "cmd": "hemot freewheeling"},
|
||||||
|
{"path": "output0", "type": "bool", "readonly": false, "cmd": "hemot output0"},
|
||||||
|
{"path": "output1", "type": "bool", "readonly": false, "cmd": "hemot output1"},
|
||||||
|
{"path": "input3", "type": "bool"},
|
||||||
|
{"path": "pullup", "type": "float", "readonly": false, "cmd": "hemot pullup"},
|
||||||
|
{"path": "nopumpfeedback", "type": "bool", "readonly": false, "cmd": "hemot nopumpfeedback"},
|
||||||
|
{"path": "eeprom", "type": "enum", "enum": {"ok": 0, "dirty": 1, "save": 2, "load": 3}, "readonly": false, "cmd": "hemot eeprom"},
|
||||||
|
{"path": "customadr", "type": "text", "readonly": false, "cmd": "hemot customadr"},
|
||||||
|
{"path": "custompar", "type": "float", "readonly": false, "cmd": "hemot custompar"}]},
|
||||||
|
|
||||||
|
"nvflow": {"base": "/nvflow", "params": [
|
||||||
|
{"path": "", "type": "float", "kids": 7},
|
||||||
|
{"path": "send", "type": "text", "readonly": false, "cmd": "nvflow send", "visibility": 3},
|
||||||
|
{"path": "status", "type": "text", "visibility": 3},
|
||||||
|
{"path": "stddev", "type": "float"},
|
||||||
|
{"path": "nsamples", "type": "int", "readonly": false, "cmd": "nvflow nsamples"},
|
||||||
|
{"path": "offset", "type": "float", "readonly": false, "cmd": "nvflow offset"},
|
||||||
|
{"path": "scale", "type": "float", "readonly": false, "cmd": "nvflow scale"},
|
||||||
|
{"path": "save", "type": "bool", "readonly": false, "cmd": "nvflow save", "description": "unchecked: current calib is not saved. set checked: save calib"}]},
|
||||||
|
|
||||||
|
"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 ..."}]}}
|
@ -20,8 +20,8 @@ Mod('tsam',
|
|||||||
|
|
||||||
Mod('ts',
|
Mod('ts',
|
||||||
'frappy_psi.parmod.Converging',
|
'frappy_psi.parmod.Converging',
|
||||||
'virtual stick T',
|
'stick T (controlled)',
|
||||||
meaning=['temperature', 30],
|
meaning=['temperature', 25],
|
||||||
unit='K',
|
unit='K',
|
||||||
read='tsam.value',
|
read='tsam.value',
|
||||||
write='tsam.setsamp',
|
write='tsam.setsamp',
|
||||||
|
@ -16,7 +16,7 @@ Mod('ts',
|
|||||||
json_file='ma6.config.json',
|
json_file='ma6.config.json',
|
||||||
sea_object='tt',
|
sea_object='tt',
|
||||||
rel_paths=['ts', 'setsamp'],
|
rel_paths=['ts', 'setsamp'],
|
||||||
meaning=['temperature', 20],
|
meaning=['temperature', 30],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -24,11 +24,10 @@ Mod('ts',
|
|||||||
Mod('ts',
|
Mod('ts',
|
||||||
'frappy_psi.parmod.Converging',
|
'frappy_psi.parmod.Converging',
|
||||||
'drivable stick T using setsamp',
|
'drivable stick T using setsamp',
|
||||||
meaning=['temperature', 30],
|
meaning=['temperature', 25],
|
||||||
unit='K',
|
unit='K',
|
||||||
read='tsam.value',
|
read='tsam.value',
|
||||||
write='tsam.setsamp',
|
write='tsam.setsamp',
|
||||||
meaning=['temperature', 20],
|
|
||||||
settling_time=20,
|
settling_time=20,
|
||||||
tolerance=1,
|
tolerance=1,
|
||||||
)
|
)
|
||||||
|
@ -13,8 +13,6 @@ Mod('ts',
|
|||||||
'frappy_psi.sea.SeaReadable', '',
|
'frappy_psi.sea.SeaReadable', '',
|
||||||
meaning=['temperature', 30],
|
meaning=['temperature', 30],
|
||||||
io='sea_stick',
|
io='sea_stick',
|
||||||
sea_object='tt',
|
sea_path='tt/ts',
|
||||||
json_file='ma7.config.json',
|
json_file='ma7.config.json',
|
||||||
rel_paths=['ts'],
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
75
debian/changelog
vendored
75
debian/changelog
vendored
@ -1,3 +1,78 @@
|
|||||||
|
frappy-core (0.20.4) jammy; urgency=medium
|
||||||
|
|
||||||
|
[ Georg Brandl ]
|
||||||
|
* remove unused file
|
||||||
|
|
||||||
|
[ Markus Zolliker ]
|
||||||
|
* frappy.lib.multievent: avoid deadlock
|
||||||
|
|
||||||
|
[ Jens Krüger ]
|
||||||
|
* PSI: Fix import error on ThermoFisher module
|
||||||
|
|
||||||
|
[ Markus Zolliker ]
|
||||||
|
* frappy.client: catch all errors in handleError callback
|
||||||
|
|
||||||
|
[ Jens Krüger ]
|
||||||
|
* Lib/config: Create a list of pathes only for confdir
|
||||||
|
|
||||||
|
-- Georg Brandl <jenkins@frm2.tum.de> Thu, 14 Nov 2024 14:43:54 +0100
|
||||||
|
|
||||||
|
frappy-core (0.20.3) jammy; urgency=medium
|
||||||
|
|
||||||
|
[ Georg Brandl ]
|
||||||
|
* fixup test for cfg_editor utils to run from non-checkout, and fix names, and remove example code
|
||||||
|
|
||||||
|
[ Alexander Zaft ]
|
||||||
|
* add generalConfig to etc
|
||||||
|
|
||||||
|
-- Georg Brandl <jenkins@frm2.tum.de> Thu, 07 Nov 2024 10:57:11 +0100
|
||||||
|
|
||||||
|
frappy-core (0.20.2) jammy; urgency=medium
|
||||||
|
|
||||||
|
[ Georg Brandl ]
|
||||||
|
* pylint: do not try to infer too much
|
||||||
|
|
||||||
|
[ Alexander Zaft ]
|
||||||
|
* test_server: basic description checks
|
||||||
|
* simulation: fix extra_params default, ccidu1 cfg
|
||||||
|
* sim: make amagnet sim cfg startable again
|
||||||
|
* server: fix positional argument lint
|
||||||
|
* server: show interfaces as custom property
|
||||||
|
* core: fix Dispatcher and SECNode opts handling
|
||||||
|
|
||||||
|
[ Markus Zolliker ]
|
||||||
|
* frappy_psi.sea: bugfix: revert change of updateEvent to udpateItem
|
||||||
|
* fix playground
|
||||||
|
|
||||||
|
[ Alexander Zaft ]
|
||||||
|
* config: allow using Prop(...)
|
||||||
|
* config: fix typo
|
||||||
|
* Revert "config: allow using Prop(...)"
|
||||||
|
* generalconfig: streamlined config discovery
|
||||||
|
|
||||||
|
[ Markus Zolliker ]
|
||||||
|
* better order of accessibles: 'value' 'status' and 'target' first
|
||||||
|
|
||||||
|
[ Alexander Zaft ]
|
||||||
|
* server: fix windows ctrl-c
|
||||||
|
|
||||||
|
[ Georg Brandl ]
|
||||||
|
* systemd: enable indication of reloading/stopping
|
||||||
|
|
||||||
|
[ Alexander Zaft ]
|
||||||
|
* server: service discovery over UDP.
|
||||||
|
|
||||||
|
[ Markus Zolliker ]
|
||||||
|
* generalConfig: fix the case when confdir is a list of paths
|
||||||
|
|
||||||
|
[ Georg Brandl ]
|
||||||
|
* server: better handling of cfgfile argument
|
||||||
|
|
||||||
|
[ Alexander Zaft ]
|
||||||
|
* fix frappy-server cfgfiles command
|
||||||
|
|
||||||
|
-- Georg Brandl <jenkins@frm2.tum.de> Wed, 06 Nov 2024 10:40:26 +0100
|
||||||
|
|
||||||
frappy-core (0.20.1) jammy; urgency=medium
|
frappy-core (0.20.1) jammy; urgency=medium
|
||||||
|
|
||||||
* gui: do not add a console logger when there is no sys.stdout
|
* gui: do not add a console logger when there is no sys.stdout
|
||||||
|
2
debian/frappy-core.install
vendored
2
debian/frappy-core.install
vendored
@ -1,6 +1,7 @@
|
|||||||
usr/bin/frappy-cli
|
usr/bin/frappy-cli
|
||||||
usr/bin/frappy-server
|
usr/bin/frappy-server
|
||||||
usr/bin/frappy-play
|
usr/bin/frappy-play
|
||||||
|
usr/bin/frappy-scan
|
||||||
usr/lib/python3.*/dist-packages/frappy/*.py
|
usr/lib/python3.*/dist-packages/frappy/*.py
|
||||||
usr/lib/python3.*/dist-packages/frappy/__pycache__
|
usr/lib/python3.*/dist-packages/frappy/__pycache__
|
||||||
usr/lib/python3.*/dist-packages/frappy/lib
|
usr/lib/python3.*/dist-packages/frappy/lib
|
||||||
@ -11,3 +12,4 @@ usr/lib/python3.*/dist-packages/frappy/RELEASE-VERSION
|
|||||||
usr/lib/python3.*/dist-packages/frappy_demo
|
usr/lib/python3.*/dist-packages/frappy_demo
|
||||||
lib/systemd
|
lib/systemd
|
||||||
var/log/frappy
|
var/log/frappy
|
||||||
|
etc/frappy/generalConfig.cfg
|
||||||
|
1
debian/rules
vendored
1
debian/rules
vendored
@ -11,6 +11,7 @@ override_dh_install:
|
|||||||
rmdir debian/tmp
|
rmdir debian/tmp
|
||||||
mv debian/python3-frappy 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_install -i -O--buildsystem=pybuild
|
||||||
dh_missing --fail-missing
|
dh_missing --fail-missing
|
||||||
|
|
||||||
|
4
etc/generalConfig.cfg
Normal file
4
etc/generalConfig.cfg
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
[FRAPPY]
|
||||||
|
logdir = /var/log
|
||||||
|
piddir = /var/run/frappy
|
||||||
|
confdir = /etc/frappy
|
@ -22,8 +22,6 @@
|
|||||||
# *****************************************************************************
|
# *****************************************************************************
|
||||||
"""general SECoP client"""
|
"""general SECoP client"""
|
||||||
|
|
||||||
# pylint: disable=too-many-positional-arguments
|
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import queue
|
import queue
|
||||||
import re
|
import re
|
||||||
@ -481,7 +479,10 @@ class SecopClient(ProxyClient):
|
|||||||
continue
|
continue
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
e.args = (f'error handling SECoP message {reply!r}: {e}',)
|
e.args = (f'error handling SECoP message {reply!r}: {e}',)
|
||||||
|
try:
|
||||||
self.callback(None, 'handleError', e)
|
self.callback(None, 'handleError', e)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
continue
|
continue
|
||||||
try:
|
try:
|
||||||
key = action, ident
|
key = action, ident
|
||||||
|
@ -56,10 +56,12 @@ class Param(dict):
|
|||||||
kwds['value'] = value
|
kwds['value'] = value
|
||||||
super().__init__(**kwds)
|
super().__init__(**kwds)
|
||||||
|
|
||||||
|
|
||||||
class Group(tuple):
|
class Group(tuple):
|
||||||
def __new__(cls, *args):
|
def __new__(cls, *args):
|
||||||
return super().__new__(cls, args)
|
return super().__new__(cls, args)
|
||||||
|
|
||||||
|
|
||||||
class Mod(dict):
|
class Mod(dict):
|
||||||
def __init__(self, name, cls, description, **kwds):
|
def __init__(self, name, cls, description, **kwds):
|
||||||
super().__init__(
|
super().__init__(
|
||||||
@ -70,7 +72,8 @@ class Mod(dict):
|
|||||||
|
|
||||||
# matches name from spec
|
# matches name from spec
|
||||||
if not re.match(r'^[a-zA-Z]\w{0,62}$', name, re.ASCII):
|
if not re.match(r'^[a-zA-Z]\w{0,62}$', name, re.ASCII):
|
||||||
raise ConfigError(f'Not a valid SECoP Module name: "{name}". Does it only contain letters, numbers and underscores?')
|
raise ConfigError(f'Not a valid SECoP Module name: "{name}".'
|
||||||
|
' Does it only contain letters, numbers and underscores?')
|
||||||
# Make parameters out of all keywords
|
# Make parameters out of all keywords
|
||||||
groups = {}
|
groups = {}
|
||||||
for key, val in kwds.items():
|
for key, val in kwds.items():
|
||||||
@ -85,6 +88,7 @@ class Mod(dict):
|
|||||||
for member in members:
|
for member in members:
|
||||||
self[member]['group'] = group
|
self[member]['group'] = group
|
||||||
|
|
||||||
|
|
||||||
class Collector:
|
class Collector:
|
||||||
def __init__(self, cls):
|
def __init__(self, cls):
|
||||||
self.list = []
|
self.list = []
|
||||||
@ -120,12 +124,14 @@ class Config(dict):
|
|||||||
def merge_modules(self, other):
|
def merge_modules(self, other):
|
||||||
""" merges only the modules from 'other' into 'self'"""
|
""" merges only the modules from 'other' into 'self'"""
|
||||||
self.ambiguous |= self.module_names & other.module_names
|
self.ambiguous |= self.module_names & other.module_names
|
||||||
|
equipment_id = other['node']['equipment_id']
|
||||||
for name, mod in other.items():
|
for name, mod in other.items():
|
||||||
if name == 'node':
|
if name == 'node':
|
||||||
continue
|
continue
|
||||||
if name not in self.module_names:
|
if name not in self.module_names:
|
||||||
self.module_names.add(name)
|
self.module_names.add(name)
|
||||||
self[name] = mod
|
self[name] = mod
|
||||||
|
mod['original_id'] = equipment_id
|
||||||
|
|
||||||
|
|
||||||
def process_file(filename, log):
|
def process_file(filename, log):
|
||||||
@ -172,8 +178,8 @@ def load_config(cfgfiles, log):
|
|||||||
Only the node-section of the first config file will be returned.
|
Only the node-section of the first config file will be returned.
|
||||||
The others will be discarded.
|
The others will be discarded.
|
||||||
Arguments
|
Arguments
|
||||||
- cfgfiles : str
|
- cfgfiles : list
|
||||||
Comma separated list of config-files
|
List of config file paths
|
||||||
- log : frappy.logging.Mainlogger
|
- log : frappy.logging.Mainlogger
|
||||||
Logger aquired from frappy.logging
|
Logger aquired from frappy.logging
|
||||||
Returns
|
Returns
|
||||||
@ -181,8 +187,8 @@ def load_config(cfgfiles, log):
|
|||||||
merged configuration
|
merged configuration
|
||||||
"""
|
"""
|
||||||
config = None
|
config = None
|
||||||
for cfgfile in cfgfiles.split(','):
|
for cfgfile in cfgfiles:
|
||||||
filename = to_config_path(cfgfile, log)
|
filename = to_config_path(str(cfgfile), log)
|
||||||
log.debug('Parsing config file %s...', filename)
|
log.debug('Parsing config file %s...', filename)
|
||||||
cfg = process_file(filename, log)
|
cfg = process_file(filename, log)
|
||||||
if config:
|
if config:
|
||||||
|
@ -218,8 +218,9 @@ def write_config(file_name, tree_widget):
|
|||||||
with open(file_name, 'w', encoding='utf-8') as configfile:
|
with open(file_name, 'w', encoding='utf-8') as configfile:
|
||||||
configfile.write('\n'.join(lines))
|
configfile.write('\n'.join(lines))
|
||||||
|
|
||||||
|
|
||||||
def read_config(file_path, log):
|
def read_config(file_path, log):
|
||||||
config = load_config(file_path, log)
|
config = load_config([file_path], log)
|
||||||
node = TreeWidgetItem(NODE)
|
node = TreeWidgetItem(NODE)
|
||||||
ifs = TreeWidgetItem(name='Interfaces')
|
ifs = TreeWidgetItem(name='Interfaces')
|
||||||
mods = TreeWidgetItem(name='Modules')
|
mods = TreeWidgetItem(name='Modules')
|
||||||
|
@ -106,6 +106,7 @@ def get_file_paths(widget, open_file=True):
|
|||||||
|
|
||||||
def get_modules():
|
def get_modules():
|
||||||
modules = {}
|
modules = {}
|
||||||
|
if not generalConfig.initialized:
|
||||||
generalConfig.init()
|
generalConfig.init()
|
||||||
base_path = generalConfig.basedir
|
base_path = generalConfig.basedir
|
||||||
# pylint: disable=too-many-nested-blocks
|
# pylint: disable=too-many-nested-blocks
|
||||||
@ -157,6 +158,7 @@ def get_interface_class_from_name(name):
|
|||||||
def get_interfaces():
|
def get_interfaces():
|
||||||
# TODO class must be found out like for modules
|
# TODO class must be found out like for modules
|
||||||
interfaces = []
|
interfaces = []
|
||||||
|
if not generalConfig.initialized:
|
||||||
generalConfig.init()
|
generalConfig.init()
|
||||||
interface_path = path.join(generalConfig.basedir, 'frappy',
|
interface_path = path.join(generalConfig.basedir, 'frappy',
|
||||||
'protocol', 'interface')
|
'protocol', 'interface')
|
||||||
|
@ -57,11 +57,12 @@ class GeneralConfig:
|
|||||||
|
|
||||||
:param configfile: if present, keys and values from the [FRAPPY] section are read
|
:param configfile: if present, keys and values from the [FRAPPY] section are read
|
||||||
|
|
||||||
default values for 'piddir', 'logdir' and 'confdir' are guessed from the
|
The following locations are searched for the generalConfig.cfg file.
|
||||||
location of this source file and from sys.executable.
|
- command line argument
|
||||||
|
- environment variable FRAPPY_CONFIG_FILE
|
||||||
if configfile is not given, the general config file is determined by
|
- git location (../cfg)
|
||||||
the env. variable FRAPPY_CONFIG_FILE or <confdir>/generalConfig.cfg is used
|
- local location (cwd)
|
||||||
|
- global location (/etc/frappy)
|
||||||
|
|
||||||
if a configfile is given, the values from the FRAPPY section are
|
if a configfile is given, the values from the FRAPPY section are
|
||||||
overriding above defaults
|
overriding above defaults
|
||||||
@ -69,37 +70,12 @@ class GeneralConfig:
|
|||||||
finally, the env. variables FRAPPY_PIDDIR, FRAPPY_LOGDIR and FRAPPY_CONFDIR
|
finally, the env. variables FRAPPY_PIDDIR, FRAPPY_LOGDIR and FRAPPY_CONFDIR
|
||||||
are overriding these values when given
|
are overriding these values when given
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
configfile = self._get_file_location(configfile)
|
||||||
|
|
||||||
cfg = {}
|
cfg = {}
|
||||||
mandatory = 'piddir', 'logdir', 'confdir'
|
mandatory = 'piddir', 'logdir', 'confdir'
|
||||||
repodir = Path(__file__).parents[2].expanduser().resolve()
|
repodir = Path(__file__).parents[2].expanduser().resolve()
|
||||||
# create default paths
|
|
||||||
if (Path(sys.executable).suffix == ".exe"
|
|
||||||
and not Path(sys.executable).name.startswith('python')):
|
|
||||||
# special MS windows environment
|
|
||||||
confdir = Path('./')
|
|
||||||
self.update_defaults(piddir=Path('./'), logdir=Path('./log'))
|
|
||||||
elif path.exists(path.join(repodir, 'cfg')):
|
|
||||||
# running from git repo
|
|
||||||
confdir = repodir / 'cfg'
|
|
||||||
# take logdir and piddir from <repodir>/cfg/generalConfig.cfg
|
|
||||||
else:
|
|
||||||
# running on installed system (typically with systemd)
|
|
||||||
self.update_defaults(
|
|
||||||
piddir=Path('/var/run/frappy'),
|
|
||||||
logdir=Path('/var/log'),
|
|
||||||
)
|
|
||||||
confdir = Path('/etc/frappy')
|
|
||||||
self.set_default('confdir', confdir)
|
|
||||||
if configfile is None:
|
|
||||||
configfile = environ.get('FRAPPY_CONFIG_FILE')
|
|
||||||
if configfile:
|
|
||||||
configfile = Path(configfile).expanduser()
|
|
||||||
if not configfile.exists():
|
|
||||||
raise FileNotFoundError(configfile)
|
|
||||||
else:
|
|
||||||
configfile = confdir / 'generalConfig.cfg'
|
|
||||||
if not configfile.exists():
|
|
||||||
configfile = None
|
|
||||||
if configfile:
|
if configfile:
|
||||||
parser = ConfigParser()
|
parser = ConfigParser()
|
||||||
parser.optionxform = str
|
parser.optionxform = str
|
||||||
@ -113,28 +89,63 @@ class GeneralConfig:
|
|||||||
cfg[key] = ':'.join(path.expanduser(v) for v in value.split(':'))
|
cfg[key] = ':'.join(path.expanduser(v) for v in value.split(':'))
|
||||||
if cfg.get('confdir') is None:
|
if cfg.get('confdir') is None:
|
||||||
cfg['confdir'] = configfile.parent
|
cfg['confdir'] = configfile.parent
|
||||||
|
# environment variables will overwrite the config file
|
||||||
|
missing_keys = []
|
||||||
for key in mandatory:
|
for key in mandatory:
|
||||||
env = environ.get(f'FRAPPY_{key.upper()}')
|
env = environ.get(f'FRAPPY_{key.upper()}') or cfg.get(key)
|
||||||
if env is not None:
|
if env is None:
|
||||||
if ':' in env:
|
if self.defaults.get(key) is None:
|
||||||
cfg[key] = [Path(v) for v in env.split(':')]
|
missing_keys.append(key)
|
||||||
else:
|
else:
|
||||||
cfg[key] = Path(env)
|
if not isinstance(env, Path):
|
||||||
missing_keys = [
|
if key == 'confdir':
|
||||||
key for key in mandatory
|
env = [Path(v) for v in env.split(':')]
|
||||||
if cfg.get(key) is None and self.defaults.get(key) is None
|
else:
|
||||||
]
|
env = Path(env)
|
||||||
|
cfg[key] = env
|
||||||
if missing_keys:
|
if missing_keys:
|
||||||
if configfile:
|
if configfile:
|
||||||
raise KeyError(f"missing value for {' and '.join(missing_keys)} in {configfile}")
|
raise KeyError(f"missing value for {' and '.join(missing_keys)} in {configfile}")
|
||||||
raise KeyError('missing %s'
|
|
||||||
% ' and '.join('FRAPPY_%s' % k.upper() for k in missing_keys))
|
if len(missing_keys) < 3:
|
||||||
|
# user specified at least one env variable already
|
||||||
|
missing = ' (missing %s)' % ', '.join('FRAPPY_%s' % k.upper() for k in missing_keys)
|
||||||
|
else:
|
||||||
|
missing = ''
|
||||||
|
raise FileNotFoundError(
|
||||||
|
'Could not determine config file location for the general frappy config. '
|
||||||
|
f'Provide a config file or all required environment variables{missing}. '
|
||||||
|
'For more information, see frappy-server --help.'
|
||||||
|
)
|
||||||
if 'confdir' in cfg and isinstance(cfg['confdir'], Path):
|
if 'confdir' in cfg and isinstance(cfg['confdir'], Path):
|
||||||
cfg['confdir'] = [cfg['confdir']]
|
cfg['confdir'] = [cfg['confdir']]
|
||||||
# this is not customizable
|
# this is not customizable
|
||||||
cfg['basedir'] = repodir
|
cfg['basedir'] = repodir
|
||||||
self._config = cfg
|
self._config = cfg
|
||||||
|
|
||||||
|
def _get_file_location(self, configfile):
|
||||||
|
"""Determining the defaultConfig.cfg location as documented in init()"""
|
||||||
|
# given as command line arg
|
||||||
|
if configfile and Path(configfile).exists():
|
||||||
|
return configfile
|
||||||
|
# if not given as argument, check different sources
|
||||||
|
# env variable
|
||||||
|
fromenv = environ.get('FRAPPY_CONFIG_FILE')
|
||||||
|
if fromenv and Path(fromenv).exists():
|
||||||
|
return fromenv
|
||||||
|
# from ../cfg (there if running from checkout)
|
||||||
|
repodir = Path(__file__).parents[2].expanduser().resolve()
|
||||||
|
if (repodir / 'cfg' / 'generalConfig.cfg').exists():
|
||||||
|
return repodir / 'cfg' / 'generalConfig.cfg'
|
||||||
|
localfile = Path.cwd() / 'generalConfig.cfg'
|
||||||
|
if localfile.exists():
|
||||||
|
return localfile
|
||||||
|
# TODO: leave this hardcoded?
|
||||||
|
globalfile = Path('/etc/frappy/generalConfig.cfg')
|
||||||
|
if globalfile.exists():
|
||||||
|
return globalfile
|
||||||
|
return None
|
||||||
|
|
||||||
def __getitem__(self, key):
|
def __getitem__(self, key):
|
||||||
"""access for keys known to exist
|
"""access for keys known to exist
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ class MultiEvent(threading.Event):
|
|||||||
|
|
||||||
def __init__(self, default_timeout=None):
|
def __init__(self, default_timeout=None):
|
||||||
self.events = set()
|
self.events = set()
|
||||||
self._lock = threading.Lock()
|
self._lock = threading.RLock()
|
||||||
self.default_timeout = default_timeout or None # treat 0 as None
|
self.default_timeout = default_timeout or None # treat 0 as None
|
||||||
self.name = None # default event name
|
self.name = None # default event name
|
||||||
self._actions = [] # actions to be executed on trigger
|
self._actions = [] # actions to be executed on trigger
|
||||||
|
@ -33,7 +33,7 @@ from frappy.datatypes import ArrayOf, BoolType, EnumType, FloatRange, \
|
|||||||
from frappy.errors import BadValueError, CommunicationFailedError, ConfigError, \
|
from frappy.errors import BadValueError, CommunicationFailedError, ConfigError, \
|
||||||
ProgrammingError, SECoPError, secop_error, RangeError
|
ProgrammingError, SECoPError, secop_error, RangeError
|
||||||
from frappy.lib import formatException, mkthread, UniqueObject
|
from frappy.lib import formatException, mkthread, UniqueObject
|
||||||
from frappy.params import Accessible, Command, Parameter, Limit
|
from frappy.params import Accessible, Command, Parameter, Limit, PREDEFINED_ACCESSIBLES
|
||||||
from frappy.properties import HasProperties, Property
|
from frappy.properties import HasProperties, Property
|
||||||
from frappy.logging import RemoteLogHandler
|
from frappy.logging import RemoteLogHandler
|
||||||
|
|
||||||
@ -41,6 +41,7 @@ from frappy.logging import RemoteLogHandler
|
|||||||
# from .interfaces import SECoP_BASE_CLASSES
|
# from .interfaces import SECoP_BASE_CLASSES
|
||||||
# WORKAROUND:
|
# WORKAROUND:
|
||||||
SECoP_BASE_CLASSES = ['Readable', 'Writable', 'Drivable', 'Communicator']
|
SECoP_BASE_CLASSES = ['Readable', 'Writable', 'Drivable', 'Communicator']
|
||||||
|
PREDEF_ORDER = list(PREDEFINED_ACCESSIBLES)
|
||||||
|
|
||||||
Done = UniqueObject('Done')
|
Done = UniqueObject('Done')
|
||||||
"""a special return value for a read_<param>/write_<param> method
|
"""a special return value for a read_<param>/write_<param> method
|
||||||
@ -77,7 +78,7 @@ class HasAccessibles(HasProperties):
|
|||||||
for key, value in base.__dict__.items():
|
for key, value in base.__dict__.items():
|
||||||
if isinstance(value, Accessible):
|
if isinstance(value, Accessible):
|
||||||
value.updateProperties(merged_properties.setdefault(key, {}))
|
value.updateProperties(merged_properties.setdefault(key, {}))
|
||||||
if base == cls and key not in accessibles:
|
if base == cls and key not in accessibles and key not in PREDEFINED_ACCESSIBLES:
|
||||||
new_names.append(key)
|
new_names.append(key)
|
||||||
accessibles[key] = value
|
accessibles[key] = value
|
||||||
override_values.pop(key, None)
|
override_values.pop(key, None)
|
||||||
@ -97,16 +98,14 @@ class HasAccessibles(HasProperties):
|
|||||||
aobj.merge(merged_properties[aname])
|
aobj.merge(merged_properties[aname])
|
||||||
accessibles[aname] = aobj
|
accessibles[aname] = aobj
|
||||||
|
|
||||||
# rebuild order: (1) inherited items, (2) items from paramOrder, (3) new accessibles
|
# rebuild order:
|
||||||
# move (2) to the end
|
# (1) predefined accessibles, in a predefined order, (2) inherited custom items, (3) new custom items
|
||||||
paramOrder = cls.__dict__.get('paramOrder', ())
|
# move (1) to the beginning
|
||||||
for aname in paramOrder:
|
for key in reversed(PREDEF_ORDER):
|
||||||
if aname in accessibles:
|
if key in accessibles:
|
||||||
accessibles.move_to_end(aname)
|
accessibles.move_to_end(key, last=False)
|
||||||
# ignore unknown names
|
|
||||||
# move (3) to the end
|
# move (3) to the end
|
||||||
for aname in new_names:
|
for aname in new_names:
|
||||||
if aname not in paramOrder:
|
|
||||||
accessibles.move_to_end(aname)
|
accessibles.move_to_end(aname)
|
||||||
cls.accessibles = accessibles
|
cls.accessibles = accessibles
|
||||||
|
|
||||||
@ -189,10 +188,8 @@ class HasAccessibles(HasProperties):
|
|||||||
if new_value is Done: # TODO: to be removed when all code using Done is updated
|
if new_value is Done: # TODO: to be removed when all code using Done is updated
|
||||||
return getattr(self, pname)
|
return getattr(self, pname)
|
||||||
new_value = value if new_value is None else validate(new_value)
|
new_value = value if new_value is None else validate(new_value)
|
||||||
except Exception as e:
|
except SECoPError as e:
|
||||||
if isinstance(e, SECoPError):
|
|
||||||
e.raising_methods.append(f'{self.name}.write_{pname}')
|
e.raising_methods.append(f'{self.name}.write_{pname}')
|
||||||
self.announceUpdate(pname, err=e)
|
|
||||||
raise
|
raise
|
||||||
self.announceUpdate(pname, new_value, validate=False)
|
self.announceUpdate(pname, new_value, validate=False)
|
||||||
return new_value
|
return new_value
|
||||||
@ -322,6 +319,8 @@ class Module(HasAccessibles):
|
|||||||
slowinterval = Property('poll interval for other parameters', FloatRange(0.1, 120), default=15)
|
slowinterval = Property('poll interval for other parameters', FloatRange(0.1, 120), default=15)
|
||||||
omit_unchanged_within = Property('default for minimum time between updates of unchanged values',
|
omit_unchanged_within = Property('default for minimum time between updates of unchanged values',
|
||||||
NoneOr(FloatRange(0)), export=False, default=None)
|
NoneOr(FloatRange(0)), export=False, default=None)
|
||||||
|
original_id = Property('original equipment_id\n\ngiven only if different from equipment_id of node',
|
||||||
|
NoneOr(StringType()), default=None, export=True) # exported as custom property _original_id
|
||||||
enablePoll = True
|
enablePoll = True
|
||||||
|
|
||||||
pollInfo = None
|
pollInfo = None
|
||||||
@ -517,13 +516,13 @@ class Module(HasAccessibles):
|
|||||||
with self.updateLock:
|
with self.updateLock:
|
||||||
pobj = self.parameters[pname]
|
pobj = self.parameters[pname]
|
||||||
timestamp = timestamp or time.time()
|
timestamp = timestamp or time.time()
|
||||||
|
changed = False
|
||||||
if not err:
|
if not err:
|
||||||
try:
|
try:
|
||||||
if validate:
|
if validate:
|
||||||
value = pobj.datatype(value)
|
value = pobj.datatype(value)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
err = e
|
err = e
|
||||||
changed = False
|
|
||||||
else:
|
else:
|
||||||
changed = pobj.value != value or pobj.readerror
|
changed = pobj.value != value or pobj.readerror
|
||||||
# store the value even in case of error
|
# store the value even in case of error
|
||||||
|
@ -259,8 +259,16 @@ class Parameter(Accessible):
|
|||||||
merged_properties.update(self.ownProperties)
|
merged_properties.update(self.ownProperties)
|
||||||
|
|
||||||
def create_from_value(self, properties, value):
|
def create_from_value(self, properties, value):
|
||||||
"""return a clone with given value and inherited properties"""
|
"""return a clone with given value and inherited properties
|
||||||
return self.clone(properties, value=self.datatype(value))
|
|
||||||
|
called when a Parameter is overridden with a bare value
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
value = self.datatype(value)
|
||||||
|
except Exception as e:
|
||||||
|
raise ProgrammingError(f'{self.name} must be assigned to a Parameter '
|
||||||
|
f'or a value compatible with {type(self.datatype).__name__}') from e
|
||||||
|
return self.clone(properties, value=value)
|
||||||
|
|
||||||
def merge(self, merged_properties):
|
def merge(self, merged_properties):
|
||||||
"""merge with inherited properties
|
"""merge with inherited properties
|
||||||
@ -462,7 +470,8 @@ class Command(Accessible):
|
|||||||
def create_from_value(self, properties, value):
|
def create_from_value(self, properties, value):
|
||||||
"""return a clone with given value and inherited properties
|
"""return a clone with given value and inherited properties
|
||||||
|
|
||||||
this is needed when the @Command is missing on a method overriding a command"""
|
called when the @Command is missing on a method overriding a command
|
||||||
|
"""
|
||||||
if not callable(value):
|
if not callable(value):
|
||||||
raise ProgrammingError(f'{self.name} = {value!r} is overriding a Command')
|
raise ProgrammingError(f'{self.name} = {value!r} is overriding a Command')
|
||||||
return self.clone(properties)(value)
|
return self.clone(properties)(value)
|
||||||
@ -564,15 +573,18 @@ class Limit(Parameter):
|
|||||||
|
|
||||||
|
|
||||||
# list of predefined accessibles with their type
|
# list of predefined accessibles with their type
|
||||||
|
# the order of this list affects the parameter order
|
||||||
PREDEFINED_ACCESSIBLES = {
|
PREDEFINED_ACCESSIBLES = {
|
||||||
'value': Parameter,
|
'value': Parameter,
|
||||||
'status': Parameter,
|
'status': Parameter,
|
||||||
'target': Parameter,
|
'target': Parameter,
|
||||||
'pollinterval': Parameter,
|
'pollinterval': Parameter,
|
||||||
'ramp': Parameter,
|
'ramp': Parameter,
|
||||||
'user_ramp': Parameter,
|
'use_ramp': Parameter,
|
||||||
'setpoint': Parameter,
|
'setpoint': Parameter,
|
||||||
'time_to_target': Parameter,
|
'time_to_target': Parameter,
|
||||||
|
'controlled_by': Parameter,
|
||||||
|
'control_active': Parameter,
|
||||||
'unit': Parameter, # reserved name
|
'unit': Parameter, # reserved name
|
||||||
'loglevel': Parameter, # reserved name
|
'loglevel': Parameter, # reserved name
|
||||||
'mode': Parameter, # reserved name
|
'mode': Parameter, # reserved name
|
||||||
|
@ -97,7 +97,9 @@ class Playground(Server):
|
|||||||
for modname, cfg in kwds.items():
|
for modname, cfg in kwds.items():
|
||||||
cfg.setdefault('description', modname)
|
cfg.setdefault('description', modname)
|
||||||
self.log = logger.log
|
self.log = logger.log
|
||||||
self.node_cfg = {'cls': 'frappy.playground.Dispatcher', 'name': 'playground'}
|
self.node_cfg = {'cls': 'frappy.playground.Dispatcher',
|
||||||
|
'name': 'playground',
|
||||||
|
'description': 'playground'}
|
||||||
self._testonly = True # stops before calling startModule
|
self._testonly = True # stops before calling startModule
|
||||||
self._cfgfiles = 'main'
|
self._cfgfiles = 'main'
|
||||||
self.module_cfg = {}
|
self.module_cfg = {}
|
||||||
@ -106,6 +108,7 @@ class Playground(Server):
|
|||||||
if cfgfiles:
|
if cfgfiles:
|
||||||
if not generalConfig.initialized:
|
if not generalConfig.initialized:
|
||||||
generalConfig.init()
|
generalConfig.init()
|
||||||
|
cfgfiles = [s.strip() for s in cfgfiles.split(',')]
|
||||||
merged_cfg = load_config(cfgfiles, self.log)
|
merged_cfg = load_config(cfgfiles, self.log)
|
||||||
merged_cfg.pop('node', None)
|
merged_cfg.pop('node', None)
|
||||||
self.module_cfg = merged_cfg
|
self.module_cfg = merged_cfg
|
||||||
|
@ -143,6 +143,7 @@ class HasProperties(HasDescriptors):
|
|||||||
try:
|
try:
|
||||||
# try to apply bare value to Property
|
# try to apply bare value to Property
|
||||||
po.value = po.datatype.validate(value)
|
po.value = po.datatype.validate(value)
|
||||||
|
setattr(cls, pn, po) # replace bare value by updated Property
|
||||||
except BadValueError:
|
except BadValueError:
|
||||||
if callable(value):
|
if callable(value):
|
||||||
raise ProgrammingError(f'method {cls.__name__}.{pn} collides with property of {base.__name__}') from None
|
raise ProgrammingError(f'method {cls.__name__}.{pn} collides with property of {base.__name__}') from None
|
||||||
|
108
frappy/protocol/discovery.py
Normal file
108
frappy/protocol/discovery.py
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
# *****************************************************************************
|
||||||
|
#
|
||||||
|
# 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>
|
||||||
|
#
|
||||||
|
# *****************************************************************************
|
||||||
|
"""Discovery via UDP broadcasts."""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import json
|
||||||
|
import socket
|
||||||
|
|
||||||
|
from frappy.lib import closeSocket
|
||||||
|
from frappy.protocol.interface.tcp import format_address
|
||||||
|
from frappy.version import get_version
|
||||||
|
|
||||||
|
UDP_PORT = 10767
|
||||||
|
MAX_MESSAGE_LEN = 508
|
||||||
|
|
||||||
|
|
||||||
|
class UDPListener:
|
||||||
|
def __init__(self, equipment_id, description, ifaces, logger, *,
|
||||||
|
startup_broadcast=True):
|
||||||
|
self.equipment_id = equipment_id
|
||||||
|
self.log = logger
|
||||||
|
self.description = description or ''
|
||||||
|
self.firmware = 'FRAPPY ' + get_version()
|
||||||
|
self.ports = [int(iface.split('://')[1])
|
||||||
|
for iface in ifaces if iface.startswith('tcp')]
|
||||||
|
self.running = False
|
||||||
|
self.is_enabled = True
|
||||||
|
self.startup_broadcast = startup_broadcast
|
||||||
|
|
||||||
|
self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||||
|
if os.name == 'nt':
|
||||||
|
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||||
|
else:
|
||||||
|
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
|
||||||
|
if startup_broadcast:
|
||||||
|
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
|
||||||
|
self.sock.bind(('0.0.0.0', UDP_PORT))
|
||||||
|
|
||||||
|
available = MAX_MESSAGE_LEN - len(self._getMessage(2**16-1))
|
||||||
|
if available < 0:
|
||||||
|
desc_length = len(self.description.encode('utf-8'))
|
||||||
|
if available + desc_length < 0:
|
||||||
|
self.log.warn('Equipment id and firmware name exceed 430 byte '
|
||||||
|
'limit, not answering to udp discovery')
|
||||||
|
self.is_enabled = False
|
||||||
|
else:
|
||||||
|
self.log.debug('truncating description for udp discovery')
|
||||||
|
# with errors='ignore', cutting insite a utf-8 glyph will not
|
||||||
|
# report an error but remove the rest of the glyph from the
|
||||||
|
# output.
|
||||||
|
self.description = self.description \
|
||||||
|
.encode('utf-8')[:available] \
|
||||||
|
.decode('utf-8', errors='ignore')
|
||||||
|
|
||||||
|
def _getMessage(self, port):
|
||||||
|
return json.dumps({
|
||||||
|
'SECoP': 'node',
|
||||||
|
'port': port,
|
||||||
|
'equipment_id': self.equipment_id,
|
||||||
|
'firmware': self.firmware,
|
||||||
|
'description': self.description,
|
||||||
|
}, ensure_ascii=False, separators=(',', ':')).encode('utf-8')
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
if self.startup_broadcast:
|
||||||
|
self.log.debug('Sending startup UDP broadcast.')
|
||||||
|
for port in self.ports:
|
||||||
|
self.sock.sendto(self._getMessage(port),
|
||||||
|
('255.255.255.255', UDP_PORT))
|
||||||
|
self.running = True
|
||||||
|
while self.running and self.is_enabled:
|
||||||
|
try:
|
||||||
|
msg, addr = self.sock.recvfrom(1024)
|
||||||
|
except socket.error:
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
request = json.loads(msg.decode('utf-8'))
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
continue
|
||||||
|
if 'SECoP' not in request or request['SECoP'] != 'discover':
|
||||||
|
continue
|
||||||
|
self.log.debug('Answering UDP broadcast from: %s',
|
||||||
|
format_address(addr))
|
||||||
|
for port in self.ports:
|
||||||
|
self.sock.sendto(self._getMessage(port), addr)
|
||||||
|
|
||||||
|
def shutdown(self):
|
||||||
|
self.log.debug('shut down of discovery listener')
|
||||||
|
self.running = False
|
||||||
|
closeSocket(self.sock)
|
@ -77,25 +77,29 @@ class SecopClient(frappy.client.SecopClient):
|
|||||||
|
|
||||||
|
|
||||||
class Router(frappy.protocol.dispatcher.Dispatcher):
|
class Router(frappy.protocol.dispatcher.Dispatcher):
|
||||||
singlenode = None
|
|
||||||
|
|
||||||
def __init__(self, name, logger, options, srv):
|
def __init__(self, name, logger, options, srv):
|
||||||
"""initialize router
|
"""initialize router
|
||||||
|
|
||||||
Use the option node = <uri> for a single node or
|
Use the option node = <uri> for a single node or
|
||||||
nodes = ["<uri1>", "<uri2>" ...] for multiple nodes.
|
nodes = ["<uri1>", "<uri2>" ...] for multiple nodes.
|
||||||
If a single node is given, the node properties are forwarded transparently,
|
If a single node is given, and no more additional modules are given,
|
||||||
|
the node properties are forwarded transparently,
|
||||||
else the description property is a merge from all client node properties.
|
else the description property is a merge from all client node properties.
|
||||||
"""
|
"""
|
||||||
uri = options.pop('node', None)
|
uri = options.pop('node', None)
|
||||||
uris = options.pop('nodes', None)
|
uris = options.pop('nodes', None)
|
||||||
if uri and uris:
|
try:
|
||||||
raise frappy.errors.ConfigError('can not specify node _and_ nodes')
|
if uris is not None:
|
||||||
super().__init__(name, logger, options, srv)
|
if isinstance(uris, str) or not all(isinstance(v, str) for v in uris) or uri:
|
||||||
if uri:
|
raise TypeError()
|
||||||
self.nodes = [SecopClient(uri, logger.getChild('routed'), self)]
|
elif isinstance(uri, str):
|
||||||
self.singlenode = self.nodes[0]
|
uris = [uri]
|
||||||
else:
|
else:
|
||||||
|
raise TypeError()
|
||||||
|
except Exception as e:
|
||||||
|
raise frappy.errors.ConfigError("a router needs either 'node' as a string'"
|
||||||
|
"' or 'nodes' as a list of strings") from e
|
||||||
|
super().__init__(name, logger, options, srv)
|
||||||
self.nodes = [SecopClient(uri, logger.getChild(f'routed{i}'), self) for i, uri in enumerate(uris)]
|
self.nodes = [SecopClient(uri, logger.getChild(f'routed{i}'), self) for i, uri in enumerate(uris)]
|
||||||
# register callbacks
|
# register callbacks
|
||||||
for node in self.nodes:
|
for node in self.nodes:
|
||||||
@ -127,8 +131,8 @@ class Router(frappy.protocol.dispatcher.Dispatcher):
|
|||||||
logger.warning('can not connect to node %r', node.nodename)
|
logger.warning('can not connect to node %r', node.nodename)
|
||||||
|
|
||||||
def handle_describe(self, conn, specifier, data):
|
def handle_describe(self, conn, specifier, data):
|
||||||
if self.singlenode:
|
if len(self.nodes) == 1 and not self.secnode.modules:
|
||||||
return DESCRIPTIONREPLY, specifier, self.singlenode.descriptive_data
|
return DESCRIPTIONREPLY, specifier, self.nodes[0].descriptive_data
|
||||||
reply = super().handle_describe(conn, specifier, data)
|
reply = super().handle_describe(conn, specifier, data)
|
||||||
result = reply[2]
|
result = reply[2]
|
||||||
allmodules = result.get('modules', {})
|
allmodules = result.get('modules', {})
|
||||||
@ -144,6 +148,7 @@ class Router(frappy.protocol.dispatcher.Dispatcher):
|
|||||||
self.log.info('module %r is already present', modname)
|
self.log.info('module %r is already present', modname)
|
||||||
else:
|
else:
|
||||||
allmodules[modname] = moddesc
|
allmodules[modname] = moddesc
|
||||||
|
moddesc.setdefault('original_id', equipment_id)
|
||||||
result['modules'] = allmodules
|
result['modules'] = allmodules
|
||||||
result['description'] = '\n\n'.join(node_description)
|
result['description'] = '\n\n'.join(node_description)
|
||||||
return DESCRIPTIONREPLY, specifier, result
|
return DESCRIPTIONREPLY, specifier, result
|
||||||
|
@ -54,8 +54,17 @@ class SecNode:
|
|||||||
self.name = name
|
self.name = name
|
||||||
|
|
||||||
def add_secnode_property(self, prop, value):
|
def add_secnode_property(self, prop, value):
|
||||||
|
"""Add SECNode property. If starting with an underscore, it is exported
|
||||||
|
in the description."""
|
||||||
self.nodeprops[prop] = value
|
self.nodeprops[prop] = value
|
||||||
|
|
||||||
|
def get_secnode_property(self, prop):
|
||||||
|
"""Get SECNode property.
|
||||||
|
|
||||||
|
Returns None if not present.
|
||||||
|
"""
|
||||||
|
return self.nodeprops.get(prop)
|
||||||
|
|
||||||
def get_module(self, modulename):
|
def get_module(self, modulename):
|
||||||
""" Returns a fully initialized module. Or None, if something went
|
""" Returns a fully initialized module. Or None, if something went
|
||||||
wrong during instatiating/initializing the module."""
|
wrong during instatiating/initializing the module."""
|
||||||
|
@ -26,6 +26,7 @@ import os
|
|||||||
import signal
|
import signal
|
||||||
import sys
|
import sys
|
||||||
import threading
|
import threading
|
||||||
|
import time
|
||||||
|
|
||||||
import mlzlog
|
import mlzlog
|
||||||
|
|
||||||
@ -36,6 +37,7 @@ from frappy.lib.multievent import MultiEvent
|
|||||||
from frappy.logging import init_remote_logging
|
from frappy.logging import init_remote_logging
|
||||||
from frappy.params import PREDEFINED_ACCESSIBLES
|
from frappy.params import PREDEFINED_ACCESSIBLES
|
||||||
from frappy.secnode import SecNode
|
from frappy.secnode import SecNode
|
||||||
|
from frappy.protocol.discovery import UDPListener
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from daemon import DaemonContext
|
from daemon import DaemonContext
|
||||||
@ -67,9 +69,9 @@ class Server:
|
|||||||
- name: the node name
|
- name: the node name
|
||||||
- parent_logger: the logger to inherit from. a handler is installed by
|
- parent_logger: the logger to inherit from. a handler is installed by
|
||||||
the server to provide remote logging
|
the server to provide remote logging
|
||||||
- cfgfiles: if not given, defaults to name
|
- cfgfiles: if not given, defaults to [name]
|
||||||
may be a comma separated list of cfg files
|
may be a list of cfg files
|
||||||
items ending with .cfg are taken as paths, else .cfg is appended and
|
items ending with .py are taken as paths, else _cfg.py is appended and
|
||||||
files are looked up in the config path retrieved from the general config
|
files are looked up in the config path retrieved from the general config
|
||||||
- interface: an uri of the from tcp://<port> or a bare port number for tcp
|
- interface: an uri of the from tcp://<port> or a bare port number for tcp
|
||||||
if not given, the interface is taken from the config file. In case of
|
if not given, the interface is taken from the config file. In case of
|
||||||
@ -93,9 +95,9 @@ class Server:
|
|||||||
self._testonly = testonly
|
self._testonly = testonly
|
||||||
|
|
||||||
if not cfgfiles:
|
if not cfgfiles:
|
||||||
cfgfiles = name
|
cfgfiles = [name]
|
||||||
# sanitize name (in case it is a cfgfile)
|
# sanitize name (in case it is a cfgfile)
|
||||||
name = os.path.splitext(os.path.basename(name))[0]
|
self.name = name = os.path.splitext(os.path.basename(name))[0]
|
||||||
if isinstance(parent_logger, mlzlog.MLZLogger):
|
if isinstance(parent_logger, mlzlog.MLZLogger):
|
||||||
self.log = parent_logger.getChild(name, True)
|
self.log = parent_logger.getChild(name, True)
|
||||||
else:
|
else:
|
||||||
@ -106,7 +108,6 @@ class Server:
|
|||||||
self.node_cfg = merged_cfg.pop('node')
|
self.node_cfg = merged_cfg.pop('node')
|
||||||
self.module_cfg = merged_cfg
|
self.module_cfg = merged_cfg
|
||||||
if interface:
|
if interface:
|
||||||
self.node_cfg['equipment_id'] = name
|
|
||||||
self.node_cfg['interface'] = str(interface)
|
self.node_cfg['interface'] = str(interface)
|
||||||
elif not self.node_cfg.get('interface'):
|
elif not self.node_cfg.get('interface'):
|
||||||
raise ConfigError('No interface specified in configuration or arguments!')
|
raise ConfigError('No interface specified in configuration or arguments!')
|
||||||
@ -116,6 +117,8 @@ class Server:
|
|||||||
signal.signal(signal.SIGINT, self.signal_handler)
|
signal.signal(signal.SIGINT, self.signal_handler)
|
||||||
signal.signal(signal.SIGTERM, self.signal_handler)
|
signal.signal(signal.SIGTERM, self.signal_handler)
|
||||||
|
|
||||||
|
self.discovery = None
|
||||||
|
|
||||||
def signal_handler(self, num, frame):
|
def signal_handler(self, num, frame):
|
||||||
if hasattr(self, 'interfaces') and self.interfaces:
|
if hasattr(self, 'interfaces') and self.interfaces:
|
||||||
self.shutdown()
|
self.shutdown()
|
||||||
@ -164,6 +167,7 @@ class Server:
|
|||||||
print(formatException(verbose=True))
|
print(formatException(verbose=True))
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
# client interfaces
|
||||||
self.interfaces = {}
|
self.interfaces = {}
|
||||||
iface_threads = []
|
iface_threads = []
|
||||||
# default_timeout 12 sec: TCPServer might need up to 10 sec to wait for Address no longer in use
|
# default_timeout 12 sec: TCPServer might need up to 10 sec to wait for Address no longer in use
|
||||||
@ -171,7 +175,9 @@ class Server:
|
|||||||
lock = threading.Lock()
|
lock = threading.Lock()
|
||||||
failed = {}
|
failed = {}
|
||||||
interfaces = [self.node_cfg['interface']] + self.node_cfg.get('secondary', [])
|
interfaces = [self.node_cfg['interface']] + self.node_cfg.get('secondary', [])
|
||||||
# TODO: check if only one interface of each type is open?
|
# allow missing "tcp://"
|
||||||
|
interfaces = [iface if '://' in iface else f'tcp://{iface}' for iface in interfaces]
|
||||||
|
with lock:
|
||||||
for interface in interfaces:
|
for interface in interfaces:
|
||||||
opts = {'uri': interface}
|
opts = {'uri': interface}
|
||||||
t = mkthread(
|
t = mkthread(
|
||||||
@ -179,6 +185,7 @@ class Server:
|
|||||||
opts,
|
opts,
|
||||||
lock,
|
lock,
|
||||||
failed,
|
failed,
|
||||||
|
interfaces,
|
||||||
interfaces_started.get_trigger(),
|
interfaces_started.get_trigger(),
|
||||||
)
|
)
|
||||||
iface_threads.append(t)
|
iface_threads.append(t)
|
||||||
@ -192,13 +199,31 @@ class Server:
|
|||||||
if not self.interfaces:
|
if not self.interfaces:
|
||||||
self.log.error('no interface started')
|
self.log.error('no interface started')
|
||||||
return
|
return
|
||||||
self.secnode.add_secnode_property('_interfaces', list(self.interfaces.keys()))
|
self.secnode.add_secnode_property('_interfaces', list(self.interfaces))
|
||||||
self.log.info('startup done with interface(s) %s' % ', '.join(self.interfaces))
|
self.log.info('startup done with interface(s) %s',
|
||||||
|
', '.join(self.interfaces))
|
||||||
|
|
||||||
|
# start discovery interface when we know where we listen
|
||||||
|
self.discovery = UDPListener(
|
||||||
|
self.secnode.equipment_id,
|
||||||
|
self.secnode.get_secnode_property('description'),
|
||||||
|
list(self.interfaces),
|
||||||
|
self.log.getChild('discovery')
|
||||||
|
)
|
||||||
|
mkthread(self.discovery.run)
|
||||||
|
|
||||||
if systemd:
|
if systemd:
|
||||||
systemd.daemon.notify("READY=1\nSTATUS=accepting requests")
|
systemd.daemon.notify("READY=1\nSTATUS=accepting requests")
|
||||||
|
|
||||||
# we wait here on the thread finishing, which means we got a
|
if os.name == 'nt':
|
||||||
# signal to shut down or an exception was raised
|
# workaround: thread.join() on Windows blocks and is not
|
||||||
|
# interruptible by the signal handler, so loop and check
|
||||||
|
# periodically whether the interfaces are still running.
|
||||||
|
while True:
|
||||||
|
time.sleep(1)
|
||||||
|
if not interfaces:
|
||||||
|
break
|
||||||
|
else:
|
||||||
for t in iface_threads:
|
for t in iface_threads:
|
||||||
t.join()
|
t.join()
|
||||||
|
|
||||||
@ -208,11 +233,11 @@ class Server:
|
|||||||
|
|
||||||
self.log.info('stopped listening, cleaning up %d modules',
|
self.log.info('stopped listening, cleaning up %d modules',
|
||||||
len(self.secnode.modules))
|
len(self.secnode.modules))
|
||||||
# if systemd:
|
if systemd:
|
||||||
# if self._restart:
|
if self._restart:
|
||||||
# systemd.daemon.notify('RELOADING=1')
|
systemd.daemon.notify('RELOADING=1')
|
||||||
# else:
|
else:
|
||||||
# systemd.daemon.notify('STOPPING=1')
|
systemd.daemon.notify('STOPPING=1')
|
||||||
self.secnode.shutdown_modules()
|
self.secnode.shutdown_modules()
|
||||||
if self._restart:
|
if self._restart:
|
||||||
self.restart_hook()
|
self.restart_hook()
|
||||||
@ -227,13 +252,14 @@ class Server:
|
|||||||
|
|
||||||
def shutdown(self):
|
def shutdown(self):
|
||||||
self._restart = False
|
self._restart = False
|
||||||
|
if self.discovery:
|
||||||
|
self.discovery.shutdown()
|
||||||
for iface in self.interfaces.values():
|
for iface in self.interfaces.values():
|
||||||
iface.shutdown()
|
iface.shutdown()
|
||||||
|
|
||||||
def _interfaceThread(self, opts, lock, failed, start_cb):
|
def _interfaceThread(self, opts, lock, failed, interfaces, start_cb):
|
||||||
iface = opts['uri']
|
iface = opts['uri']
|
||||||
scheme, _, _ = iface.rpartition('://')
|
scheme = iface.split('://')[0]
|
||||||
scheme = scheme or 'tcp'
|
|
||||||
cls = get_class(self.INTERFACES[scheme])
|
cls = get_class(self.INTERFACES[scheme])
|
||||||
try:
|
try:
|
||||||
with cls(scheme, self.log.getChild(scheme), opts, self) as interface:
|
with cls(scheme, self.log.getChild(scheme), opts, self) as interface:
|
||||||
@ -247,8 +273,11 @@ class Server:
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
with lock:
|
with lock:
|
||||||
failed[iface] = e
|
failed[iface] = e
|
||||||
start_cb()
|
interfaces.remove(iface)
|
||||||
return
|
start_cb() # callback should also be called on failure
|
||||||
|
else:
|
||||||
|
with lock:
|
||||||
|
interfaces.remove(iface)
|
||||||
self.log.info(f'stopped {iface}')
|
self.log.info(f'stopped {iface}')
|
||||||
|
|
||||||
def _processCfg(self):
|
def _processCfg(self):
|
||||||
@ -263,10 +292,8 @@ class Server:
|
|||||||
errors = []
|
errors = []
|
||||||
opts = dict(self.node_cfg)
|
opts = dict(self.node_cfg)
|
||||||
cls = get_class(opts.pop('cls'))
|
cls = get_class(opts.pop('cls'))
|
||||||
name = opts.pop('name', self._cfgfiles)
|
self.secnode = SecNode(self.name, self.log.getChild('secnode'), opts, self)
|
||||||
# TODO: opts not in both
|
self.dispatcher = cls(self.name, self.log.getChild('dispatcher'), opts, self)
|
||||||
self.secnode = SecNode(name, self.log.getChild('secnode'), opts, self)
|
|
||||||
self.dispatcher = cls(name, self.log.getChild('dispatcher'), opts, self)
|
|
||||||
|
|
||||||
# add other options as SECNode properties, those with '_' prefixed will
|
# add other options as SECNode properties, those with '_' prefixed will
|
||||||
# get exported
|
# get exported
|
||||||
|
@ -69,14 +69,16 @@ class TemperatureLoop(TemperatureSensor, Drivable):
|
|||||||
# lakeshore loop number to be used for this module
|
# lakeshore loop number to be used for this module
|
||||||
loop = Property('lakeshore loop', IntRange(1, 2), default=1)
|
loop = Property('lakeshore loop', IntRange(1, 2), default=1)
|
||||||
target = Parameter(datatype=FloatRange(unit='K', min=0, max=1500))
|
target = Parameter(datatype=FloatRange(unit='K', min=0, max=1500))
|
||||||
heater_range = Property('heater power range', IntRange(0, 5)) # max. 3 on LakeShore 336
|
heater_range = Property('heater power range', IntRange(0, 3), readonly=False)
|
||||||
tolerance = Parameter('convergence criterion', FloatRange(0), default=0.1, readonly=False)
|
tolerance = Parameter('convergence criterion', FloatRange(0), default=0.1, readonly=False)
|
||||||
_driving = False
|
_driving = False
|
||||||
|
|
||||||
|
def write_heater_range(self, value):
|
||||||
|
self.communicate(f'RANGE {self.loop},{value};RANGE?{self.loop}')
|
||||||
|
|
||||||
def write_target(self, target):
|
def write_target(self, target):
|
||||||
# reactivate heater in case it was switched off
|
# reactivate heater in case it was switched off
|
||||||
# the command has to be changed in case of model 340 to f'RANGE {self.heater_range};RANGE?'
|
self.write_heater_range(self.heater_range)
|
||||||
self.communicate(f'RANGE {self.loop},{self.heater_range};RANGE?{self.loop}')
|
|
||||||
self.communicate(f'SETP {self.loop},{target};*OPC?')
|
self.communicate(f'SETP {self.loop},{target};*OPC?')
|
||||||
self._driving = True
|
self._driving = True
|
||||||
# Setting the status attribute triggers an update message for the SECoP status
|
# Setting the status attribute triggers an update message for the SECoP status
|
||||||
@ -85,23 +87,21 @@ class TemperatureLoop(TemperatureSensor, Drivable):
|
|||||||
return target
|
return target
|
||||||
|
|
||||||
def read_status(self):
|
def read_status(self):
|
||||||
code = int(self.communicate(f'RDGST?{self.channel}'))
|
status = super().read_status()
|
||||||
if code >= 128:
|
if status[0] == ERROR:
|
||||||
text = 'units overrange'
|
return status
|
||||||
elif code >= 64:
|
if abs(self.target - self.value) > self.tolerance:
|
||||||
text = 'units zero'
|
|
||||||
elif code >= 32:
|
|
||||||
text = 'temperature overrange'
|
|
||||||
elif code >= 16:
|
|
||||||
text = 'temperature underrange'
|
|
||||||
elif code % 2:
|
|
||||||
# ignore 'old reading', as this may happen in normal operation
|
|
||||||
text = 'invalid reading'
|
|
||||||
elif abs(self.target - self.value) > self.tolerance:
|
|
||||||
if self._driving:
|
if self._driving:
|
||||||
return BUSY, 'approaching setpoint'
|
return BUSY, 'approaching setpoint'
|
||||||
return WARN, 'temperature out of tolerance'
|
return WARN, 'temperature out of tolerance'
|
||||||
else: # within tolerance: simple convergence criterion
|
# within tolerance: simple convergence criterion
|
||||||
self._driving = False
|
self._driving = False
|
||||||
return IDLE, ''
|
return IDLE, ''
|
||||||
return ERROR, text
|
|
||||||
|
|
||||||
|
class TemperatureLoop340(TemperatureLoop):
|
||||||
|
# slightly different behaviour for model 340
|
||||||
|
heater_range = Property('heater power range', IntRange(0, 5))
|
||||||
|
|
||||||
|
def write_heater_range(self, value):
|
||||||
|
self.communicate(f'RANGE {value};RANGE?')
|
||||||
|
@ -26,7 +26,7 @@ from frappy.datatypes import FloatRange, StringType, ValueType, TupleOf, StructO
|
|||||||
from frappy.modules import Communicator, Drivable, Parameter, Property, Readable, Module, Attached
|
from frappy.modules import Communicator, Drivable, Parameter, Property, Readable, Module, Attached
|
||||||
from frappy.params import Command
|
from frappy.params import Command
|
||||||
from frappy.dynamic import Pinata
|
from frappy.dynamic import Pinata
|
||||||
from frappy.errors import RangeError
|
from frappy.errors import RangeError, HardwareError
|
||||||
|
|
||||||
class Pin(Pinata):
|
class Pin(Pinata):
|
||||||
def scanModules(self):
|
def scanModules(self):
|
||||||
@ -72,8 +72,12 @@ class Heater(Drivable):
|
|||||||
maxheaterpower = Parameter('maximum allowed heater power',
|
maxheaterpower = Parameter('maximum allowed heater power',
|
||||||
datatype=FloatRange(0, 100), unit='W',
|
datatype=FloatRange(0, 100), unit='W',
|
||||||
)
|
)
|
||||||
|
error_message = Parameter('simulated error message', StringType(),
|
||||||
|
default='', readonly=False)
|
||||||
|
|
||||||
def read_value(self):
|
def read_value(self):
|
||||||
|
if self.error_message:
|
||||||
|
raise HardwareError(self.error_message)
|
||||||
return round(100 * random.random(), 1)
|
return round(100 * random.random(), 1)
|
||||||
|
|
||||||
def write_target(self, target):
|
def write_target(self, target):
|
||||||
|
@ -1,25 +1,37 @@
|
|||||||
"""
|
# *****************************************************************************
|
||||||
Created on Tue Nov 26 15:42:43 2019
|
# 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
|
||||||
@author: tartarotti_d-adm
|
# 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:
|
||||||
|
# Damaris Tartarotti Maimone
|
||||||
|
# Markus Zolliker <markus.zolliker@psi.ch>
|
||||||
|
# *****************************************************************************
|
||||||
|
"""Wrapper for the ADQ data acquisition card for ultrasound"""
|
||||||
|
import sys
|
||||||
|
import atexit
|
||||||
|
import signal
|
||||||
|
import time
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import ctypes as ct
|
import ctypes as ct
|
||||||
import time
|
from scipy.signal import butter, filtfilt
|
||||||
from numpy import sqrt, arctan2, sin, cos
|
|
||||||
|
|
||||||
#from pylab import *
|
|
||||||
|
|
||||||
from scipy import signal
|
# For different trigger modes
|
||||||
|
|
||||||
#ADQAPI = ct.cdll.LoadLibrary("ADQAPI.dll")
|
|
||||||
ADQAPI = ct.cdll.LoadLibrary("libadq.so.0")
|
|
||||||
|
|
||||||
#For different trigger modes
|
|
||||||
SW_TRIG = 1
|
SW_TRIG = 1
|
||||||
EXT_TRIG_1 = 2 #This external trigger does not work if the level of the trigger is very close to 0.5V. Now we have it close to 3V, and it works
|
# The following external trigger does not work if the level of the trigger is very close to 0.5V.
|
||||||
|
# Now we have it close to 3V, and it works
|
||||||
|
EXT_TRIG_1 = 2
|
||||||
EXT_TRIG_2 = 7
|
EXT_TRIG_2 = 7
|
||||||
EXT_TRIG_3 = 8
|
EXT_TRIG_3 = 8
|
||||||
LVL_TRIG = 3
|
LVL_TRIG = 3
|
||||||
@ -27,29 +39,36 @@ INT_TRIG = 4
|
|||||||
LVL_FALLING = 0
|
LVL_FALLING = 0
|
||||||
LVL_RISING = 1
|
LVL_RISING = 1
|
||||||
|
|
||||||
#samples_per_record=16384
|
ADQ_CLOCK_INT_INTREF = 0 # internal clock source
|
||||||
|
ADQ_CLOCK_EXT_REF = 1 # internal clock source, external reference
|
||||||
|
ADQ_CLOCK_EXT_CLOCK = 2 # External clock source
|
||||||
|
|
||||||
ADQ_TRANSFER_MODE_NORMAL = 0x00
|
ADQ_TRANSFER_MODE_NORMAL = 0x00
|
||||||
ADQ_CHANNELS_MASK = 0x3
|
ADQ_CHANNELS_MASK = 0x3
|
||||||
|
|
||||||
#f_LO = 40
|
GHz = 1e9
|
||||||
|
|
||||||
def butter_lowpass(cutoff, sr, order=5):
|
|
||||||
nyq = 0.5 * sr
|
|
||||||
normal_cutoff = cutoff / nyq
|
|
||||||
b, a = signal.butter(order, normal_cutoff, btype = 'low', analog = False)
|
|
||||||
return b, a
|
|
||||||
|
|
||||||
|
|
||||||
class Adq(object):
|
class Adq:
|
||||||
|
sample_rate = 2 * GHz
|
||||||
max_number_of_channels = 2
|
max_number_of_channels = 2
|
||||||
samp_freq = 2
|
ndecimate = 50 # decimation ratio (2GHz / 40 MHz)
|
||||||
#ndecimate = 50 # decimation ratio (2GHz / 40 MHz)
|
number_of_records = 1
|
||||||
ndecimate = 50
|
samples_per_record = 16384
|
||||||
|
bw_cutoff = 10E6
|
||||||
|
trigger = EXT_TRIG_1
|
||||||
|
adq_num = 1
|
||||||
|
UNDEFINED = -1
|
||||||
|
IDLE = 0
|
||||||
|
BUSY = 1
|
||||||
|
READY = 2
|
||||||
|
status = UNDEFINED
|
||||||
|
data = None
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
global ADQAPI
|
||||||
|
ADQAPI = ct.cdll.LoadLibrary("libadq.so.0")
|
||||||
|
|
||||||
def __init__(self, number_of_records, samples_per_record, bw_cutoff):
|
|
||||||
self.number_of_records = number_of_records
|
|
||||||
self.samples_per_record = samples_per_record
|
|
||||||
self.bw_cutoff = bw_cutoff
|
|
||||||
ADQAPI.ADQAPI_GetRevision()
|
ADQAPI.ADQAPI_GetRevision()
|
||||||
|
|
||||||
# Manually set return type from some ADQAPI functions
|
# Manually set return type from some ADQAPI functions
|
||||||
@ -60,74 +79,67 @@ class Adq(object):
|
|||||||
# Create ADQControlUnit
|
# Create ADQControlUnit
|
||||||
self.adq_cu = ct.c_void_p(ADQAPI.CreateADQControlUnit())
|
self.adq_cu = ct.c_void_p(ADQAPI.CreateADQControlUnit())
|
||||||
ADQAPI.ADQControlUnit_EnableErrorTrace(self.adq_cu, 3, '.')
|
ADQAPI.ADQControlUnit_EnableErrorTrace(self.adq_cu, 3, '.')
|
||||||
self.adq_num = 1
|
|
||||||
|
|
||||||
# Find ADQ devices
|
# Find ADQ devices
|
||||||
ADQAPI.ADQControlUnit_FindDevices(self.adq_cu)
|
ADQAPI.ADQControlUnit_FindDevices(self.adq_cu)
|
||||||
n_of_ADQ = ADQAPI.ADQControlUnit_NofADQ(self.adq_cu)
|
n_of_adq = ADQAPI.ADQControlUnit_NofADQ(self.adq_cu)
|
||||||
if n_of_ADQ != 1:
|
if n_of_adq != 1:
|
||||||
raise ValueError('number of ADQs must be 1, not %d' % n_of_ADQ)
|
raise RuntimeError('number of ADQs must be 1, not %d' % n_of_adq)
|
||||||
|
|
||||||
rev = ADQAPI.ADQ_GetRevision(self.adq_cu, self.adq_num)
|
rev = ADQAPI.ADQ_GetRevision(self.adq_cu, self.adq_num)
|
||||||
revision = ct.cast(rev,ct.POINTER(ct.c_int))
|
revision = ct.cast(rev, ct.POINTER(ct.c_int))
|
||||||
print('\nConnected to ADQ #1')
|
print('\nConnected to ADQ #1')
|
||||||
# Print revision information
|
# Print revision information
|
||||||
print('FPGA Revision: {}'.format(revision[0]))
|
print('FPGA Revision: {}'.format(revision[0]))
|
||||||
if (revision[1]):
|
if revision[1]:
|
||||||
print('Local copy')
|
print('Local copy')
|
||||||
else :
|
else:
|
||||||
print('SVN Managed')
|
print('SVN Managed')
|
||||||
if (revision[2]):
|
if revision[2]:
|
||||||
print('Mixed Revision')
|
print('Mixed Revision')
|
||||||
else :
|
else:
|
||||||
print('SVN Updated')
|
print('SVN Updated')
|
||||||
print('')
|
print('')
|
||||||
|
|
||||||
ADQ_CLOCK_INT_INTREF = 0 #internal clock source
|
ADQAPI.ADQ_SetClockSource(self.adq_cu, self.adq_num, ADQ_CLOCK_EXT_REF)
|
||||||
ADQ_CLOCK_EXT_REF = 1 #internal clock source, external reference
|
|
||||||
ADQ_CLOCK_EXT_CLOCK = 2 #External clock source
|
|
||||||
ADQAPI.ADQ_SetClockSource(self.adq_cu, self.adq_num, ADQ_CLOCK_EXT_REF);
|
|
||||||
|
|
||||||
##########################
|
##########################
|
||||||
# Test pattern
|
# Test pattern
|
||||||
#ADQAPI.ADQ_SetTestPatternMode(self.adq_cu, self.adq_num, 4)
|
# ADQAPI.ADQ_SetTestPatternMode(self.adq_cu, self.adq_num, 4)
|
||||||
##########################
|
##########################
|
||||||
# Sample skip
|
# Sample skip
|
||||||
#ADQAPI.ADQ_SetSampleSkip(self.adq_cu, self.adq_num, 1)
|
# ADQAPI.ADQ_SetSampleSkip(self.adq_cu, self.adq_num, 1)
|
||||||
##########################
|
##########################
|
||||||
|
|
||||||
# Set trig mode
|
# set trigger mode
|
||||||
self.trigger = EXT_TRIG_1
|
if not ADQAPI.ADQ_SetTriggerMode(self.adq_cu, self.adq_num, self.trigger):
|
||||||
#trigger = LVL_TRIG
|
raise RuntimeError('ADQ_SetTriggerMode failed.')
|
||||||
success = ADQAPI.ADQ_SetTriggerMode(self.adq_cu, self.adq_num, self.trigger)
|
if self.trigger == LVL_TRIG:
|
||||||
if (success == 0):
|
if not ADQAPI.ADQ_SetLvlTrigLevel(self.adq_cu, self.adq_num, -100):
|
||||||
print('ADQ_SetTriggerMode failed.')
|
raise RuntimeError('ADQ_SetLvlTrigLevel failed.')
|
||||||
if (self.trigger == LVL_TRIG):
|
if not ADQAPI.ADQ_SetTrigLevelResetValue(self.adq_cu, self.adq_num, 1000):
|
||||||
success = ADQAPI.ADQ_SetLvlTrigLevel(self.adq_cu, self.adq_num, -100)
|
raise RuntimeError('ADQ_SetTrigLevelResetValue failed.')
|
||||||
if (success == 0):
|
if not ADQAPI.ADQ_SetLvlTrigChannel(self.adq_cu, self.adq_num, 1):
|
||||||
print('ADQ_SetLvlTrigLevel failed.')
|
raise RuntimeError('ADQ_SetLvlTrigChannel failed.')
|
||||||
success = ADQAPI.ADQ_SetTrigLevelResetValue(self.adq_cu, self.adq_num, 1000)
|
if not ADQAPI.ADQ_SetLvlTrigEdge(self.adq_cu, self.adq_num, LVL_RISING):
|
||||||
if (success == 0):
|
raise RuntimeError('ADQ_SetLvlTrigEdge failed.')
|
||||||
print('ADQ_SetTrigLevelResetValue failed.')
|
elif self.trigger == EXT_TRIG_1:
|
||||||
success = ADQAPI.ADQ_SetLvlTrigChannel(self.adq_cu, self.adq_num, 1)
|
if not ADQAPI.ADQ_SetExternTrigEdge(self.adq_cu, self.adq_num, 2):
|
||||||
if (success == 0):
|
raise RuntimeError('ADQ_SetLvlTrigEdge failed.')
|
||||||
print('ADQ_SetLvlTrigChannel failed.')
|
# if not ADQAPI.ADQ_SetTriggerThresholdVoltage(self.adq_cu, self.adq_num, trigger, ct.c_double(0.2)):
|
||||||
success = ADQAPI.ADQ_SetLvlTrigEdge(self.adq_cu, self.adq_num, LVL_RISING)
|
# raise RuntimeError('SetTriggerThresholdVoltage failed.')
|
||||||
if (success == 0):
|
|
||||||
print('ADQ_SetLvlTrigEdge failed.')
|
|
||||||
elif (self.trigger == EXT_TRIG_1) :
|
|
||||||
success = ADQAPI.ADQ_SetExternTrigEdge(self.adq_cu, self.adq_num,2)
|
|
||||||
if (success == 0):
|
|
||||||
print('ADQ_SetLvlTrigEdge failed.')
|
|
||||||
# success = ADQAPI.ADQ_SetTriggerThresholdVoltage(self.adq_cu, self.adq_num, trigger, ct.c_double(0.2))
|
|
||||||
# if (success == 0):
|
|
||||||
# print('SetTriggerThresholdVoltage failed.')
|
|
||||||
print("CHANNEL:"+str(ct.c_int(ADQAPI.ADQ_GetLvlTrigChannel(self.adq_cu, self.adq_num))))
|
print("CHANNEL:"+str(ct.c_int(ADQAPI.ADQ_GetLvlTrigChannel(self.adq_cu, self.adq_num))))
|
||||||
self.setup_target_buffers()
|
atexit.register(self.deletecu)
|
||||||
|
signal.signal(signal.SIGTERM, lambda *_: sys.exit(0))
|
||||||
|
|
||||||
def setup_target_buffers(self):
|
def init(self, samples_per_record=None, number_of_records=None):
|
||||||
|
"""initialize dimensions"""
|
||||||
|
if samples_per_record:
|
||||||
|
self.samples_per_record = samples_per_record
|
||||||
|
if number_of_records:
|
||||||
|
self.number_of_records = number_of_records
|
||||||
# Setup target buffers for data
|
# Setup target buffers for data
|
||||||
self.target_buffers=(ct.POINTER(ct.c_int16 * self.samples_per_record * self.number_of_records)
|
self.target_buffers = (ct.POINTER(ct.c_int16 * self.samples_per_record * self.number_of_records)
|
||||||
* self.max_number_of_channels)()
|
* self.max_number_of_channels)()
|
||||||
for bufp in self.target_buffers:
|
for bufp in self.target_buffers:
|
||||||
bufp.contents = (ct.c_int16 * self.samples_per_record * self.number_of_records)()
|
bufp.contents = (ct.c_int16 * self.samples_per_record * self.number_of_records)()
|
||||||
@ -135,14 +147,11 @@ class Adq(object):
|
|||||||
def deletecu(self):
|
def deletecu(self):
|
||||||
# Only disarm trigger after data is collected
|
# Only disarm trigger after data is collected
|
||||||
ADQAPI.ADQ_DisarmTrigger(self.adq_cu, self.adq_num)
|
ADQAPI.ADQ_DisarmTrigger(self.adq_cu, self.adq_num)
|
||||||
ADQAPI.ADQ_MultiRecordClose(self.adq_cu, self.adq_num);
|
ADQAPI.ADQ_MultiRecordClose(self.adq_cu, self.adq_num)
|
||||||
# Delete ADQControlunit
|
# Delete ADQControlunit
|
||||||
ADQAPI.DeleteADQControlUnit(self.adq_cu)
|
ADQAPI.DeleteADQControlUnit(self.adq_cu)
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
"""start datat acquisition"""
|
|
||||||
# samples_per_records = samples_per_record/number_of_records
|
|
||||||
# Change number of pulses to be acquired acording to how many records are taken
|
|
||||||
# Start acquisition
|
# Start acquisition
|
||||||
ADQAPI.ADQ_MultiRecordSetup(self.adq_cu, self.adq_num,
|
ADQAPI.ADQ_MultiRecordSetup(self.adq_cu, self.adq_num,
|
||||||
self.number_of_records,
|
self.number_of_records,
|
||||||
@ -150,79 +159,50 @@ class Adq(object):
|
|||||||
|
|
||||||
ADQAPI.ADQ_DisarmTrigger(self.adq_cu, self.adq_num)
|
ADQAPI.ADQ_DisarmTrigger(self.adq_cu, self.adq_num)
|
||||||
ADQAPI.ADQ_ArmTrigger(self.adq_cu, self.adq_num)
|
ADQAPI.ADQ_ArmTrigger(self.adq_cu, self.adq_num)
|
||||||
|
self.status = self.BUSY
|
||||||
|
|
||||||
def getdata(self):
|
def get_status(self):
|
||||||
"""wait for aquisition to be finished and get data"""
|
"""check if ADQ card is busy"""
|
||||||
#start = time.time()
|
if self.status == self.BUSY:
|
||||||
while(ADQAPI.ADQ_GetAcquiredAll(self.adq_cu,self.adq_num) == 0):
|
if ADQAPI.ADQ_GetAcquiredAll(self.adq_cu, self.adq_num):
|
||||||
time.sleep(0.001)
|
self.status = self.READY
|
||||||
#if (self.trigger == SW_TRIG):
|
else:
|
||||||
# ADQAPI.ADQ_SWTrig(self.adq_cu, self.adq_num)
|
if self.trigger == SW_TRIG:
|
||||||
#mid = time.time()
|
ADQAPI.ADQ_SWTrig(self.adq_cu, self.adq_num)
|
||||||
status = ADQAPI.ADQ_GetData(self.adq_cu, self.adq_num, self.target_buffers,
|
return self.status
|
||||||
|
|
||||||
|
def get_data(self, dataclass, **kwds):
|
||||||
|
"""when ready, get raw data from card, else return cached data
|
||||||
|
|
||||||
|
return
|
||||||
|
"""
|
||||||
|
if self.get_status() == self.READY:
|
||||||
|
# Get data from ADQ
|
||||||
|
if not ADQAPI.ADQ_GetData(self.adq_cu, self.adq_num, self.target_buffers,
|
||||||
self.samples_per_record * self.number_of_records, 2,
|
self.samples_per_record * self.number_of_records, 2,
|
||||||
0, self.number_of_records, ADQ_CHANNELS_MASK,
|
0, self.number_of_records, ADQ_CHANNELS_MASK,
|
||||||
0, self.samples_per_record, ADQ_TRANSFER_MODE_NORMAL);
|
0, self.samples_per_record, ADQ_TRANSFER_MODE_NORMAL):
|
||||||
#print(time.time()-mid,mid-start)
|
raise RuntimeError('no success from ADQ_GetDATA')
|
||||||
if not status:
|
self.data = dataclass(self, **kwds)
|
||||||
raise ValueError('no succesS from ADQ_GetDATA')
|
self.status = self.IDLE
|
||||||
# Now this is an array with all records, but the time is artificial
|
if self.status == self.UNDEFINED:
|
||||||
|
raise RuntimeError('no data available yet')
|
||||||
|
return self.data
|
||||||
|
|
||||||
|
|
||||||
|
class PEdata:
|
||||||
|
def __init__(self, adq):
|
||||||
|
self.sample_rate = adq.sample_rate
|
||||||
|
self.samp_freq = self.sample_rate / GHz
|
||||||
|
self.number_of_records = adq.number_of_records
|
||||||
data = []
|
data = []
|
||||||
for ch in range(2):
|
for ch in range(2):
|
||||||
onedim = np.frombuffer(self.target_buffers[ch].contents, dtype=np.int16)
|
onedim = np.frombuffer(adq.target_buffers[ch].contents, dtype=np.int16)
|
||||||
data.append(onedim.reshape(self.number_of_records, self.samples_per_record) / float(2**14)) # 14 bits ADC
|
data.append(onedim.reshape(adq.number_of_records, adq.samples_per_record) / float(2**14)) # 14 bits ADC
|
||||||
return data
|
# Now this is an array with all records, but the time is artificial
|
||||||
|
self.data = data
|
||||||
|
|
||||||
def acquire(self):
|
def sinW(self, sig, freq, ti, tf):
|
||||||
self.start()
|
|
||||||
return self.getdata()
|
|
||||||
'''
|
|
||||||
def average(self, data):
|
|
||||||
#Average over records
|
|
||||||
return [data[ch].sum(axis=0) / self.number_of_records for ch in range(2)]
|
|
||||||
|
|
||||||
def iq(self, channel, f_LO):
|
|
||||||
newx = np.linspace(0, self.samples_per_record /2, self.samples_per_record)
|
|
||||||
s0 = channel /((2**16)/2)*0.5*np.exp(1j*2*np.pi*f_LO/(1e3)*newx)
|
|
||||||
I0 = s0.real
|
|
||||||
Q0 = s0.imag
|
|
||||||
return I0, Q0
|
|
||||||
|
|
||||||
|
|
||||||
def fitting(self, data, f_LO, ti, tf):
|
|
||||||
# As long as data[0] is the pulse
|
|
||||||
si = 2*ti #Those are for fitting the pulse
|
|
||||||
sf = 2*tf
|
|
||||||
phase = np.zeros(self.number_of_records)
|
|
||||||
amplitude = np.zeros(self.number_of_records)
|
|
||||||
offset = np.zeros(self.number_of_records)
|
|
||||||
|
|
||||||
for i in range(self.number_of_records):
|
|
||||||
phase[i], amplitude[i] = sineW(data[0][i][si:sf],f_LO*1e-9,ti,tf)
|
|
||||||
offset[i] = np.average(data[0][i][si:sf])
|
|
||||||
return phase, amplitude, offset
|
|
||||||
|
|
||||||
|
|
||||||
def waveIQ(self, channel,ti,f_LO):
|
|
||||||
#channel is not the sample data
|
|
||||||
t = np.linspace(0, self.samples_per_record /2, self.samples_per_record + 1)[:-1]
|
|
||||||
si = 2*ti # Again that is where the wave pulse starts
|
|
||||||
cwi = np.zeros((self.number_of_records,self.samples_per_record))
|
|
||||||
cwq = np.zeros((self.number_of_records,self.samples_per_record))
|
|
||||||
iq = np.zeros((self.number_of_records,self.samples_per_record))
|
|
||||||
q = np.zeros((self.number_of_records,self.samples_per_record))
|
|
||||||
for i in range(self.number_of_records):
|
|
||||||
cwi[i] = np.zeros(self.samples_per_record)
|
|
||||||
cwq[i] = np.zeros(self.samples_per_record)
|
|
||||||
cwi[i] = amplitude[i]*sin(t[si:]*f_LO*1e-9*2*np.pi+phase[i]*np.pi/180)+bias[i]
|
|
||||||
cwq[i] = amplitude[i]*sin(t[si:]*f_LO*1e-9*(2*np.pi+(phase[i]+90)*np.pi/180))+bias[i]
|
|
||||||
|
|
||||||
iq[i] = channel[i]*cwi[i]
|
|
||||||
q[i] = channel[i]*cwq[i]
|
|
||||||
|
|
||||||
return iq,q
|
|
||||||
'''
|
|
||||||
def sinW(self,sig,freq,ti,tf):
|
|
||||||
# sig: signal array
|
# sig: signal array
|
||||||
# freq
|
# freq
|
||||||
# ti, tf: initial and end time
|
# ti, tf: initial and end time
|
||||||
@ -241,30 +221,28 @@ class Adq(object):
|
|||||||
def mix(self, sigin, sigout, freq, ti, tf):
|
def mix(self, sigin, sigout, freq, ti, tf):
|
||||||
# sigin, sigout: signal array, incomping, output
|
# sigin, sigout: signal array, incomping, output
|
||||||
# freq
|
# freq
|
||||||
# ti, tf: initial and end time if sigin
|
# ti, tf: initial and end time of sigin
|
||||||
a, b = self.sinW(sigin, freq, ti, tf)
|
a, b = self.sinW(sigin, freq, ti, tf)
|
||||||
phase = arctan2(a,b) * 180 / np.pi
|
amp = np.sqrt(a**2 + b**2)
|
||||||
amp = sqrt(a**2 + b**2)
|
|
||||||
a, b = a/amp, b/amp
|
a, b = a/amp, b/amp
|
||||||
#si = int(ti * self.samp_freq)
|
# si = int(ti * self.samp_freq)
|
||||||
t = np.arange(len(sigout)) / self.samp_freq
|
t = np.arange(len(sigout)) / self.samp_freq
|
||||||
wave1 = sigout * (a * cos(2*np.pi*freq*t) + b * sin(2*np.pi*freq*t))
|
wave1 = sigout * (a * np.cos(2*np.pi*freq*t) + b * np.sin(2*np.pi*freq*t))
|
||||||
wave2 = sigout * (a * sin(2*np.pi*freq*t) - b * cos(2*np.pi*freq*t))
|
wave2 = sigout * (a * np.sin(2*np.pi*freq*t) - b * np.cos(2*np.pi*freq*t))
|
||||||
return wave1, wave2
|
return wave1, wave2
|
||||||
|
|
||||||
def averageiq(self, data, freq, ti, tf):
|
def averageiq(self, data, freq, ti, tf):
|
||||||
'''Average over records'''
|
"""Average over records"""
|
||||||
iorq = np.array([self.mix(data[0][i], data[1][i], freq, ti, tf) for i in range(self.number_of_records)])
|
iorq = np.array([self.mix(data[0][i], data[1][i], freq, ti, tf) for i in range(self.number_of_records)])
|
||||||
# iorq = np.array([self.mix(data[0][:], data[1][:], freq, ti, tf)])
|
|
||||||
return iorq.sum(axis=0) / self.number_of_records
|
return iorq.sum(axis=0) / self.number_of_records
|
||||||
|
|
||||||
def filtro(self, iorq, cutoff):
|
def filtro(self, iorq, cutoff):
|
||||||
b, a = butter_lowpass(cutoff, self.samp_freq*1e9)
|
# butter lowpass
|
||||||
|
nyq = 0.5 * self.sample_rate
|
||||||
#ifi = np.array(signal.filtfilt(b,a,iorq[0]))
|
normal_cutoff = cutoff / nyq
|
||||||
#qf = np.array(signal.filtfilt(b,a,iorq[1]))
|
order = 5
|
||||||
iqf = [signal.filtfilt(b,a,iorq[i]) for i in np.arange(len(iorq))]
|
b, a = butter(order, normal_cutoff, btype='low', analog=False)
|
||||||
|
iqf = [filtfilt(b, a, iorq[i]) for i in np.arange(len(iorq))]
|
||||||
return iqf
|
return iqf
|
||||||
|
|
||||||
def box(self, iorq, ti, tf):
|
def box(self, iorq, ti, tf):
|
||||||
@ -273,21 +251,63 @@ class Adq(object):
|
|||||||
bxa = [sum(iorq[i][si:sf])/(sf-si) for i in np.arange(len(iorq))]
|
bxa = [sum(iorq[i][si:sf])/(sf-si) for i in np.arange(len(iorq))]
|
||||||
return bxa
|
return bxa
|
||||||
|
|
||||||
def gates_and_curves(self, data, freq, pulse, roi):
|
def gates_and_curves(self, freq, pulse, roi, bw_cutoff):
|
||||||
"""return iq values of rois and prepare plottable curves for iq"""
|
"""return iq values of rois and prepare plottable curves for iq"""
|
||||||
times = []
|
self.ndecimate = int(round(self.sample_rate / freq))
|
||||||
times.append(('aviq', time.time()))
|
# times = []
|
||||||
iq = self.averageiq(data,freq*1e-9,*pulse)
|
# times.append(('aviq', time.time()))
|
||||||
times.append(('filtro', time.time()))
|
iq = self.averageiq(self.data, freq / GHz, *pulse)
|
||||||
iqf = self.filtro(iq,self.bw_cutoff)
|
# times.append(('filtro', time.time()))
|
||||||
|
iqf = self.filtro(iq, bw_cutoff)
|
||||||
m = len(iqf[0]) // self.ndecimate
|
m = len(iqf[0]) // self.ndecimate
|
||||||
times.append(('iqdec', time.time()))
|
ll = m * self.ndecimate
|
||||||
|
iqf = [iqfx[0:ll] for iqfx in iqf]
|
||||||
|
# times.append(('iqdec', time.time()))
|
||||||
iqd = np.average(np.resize(iqf, (2, m, self.ndecimate)), axis=2)
|
iqd = np.average(np.resize(iqf, (2, m, self.ndecimate)), axis=2)
|
||||||
t_axis = np.arange(m) * self.ndecimate / self.samp_freq
|
t_axis = np.arange(m) * self.ndecimate / self.samp_freq
|
||||||
pulsig = np.abs(data[0][0])
|
pulsig = np.abs(self.data[0][0])
|
||||||
times.append(('pulsig', time.time()))
|
# times.append(('pulsig', time.time()))
|
||||||
pulsig = np.average(np.resize(pulsig, (m, self.ndecimate)), axis=1)
|
pulsig = np.average(np.resize(pulsig, (m, self.ndecimate)), axis=1)
|
||||||
self.curves = (t_axis, iqd[0], iqd[1], pulsig)
|
self.curves = (t_axis, iqd[0], iqd[1], pulsig)
|
||||||
#print(times)
|
# print(times)
|
||||||
return [self.box(iqf,*r) for r in roi]
|
return [self.box(iqf, *r) for r in roi]
|
||||||
|
|
||||||
|
|
||||||
|
class RUSdata:
|
||||||
|
def __init__(self, adq, freq, periods):
|
||||||
|
self.sample_rate = adq.sample_rate
|
||||||
|
self.freq = freq
|
||||||
|
self.periods = periods
|
||||||
|
self.samples_per_record = adq.samples_per_record
|
||||||
|
input_signal = np.frombuffer(adq.target_buffers[0].contents, dtype=np.int16)
|
||||||
|
output_signal = np.frombuffer(adq.target_buffers[1].contents, dtype=np.int16)
|
||||||
|
complex_sinusoid = np.exp(1j * 2 * np.pi * self.freq / self.sample_rate * np.arange(len(input_signal)))
|
||||||
|
self.input_mixed = input_signal * complex_sinusoid
|
||||||
|
self.output_mixed = output_signal * complex_sinusoid
|
||||||
|
self.input_mean = self.input_mixed.mean()
|
||||||
|
self.output_mean = self.output_mixed.mean()
|
||||||
|
self.iq = self.output_mean / self.input_mean
|
||||||
|
|
||||||
|
def get_reduced(self, mixed):
|
||||||
|
"""get reduced array and normalize"""
|
||||||
|
nper = self.samples_per_record // self.periods
|
||||||
|
mean = mixed.mean()
|
||||||
|
return mixed[:self.period * nper].reshape((-1, nper)).mean(axis=0) / mean
|
||||||
|
|
||||||
|
def calc_quality(self):
|
||||||
|
"""get signal quality info
|
||||||
|
|
||||||
|
quality info (small values indicate good quality):
|
||||||
|
- input_std and output_std:
|
||||||
|
the imaginary part indicates deviations in phase
|
||||||
|
the real part indicates deviations in amplitude
|
||||||
|
- input_slope and output_slope:
|
||||||
|
the imaginary part indicates a turning phase (rad/sec)
|
||||||
|
the real part indicates changes in amplitude (0.01 ~= 1%/sec)
|
||||||
|
"""
|
||||||
|
reduced = self.get_reduced(self.input_mixed)
|
||||||
|
self.input_stdev = reduced.std()
|
||||||
|
|
||||||
|
reduced = self.get_reduced(self.output_mixed)
|
||||||
|
timeaxis = np.arange(len(reduced)) * self.sample_rate / self.freq
|
||||||
|
self.output_slope = np.polyfit(timeaxis, reduced, 1)[0]
|
||||||
|
@ -17,10 +17,39 @@
|
|||||||
# Markus Zolliker <markus.zolliker@psi.ch>
|
# Markus Zolliker <markus.zolliker@psi.ch>
|
||||||
# Jael Celia Lorenzana <jael-celia.lorenzana@psi.ch>
|
# Jael Celia Lorenzana <jael-celia.lorenzana@psi.ch>
|
||||||
# *****************************************************************************
|
# *****************************************************************************
|
||||||
"""Powersupply B&K Precision BK168xB"""
|
"""Powersupply B&K Precision BK168xB
|
||||||
|
|
||||||
|
The following lines are part of a config file for the frappy-server process
|
||||||
|
The frappy server creates the following modules and refreshes the values with a refresh rate of 1 sec.
|
||||||
|
The communication with the powersupply is established via serial over USB.
|
||||||
|
The manual can be found here https://www.vectortechnologies.gr/images/products/2022/02/168xB_programming_manual.pdf
|
||||||
|
|
||||||
|
Mod('htr_io',
|
||||||
|
'frappy_psi.bkpower.IO',
|
||||||
|
'powersupply communicator',
|
||||||
|
uri = 'serial:///dev/ttyUSBupper',
|
||||||
|
)
|
||||||
|
|
||||||
|
Mod('htr',
|
||||||
|
'frappy_psi.bkpower.Power',
|
||||||
|
'heater power',
|
||||||
|
io= 'htr_io',
|
||||||
|
)
|
||||||
|
|
||||||
|
Mod('out',
|
||||||
|
'frappy_psi.bkpower.Output',
|
||||||
|
'heater output',
|
||||||
|
io = 'htr_io',
|
||||||
|
maxvolt = 50,
|
||||||
|
maxcurrent = 2,
|
||||||
|
)
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
from frappy.core import StringIO, Readable, Parameter, FloatRange, Writable, HasIO, BoolType
|
from frappy.core import StringIO, Readable, Parameter, FloatRange, Writable, HasIO, BoolType
|
||||||
|
|
||||||
|
|
||||||
|
# define the IO class
|
||||||
class IO(StringIO):
|
class IO(StringIO):
|
||||||
end_of_line = ('OK\r', '\r')
|
end_of_line = ('OK\r', '\r')
|
||||||
default_settings = {'baudrate': 9600}
|
default_settings = {'baudrate': 9600}
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
"""drivers for CCU4, the cryostat control unit at SINQ"""
|
"""drivers for CCU4, the cryostat control unit at SINQ"""
|
||||||
import time
|
import time
|
||||||
import math
|
import math
|
||||||
|
from frappy.lib.enum import Enum
|
||||||
# the most common Frappy classes can be imported from frappy.core
|
# the most common Frappy classes can be imported from frappy.core
|
||||||
from frappy.core import HasIO, Parameter, Command, Readable, Writable, Drivable, \
|
from frappy.core import HasIO, Parameter, Command, Readable, Writable, Drivable, \
|
||||||
Property, StringIO, BUSY, IDLE, WARN, ERROR, DISABLED, Attached
|
Property, StringIO, BUSY, IDLE, WARN, ERROR, DISABLED, Attached
|
||||||
@ -32,6 +33,10 @@ from frappy.errors import CommunicationFailedError
|
|||||||
from frappy.states import HasStates, status_code, Retry
|
from frappy.states import HasStates, status_code, Retry
|
||||||
|
|
||||||
|
|
||||||
|
M = Enum(idle=0, opening=1, closing=2, opened=3, closed=5, no_motor=6)
|
||||||
|
A = Enum(disabled=0, manual=1, auto=2)
|
||||||
|
|
||||||
|
|
||||||
class CCU4IO(StringIO):
|
class CCU4IO(StringIO):
|
||||||
"""communication with CCU4"""
|
"""communication with CCU4"""
|
||||||
# for completeness: (not needed, as it is the default)
|
# for completeness: (not needed, as it is the default)
|
||||||
@ -43,25 +48,34 @@ class CCU4IO(StringIO):
|
|||||||
class CCU4Base(HasIO):
|
class CCU4Base(HasIO):
|
||||||
ioClass = CCU4IO
|
ioClass = CCU4IO
|
||||||
|
|
||||||
def command(self, *args, **kwds):
|
def command(self, **kwds):
|
||||||
"""send a command and get the response
|
"""send a command and get the response
|
||||||
|
|
||||||
:param args: the name of the parameters to query
|
:param kwds: <parameter>=<value> for changing a parameter <parameter>=<type> for querying a parameter
|
||||||
:param kwds: <parameter>=<value> for changing a parameter
|
|
||||||
:returns: the (new) values of the parameters
|
:returns: the (new) values of the parameters
|
||||||
"""
|
"""
|
||||||
cmds = [f'{k}={v:g}' for k, v in kwds.items()] + list(args)
|
types = {}
|
||||||
|
cmds = []
|
||||||
|
for key, value in kwds.items():
|
||||||
|
if isinstance(value, type):
|
||||||
|
types[key] = value
|
||||||
|
cmds.append(key)
|
||||||
|
elif isinstance(value, str):
|
||||||
|
types[key] = str
|
||||||
|
cmds.append(f'{key}={value}')
|
||||||
|
else:
|
||||||
|
types[key] = float
|
||||||
|
cmds.append(f'{key}={value:g}')
|
||||||
reply = self.io.communicate(' '.join(cmds)).split()
|
reply = self.io.communicate(' '.join(cmds)).split()
|
||||||
names = list(args) + list(kwds)
|
if len(reply) != len(types):
|
||||||
if len(reply) != len(names):
|
|
||||||
raise CommunicationFailedError('number of reply items does not match')
|
raise CommunicationFailedError('number of reply items does not match')
|
||||||
result = []
|
result = []
|
||||||
for given, item in zip(names, reply):
|
for (given, typ), res in zip(types.items(), reply):
|
||||||
name, txtvalue = item.split('=')
|
name, txtvalue = res.split('=')
|
||||||
if given != name:
|
if given != name:
|
||||||
raise CommunicationFailedError('result keys do not match given keys')
|
raise CommunicationFailedError('result keys do not match given keys')
|
||||||
result.append(float(txtvalue))
|
result.append(typ(txtvalue))
|
||||||
if len(result) == 1:
|
if len(kwds) == 1:
|
||||||
return result[0]
|
return result[0]
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@ -89,13 +103,13 @@ class HeLevel(CCU4Base, Readable):
|
|||||||
}
|
}
|
||||||
|
|
||||||
def read_value(self):
|
def read_value(self):
|
||||||
return self.command('h')
|
return self.command(h=float)
|
||||||
|
|
||||||
def read_status(self):
|
def read_status(self):
|
||||||
return self.STATUS_MAP[int(self.command('hsf'))]
|
return self.STATUS_MAP[int(self.command(hsf=int))]
|
||||||
|
|
||||||
def read_sample_rate(self):
|
def read_sample_rate(self):
|
||||||
value, self.empty_length, self.full_length = self.command('hf', 'hem', 'hfu')
|
value, self.empty_length, self.full_length = self.command(hf=int, hem=float, hfu=float)
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def write_sample_rate(self, value):
|
def write_sample_rate(self, value):
|
||||||
@ -138,13 +152,13 @@ class Valve(CCU4Base, Writable):
|
|||||||
class HeFillValve(Valve):
|
class HeFillValve(Valve):
|
||||||
_open_command = {'hcd': 1, 'hf': 1}
|
_open_command = {'hcd': 1, 'hf': 1}
|
||||||
_close_command = {'hcd': 0, 'hf': 0}
|
_close_command = {'hcd': 0, 'hf': 0}
|
||||||
_query_state = 'hv'
|
_query_state = {'hv': int}
|
||||||
|
|
||||||
|
|
||||||
class N2FillValve(Valve):
|
class N2FillValve(Valve):
|
||||||
_open_command = {'nc': 1}
|
_open_command = {'nc': 1}
|
||||||
_close_command = {'nc': 0}
|
_close_command = {'nc': 0}
|
||||||
_query_state = 'nv'
|
_query_state = {'nv': int}
|
||||||
|
|
||||||
|
|
||||||
class AuxValve(Valve):
|
class AuxValve(Valve):
|
||||||
@ -153,7 +167,7 @@ class AuxValve(Valve):
|
|||||||
def initModule(self):
|
def initModule(self):
|
||||||
self._open_command = {f'vc{self.channel}': 1}
|
self._open_command = {f'vc{self.channel}': 1}
|
||||||
self._close_command = {f'vc{self.channel}': 0}
|
self._close_command = {f'vc{self.channel}': 0}
|
||||||
self._query_state = f'v{self.channel}'
|
self._query_state = {f'v{self.channel}': int}
|
||||||
|
|
||||||
|
|
||||||
class N2TempSensor(Readable):
|
class N2TempSensor(Readable):
|
||||||
@ -167,7 +181,7 @@ class N2Level(CCU4Base, Pinata, Readable):
|
|||||||
|
|
||||||
value = Parameter('vessel state', EnumType(empty=0, ok=1, full=2))
|
value = Parameter('vessel state', EnumType(empty=0, ok=1, full=2))
|
||||||
status = Parameter(datatype=StatusType(Readable, 'BUSY'))
|
status = Parameter(datatype=StatusType(Readable, 'BUSY'))
|
||||||
mode = Parameter('auto mode', EnumType(disabled=0, manual=1, auto=2), readonly=False)
|
mode = Parameter('auto mode', EnumType(A), readonly=False)
|
||||||
|
|
||||||
threshold = Parameter('threshold triggering start/stop filling',
|
threshold = Parameter('threshold triggering start/stop filling',
|
||||||
FloatRange(unit='K'), readonly=False)
|
FloatRange(unit='K'), readonly=False)
|
||||||
@ -206,17 +220,17 @@ class N2Level(CCU4Base, Pinata, Readable):
|
|||||||
super().initialReads()
|
super().initialReads()
|
||||||
|
|
||||||
def read_status(self):
|
def read_status(self):
|
||||||
auto, nstate = self.command('na', 'ns')
|
auto, nstate = self.command(na=int, ns=int)
|
||||||
if not self.valve or not auto:
|
if not self.valve or not auto:
|
||||||
if self.mode == 'auto':
|
if self.mode == A.auto:
|
||||||
# no valve assigned
|
# no valve assigned
|
||||||
self.mode = 'manual'
|
self.mode = A.manual
|
||||||
if self.mode == 'disabled':
|
if self.mode == A.disabled:
|
||||||
return DISABLED, ''
|
return DISABLED, ''
|
||||||
status = self.STATUS_MAP[nstate]
|
status = self.STATUS_MAP[nstate]
|
||||||
if status[0] // 100 != IDLE // 100:
|
if status[0] // 100 != IDLE // 100:
|
||||||
return status
|
return status
|
||||||
if self.mode == 'manual':
|
if self.mode == A.manual:
|
||||||
return IDLE, ''
|
return IDLE, ''
|
||||||
vstatus = self.valve.status
|
vstatus = self.valve.status
|
||||||
if vstatus[0] // 100 == WARN // 100:
|
if vstatus[0] // 100 == WARN // 100:
|
||||||
@ -229,7 +243,7 @@ class N2Level(CCU4Base, Pinata, Readable):
|
|||||||
|
|
||||||
def read_value(self):
|
def read_value(self):
|
||||||
# read sensors
|
# read sensors
|
||||||
lower, upper = self.command('nl', 'nu')
|
lower, upper = self.command(nl=float, nu=float)
|
||||||
if self.lower:
|
if self.lower:
|
||||||
self.lower.value = lower
|
self.lower.value = lower
|
||||||
if self.upper:
|
if self.upper:
|
||||||
@ -241,7 +255,7 @@ class N2Level(CCU4Base, Pinata, Readable):
|
|||||||
return 'empty'
|
return 'empty'
|
||||||
|
|
||||||
def write_mode(self, mode):
|
def write_mode(self, mode):
|
||||||
if mode == 'auto':
|
if mode == A.auto:
|
||||||
if self.isBusy():
|
if self.isBusy():
|
||||||
return mode
|
return mode
|
||||||
# set to watching
|
# set to watching
|
||||||
@ -252,7 +266,7 @@ class N2Level(CCU4Base, Pinata, Readable):
|
|||||||
return mode
|
return mode
|
||||||
|
|
||||||
def read_threshold(self):
|
def read_threshold(self):
|
||||||
value, self.cool_delay, self.fill_timeout = self.command('nth', 'ntc', 'ntm')
|
value, self.cool_delay, self.fill_timeout = self.command(nth=float, ntc=float, ntm=float)
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def write_threshold(self, value):
|
def write_threshold(self, value):
|
||||||
@ -266,12 +280,12 @@ class N2Level(CCU4Base, Pinata, Readable):
|
|||||||
|
|
||||||
@Command()
|
@Command()
|
||||||
def fill(self):
|
def fill(self):
|
||||||
self.mode = 'auto'
|
self.mode = A.auto
|
||||||
self.io.write(nc=1)
|
self.io.write(nc=1)
|
||||||
|
|
||||||
@Command()
|
@Command()
|
||||||
def stop(self):
|
def stop(self):
|
||||||
if self.mode == 'auto':
|
if self.mode == A.auto:
|
||||||
# set to watching
|
# set to watching
|
||||||
self.command(nc=3)
|
self.command(nc=3)
|
||||||
else:
|
else:
|
||||||
@ -285,7 +299,7 @@ class FlowPressure(CCU4Base, Readable):
|
|||||||
pollinterval = Parameter(default=0.25)
|
pollinterval = Parameter(default=0.25)
|
||||||
|
|
||||||
def read_value(self):
|
def read_value(self):
|
||||||
return self.filter(self.command('f')) - self.mbar_offset
|
return self.filter(self.command(f=float)) - self.mbar_offset
|
||||||
|
|
||||||
|
|
||||||
class NeedleValve(HasStates, CCU4Base, Drivable):
|
class NeedleValve(HasStates, CCU4Base, Drivable):
|
||||||
@ -298,9 +312,7 @@ class NeedleValve(HasStates, CCU4Base, Drivable):
|
|||||||
lnm_per_mbar = Parameter(unit='ln/min/mbar', default=0.6, readonly=False)
|
lnm_per_mbar = Parameter(unit='ln/min/mbar', default=0.6, readonly=False)
|
||||||
use_pressure = Parameter('use flow from pressure', BoolType(),
|
use_pressure = Parameter('use flow from pressure', BoolType(),
|
||||||
default=False, readonly=False)
|
default=False, readonly=False)
|
||||||
motor_state = Parameter('motor_state',
|
motor_state = Parameter('motor_state', EnumType(M))
|
||||||
EnumType(idle=0, opening=1, closing=2,
|
|
||||||
opened=3, closed=5, no_motor=6))
|
|
||||||
tolerance = Parameter('tolerance', FloatRange(0), value=0.25, readonly=False)
|
tolerance = Parameter('tolerance', FloatRange(0), value=0.25, readonly=False)
|
||||||
tolerance2 = Parameter('tolerance limit above 2 lnm', FloatRange(0), value=0.5, readonly=False)
|
tolerance2 = Parameter('tolerance limit above 2 lnm', FloatRange(0), value=0.5, readonly=False)
|
||||||
prop = Parameter('proportional term', FloatRange(unit='s/lnm'), readonly=False)
|
prop = Parameter('proportional term', FloatRange(unit='s/lnm'), readonly=False)
|
||||||
@ -341,12 +353,12 @@ class NeedleValve(HasStates, CCU4Base, Drivable):
|
|||||||
def update_flow(self, value):
|
def update_flow(self, value):
|
||||||
if not self.use_pressure:
|
if not self.use_pressure:
|
||||||
self.value = value
|
self.value = value
|
||||||
self.doPoll()
|
self.cycle_machine()
|
||||||
|
|
||||||
def update_flow_pressure(self, value):
|
def update_flow_pressure(self, value):
|
||||||
if self.use_pressure:
|
if self.use_pressure:
|
||||||
self.value = value * self.lnm_per_mbar
|
self.value = value * self.lnm_per_mbar
|
||||||
self.doPoll()
|
self.cycle_machine()
|
||||||
|
|
||||||
def write_target(self, value):
|
def write_target(self, value):
|
||||||
self.start_machine(self.controlling, in_tol_time=0,
|
self.start_machine(self.controlling, in_tol_time=0,
|
||||||
@ -354,7 +366,7 @@ class NeedleValve(HasStates, CCU4Base, Drivable):
|
|||||||
|
|
||||||
@status_code(BUSY)
|
@status_code(BUSY)
|
||||||
def unblock_from_open(self, state):
|
def unblock_from_open(self, state):
|
||||||
self.motor_state = self.command('fm')
|
self.motor_state = self.command(fm=int)
|
||||||
if self.motor_state == 'opened':
|
if self.motor_state == 'opened':
|
||||||
self.command(mp=-60)
|
self.command(mp=-60)
|
||||||
return Retry
|
return Retry
|
||||||
@ -372,7 +384,7 @@ class NeedleValve(HasStates, CCU4Base, Drivable):
|
|||||||
|
|
||||||
@status_code(BUSY)
|
@status_code(BUSY)
|
||||||
def unblock_open(self, state):
|
def unblock_open(self, state):
|
||||||
self.motor_state = self.command('fm')
|
self.motor_state = self.command(fm=int)
|
||||||
if self.value < state.flow_before:
|
if self.value < state.flow_before:
|
||||||
state.flow_before_open = self.value
|
state.flow_before_open = self.value
|
||||||
elif self.value > state.flow_before + 1:
|
elif self.value > state.flow_before + 1:
|
||||||
@ -393,7 +405,7 @@ class NeedleValve(HasStates, CCU4Base, Drivable):
|
|||||||
|
|
||||||
@status_code(BUSY)
|
@status_code(BUSY)
|
||||||
def unblock_close(self, state):
|
def unblock_close(self, state):
|
||||||
self.motor_state = self.command('fm')
|
self.motor_state = self.command(fm=int)
|
||||||
if self.value > state.flow_before:
|
if self.value > state.flow_before:
|
||||||
state.flow_before_open = self.value
|
state.flow_before_open = self.value
|
||||||
elif self.value < state.flow_before - 1:
|
elif self.value < state.flow_before - 1:
|
||||||
@ -435,7 +447,7 @@ class NeedleValve(HasStates, CCU4Base, Drivable):
|
|||||||
dif = self.target - self.value
|
dif = self.target - self.value
|
||||||
difdif = dif - state.prev_dif
|
difdif = dif - state.prev_dif
|
||||||
state.prev_dif = dif
|
state.prev_dif = dif
|
||||||
self.motor_state = self.command('fm')
|
self.motor_state = self.command(fm=int)
|
||||||
if self.motor_state == 'closed':
|
if self.motor_state == 'closed':
|
||||||
if dif < 0 or difdif < 0:
|
if dif < 0 or difdif < 0:
|
||||||
return Retry
|
return Retry
|
||||||
@ -467,5 +479,3 @@ class NeedleValve(HasStates, CCU4Base, Drivable):
|
|||||||
return Retry
|
return Retry
|
||||||
self.command(mp=state.step)
|
self.command(mp=state.step)
|
||||||
return Retry
|
return Retry
|
||||||
|
|
||||||
|
|
||||||
|
@ -63,7 +63,12 @@ def parse_result(reply):
|
|||||||
|
|
||||||
class LakeShoreIO(HasIO):
|
class LakeShoreIO(HasIO):
|
||||||
def set_param(self, cmd, *args):
|
def set_param(self, cmd, *args):
|
||||||
head = ','.join([cmd] + [f'{a:g}' for a in args])
|
args = [f'{a:g}' for a in args]
|
||||||
|
if ' ' in cmd.strip():
|
||||||
|
args.insert(0, cmd)
|
||||||
|
else:
|
||||||
|
args[0] = cmd + args[0]
|
||||||
|
head = ','.join(args)
|
||||||
tail = cmd.replace(' ', '?')
|
tail = cmd.replace(' ', '?')
|
||||||
reply = self.io.communicate(f'{head};{tail}')
|
reply = self.io.communicate(f'{head};{tail}')
|
||||||
return parse_result(reply)
|
return parse_result(reply)
|
||||||
@ -99,7 +104,7 @@ class Switcher(LakeShoreIO, ChannelSwitcher):
|
|||||||
if channelno is None:
|
if channelno is None:
|
||||||
self.status = 'ERROR', 'no enabled channel'
|
self.status = 'ERROR', 'no enabled channel'
|
||||||
return
|
return
|
||||||
self.set_param(f'SCAN {channelno},0')
|
self.set_param('SCAN ', channelno, 0)
|
||||||
|
|
||||||
def doPoll(self):
|
def doPoll(self):
|
||||||
"""poll buttons
|
"""poll buttons
|
||||||
@ -160,7 +165,7 @@ class Switcher(LakeShoreIO, ChannelSwitcher):
|
|||||||
self.measure_delay = chan.dwell
|
self.measure_delay = chan.dwell
|
||||||
|
|
||||||
def set_active_channel(self, chan):
|
def set_active_channel(self, chan):
|
||||||
self.set_param(f'SCAN {chan.channel},0')
|
self.set_param('SCAN ', chan.channel, 0)
|
||||||
chan._last_range_change = time.monotonic()
|
chan._last_range_change = time.monotonic()
|
||||||
self.set_delays(chan)
|
self.set_delays(chan)
|
||||||
|
|
||||||
@ -227,7 +232,7 @@ class ResChannel(LakeShoreIO, Channel):
|
|||||||
now = time.monotonic()
|
now = time.monotonic()
|
||||||
if now + 0.5 < max(self._last_range_change, self.switcher._start_switch) + self.pause:
|
if now + 0.5 < max(self._last_range_change, self.switcher._start_switch) + self.pause:
|
||||||
return None
|
return None
|
||||||
result = self.get_param(f'RDGR{self.channel}')
|
result = self.get_param(f'RDGR?{self.channel}')
|
||||||
if self.autorange:
|
if self.autorange:
|
||||||
self.fix_autorange()
|
self.fix_autorange()
|
||||||
if now + 0.5 > self._last_range_change + self.pause:
|
if now + 0.5 > self._last_range_change + self.pause:
|
||||||
@ -251,7 +256,7 @@ class ResChannel(LakeShoreIO, Channel):
|
|||||||
|
|
||||||
def read_value(self):
|
def read_value(self):
|
||||||
if self.channel == self.switcher.value == self.switcher.target:
|
if self.channel == self.switcher.value == self.switcher.target:
|
||||||
value = self._read_value()
|
value = self.get_value()
|
||||||
if value is not None:
|
if value is not None:
|
||||||
return value
|
return value
|
||||||
return self.value # return previous value
|
return self.value # return previous value
|
||||||
@ -264,7 +269,7 @@ class ResChannel(LakeShoreIO, Channel):
|
|||||||
|
|
||||||
@CommonReadHandler(rdgrng_params)
|
@CommonReadHandler(rdgrng_params)
|
||||||
def read_rdgrng(self):
|
def read_rdgrng(self):
|
||||||
iscur, exc, rng, autorange, excoff = self.get_param(f'RDGRNG{self.channel}')
|
iscur, exc, rng, autorange, excoff = self.get_param(f'RDGRNG?{self.channel}')
|
||||||
self._prev_rdgrng = iscur, exc
|
self._prev_rdgrng = iscur, exc
|
||||||
if autorange: # pressed autorange button
|
if autorange: # pressed autorange button
|
||||||
if not self._toggle_autorange:
|
if not self._toggle_autorange:
|
||||||
@ -293,8 +298,7 @@ class ResChannel(LakeShoreIO, Channel):
|
|||||||
excoff = 1
|
excoff = 1
|
||||||
rng = change['range']
|
rng = change['range']
|
||||||
if self.autorange:
|
if self.autorange:
|
||||||
if rng < self.minrange:
|
rng = max(rng, self.minrange)
|
||||||
rng = self.minrange
|
|
||||||
self.set_param(f'RDGRNG {self.channel}', iscur, exc, rng, 0, excoff)
|
self.set_param(f'RDGRNG {self.channel}', iscur, exc, rng, 0, excoff)
|
||||||
self.read_range()
|
self.read_range()
|
||||||
|
|
||||||
|
@ -16,84 +16,38 @@
|
|||||||
# Module authors:
|
# Module authors:
|
||||||
# Markus Zolliker <markus.zolliker@psi.ch>
|
# Markus Zolliker <markus.zolliker@psi.ch>
|
||||||
# *****************************************************************************
|
# *****************************************************************************
|
||||||
"""a very simple simulator for a LakeShore Model 370"""
|
"""a very simple simulator for LakeShore Models 370 and 372
|
||||||
|
|
||||||
|
reduced to the functionality actually used in e.g. frappy_psi.ls370res
|
||||||
|
"""
|
||||||
|
|
||||||
|
import time
|
||||||
from frappy.modules import Communicator
|
from frappy.modules import Communicator
|
||||||
|
|
||||||
|
|
||||||
class Ls370Sim(Communicator):
|
class _Ls37xSim(Communicator):
|
||||||
CHANNEL_COMMANDS = [
|
# commands containing %d for the channel number
|
||||||
('RDGR?%d', '1.0'),
|
|
||||||
('RDGST?%d', '0'),
|
|
||||||
('RDGRNG?%d', '0,5,5,0,0'),
|
|
||||||
('INSET?%d', '1,5,5,0,0'),
|
|
||||||
('FILTER?%d', '1,5,80'),
|
|
||||||
]
|
|
||||||
OTHER_COMMANDS = [
|
|
||||||
('*IDN?', 'LSCI,MODEL370,370184,05302003'),
|
|
||||||
('SCAN?', '3,1'),
|
|
||||||
('*OPC?', '1'),
|
|
||||||
]
|
|
||||||
|
|
||||||
def earlyInit(self):
|
|
||||||
super().earlyInit()
|
|
||||||
self._data = dict(self.OTHER_COMMANDS)
|
|
||||||
for fmt, v in self.CHANNEL_COMMANDS:
|
|
||||||
for chan in range(1,17):
|
|
||||||
self._data[fmt % chan] = v
|
|
||||||
|
|
||||||
def communicate(self, command):
|
|
||||||
self.comLog('> %s' % command)
|
|
||||||
# simulation part, time independent
|
|
||||||
for channel in range(1,17):
|
|
||||||
_, _, _, _, excoff = self._data['RDGRNG?%d' % channel].split(',')
|
|
||||||
if excoff == '1':
|
|
||||||
self._data['RDGST?%d' % channel] = '6'
|
|
||||||
else:
|
|
||||||
self._data['RDGST?%d' % channel] = '0'
|
|
||||||
|
|
||||||
chunks = command.split(';')
|
|
||||||
reply = []
|
|
||||||
for chunk in chunks:
|
|
||||||
if '?' in chunk:
|
|
||||||
reply.append(self._data[chunk])
|
|
||||||
else:
|
|
||||||
for nqarg in (1,0):
|
|
||||||
if nqarg == 0:
|
|
||||||
qcmd, arg = chunk.split(' ', 1)
|
|
||||||
qcmd += '?'
|
|
||||||
else:
|
|
||||||
qcmd, arg = chunk.split(',', nqarg)
|
|
||||||
qcmd = qcmd.replace(' ', '?', 1)
|
|
||||||
if qcmd in self._data:
|
|
||||||
self._data[qcmd] = arg
|
|
||||||
break
|
|
||||||
reply = ';'.join(reply)
|
|
||||||
self.comLog('< %s' % reply)
|
|
||||||
return reply
|
|
||||||
|
|
||||||
|
|
||||||
class Ls372Sim(Communicator):
|
|
||||||
CHANNEL_COMMANDS = [
|
CHANNEL_COMMANDS = [
|
||||||
('RDGR?%d', '1.0'),
|
('RDGR?%d', '1.0'),
|
||||||
('RDGK?%d', '1.5'),
|
('RDGK?%d', '1.5'),
|
||||||
('RDGST?%d', '0'),
|
('RDGST?%d', '0'),
|
||||||
('RDGRNG?%d', '0,5,5,0,0'),
|
('RDGRNG?%d', '0,5,5,0,0'),
|
||||||
('INSET?%d', '1,5,5,0,0'),
|
('INSET?%d', '1,3,3,0,0'),
|
||||||
('FILTER?%d', '1,5,80'),
|
('FILTER?%d', '1,5,80'),
|
||||||
]
|
]
|
||||||
|
# commands not related to a channel
|
||||||
OTHER_COMMANDS = [
|
OTHER_COMMANDS = [
|
||||||
('*IDN?', 'LSCI,MODEL372,372184,05302003'),
|
|
||||||
('SCAN?', '3,1'),
|
('SCAN?', '3,1'),
|
||||||
('PID?1', '10,10,0'),
|
|
||||||
('*OPC?', '1'),
|
('*OPC?', '1'),
|
||||||
]
|
]
|
||||||
|
|
||||||
def earlyInit(self):
|
def earlyInit(self):
|
||||||
super().earlyInit()
|
super().earlyInit()
|
||||||
|
self._res = {}
|
||||||
|
self._start = time.time()
|
||||||
self._data = dict(self.OTHER_COMMANDS)
|
self._data = dict(self.OTHER_COMMANDS)
|
||||||
for fmt, v in self.CHANNEL_COMMANDS:
|
for fmt, v in self.CHANNEL_COMMANDS:
|
||||||
for chan in range(1,17):
|
for chan in range(1, 17):
|
||||||
self._data[fmt % chan] = v
|
self._data[fmt % chan] = v
|
||||||
|
|
||||||
def communicate(self, command):
|
def communicate(self, command):
|
||||||
@ -105,6 +59,10 @@ class Ls372Sim(Communicator):
|
|||||||
self._data['RDGST?%d' % channel] = '6'
|
self._data['RDGST?%d' % channel] = '6'
|
||||||
else:
|
else:
|
||||||
self._data['RDGST?%d' % channel] = '0'
|
self._data['RDGST?%d' % channel] = '0'
|
||||||
|
channel = int(self._data['SCAN?'].split(',', 1)[0])
|
||||||
|
self._res[channel] = channel + (time.time() - self._start) / 3600
|
||||||
|
strvalue = f'{self._res[channel]:g}'
|
||||||
|
self._data['RDGR?%d' % channel] = self._data['RDGK?%d' % channel] = strvalue
|
||||||
|
|
||||||
chunks = command.split(';')
|
chunks = command.split(';')
|
||||||
reply = []
|
reply = []
|
||||||
@ -112,7 +70,7 @@ class Ls372Sim(Communicator):
|
|||||||
if '?' in chunk:
|
if '?' in chunk:
|
||||||
reply.append(self._data[chunk])
|
reply.append(self._data[chunk])
|
||||||
else:
|
else:
|
||||||
for nqarg in (1,0):
|
for nqarg in (1, 0):
|
||||||
if nqarg == 0:
|
if nqarg == 0:
|
||||||
qcmd, arg = chunk.split(' ', 1)
|
qcmd, arg = chunk.split(' ', 1)
|
||||||
qcmd += '?'
|
qcmd += '?'
|
||||||
@ -125,3 +83,16 @@ class Ls372Sim(Communicator):
|
|||||||
reply = ';'.join(reply)
|
reply = ';'.join(reply)
|
||||||
self.comLog('< %s' % reply)
|
self.comLog('< %s' % reply)
|
||||||
return reply
|
return reply
|
||||||
|
|
||||||
|
|
||||||
|
class Ls370Sim(_Ls37xSim):
|
||||||
|
OTHER_COMMANDS = _Ls37xSim.OTHER_COMMANDS + [
|
||||||
|
('*IDN?', 'LSCI,MODEL370,370184,05302003'),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class Ls372Sim(_Ls37xSim):
|
||||||
|
OTHER_COMMANDS = _Ls37xSim.OTHER_COMMANDS + [
|
||||||
|
('*IDN?', 'LSCI,MODEL372,372184,05302003'),
|
||||||
|
('PID?1', '10,10,0'),
|
||||||
|
]
|
||||||
|
@ -140,6 +140,15 @@ class SimpleMagfield(HasStates, Drivable):
|
|||||||
self.setFastPoll(True, 1.0)
|
self.setFastPoll(True, 1.0)
|
||||||
return self.start_ramp_to_target
|
return self.start_ramp_to_target
|
||||||
|
|
||||||
|
@status_code(Status.RAMPING)
|
||||||
|
def start_ramp_to_target(self, sm):
|
||||||
|
"""start ramping current to target field
|
||||||
|
|
||||||
|
initiate ramp to target
|
||||||
|
the implementation should return ramp_to_target
|
||||||
|
"""
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
@status_code(BUSY, 'ramping field')
|
@status_code(BUSY, 'ramping field')
|
||||||
def ramp_to_target(self, sm):
|
def ramp_to_target(self, sm):
|
||||||
if sm.init:
|
if sm.init:
|
||||||
@ -324,15 +333,6 @@ class Magfield(SimpleMagfield):
|
|||||||
self._last_target = sm.target
|
self._last_target = sm.target
|
||||||
return self.start_ramp_to_target
|
return self.start_ramp_to_target
|
||||||
|
|
||||||
@status_code(Status.RAMPING)
|
|
||||||
def start_ramp_to_target(self, sm):
|
|
||||||
"""start ramping current to target field
|
|
||||||
|
|
||||||
initiate ramp to target
|
|
||||||
the implementation should return ramp_to_target
|
|
||||||
"""
|
|
||||||
raise NotImplementedError
|
|
||||||
|
|
||||||
@status_code(Status.RAMPING)
|
@status_code(Status.RAMPING)
|
||||||
def ramp_to_target(self, sm):
|
def ramp_to_target(self, sm):
|
||||||
dif = abs(self.value - sm.target)
|
dif = abs(self.value - sm.target)
|
||||||
|
276
frappy_psi/oxinst.py
Normal file
276
frappy_psi/oxinst.py
Normal file
@ -0,0 +1,276 @@
|
|||||||
|
# *****************************************************************************
|
||||||
|
# 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>
|
||||||
|
# *****************************************************************************
|
||||||
|
"""oxford instruments old devices (ILM, IGH, IPS)"""
|
||||||
|
|
||||||
|
import re
|
||||||
|
import time
|
||||||
|
from frappy.core import StringIO, HasIO, Readable, Parameter, ERROR, IDLE, PREPARING
|
||||||
|
from frappy.datatypes import FloatRange, BoolType, EnumType
|
||||||
|
from frappy.errors import HardwareError, RangeError
|
||||||
|
from frappy.lib import formatStatusBits, clamp
|
||||||
|
from frappy.lib.enum import Enum
|
||||||
|
from frappy_psi.magfield import Magfield
|
||||||
|
from frappy.states import Retry
|
||||||
|
|
||||||
|
|
||||||
|
class IlmIO(StringIO):
|
||||||
|
end_of_line = '\r'
|
||||||
|
identification = [('V', r'ILM200.*')]
|
||||||
|
timeout = 5
|
||||||
|
|
||||||
|
|
||||||
|
class OxiBase(HasIO):
|
||||||
|
def query(self, cmd, dig=0):
|
||||||
|
reply = self.communicate(cmd)
|
||||||
|
if reply[0] == cmd[0]:
|
||||||
|
if '.' not in reply and dig > 0:
|
||||||
|
# add decimal point if not already there (for older systems)
|
||||||
|
reply = f'{reply[1:-dig]}.{reply[-dig:]}'
|
||||||
|
try:
|
||||||
|
value = float(reply)
|
||||||
|
return value
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
raise HardwareError(f'bad reply {reply!r} to {cmd!r}')
|
||||||
|
|
||||||
|
def command(self, *cmds):
|
||||||
|
try:
|
||||||
|
self.communicate('C3')
|
||||||
|
for cmd in cmds:
|
||||||
|
self.communicate(cmd)
|
||||||
|
finally:
|
||||||
|
self.communicate('C0')
|
||||||
|
|
||||||
|
def change(self, cmd, query, value):
|
||||||
|
try:
|
||||||
|
self.communicate('C3')
|
||||||
|
self.communicate(f'{cmd}{value:g}')
|
||||||
|
return self.query(query)
|
||||||
|
finally:
|
||||||
|
self.communicate('C0')
|
||||||
|
|
||||||
|
|
||||||
|
class Level(OxiBase, Readable):
|
||||||
|
ioClass = IlmIO
|
||||||
|
value = Parameter(datatype=FloatRange(unit='%'))
|
||||||
|
CHANNEL = None
|
||||||
|
XPAT = re.compile(r'X(\d)(\d)(\d)S([0-9A-F]{2}){3}R\d\d$')
|
||||||
|
FLUID = None
|
||||||
|
_statusbits = None
|
||||||
|
|
||||||
|
def read_value(self):
|
||||||
|
return self.query(f'R{self.CHANNEL}', 1)
|
||||||
|
|
||||||
|
def write_fast(self, fast):
|
||||||
|
self.command(f'T{self.CHANNEL}' if fast else f'S{self.CHANNEL}')
|
||||||
|
|
||||||
|
def get_status(self):
|
||||||
|
reply = self.communicate('X')
|
||||||
|
match = self.XPAT.match(reply)
|
||||||
|
if match:
|
||||||
|
statuslist = match.groups()
|
||||||
|
if statuslist[self.CHANNEL] == '9':
|
||||||
|
return ERROR, f'error on {self.FLUID} level channel (not connected?)'
|
||||||
|
if statuslist[self.CHANNEL] != '2':
|
||||||
|
return ERROR, f'{self.FLUID} level channel not configured properly'
|
||||||
|
self._statusbits = int(statuslist[self.CHANNEL + 3], 16)
|
||||||
|
return None
|
||||||
|
return ERROR, f'bad status message {reply}'
|
||||||
|
|
||||||
|
|
||||||
|
class HeLevel:
|
||||||
|
CHANNEL = 1
|
||||||
|
FLUID = 'He'
|
||||||
|
fast = Parameter('measuring mode: True is fast', BoolType())
|
||||||
|
|
||||||
|
def read_status(self):
|
||||||
|
status = self.get_status()
|
||||||
|
if status is not None:
|
||||||
|
return status
|
||||||
|
return IDLE, formatStatusBits(self._statusbits, ['meas', 'fast', 'slow'])
|
||||||
|
|
||||||
|
|
||||||
|
class N2Level:
|
||||||
|
CHANNEL = 2
|
||||||
|
MEDIUM = 'N2'
|
||||||
|
|
||||||
|
def read_status(self):
|
||||||
|
status = self.get_status()
|
||||||
|
if status is not None:
|
||||||
|
return status
|
||||||
|
return IDLE, ''
|
||||||
|
|
||||||
|
|
||||||
|
A = Enum(hold=0, run_to_set=1, run_to_zero=2, clamped=4)
|
||||||
|
|
||||||
|
|
||||||
|
class Field(OxiBase, Magfield):
|
||||||
|
action = Parameter('action', EnumType(A), readonly=False)
|
||||||
|
setpoint = Parameter('field setpoint', FloatRange(unit='T'), default=0)
|
||||||
|
voltage = Parameter('leads voltage', FloatRange(unit='V'), default=0)
|
||||||
|
atob = Parameter('field to amp', FloatRange(0, unit='A/T'), default=0)
|
||||||
|
working_ramp = Parameter('effective ramp', FloatRange(0, unit='T/min'), default=0)
|
||||||
|
persistent_field = Parameter(
|
||||||
|
'persistent field at last switch off', FloatRange(unit='$'), readonly=False)
|
||||||
|
wait_switch_on = Parameter(default=60)
|
||||||
|
wait_switch_off = Parameter(default=60)
|
||||||
|
forced_persistent_field = Parameter(
|
||||||
|
'manual indication that persistent field is bad', BoolType(), readonly=False, default=False)
|
||||||
|
|
||||||
|
XPAT = re.compile(r'X(\d)(\d)A(\d)C\dH(\d)M(\d\d)P\d\d$')
|
||||||
|
|
||||||
|
def startModule(self, start_events):
|
||||||
|
# on restart, assume switch is changed long time ago, if not, the mercury
|
||||||
|
# will complain and this will be handled in start_ramp_to_field
|
||||||
|
self.switch_on_time = 0
|
||||||
|
self.switch_off_time = 0
|
||||||
|
super().startModule(start_events)
|
||||||
|
|
||||||
|
def read_value(self):
|
||||||
|
current = self.query('R7')
|
||||||
|
if self.switch_heater == self.switch_heater.on:
|
||||||
|
self.__persistent_field = current
|
||||||
|
self.forced_persistent_field = False
|
||||||
|
self._field_mismatch = False
|
||||||
|
return current
|
||||||
|
pf = self.query('R18')
|
||||||
|
if self.__persistent_field is None:
|
||||||
|
self.__persistent_field = pf
|
||||||
|
self._field_mismatch = False
|
||||||
|
else:
|
||||||
|
self._field_mismatch = abs(self.__persistent_field - pf) > self.tolerance * 10
|
||||||
|
self.persistent_field = self.__persistent_field
|
||||||
|
return self.__persistent_field
|
||||||
|
|
||||||
|
def read_current(self):
|
||||||
|
current = self.query('R2')
|
||||||
|
return current / self.atob
|
||||||
|
|
||||||
|
def write_persistent_field(self, value):
|
||||||
|
if self.forced_persistent_field or abs(self.__persistent_field - value) <= self.tolerance * 10:
|
||||||
|
self._field_mismatch = False
|
||||||
|
self.__persistent_field = value
|
||||||
|
return value
|
||||||
|
raise RangeError('changing persistent field needs forced_persistent_field=True')
|
||||||
|
|
||||||
|
def write_target(self, target):
|
||||||
|
if self._field_mismatch:
|
||||||
|
self.forced_persistent_field = True
|
||||||
|
raise RangeError('persistent field does not match - set persistent field to guessed value first')
|
||||||
|
return super().write_target(target)
|
||||||
|
|
||||||
|
def read_status(self):
|
||||||
|
status = super().read_status() # from HasStates
|
||||||
|
reply = self.communicate('X')
|
||||||
|
match = self.XPAT.match(reply)
|
||||||
|
statuslist = match.group()
|
||||||
|
if statuslist[0] != '0':
|
||||||
|
return ERROR, formatStatusBits(int(statuslist[0]),
|
||||||
|
['quenched', 'overheated', 'warming up', 'fault'])
|
||||||
|
# TODO: statuslist[1]: voltage / current limit status
|
||||||
|
self.action = int(statuslist[2])
|
||||||
|
if statuslist[3] >= '4':
|
||||||
|
return ERROR, 'auto run-down'
|
||||||
|
self.switch_heater = statuslist[3] == '1'
|
||||||
|
if statuslist[3] == '5':
|
||||||
|
return ERROR, 'switch heater failure'
|
||||||
|
# TODO: sweep mode (fast, slow), sweep limits
|
||||||
|
return status
|
||||||
|
|
||||||
|
def read_ramp(self):
|
||||||
|
return self.query('R9')
|
||||||
|
|
||||||
|
def write_ramp(self, value):
|
||||||
|
return self.change('T', 'R9', value)
|
||||||
|
|
||||||
|
def write_action(self, value):
|
||||||
|
return self.change(f'A{int(value)}')
|
||||||
|
|
||||||
|
def read_voltage(self):
|
||||||
|
return self.query('R1')
|
||||||
|
|
||||||
|
def read_working_ramp(self):
|
||||||
|
return self.query('R6')
|
||||||
|
|
||||||
|
def read_setpoint(self):
|
||||||
|
return self.query('R8')
|
||||||
|
|
||||||
|
def write_setpoint(self, value):
|
||||||
|
return self.change('J', 'R8', value)
|
||||||
|
|
||||||
|
def write_switch_heater(self, value):
|
||||||
|
self.read_status()
|
||||||
|
if value == self.switch_heater:
|
||||||
|
self.log.info('switch heater already %r', value)
|
||||||
|
# we do not want to restart the timer
|
||||||
|
return value
|
||||||
|
self.command('H1')
|
||||||
|
|
||||||
|
# inherit Magfield.start_field_change
|
||||||
|
|
||||||
|
def start_ramp_to_field(self, sm):
|
||||||
|
if abs(self.current - self.__persistent_field) <= self.tolerance:
|
||||||
|
self.log.info('leads %g are already at %g', self.current, self.__persistent_field)
|
||||||
|
return self.ramp_to_field
|
||||||
|
self.read_value()
|
||||||
|
self.write_setpoint(self.__persistent_field)
|
||||||
|
self.write_action(A.run_to_set)
|
||||||
|
return self.ramp_to_field
|
||||||
|
|
||||||
|
# inherit from Magfield: ramp_to_field, stabilize_current, start_switch_on
|
||||||
|
|
||||||
|
def wait_for_switch_on(self, sm):
|
||||||
|
self.read_status()
|
||||||
|
if self.switch_heater == self.switch_heater.off:
|
||||||
|
if sm.init: # avoid too many states chained
|
||||||
|
return Retry
|
||||||
|
self.log.warning('switch turned off manually?')
|
||||||
|
return self.start_switch_on
|
||||||
|
return super().wait_for_switch_on(sm) # will eventually return start_ramp_to_target
|
||||||
|
|
||||||
|
def start_ramp_to_target(self, sm):
|
||||||
|
self.write_action(A.run_to_set)
|
||||||
|
return self.ramp_to_target
|
||||||
|
|
||||||
|
def ramp_to_target(self, sm):
|
||||||
|
step = self.ramp / 4 # step to be done in 15 seconds
|
||||||
|
# change the setpoint only gradually, ramping stoppes soon after connection is lost
|
||||||
|
self.write_setpoint(clamp(self.target, self.setpoint + step, self.setpoint - step))
|
||||||
|
return super().ramp_to_target() # will eventually return stabilize_field
|
||||||
|
|
||||||
|
# inherit from Magfield: stabilize_field, check_switch_off, start_switch_off
|
||||||
|
|
||||||
|
def wait_for_switch_off(self, sm):
|
||||||
|
self.read_status()
|
||||||
|
if self.switch_heater == self.switch_heater.on:
|
||||||
|
if sm.init: # avoid too many states chained
|
||||||
|
return Retry
|
||||||
|
self.log.warning('switch turned on manually?')
|
||||||
|
return self.start_switch_off
|
||||||
|
return super().wait_for_switch_off(sm) # will eventually return start_ramp_to_zero
|
||||||
|
|
||||||
|
def start_ramp_to_zero(self, sm):
|
||||||
|
self.write_action(A.run_to_zero)
|
||||||
|
return self.ramp_to_zero
|
||||||
|
|
||||||
|
# inherit from Magfield: ramp_to_zero
|
||||||
|
|
||||||
|
def final_status(self, *args, **kwds):
|
||||||
|
self.write_action(A.hold)
|
||||||
|
return super().final_status(*args, **kwds)
|
@ -166,7 +166,7 @@ class Motor(HasOffset, HasStates, PersistentMixin, HasIO, Drivable):
|
|||||||
def write_target(self, value):
|
def write_target(self, value):
|
||||||
self.read_alive_time()
|
self.read_alive_time()
|
||||||
if self._blocking_error:
|
if self._blocking_error:
|
||||||
self.status = ERROR, 'clear_errors needed after ' + self._blocking_error
|
self.status = ERROR, '<motor>.clear_errors() needed after ' + self._blocking_error
|
||||||
raise HardwareError(self.status[1])
|
raise HardwareError(self.status[1])
|
||||||
self.saveParameters()
|
self.saveParameters()
|
||||||
self.start_machine(self.starting, target=value)
|
self.start_machine(self.starting, target=value)
|
||||||
|
@ -48,7 +48,7 @@ class Base(HasIO):
|
|||||||
return self.communicate(f'smua.measure.{cmd} = {val}')
|
return self.communicate(f'smua.measure.{cmd} = {val}')
|
||||||
|
|
||||||
|
|
||||||
class Create_Pulse(Base, Readable, Writable):
|
class Create_Pulse(Base, Writable):
|
||||||
target = Parameter('source target', FloatRange, unit='A', readonly=False)
|
target = Parameter('source target', FloatRange, unit='A', readonly=False)
|
||||||
width = Parameter('pulse width', FloatRange, unit="s", readonly=False)
|
width = Parameter('pulse width', FloatRange, unit="s", readonly=False)
|
||||||
resistance = Parameter('resistance', FloatRange)
|
resistance = Parameter('resistance', FloatRange)
|
||||||
@ -72,3 +72,4 @@ class Create_Pulse(Base, Readable, Writable):
|
|||||||
|
|
||||||
|
|
||||||
class Script(Create_Pulse):
|
class Script(Create_Pulse):
|
||||||
|
pass
|
||||||
|
@ -36,11 +36,12 @@ import time
|
|||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from frappy.client import ProxyClient
|
from frappy.client import ProxyClient, CacheItem
|
||||||
from frappy.datatypes import ArrayOf, BoolType, \
|
from frappy.datatypes import ArrayOf, BoolType, \
|
||||||
EnumType, FloatRange, IntRange, StringType, StatusType
|
EnumType, FloatRange, IntRange, StringType, StatusType
|
||||||
from frappy.core import IDLE, BUSY, WARN, ERROR, DISABLED
|
from frappy.core import IDLE, BUSY, WARN, ERROR, DISABLED
|
||||||
from frappy.errors import ConfigError, HardwareError, ReadFailedError, CommunicationFailedError
|
from frappy.errors import ConfigError, HardwareError, ReadFailedError, \
|
||||||
|
CommunicationFailedError, ProgrammingError
|
||||||
from frappy.lib import generalConfig, mkthread, lazy_property
|
from frappy.lib import generalConfig, mkthread, lazy_property
|
||||||
from frappy.lib.asynconn import AsynConn, ConnectionClosed
|
from frappy.lib.asynconn import AsynConn, ConnectionClosed
|
||||||
from frappy.modulebase import Done
|
from frappy.modulebase import Done
|
||||||
@ -332,9 +333,10 @@ class SeaClient(ProxyClient, Module):
|
|||||||
self.secNode.srv.shutdown()
|
self.secNode.srv.shutdown()
|
||||||
else:
|
else:
|
||||||
for module, param in mplist:
|
for module, param in mplist:
|
||||||
oldv, oldt, oldr = self.cache.get((module, param), [None, None, None])
|
oldv, oldt, oldr = self.cache[module, param]
|
||||||
if value is None:
|
if value is None:
|
||||||
value = oldv
|
value = oldv
|
||||||
|
self.cache[module, param] = CacheItem(value, now, readerror)
|
||||||
if value != oldv or str(readerror) != str(oldr) or abs(now - oldt) > 60:
|
if value != oldv or str(readerror) != str(oldr) or abs(now - oldt) > 60:
|
||||||
# do not update unchanged values within 60 sec
|
# do not update unchanged values within 60 sec
|
||||||
self.updateValue(module, param, value, now, readerror)
|
self.updateValue(module, param, value, now, readerror)
|
||||||
@ -417,11 +419,24 @@ class SeaConfigCreator(SeaClient):
|
|||||||
return reply
|
return reply
|
||||||
|
|
||||||
|
|
||||||
|
class SeaBool(BoolType):
|
||||||
|
"""some sea enum nodes used as boolean have text type -> accept '<integer>' also"""
|
||||||
|
def copy(self):
|
||||||
|
return SeaBool()
|
||||||
|
|
||||||
|
def __call__(self, value):
|
||||||
|
try:
|
||||||
|
value = int(value)
|
||||||
|
return super().__call__(value)
|
||||||
|
except Exception as e:
|
||||||
|
raise ReadFailedError(e) from e
|
||||||
|
|
||||||
|
|
||||||
SEA_TO_SECOPTYPE = {
|
SEA_TO_SECOPTYPE = {
|
||||||
'float': FloatRange(),
|
'float': FloatRange(),
|
||||||
'text': StringType(),
|
'text': StringType(),
|
||||||
'int': IntRange(-1 << 63, 1 << 63 - 1),
|
'int': IntRange(-1 << 63, 1 << 63 - 1),
|
||||||
'bool': BoolType(),
|
'bool': SeaBool(),
|
||||||
'none': None,
|
'none': None,
|
||||||
'floatvarar': ArrayOf(FloatRange(), 0, 400), # 400 is the current limit for proper notify events in SEA
|
'floatvarar': ArrayOf(FloatRange(), 0, 400), # 400 is the current limit for proper notify events in SEA
|
||||||
}
|
}
|
||||||
@ -451,13 +466,19 @@ def get_datatype(paramdesc):
|
|||||||
raise ValueError('unknown SEA type %r' % typ)
|
raise ValueError('unknown SEA type %r' % typ)
|
||||||
|
|
||||||
|
|
||||||
|
def get_cfg(cfgdict, *args):
|
||||||
|
result = cfgdict.get(*args)
|
||||||
|
return result['value'] if isinstance(result, dict) else result
|
||||||
|
|
||||||
|
|
||||||
|
def pop_cfg(cfgdict, *args):
|
||||||
|
result = cfgdict.pop(*args)
|
||||||
|
return result['value'] if isinstance(result, dict) else result
|
||||||
|
|
||||||
|
|
||||||
class SeaModule(Module):
|
class SeaModule(Module):
|
||||||
io = Attached()
|
io = Attached()
|
||||||
|
|
||||||
path2param = None
|
|
||||||
sea_object = None
|
|
||||||
hdbpath = None # hdbpath for main writable
|
|
||||||
|
|
||||||
# pylint: disable=too-many-statements,arguments-differ,too-many-branches
|
# pylint: disable=too-many-statements,arguments-differ,too-many-branches
|
||||||
def __new__(cls, name, logger, cfgdict, srv):
|
def __new__(cls, name, logger, cfgdict, srv):
|
||||||
if hasattr(srv, 'extra_sea_modules'):
|
if hasattr(srv, 'extra_sea_modules'):
|
||||||
@ -465,90 +486,100 @@ class SeaModule(Module):
|
|||||||
else:
|
else:
|
||||||
extra_modules = {}
|
extra_modules = {}
|
||||||
srv.extra_sea_modules = extra_modules
|
srv.extra_sea_modules = extra_modules
|
||||||
for k, v in cfgdict.items():
|
|
||||||
try:
|
|
||||||
cfgdict[k] = v['value']
|
|
||||||
except (KeyError, TypeError):
|
|
||||||
pass
|
|
||||||
json_file = cfgdict.pop('json_file', None) or SeaClient.default_json_file[cfgdict['io']]
|
|
||||||
visibility_level = cfgdict.pop('visibility_level', 2)
|
|
||||||
|
|
||||||
single_module = cfgdict.pop('single_module', None)
|
json_file = pop_cfg(cfgdict, 'json_file', None) or SeaClient.default_json_file[get_cfg(cfgdict, 'io')]
|
||||||
|
visibility_level = pop_cfg(cfgdict, 'visibility_level', 2)
|
||||||
|
|
||||||
|
single_module = pop_cfg(cfgdict, 'single_module', None)
|
||||||
if single_module:
|
if single_module:
|
||||||
sea_object, base, paramdesc = extra_modules[single_module]
|
sea_object, base, paramdesc = extra_modules[single_module]
|
||||||
params = [paramdesc]
|
params = [paramdesc]
|
||||||
paramdesc['key'] = 'value'
|
paramdesc['key'] = 'value'
|
||||||
if issubclass(cls, SeaWritable):
|
if issubclass(cls, SeaWritable): # and not SeaDrivable!
|
||||||
if paramdesc.get('readonly', True):
|
if paramdesc.get('readonly', True):
|
||||||
raise ConfigError(f"{sea_object}/{paramdesc['path']} is not writable")
|
raise ConfigError(f"{sea_object}/{paramdesc['path']} is not writable")
|
||||||
params.insert(0, paramdesc.copy()) # copy value
|
params.insert(0, paramdesc.copy()) # copy value
|
||||||
paramdesc['key'] = 'target'
|
paramdesc['key'] = 'target'
|
||||||
paramdesc['readonly'] = False
|
paramdesc['readonly'] = False
|
||||||
extra_module_set = ()
|
extra_module_set = ()
|
||||||
if 'description' not in cfgdict:
|
if not get_cfg(cfgdict, 'description'):
|
||||||
cfgdict['description'] = f'{single_module}@{json_file}'
|
cfgdict['description'] = f'{single_module}@{json_file}'
|
||||||
else:
|
else:
|
||||||
sea_object = cfgdict.pop('sea_object')
|
sea_object = pop_cfg(cfgdict, 'sea_object', None)
|
||||||
rel_paths = cfgdict.pop('rel_paths', '.')
|
sea_path = pop_cfg(cfgdict, 'sea_path', None)
|
||||||
if 'description' not in cfgdict:
|
if sea_object:
|
||||||
|
if sea_path:
|
||||||
|
raise ConfigError(f'module {name}: superfluous sea_object property (sea_path is given)')
|
||||||
|
sea_path = sea_object
|
||||||
|
rel_paths = get_cfg(cfgdict, 'rel_paths', None)
|
||||||
|
if rel_paths is None:
|
||||||
|
sea_object, *rel_paths = sea_path.split('/', 1)
|
||||||
|
if not rel_paths:
|
||||||
|
rel_paths = None
|
||||||
|
else:
|
||||||
|
if '/' in sea_path:
|
||||||
|
raise ConfigError(f'module {name}: superfluous rel_paths property (sea_path is given)')
|
||||||
|
sea_object = sea_path
|
||||||
|
# rel_paths:
|
||||||
|
# a list of sub nodes to look for parameters
|
||||||
|
# '.' denotes the main path
|
||||||
|
# Readable: the main value is taken from the first subpath
|
||||||
|
# Writable:
|
||||||
|
# - read the target value: <sicsobj> target
|
||||||
|
# - write target value: command from first subpath
|
||||||
|
# Drivable:
|
||||||
|
# - write target value: run <sea_object> <target>
|
||||||
|
if not get_cfg(cfgdict, 'description'):
|
||||||
cfgdict['description'] = '%s@%s%s' % (
|
cfgdict['description'] = '%s@%s%s' % (
|
||||||
name, json_file, '' if rel_paths == '.' else f' (rel_paths={rel_paths})')
|
name, json_file, '' if rel_paths is None else f' (rel_paths={rel_paths})')
|
||||||
|
|
||||||
with (seaconfig.dir / json_file).open(encoding='utf-8') as fp:
|
with (seaconfig.dir / json_file).open(encoding='utf-8') as fp:
|
||||||
content = json.load(fp)
|
content = json.load(fp)
|
||||||
descr = content[sea_object]
|
descr = content[sea_object]
|
||||||
if rel_paths == '*' or not rel_paths:
|
|
||||||
# take all
|
|
||||||
main = descr['params'][0]
|
|
||||||
if issubclass(cls, Readable):
|
|
||||||
# assert main['path'] == '' # TODO: check cases where this fails
|
|
||||||
main['key'] = 'value'
|
|
||||||
else:
|
|
||||||
descr['params'].pop(0)
|
|
||||||
else:
|
|
||||||
# filter by relative paths
|
# filter by relative paths
|
||||||
result = []
|
if rel_paths:
|
||||||
|
result = {k: [] for k in rel_paths}
|
||||||
|
else:
|
||||||
|
result = {True: []}
|
||||||
is_running = None
|
is_running = None
|
||||||
for rpath in rel_paths:
|
|
||||||
include = True
|
|
||||||
for paramdesc in descr['params']:
|
for paramdesc in descr['params']:
|
||||||
path = paramdesc['path']
|
path = paramdesc['path']
|
||||||
if path.endswith('is_running') and issubclass(cls, Drivable):
|
pathlist = path.split('/')
|
||||||
|
if pathlist[-1] == 'is_running' and issubclass(cls, Drivable):
|
||||||
# take this independent of visibility
|
# take this independent of visibility
|
||||||
is_running = paramdesc
|
is_running = paramdesc
|
||||||
continue
|
continue
|
||||||
if paramdesc.get('visibility', 1) > visibility_level:
|
if paramdesc.get('visibility', 1) > visibility_level:
|
||||||
continue
|
continue
|
||||||
sub = path.split('/', 1)
|
if rel_paths is None:
|
||||||
if rpath == '.': # take all except subpaths with readonly node at top
|
result[True].append(paramdesc)
|
||||||
if len(sub) == 1:
|
else:
|
||||||
include = paramdesc.get('kids', 0) == 0 or not paramdesc.get('readonly', True)
|
cls.paramFilter(result, paramdesc)
|
||||||
if include or path == '':
|
cfgdict.pop('rel_paths', None)
|
||||||
result.append(paramdesc)
|
params = sum(result.values(), [])
|
||||||
elif sub[0] == rpath:
|
|
||||||
result.append(paramdesc)
|
|
||||||
if is_running: # take this at end
|
if is_running: # take this at end
|
||||||
result.append(is_running)
|
params.append(is_running)
|
||||||
descr['params'] = result
|
|
||||||
rel0 = '' if rel_paths[0] == '.' else rel_paths[0]
|
main_value = params[0]
|
||||||
if result[0]['path'] == rel0:
|
|
||||||
if issubclass(cls, Readable):
|
if issubclass(cls, Readable):
|
||||||
result[0]['key'] = 'value'
|
if 'key' in main_value:
|
||||||
|
raise ProgrammingError(f'main_value {main_value!r}')
|
||||||
|
main_value['key'] = 'value'
|
||||||
else:
|
else:
|
||||||
result.pop(0)
|
params.pop(0)
|
||||||
else:
|
|
||||||
logger.error('%s: no value found', name)
|
|
||||||
base = descr['base']
|
base = descr['base']
|
||||||
params = descr['params']
|
if issubclass(cls, SeaWritable): # and not SeaDrivable!
|
||||||
if issubclass(cls, SeaWritable):
|
|
||||||
paramdesc = params[0]
|
paramdesc = params[0]
|
||||||
assert paramdesc['key'] == 'value'
|
if paramdesc.get('key') != 'value':
|
||||||
|
raise ProgrammingError(f"key of first parameter of {name} must be 'value'")
|
||||||
params.append(paramdesc.copy()) # copy value?
|
params.append(paramdesc.copy()) # copy value?
|
||||||
if paramdesc.get('readonly', True):
|
if paramdesc.get('readonly', True):
|
||||||
raise ConfigError(f"{sea_object}/{paramdesc['path']} is not writable")
|
raise ConfigError(f"{sea_object}/{paramdesc['path']} is not writable")
|
||||||
paramdesc['key'] = 'target'
|
paramdesc['key'] = 'target'
|
||||||
paramdesc['readonly'] = False
|
paramdesc['readonly'] = False
|
||||||
extra_module_set = set(cfgdict.pop('extra_modules', ()))
|
|
||||||
|
extra_module_set = set(pop_cfg(cfgdict, 'extra_modules', ()))
|
||||||
path2param = {}
|
path2param = {}
|
||||||
attributes = {'sea_object': sea_object, 'path2param': path2param}
|
attributes = {'sea_object': sea_object, 'path2param': path2param}
|
||||||
|
|
||||||
@ -559,14 +590,14 @@ class SeaModule(Module):
|
|||||||
attributes['visibility'] = 2
|
attributes['visibility'] = 2
|
||||||
# check for ambiguous names. candidates are either the last item
|
# check for ambiguous names. candidates are either the last item
|
||||||
# of the path or the full path (underscore separated)
|
# of the path or the full path (underscore separated)
|
||||||
simple_names = {k: 1 for k in cls.accessibles}
|
duplicates = {k: [k] for k in cls.accessibles}
|
||||||
for paramdesc in params:
|
for paramdesc in params:
|
||||||
path = paramdesc['path']
|
path = paramdesc['path']
|
||||||
if path:
|
if path:
|
||||||
pathlist = path.split('/')
|
pathlist = path.split('/')
|
||||||
if 'key' not in paramdesc:
|
if 'key' not in paramdesc:
|
||||||
pname = pathlist[-1]
|
pname = pathlist[-1]
|
||||||
simple_names[pname] = simple_names.get(pname, 0) + 1
|
duplicates.setdefault(pname, pathlist)
|
||||||
for paramdesc in params:
|
for paramdesc in params:
|
||||||
path = paramdesc['path']
|
path = paramdesc['path']
|
||||||
readonly = paramdesc.get('readonly', True)
|
readonly = paramdesc.get('readonly', True)
|
||||||
@ -583,11 +614,11 @@ class SeaModule(Module):
|
|||||||
if len(pathlist) > 0:
|
if len(pathlist) > 0:
|
||||||
if len(pathlist) == 1:
|
if len(pathlist) == 1:
|
||||||
if issubclass(cls, Readable):
|
if issubclass(cls, Readable):
|
||||||
kwds['group'] = 'more'
|
kwds['group'] = 'more_'
|
||||||
else:
|
else:
|
||||||
kwds['group'] = pathlist[-2]
|
kwds['group'] = pathlist[-2] + '_'
|
||||||
# take short name if unique
|
# take short name if unique
|
||||||
if simple_names[pathlist[-1]] == 1:
|
if duplicates[pathlist[-1]] == pathlist:
|
||||||
key = pathlist[-1]
|
key = pathlist[-1]
|
||||||
else:
|
else:
|
||||||
key = '_'.join(pathlist)
|
key = '_'.join(pathlist)
|
||||||
@ -595,29 +626,39 @@ class SeaModule(Module):
|
|||||||
kwds['export'] = False
|
kwds['export'] = False
|
||||||
if key == 'target' and kwds.get('group') == 'more':
|
if key == 'target' and kwds.get('group') == 'more':
|
||||||
kwds.pop('group')
|
kwds.pop('group')
|
||||||
|
prev = cls.accessibles.get(key)
|
||||||
if key in cls.accessibles:
|
if key in cls.accessibles:
|
||||||
if key == 'target':
|
if key == 'target':
|
||||||
kwds['readonly'] = False
|
kwds['readonly'] = False
|
||||||
prev = cls.accessibles[key]
|
|
||||||
if key == 'status':
|
if key == 'status':
|
||||||
# special case: status from sea is a string, not the status tuple
|
# special case: status from sea is a string, not the status tuple
|
||||||
pobj = prev.copy()
|
pobj = prev.copy()
|
||||||
else:
|
else:
|
||||||
pobj = Parameter(**kwds)
|
pobj = Parameter(**kwds)
|
||||||
merged_properties = prev.propertyValues.copy()
|
|
||||||
pobj.updateProperties(merged_properties)
|
|
||||||
pobj.merge(merged_properties)
|
|
||||||
else:
|
else:
|
||||||
pobj = Parameter(**kwds)
|
pobj = Parameter(**kwds)
|
||||||
datatype = pobj.datatype
|
datatype = pobj.datatype
|
||||||
if issubclass(cls, SeaWritable) and key == 'target':
|
if issubclass(cls, SeaWritable) and key == 'target':
|
||||||
kwds['readonly'] = False
|
kwds['readonly'] = False
|
||||||
attributes['value'] = Parameter(**kwds)
|
attributes['target'] = pobj = Parameter(**kwds)
|
||||||
|
if prev:
|
||||||
|
merged_properties = prev.propertyValues.copy()
|
||||||
|
pobj.updateProperties(merged_properties)
|
||||||
|
pobj.merge(merged_properties)
|
||||||
|
|
||||||
|
if key in ('value', 'target'):
|
||||||
|
unit = get_cfg(cfgdict, 'unit')
|
||||||
|
if unit is not None:
|
||||||
|
pcfg = cfgdict.get(key, None)
|
||||||
|
if not isinstance(pcfg, dict):
|
||||||
|
cfgdict[key] = pcfg = {} if pcfg is None else {'value': pcfg}
|
||||||
|
pcfg['unit'] = unit
|
||||||
|
|
||||||
hdbpath = '/'.join([base] + pathlist)
|
hdbpath = '/'.join([base] + pathlist)
|
||||||
if key in extra_module_set:
|
if key in extra_module_set:
|
||||||
extra_modules[name + '.' + key] = sea_object, base, paramdesc
|
extra_modules[name + '.' + key] = sea_object, base, paramdesc
|
||||||
continue # skip this parameter
|
continue # skip this parameter
|
||||||
|
if key is not None:
|
||||||
path2param.setdefault(hdbpath, []).append((name, key))
|
path2param.setdefault(hdbpath, []).append((name, key))
|
||||||
attributes[key] = pobj
|
attributes[key] = pobj
|
||||||
|
|
||||||
@ -631,7 +672,7 @@ class SeaModule(Module):
|
|||||||
return reply
|
return reply
|
||||||
|
|
||||||
rfunc.poll = False
|
rfunc.poll = False
|
||||||
if key != 'status':
|
if key != 'status' and key is not None:
|
||||||
attributes['read_' + key] = rfunc
|
attributes['read_' + key] = rfunc
|
||||||
|
|
||||||
if not readonly:
|
if not readonly:
|
||||||
@ -645,7 +686,7 @@ class SeaModule(Module):
|
|||||||
self.io.query(cmd)
|
self.io.query(cmd)
|
||||||
return Done
|
return Done
|
||||||
|
|
||||||
attributes['write_' + key] = wfunc
|
attributes['write_' + (key or 'target')] = wfunc
|
||||||
|
|
||||||
# create standard parameters like value and status, if not yet there
|
# create standard parameters like value and status, if not yet there
|
||||||
for pname, pobj in cls.accessibles.items():
|
for pname, pobj in cls.accessibles.items():
|
||||||
@ -659,10 +700,23 @@ class SeaModule(Module):
|
|||||||
pobj.__set_name__(cls, pname)
|
pobj.__set_name__(cls, pname)
|
||||||
|
|
||||||
classname = f'{cls.__name__}_{name}'
|
classname = f'{cls.__name__}_{name}'
|
||||||
|
try:
|
||||||
newcls = type(classname, (cls,), attributes)
|
newcls = type(classname, (cls,), attributes)
|
||||||
|
except Exception as e:
|
||||||
|
raise
|
||||||
|
# newcls = type(classname, (cls,), attributes)
|
||||||
result = Module.__new__(newcls)
|
result = Module.__new__(newcls)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def paramFilter(cls, result, paramdesc):
|
||||||
|
sub = paramdesc['path'].split('/', 1)
|
||||||
|
sublist = result.get(sub[0])
|
||||||
|
if sublist is None:
|
||||||
|
return False
|
||||||
|
sublist.append(paramdesc)
|
||||||
|
return True
|
||||||
|
|
||||||
def updateEvent(self, module, parameter, value, timestamp, readerror):
|
def updateEvent(self, module, parameter, value, timestamp, readerror):
|
||||||
upd = getattr(self, 'update_' + parameter, None)
|
upd = getattr(self, 'update_' + parameter, None)
|
||||||
if upd:
|
if upd:
|
||||||
@ -679,6 +733,7 @@ class SeaReadable(SeaModule, Readable):
|
|||||||
_readerror = None
|
_readerror = None
|
||||||
_status = IDLE, ''
|
_status = IDLE, ''
|
||||||
|
|
||||||
|
unit = Property('physical unit', StringType(isUTF8=True), default='')
|
||||||
status = Parameter(datatype=StatusType(Readable, 'DISABLED'))
|
status = Parameter(datatype=StatusType(Readable, 'DISABLED'))
|
||||||
|
|
||||||
def update_value(self, value, timestamp, readerror):
|
def update_value(self, value, timestamp, readerror):
|
||||||
@ -778,11 +833,6 @@ class SeaDrivable(SeaReadable, Drivable):
|
|||||||
return IDLE, f'started, but not running'
|
return IDLE, f'started, but not running'
|
||||||
return IDLE, ''
|
return IDLE, ''
|
||||||
|
|
||||||
def update_target(self, module, parameter, value, timestamp, readerror):
|
|
||||||
# TODO: check if this is needed
|
|
||||||
if value is not None:
|
|
||||||
self.target = value
|
|
||||||
|
|
||||||
@Command()
|
@Command()
|
||||||
def stop(self):
|
def stop(self):
|
||||||
"""propagate to SEA
|
"""propagate to SEA
|
||||||
@ -791,3 +841,20 @@ class SeaDrivable(SeaReadable, Drivable):
|
|||||||
- on EaseDriv this will set the stopped state
|
- on EaseDriv this will set the stopped state
|
||||||
"""
|
"""
|
||||||
self.io.query(f'{self.sea_object} is_running 0')
|
self.io.query(f'{self.sea_object} is_running 0')
|
||||||
|
|
||||||
|
|
||||||
|
class LscDrivable(SeaDrivable):
|
||||||
|
def __new__(cls, name, logger, cfgdict, srv):
|
||||||
|
cfgdict['rel_paths'] = [pop_cfg(cfgdict, 'sensor_path', 'tm'), '.',
|
||||||
|
pop_cfg(cfgdict, 'set_path', 'set'), 'dblctrl']
|
||||||
|
return super().__new__(cls, name, logger, cfgdict, srv)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def paramFilter(cls, result, paramdesc):
|
||||||
|
if super().paramFilter(result, paramdesc):
|
||||||
|
return True
|
||||||
|
pathlist = paramdesc['path'].split('/')
|
||||||
|
if len(pathlist) == 1 and paramdesc.get('kids', 0) == 0:
|
||||||
|
result['.'].append(paramdesc)
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
from frappy.core import Command, StringIO, Parameter, HasIO, \
|
from frappy.core import Command, StringIO, Parameter, HasIO, \
|
||||||
Drivable, FloatRange, IDLE, BUSY, ERROR, WARN, BoolType
|
Drivable, FloatRange, IDLE, BUSY, ERROR, WARN, BoolType
|
||||||
from frappy.structparam import StructParam
|
from frappy.extparams import StructParam
|
||||||
from frappy_psi.convergence import HasConvergence
|
from frappy_psi.convergence import HasConvergence
|
||||||
|
|
||||||
|
|
||||||
|
@ -19,17 +19,19 @@
|
|||||||
"""frappy support for ultrasound"""
|
"""frappy support for ultrasound"""
|
||||||
|
|
||||||
import math
|
import math
|
||||||
#import serial
|
|
||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
import frappy_psi.iqplot as iqplot
|
from frappy_psi.adq_mr import Adq, PEdata, RUSdata
|
||||||
from frappy_psi.adq_mr import Adq
|
|
||||||
from frappy.core import Attached, BoolType, Done, FloatRange, HasIO, \
|
from frappy.core import Attached, BoolType, Done, FloatRange, HasIO, \
|
||||||
IntRange, Module, Parameter, Readable, StringIO, StringType
|
IntRange, Module, Parameter, Readable, Writable, Drivable, StringIO, StringType, \
|
||||||
|
IDLE, BUSY, DISABLED, ERROR, TupleOf, ArrayOf, Command
|
||||||
from frappy.properties import Property
|
from frappy.properties import Property
|
||||||
|
#from frappy.modules import Collector
|
||||||
|
|
||||||
|
Collector = Readable
|
||||||
|
|
||||||
|
|
||||||
def fname_from_time(t, extension):
|
def fname_from_time(t, extension):
|
||||||
@ -52,10 +54,9 @@ class Roi(Readable):
|
|||||||
time = Parameter('start time', FloatRange(unit='nsec'), readonly=False)
|
time = Parameter('start time', FloatRange(unit='nsec'), readonly=False)
|
||||||
size = Parameter('interval (symmetric around time)', FloatRange(unit='nsec'), readonly=False)
|
size = Parameter('interval (symmetric around time)', FloatRange(unit='nsec'), readonly=False)
|
||||||
enable = Parameter('calculate this roi', BoolType(), readonly=False, default=True)
|
enable = Parameter('calculate this roi', BoolType(), readonly=False, default=True)
|
||||||
#status = Parameter(export=False)
|
|
||||||
pollinterval = Parameter(export=False)
|
pollinterval = Parameter(export=False)
|
||||||
|
|
||||||
interval = (0,0)
|
interval = (0, 0)
|
||||||
|
|
||||||
def initModule(self):
|
def initModule(self):
|
||||||
super().initModule()
|
super().initModule()
|
||||||
@ -65,6 +66,9 @@ class Roi(Readable):
|
|||||||
def calc_interval(self):
|
def calc_interval(self):
|
||||||
self.interval = (self.time - 0.5 * self.size, self.time + 0.5 * self.size)
|
self.interval = (self.time - 0.5 * self.size, self.time + 0.5 * self.size)
|
||||||
|
|
||||||
|
def read_status(self):
|
||||||
|
return (IDLE, '') if self.enable else (DISABLED, 'disabled')
|
||||||
|
|
||||||
def write_time(self, value):
|
def write_time(self, value):
|
||||||
self.time = value
|
self.time = value
|
||||||
self.calc_interval()
|
self.calc_interval()
|
||||||
@ -82,81 +86,29 @@ class Pars(Module):
|
|||||||
timestamp = Parameter('unix timestamp', StringType(), default='0', readonly=False)
|
timestamp = Parameter('unix timestamp', StringType(), default='0', readonly=False)
|
||||||
temperature = Parameter('T', FloatRange(unit='K'), default=0, readonly=False)
|
temperature = Parameter('T', FloatRange(unit='K'), default=0, readonly=False)
|
||||||
mf = Parameter('field', FloatRange(unit='T'), default=0, readonly=False)
|
mf = Parameter('field', FloatRange(unit='T'), default=0, readonly=False)
|
||||||
sr = Parameter('rotaion angle', FloatRange(unit='deg'), default=0, readonly=False)
|
sr = Parameter('rotation angle', FloatRange(unit='deg'), default=0, readonly=False)
|
||||||
|
|
||||||
|
|
||||||
class FreqStringIO(StringIO):
|
class FreqStringIO(StringIO):
|
||||||
end_of_line = '\r'
|
end_of_line = '\r'
|
||||||
|
|
||||||
|
|
||||||
class Frequency(HasIO, Readable):
|
class Frequency(HasIO, Writable):
|
||||||
pars = Attached()
|
value = Parameter('frequency', unit='Hz')
|
||||||
sr = Property('samples per record', datatype=IntRange(), default=16384)
|
|
||||||
maxy = Property('plot y scale', datatype=FloatRange(), default=0.5)
|
|
||||||
|
|
||||||
value = Parameter('frequency@I,q', datatype=FloatRange(unit='Hz'), default=0)
|
|
||||||
basefreq = Parameter('base frequency', FloatRange(unit='Hz'), readonly=False)
|
|
||||||
nr = Parameter('number of records', datatype=IntRange(1,10000), default=500)
|
|
||||||
freq = Parameter('target frequency', FloatRange(unit='Hz'), readonly=False)
|
|
||||||
bw = Parameter('bandwidth lowpassfilter', datatype=FloatRange(unit='Hz'),default=10E6)
|
|
||||||
amp = Parameter('amplitude', FloatRange(unit='dBm'), readonly=False)
|
amp = Parameter('amplitude', FloatRange(unit='dBm'), readonly=False)
|
||||||
control = Parameter('control loop on?', BoolType(), readonly=False, default=True)
|
|
||||||
time = Parameter('pulse start time', FloatRange(unit='nsec'),
|
|
||||||
readonly=False)
|
|
||||||
size = Parameter('pulse length (starting from time)', FloatRange(unit='nsec'),
|
|
||||||
readonly=False)
|
|
||||||
pulselen = Parameter('adjusted pulse length (integer number of periods)', FloatRange(unit='nsec'), default=1)
|
|
||||||
maxstep = Parameter('max frequency step', FloatRange(unit='Hz'), readonly=False,
|
|
||||||
default=10000)
|
|
||||||
minstep = Parameter('min frequency step for slope calculation', FloatRange(unit='Hz'),
|
|
||||||
readonly=False, default=4000)
|
|
||||||
slope = Parameter('inphase/frequency slope', FloatRange(), readonly=False,
|
|
||||||
default=1e6)
|
|
||||||
plot = Parameter('create plot images', BoolType(), readonly=False, default=True)
|
|
||||||
save = Parameter('save data', BoolType(), readonly=False, default=True)
|
|
||||||
pollinterval = Parameter(datatype=FloatRange(0,120))
|
|
||||||
|
|
||||||
|
last_change = 0
|
||||||
ioClass = FreqStringIO
|
ioClass = FreqStringIO
|
||||||
|
dif = None
|
||||||
|
|
||||||
lastfreq = None
|
def register_dif(self, dif):
|
||||||
old = None
|
self.dif = dif
|
||||||
starttime = None
|
|
||||||
interval = (0,0)
|
|
||||||
|
|
||||||
def earlyInit(self):
|
def write_target(self, value):
|
||||||
super().earlyInit()
|
self.communicate('FREQ %.15g;FREQ?' % value)
|
||||||
self.adq = Adq(self.nr, self.sr, self.bw)
|
self.last_change = time.time()
|
||||||
self.roilist = []
|
if self.dif:
|
||||||
self.write_nr(self.nr)
|
self.dif.read_value()
|
||||||
self.skipctrl = 0
|
|
||||||
self.plotter = iqplot.Plot(self.maxy)
|
|
||||||
self.calc_interval()
|
|
||||||
|
|
||||||
def calc_interval(self):
|
|
||||||
self.interval = (self.time, self.time + self.size)
|
|
||||||
|
|
||||||
def write_time(self, value):
|
|
||||||
self.time = value
|
|
||||||
self.calc_interval()
|
|
||||||
return Done
|
|
||||||
|
|
||||||
def write_size(self, value):
|
|
||||||
self.size = value
|
|
||||||
self.calc_interval()
|
|
||||||
return Done
|
|
||||||
|
|
||||||
def write_nr(self, value):
|
|
||||||
# self.pollinterval = value * 0.0001
|
|
||||||
return value
|
|
||||||
|
|
||||||
def register_roi(self, roi):
|
|
||||||
self.roilist.append(roi)
|
|
||||||
|
|
||||||
def set_freq(self):
|
|
||||||
freq = self.freq + self.basefreq
|
|
||||||
self.communicate('FREQ %.15g;FREQ?' % freq)
|
|
||||||
#self._iodev.readline().decode('ascii')
|
|
||||||
return freq
|
|
||||||
|
|
||||||
def write_amp(self, amp):
|
def write_amp(self, amp):
|
||||||
reply = self.communicate('AMPR %g;AMPR?' % amp)
|
reply = self.communicate('AMPR %g;AMPR?' % amp)
|
||||||
@ -166,94 +118,196 @@ class Frequency(HasIO, Readable):
|
|||||||
reply = self.communicate('AMPR?')
|
reply = self.communicate('AMPR?')
|
||||||
return float(reply)
|
return float(reply)
|
||||||
|
|
||||||
def write_freq(self, value):
|
|
||||||
self.skipctrl = 2 # suppress control for the 2 next steps
|
|
||||||
return value
|
|
||||||
|
|
||||||
def doPoll(self):
|
class FrequencyDif(Readable):
|
||||||
"""main poll loop body"""
|
freq = Attached(Frequency)
|
||||||
if self.lastfreq is None:
|
base = Parameter('base frequency', FloatRange(unit='Hz'), default=0)
|
||||||
self.lastfreq = self.set_freq()
|
value = Parameter('difference to base frequency', FloatRange(unit='Hz'), default=0)
|
||||||
self.adq.start()
|
|
||||||
if self.starttime is None:
|
def initModule(self):
|
||||||
|
super().initModule()
|
||||||
|
self.freq.register_dif(self)
|
||||||
|
|
||||||
|
def read_value(self):
|
||||||
|
return self.freq - self.base
|
||||||
|
|
||||||
|
|
||||||
|
class Base(Collector):
|
||||||
|
freq = Attached()
|
||||||
|
adq = Attached(Adq)
|
||||||
|
sr = Parameter('samples per record', datatype=IntRange(1, 1E9), default=16384)
|
||||||
|
pollinterval = Parameter(datatype=FloatRange(0, 120)) # allow pollinterval = 0
|
||||||
|
_data = None
|
||||||
|
_data_args = None
|
||||||
|
|
||||||
|
def read_status(self):
|
||||||
|
adqstate = self.adq.get_status()
|
||||||
|
if adqstate == Adq.BUSY:
|
||||||
|
return BUSY, 'acquiring'
|
||||||
|
if adqstate == Adq.UNDEFINED:
|
||||||
|
return ERROR, 'no data yet'
|
||||||
|
if adqstate == Adq.READY:
|
||||||
|
return IDLE, 'new data available'
|
||||||
|
return IDLE, ''
|
||||||
|
|
||||||
|
def get_data(self):
|
||||||
|
data = self.adq.get_data(*self._data_args)
|
||||||
|
if id(data) != id(self._data):
|
||||||
|
self._data = data
|
||||||
|
return data
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
class PulseEcho(Base):
|
||||||
|
value = Parameter("t, i, q, pulse curves",
|
||||||
|
TupleOf(*[ArrayOf(FloatRange(), 0, 16283) for _ in range(4)]), default=[[]] * 4)
|
||||||
|
nr = Parameter('number of records', datatype=IntRange(1, 9999), default=500)
|
||||||
|
bw = Parameter('bandwidth lowpassfilter', datatype=FloatRange(unit='Hz'), default=10E6)
|
||||||
|
control = Parameter('control loop on?', BoolType(), readonly=False, default=True)
|
||||||
|
time = Parameter('pulse start time', FloatRange(unit='nsec'),
|
||||||
|
readonly=False)
|
||||||
|
size = Parameter('pulse length (starting from time)', FloatRange(unit='nsec'),
|
||||||
|
readonly=False)
|
||||||
|
pulselen = Parameter('adjusted pulse length (integer number of periods)', FloatRange(unit='nsec'), default=1)
|
||||||
|
|
||||||
|
starttime = None
|
||||||
|
|
||||||
|
def initModule(self):
|
||||||
|
super().initModule()
|
||||||
|
self.adq = Adq()
|
||||||
|
self.adq.init(self.sr, self.nr)
|
||||||
|
self.roilist = []
|
||||||
|
|
||||||
|
def write_nr(self, value):
|
||||||
|
self.adq.init(self.sr, value)
|
||||||
|
|
||||||
|
def write_sr(self, value):
|
||||||
|
self.adq.init(value, self.nr)
|
||||||
|
|
||||||
|
def write_bw(self, value):
|
||||||
|
self.adq.bw_cutoff = value
|
||||||
|
|
||||||
|
def register_roi(self, roi):
|
||||||
|
self.roilist.append(roi)
|
||||||
|
|
||||||
|
def go(self):
|
||||||
self.starttime = time.time()
|
self.starttime = time.time()
|
||||||
times = []
|
self.adq.start()
|
||||||
times.append(('init', time.time()))
|
|
||||||
seadata = {p: float(getattr(self.pars, p)) for p in self.pars.parameters}
|
|
||||||
data = self.adq.getdata() # this will wait, if not yet finished
|
|
||||||
#save sample
|
|
||||||
#np.save('sample.dat',data)
|
|
||||||
times.append(('wait',time.time()))
|
|
||||||
if self.control:
|
|
||||||
freq = self.lastfreq # data was acquired at this freq
|
|
||||||
else:
|
|
||||||
freq = self.set_freq()
|
|
||||||
seadata['frequency'] = freq
|
|
||||||
if self.control:
|
|
||||||
self.lastfreq = self.set_freq()
|
|
||||||
times.append(('setf',time.time()))
|
|
||||||
self.adq.start() # start next acq
|
|
||||||
times.append(('start',time.time()))
|
|
||||||
roilist = [r for r in self.roilist if r.enable]
|
|
||||||
|
|
||||||
gates = self.adq.gates_and_curves(data, freq, self.interval,
|
def read_value(self):
|
||||||
|
if self.get_rawdata(): # new data available
|
||||||
|
roilist = [r for r in self.roilist if r.enable]
|
||||||
|
freq = self.freq.value
|
||||||
|
gates = self.adq.gates_and_curves(self._data, freq,
|
||||||
|
(self.time, self.time + self.size),
|
||||||
[r.interval for r in roilist])
|
[r.interval for r in roilist])
|
||||||
if self.save:
|
|
||||||
times.append(('save',time.time()))
|
|
||||||
tdata, idata, qdata, pdata = self.adq.curves
|
|
||||||
seadata['timestep'] = tdata[1] - tdata[0]
|
|
||||||
iqdata = np.array((idata, qdata, pdata), dtype='f4')
|
|
||||||
ts = seadata['timestamp']
|
|
||||||
if ts:
|
|
||||||
filename = fname_from_time(ts, '.npz')
|
|
||||||
seanp = np.array(list(seadata.items()), dtype=[('name', 'U16'), ('value', 'f8')])
|
|
||||||
np.savez(filename, seadata=seanp, iqdata=iqdata)
|
|
||||||
# can be load back via
|
|
||||||
# content = np.load(filename)
|
|
||||||
# content['seadata'], content['iqdata']
|
|
||||||
self.pulselen = self.adq.pulselen
|
|
||||||
times.append(('ana',time.time()))
|
|
||||||
if self.plot:
|
|
||||||
# get reduced interval from adq.sinW
|
|
||||||
pulseint = (self.interval[0], self.interval[0] + self.pulselen)
|
|
||||||
try:
|
|
||||||
self.plotter.plot(
|
|
||||||
self.adq.curves,
|
|
||||||
rois=[pulseint] + [r.interval for r in roilist],
|
|
||||||
average=([r.time for r in roilist],
|
|
||||||
[r.i for r in roilist],
|
|
||||||
[r.q for r in roilist]))
|
|
||||||
except Exception as e:
|
|
||||||
self.log.warning('can not plot %r' % e)
|
|
||||||
else:
|
|
||||||
self.plotter.close()
|
|
||||||
now = time.time()
|
|
||||||
times.append(('plot',now))
|
|
||||||
# print(' '.join('%s %5.3f' % (label, t - self.starttime) for label, t in times))
|
|
||||||
self.starttime = now
|
|
||||||
self.value = freq - self.basefreq
|
|
||||||
for i, roi in enumerate(roilist):
|
for i, roi in enumerate(roilist):
|
||||||
roi.i = a = gates[i][0]
|
roi.i = a = gates[i][0]
|
||||||
roi.q = b = gates[i][1]
|
roi.q = b = gates[i][1]
|
||||||
roi.value = math.sqrt(a ** 2 + b ** 2)
|
roi.value = math.sqrt(a ** 2 + b ** 2)
|
||||||
roi.phase = math.atan2(a,b) * 180 / math.pi
|
roi.phase = math.atan2(a, b) * 180 / math.pi
|
||||||
inphase = self.roilist[0].i
|
return self.adq.curves
|
||||||
if self.control:
|
|
||||||
newfreq = freq + inphase * self.slope - self.basefreq
|
# TODO: CONTROL
|
||||||
# step = sorted((-self.maxstep, inphase * self.slope, self.maxstep))[1]
|
# inphase = self.roilist[0].i
|
||||||
if self.old:
|
# if self.control:
|
||||||
fdif = freq - self.old[0]
|
# newfreq = freq + inphase * self.slope - self.basefreq
|
||||||
idif = inphase - self.old[1]
|
# # step = sorted((-self.maxstep, inphase * self.slope, self.maxstep))[1]
|
||||||
if abs(fdif) >= self.minstep:
|
# if self.old:
|
||||||
self.slope = - fdif / idif
|
# fdif = freq - self.old[0]
|
||||||
else:
|
# idif = inphase - self.old[1]
|
||||||
fdif = 0
|
# if abs(fdif) >= self.minstep:
|
||||||
idif = 0
|
# self.slope = - fdif / idif
|
||||||
newfreq = freq + self.minstep
|
# else:
|
||||||
self.old = (freq, inphase)
|
# fdif = 0
|
||||||
if self.skipctrl > 0: # do no control for some time after changing frequency
|
# idif = 0
|
||||||
self.skipctrl -= 1
|
# newfreq = freq + self.minstep
|
||||||
elif self.control:
|
# self.old = (freq, inphase)
|
||||||
self.freq = sorted((self.freq - self.maxstep, newfreq, self.freq + self.maxstep))[1]
|
# if self.skipctrl > 0: # do no control for some time after changing frequency
|
||||||
#print(times)
|
# self.skipctrl -= 1
|
||||||
return Done
|
# elif self.control:
|
||||||
|
# self.freq = sorted((self.freq - self.maxstep, newfreq, self.freq + self.maxstep))[1]
|
||||||
|
|
||||||
|
|
||||||
|
class RUS(Base):
|
||||||
|
value = Parameter('averaged (I, Q) tuple', TupleOf(FloatRange(), FloatRange()))
|
||||||
|
periods = Parameter('number of periods', IntRange(1, 9999), default=12)
|
||||||
|
scale = Parameter('scale,taking into account input attenuation', FloatRange(), default=0.1)
|
||||||
|
input_phase_stddev = Parameter('input signal quality', FloatRange(unit='rad'))
|
||||||
|
output_phase_slope = Parameter('output signal phase slope', FloatRange(unit='rad/sec'))
|
||||||
|
output_amp_slope = Parameter('output signal amplitude change', FloatRange(unit='1/sec'))
|
||||||
|
phase = Parameter('phase', FloatRange(unit='deg'))
|
||||||
|
amp = Parameter('amplitude', FloatRange())
|
||||||
|
|
||||||
|
starttime = None
|
||||||
|
_data_args = None
|
||||||
|
|
||||||
|
def initModule(self):
|
||||||
|
super().initModule()
|
||||||
|
self.adq = Adq()
|
||||||
|
# self.write_periods(self.periods)
|
||||||
|
|
||||||
|
def read_value(self):
|
||||||
|
if self._data_args is None:
|
||||||
|
return self.value # or may we raise as no value is defined yet?
|
||||||
|
data = self.get_data(RUSdata, *self._data_args)
|
||||||
|
if data:
|
||||||
|
# data available
|
||||||
|
data.calc_quality()
|
||||||
|
self.input_phase_stddev = data.input_stddev.imag
|
||||||
|
self.output_phase_slope = data.output_slope.imag
|
||||||
|
self.output_amp_slope = data.output_slope.real
|
||||||
|
|
||||||
|
iq = data.iq * self.scale
|
||||||
|
self.phase = np.arctan2(iq.imag, iq.real) * 180 / np.pi
|
||||||
|
self.amp = np.abs(iq.imag, iq.real)
|
||||||
|
return iq.real, iq.imag
|
||||||
|
return self.value
|
||||||
|
|
||||||
|
def go(self):
|
||||||
|
self.starttime = time.time()
|
||||||
|
freq = self.freq.value
|
||||||
|
self._data_args = (RUSdata, freq, self.periods)
|
||||||
|
self.sr = round(self.periods * self.adq.sample_rate / freq)
|
||||||
|
self.adq.init(self.sr, 1)
|
||||||
|
self.adq.start()
|
||||||
|
self.read_status()
|
||||||
|
|
||||||
|
|
||||||
|
class ControlLoop:
|
||||||
|
maxstep = Parameter('max frequency step', FloatRange(unit='Hz'), readonly=False,
|
||||||
|
default=10000)
|
||||||
|
minstep = Parameter('min frequency step for slope calculation', FloatRange(unit='Hz'),
|
||||||
|
readonly=False, default=4000)
|
||||||
|
slope = Parameter('inphase/frequency slope', FloatRange(), readonly=False,
|
||||||
|
default=1e6)
|
||||||
|
|
||||||
|
|
||||||
|
# class Frequency(HasIO, Readable):
|
||||||
|
# pars = Attached()
|
||||||
|
# curves = Attached(mandatory=False)
|
||||||
|
# maxy = Property('plot y scale', datatype=FloatRange(), default=0.5)
|
||||||
|
#
|
||||||
|
# value = Parameter('frequency@I,q', datatype=FloatRange(unit='Hz'), default=0)
|
||||||
|
# basefreq = Parameter('base frequency', FloatRange(unit='Hz'), readonly=False)
|
||||||
|
# nr = Parameter('number of records', datatype=IntRange(1,10000), default=500)
|
||||||
|
# sr = Parameter('samples per record', datatype=IntRange(1,1E9), default=16384)
|
||||||
|
# freq = Parameter('target frequency', FloatRange(unit='Hz'), readonly=False)
|
||||||
|
# bw = Parameter('bandwidth lowpassfilter', datatype=FloatRange(unit='Hz'),default=10E6)
|
||||||
|
# amp = Parameter('amplitude', FloatRange(unit='dBm'), readonly=False)
|
||||||
|
# control = Parameter('control loop on?', BoolType(), readonly=False, default=True)
|
||||||
|
# rusmode = Parameter('RUS mode on?', BoolType(), readonly=False, default=False)
|
||||||
|
# time = Parameter('pulse start time', FloatRange(unit='nsec'),
|
||||||
|
# readonly=False)
|
||||||
|
# size = Parameter('pulse length (starting from time)', FloatRange(unit='nsec'),
|
||||||
|
# readonly=False)
|
||||||
|
# pulselen = Parameter('adjusted pulse length (integer number of periods)', FloatRange(unit='nsec'), default=1)
|
||||||
|
# maxstep = Parameter('max frequency step', FloatRange(unit='Hz'), readonly=False,
|
||||||
|
# default=10000)
|
||||||
|
# minstep = Parameter('min frequency step for slope calculation', FloatRange(unit='Hz'),
|
||||||
|
# readonly=False, default=4000)
|
||||||
|
# slope = Parameter('inphase/frequency slope', FloatRange(), readonly=False,
|
||||||
|
# default=1e6)
|
||||||
|
# plot = Parameter('create plot images', BoolType(), readonly=False, default=True)
|
||||||
|
# save = Parameter('save data', BoolType(), readonly=False, default=True)
|
||||||
|
# pollinterval = Parameter(datatype=FloatRange(0,120))
|
||||||
|
@ -96,12 +96,14 @@ def print_commit(line):
|
|||||||
print(' '.join(output), title)
|
print(' '.join(output), title)
|
||||||
cnt[0] += 1
|
cnt[0] += 1
|
||||||
if cnt[0] % 50 == 0:
|
if cnt[0] % 50 == 0:
|
||||||
input(f' {br0:11s} {br1:11s}')
|
if input(f' {br0:11s} {br1:11s}'):
|
||||||
|
raise StopIteration()
|
||||||
|
|
||||||
|
|
||||||
(br0, log0), (br1, log1) = list(log_no.items())
|
(br0, log0), (br1, log1) = list(log_no.items())
|
||||||
no1 = 0
|
no1 = 0
|
||||||
for no0, line0 in enumerate(log0):
|
try:
|
||||||
|
for no0, line0 in enumerate(log0):
|
||||||
if line0[1]: # line not yet printed
|
if line0[1]: # line not yet printed
|
||||||
infodict = commits[line0[1]]
|
infodict = commits[line0[1]]
|
||||||
if len(infodict) > 1: # found a match
|
if len(infodict) > 1: # found a match
|
||||||
@ -114,3 +116,5 @@ for no0, line0 in enumerate(log0):
|
|||||||
print_commit(line1)
|
print_commit(line1)
|
||||||
no1 = no1end
|
no1 = no1end
|
||||||
print_commit(line0)
|
print_commit(line0)
|
||||||
|
except StopIteration:
|
||||||
|
pass
|
||||||
|
@ -1,2 +1,3 @@
|
|||||||
2024-01-29 wip develop
|
2024-01-29 wip develop
|
||||||
2024-01-29 wip mlz
|
2024-01-29 wip mlz
|
||||||
|
2024-10-01 wip sinq
|
||||||
|
@ -1,21 +0,0 @@
|
|||||||
# content of conftest.py
|
|
||||||
|
|
||||||
import pytest
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="module")
|
|
||||||
def constants():
|
|
||||||
# setup
|
|
||||||
class Constants:
|
|
||||||
ONE = 1
|
|
||||||
TWO = 2
|
|
||||||
c = Constants()
|
|
||||||
yield c
|
|
||||||
# teardown
|
|
||||||
del c
|
|
||||||
|
|
||||||
|
|
||||||
# pylint: disable=redefined-builtin
|
|
||||||
@pytest.fixture(scope="session")
|
|
||||||
def globals():
|
|
||||||
return {}
|
|
13
test/test_cfg_editor.py
Normal file
13
test/test_cfg_editor.py
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from frappy.gui.cfg_editor.utils import get_modules, get_interfaces
|
||||||
|
from frappy.lib import generalConfig
|
||||||
|
|
||||||
|
basedir = Path(__file__).parent.parent.absolute()
|
||||||
|
|
||||||
|
|
||||||
|
def test_imports():
|
||||||
|
generalConfig.testinit(basedir=basedir)
|
||||||
|
|
||||||
|
get_modules()
|
||||||
|
get_interfaces()
|
@ -137,5 +137,5 @@ def test_process_file(direc, log):
|
|||||||
|
|
||||||
|
|
||||||
def test_full(direc, log):
|
def test_full(direc, log):
|
||||||
ret = load_config('pyfile_cfg.py', log)
|
ret = load_config(['pyfile_cfg.py'], log)
|
||||||
do_asserts(ret)
|
do_asserts(ret)
|
||||||
|
62
test/test_discovery.py
Normal file
62
test/test_discovery.py
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
# *****************************************************************************
|
||||||
|
#
|
||||||
|
# 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>
|
||||||
|
#
|
||||||
|
# *****************************************************************************
|
||||||
|
"""Test discovery messages"""
|
||||||
|
|
||||||
|
from test.test_modules import LoggerStub
|
||||||
|
from frappy.protocol.discovery import UDPListener, MAX_MESSAGE_LEN
|
||||||
|
from frappy.version import get_version
|
||||||
|
|
||||||
|
|
||||||
|
def test_empty():
|
||||||
|
logger = LoggerStub()
|
||||||
|
udp = UDPListener('', '', ['tcp://0'], logger)
|
||||||
|
udp.firmware = ''
|
||||||
|
# 78 is the maximum overhead
|
||||||
|
assert 78 == len(udp._getMessage(2**16-1))
|
||||||
|
|
||||||
|
|
||||||
|
def test_basic():
|
||||||
|
logger = LoggerStub()
|
||||||
|
udp = UDPListener('eq', 'desc', ['tcp://1234'], logger)
|
||||||
|
assert udp.description == 'desc'
|
||||||
|
assert udp.equipment_id == 'eq'
|
||||||
|
assert udp.ports == [1234]
|
||||||
|
assert udp.firmware == 'FRAPPY ' + get_version()
|
||||||
|
|
||||||
|
|
||||||
|
def test_ascii_truncation():
|
||||||
|
logger = LoggerStub()
|
||||||
|
desc = 'a' * MAX_MESSAGE_LEN
|
||||||
|
udp = UDPListener('eq', desc, ['tcp://1234'], logger)
|
||||||
|
assert MAX_MESSAGE_LEN == len(udp._getMessage(65535))
|
||||||
|
fw = len(('FRAPPY ' + get_version()).encode('utf-8'))
|
||||||
|
expected_length = 430 - fw - 2
|
||||||
|
assert expected_length == len(udp.description)
|
||||||
|
|
||||||
|
|
||||||
|
def test_unicode_truncation():
|
||||||
|
logger = LoggerStub()
|
||||||
|
desc = '\U0001f604' * 400
|
||||||
|
udp = UDPListener('eq', desc, ['tcp://1234'], logger)
|
||||||
|
fw = len(('FRAPPY ' + get_version()).encode('utf-8'))
|
||||||
|
# 4 bytes per symbol, rounded down for the potential cut
|
||||||
|
expected_length = (430 - fw - 2) // 4
|
||||||
|
assert expected_length == len(udp.description)
|
@ -28,7 +28,7 @@ from glob import glob
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from frappy.datatypes import BoolType, FloatRange, StringType, IntRange, ScaledInteger
|
from frappy.datatypes import BoolType, FloatRange, StringType, IntRange, ScaledInteger
|
||||||
from frappy.errors import ProgrammingError, ConfigError, RangeError
|
from frappy.errors import ProgrammingError, ConfigError, RangeError, HardwareError
|
||||||
from frappy.modules import Communicator, Drivable, Readable, Module, Writable
|
from frappy.modules import Communicator, Drivable, Readable, Module, Writable
|
||||||
from frappy.params import Command, Parameter, Limit
|
from frappy.params import Command, Parameter, Limit
|
||||||
from frappy.rwhandler import ReadHandler, WriteHandler, nopoll
|
from frappy.rwhandler import ReadHandler, WriteHandler, nopoll
|
||||||
@ -141,12 +141,10 @@ def test_ModuleMagic():
|
|||||||
|
|
||||||
|
|
||||||
# first inherited accessibles
|
# first inherited accessibles
|
||||||
sortcheck1 = ['value', 'status', 'pollinterval', 'target', 'stop',
|
sortcheck1 = ['value', 'status', 'target', 'pollinterval', 'stop',
|
||||||
'param1', 'param2', 'cmd', 'a1', 'a2', 'cmd2']
|
'param1', 'param2', 'cmd', 'a1', 'a2', 'cmd2']
|
||||||
|
|
||||||
class Newclass2(Newclass1):
|
class Newclass2(Newclass1):
|
||||||
paramOrder = 'param1', 'param2', 'cmd', 'value'
|
|
||||||
|
|
||||||
@Command(description='another stuff')
|
@Command(description='another stuff')
|
||||||
def cmd2(self, arg):
|
def cmd2(self, arg):
|
||||||
return arg
|
return arg
|
||||||
@ -171,9 +169,9 @@ def test_ModuleMagic():
|
|||||||
def read_value(self):
|
def read_value(self):
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
# first inherited items not mentioned, then the ones mentioned in paramOrder, then the other new ones
|
# first predefined parameters, then in the order of inheritance
|
||||||
sortcheck2 = ['status', 'pollinterval', 'target', 'stop',
|
sortcheck2 = ['value', 'status', 'target', 'pollinterval', 'stop',
|
||||||
'a1', 'a2', 'cmd2', 'param1', 'param2', 'cmd', 'value', 'b2']
|
'param1', 'param2', 'cmd', 'a1', 'a2', 'cmd2', 'b2']
|
||||||
|
|
||||||
updates = {}
|
updates = {}
|
||||||
srv = ServerStub(updates)
|
srv = ServerStub(updates)
|
||||||
@ -245,7 +243,7 @@ def test_ModuleMagic():
|
|||||||
'export', 'group', 'description', 'features',
|
'export', 'group', 'description', 'features',
|
||||||
'meaning', 'visibility', 'implementation', 'interface_classes', 'target', 'stop',
|
'meaning', 'visibility', 'implementation', 'interface_classes', 'target', 'stop',
|
||||||
'status', 'param1', 'param2', 'cmd', 'a2', 'pollinterval', 'slowinterval', 'b2',
|
'status', 'param1', 'param2', 'cmd', 'a2', 'pollinterval', 'slowinterval', 'b2',
|
||||||
'cmd2', 'value', 'a1', 'omit_unchanged_within'}
|
'cmd2', 'value', 'a1', 'omit_unchanged_within', 'original_id'}
|
||||||
assert set(cfg['value'].keys()) == {
|
assert set(cfg['value'].keys()) == {
|
||||||
'group', 'export', 'relative_resolution',
|
'group', 'export', 'relative_resolution',
|
||||||
'visibility', 'unit', 'default', 'value', 'datatype', 'fmtstr',
|
'visibility', 'unit', 'default', 'value', 'datatype', 'fmtstr',
|
||||||
@ -943,3 +941,36 @@ def test_stop_doc(modcls):
|
|||||||
if (modcls.stop.description == Drivable.stop.description
|
if (modcls.stop.description == Drivable.stop.description
|
||||||
and modcls.stop.func != Drivable.stop.func):
|
and modcls.stop.func != Drivable.stop.func):
|
||||||
assert modcls.stop.func.__doc__ # stop method needs a doc string
|
assert modcls.stop.func.__doc__ # stop method needs a doc string
|
||||||
|
|
||||||
|
|
||||||
|
def test_write_error():
|
||||||
|
updates = {}
|
||||||
|
srv = ServerStub(updates)
|
||||||
|
|
||||||
|
class Mod(Module):
|
||||||
|
par = Parameter('', FloatRange(), readonly=False, default=0)
|
||||||
|
|
||||||
|
def read_par(self):
|
||||||
|
raise HardwareError('failure')
|
||||||
|
|
||||||
|
def write_par(self, value):
|
||||||
|
if value < 0:
|
||||||
|
raise RangeError('outside range')
|
||||||
|
|
||||||
|
a = Mod('a', LoggerStub(), {'description': 'test'}, srv)
|
||||||
|
|
||||||
|
# behaviour on read errors:
|
||||||
|
with pytest.raises(HardwareError):
|
||||||
|
a.read_par()
|
||||||
|
assert updates == {'a': {('error', 'par'): 'failure'}}
|
||||||
|
updates.clear()
|
||||||
|
|
||||||
|
# behaviour on normal write
|
||||||
|
a.write_par(1)
|
||||||
|
assert updates['a']['par'] == 1
|
||||||
|
updates.clear()
|
||||||
|
|
||||||
|
# behaviour when write failed
|
||||||
|
with pytest.raises(RangeError):
|
||||||
|
a.write_par(-1)
|
||||||
|
assert not updates # no error update!
|
||||||
|
@ -148,6 +148,8 @@ def test_Property_override():
|
|||||||
o2 = co()
|
o2 = co()
|
||||||
assert o1.a == 1
|
assert o1.a == 1
|
||||||
assert o2.a == 3
|
assert o2.a == 3
|
||||||
|
o2.setProperty('a', 4)
|
||||||
|
assert o2.a == 4
|
||||||
|
|
||||||
with pytest.raises(ProgrammingError) as e:
|
with pytest.raises(ProgrammingError) as e:
|
||||||
class cx(c): # pylint: disable=unused-variable
|
class cx(c): # pylint: disable=unused-variable
|
||||||
|
@ -57,13 +57,13 @@ def test_name_only(direc, log):
|
|||||||
|
|
||||||
def test_file(direc, log):
|
def test_file(direc, log):
|
||||||
"""only see that this does not throw. get config from cfgfiles."""
|
"""only see that this does not throw. get config from cfgfiles."""
|
||||||
s = Server('foo', log, cfgfiles='pyfile_cfg.py')
|
s = Server('foo', log, cfgfiles=['pyfile_cfg.py'])
|
||||||
s._processCfg()
|
s._processCfg()
|
||||||
|
|
||||||
|
|
||||||
def test_basic_description(direc, log):
|
def test_basic_description(direc, log):
|
||||||
"""only see that this does not throw. get config from cfgfiles."""
|
"""only see that this does not throw. get config from cfgfiles."""
|
||||||
s = Server('foo', log, cfgfiles='pyfile_cfg.py')
|
s = Server('foo', log, cfgfiles=['pyfile_cfg.py'])
|
||||||
s._processCfg()
|
s._processCfg()
|
||||||
desc = s.secnode.get_descriptive_data('')
|
desc = s.secnode.get_descriptive_data('')
|
||||||
# secnode properties correctly exported
|
# secnode properties correctly exported
|
||||||
|
@ -1,14 +0,0 @@
|
|||||||
|
|
||||||
from frappy.gui.cfg_editor.utils import get_modules
|
|
||||||
|
|
||||||
def test_assert():
|
|
||||||
assert 1
|
|
||||||
|
|
||||||
|
|
||||||
def test_constants(constants):
|
|
||||||
assert constants.ONE == 1
|
|
||||||
assert constants.TWO == 2
|
|
||||||
|
|
||||||
|
|
||||||
def test_imports():
|
|
||||||
get_modules()
|
|
Loading…
x
Reference in New Issue
Block a user