up to date with develop/mlz

Change-Id: I5ea71bc99a2f0dffc3dbe37e1119eb188ef8a3f0
This commit is contained in:
zolliker 2023-05-31 14:27:36 +02:00
parent c5d429346d
commit 9a6421a54f
8 changed files with 149 additions and 160 deletions

View File

@ -9,7 +9,7 @@
# Add <file or directory> to the black list. It should be a base name, not a
# path. You may set this option multiple times.
ignore = .git
ignore = .git,resources_qt5.py,resources_qt6.py
# Pickle collected data for later comparisons.
persistent=yes
@ -38,27 +38,21 @@ confidence=
# multiple time.
disable=missing-docstring
,locally-disabled
,locally-enabled
,fixme
,no-member
,bad-whitespace
,wrong-import-position
,ungrouped-imports
,import-self
,bad-continuation
,protected-access
,unused-argument
,duplicate-code
,attribute-defined-outside-init
,access-member-before-definition
,no-self-use
,broad-except
,unneeded-not
,unidiomatic-typecheck
,undefined-loop-variable
,redefined-variable-type
,deprecated-lambda
,consider-using-f-string
[REPORTS]
# Set the output format. Available formats are text, parseable, colorized, msvs
@ -67,10 +61,6 @@ disable=missing-docstring
msg-template={path}:{line}: [{msg_id}({symbol}), {obj}] {msg}
# Put messages in a separate file for each module / package specified on the
# command line instead of printing them on stdout. Reports (if any) will be
# written in a file name "pylint_global.[txt|html]".
files-output=no
# Tells whether to display a full report or only the messages
reports=no
@ -93,14 +83,11 @@ dummy-variables-rgx=_|dummy
# List of additional names supposed to be defined in builtins. Remember that
# you should avoid to define new builtins when possible.
additional-builtins=
additional-builtins=Node,Mod,Param,Command,Group
[BASIC]
# List of builtins function names that should not be used, separated by a comma
#bad-functions=map,filter,apply,input
bad-functions=apply,input
# Regular expression which should only match correct module names
module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9_]+))$
@ -155,12 +142,6 @@ notes=FIXME,XXX,TODO
# Maximum number of characters on a single line.
max-line-length=132
# List of optional constructs for which whitespace checking is disabled. `dict-
# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}.
# `trailing-comma` allows a space between comma and closing bracket: (a, ).
# `empty-line` allows space-only lines.
no-space-check=trailing-comma,dict-separator
# Maximum number of lines in a module
max-module-lines=1000

View File

@ -60,4 +60,3 @@ changes are done, eventually a sync step should happen:
cp -r secop /Volumes/PPMSData/zolliker/frappy/secop
it may be that additional folder have to copied ...

View File

@ -31,7 +31,6 @@ sys.path.insert(0, path.abspath(path.join(path.dirname(__file__), '..')))
import logging
from mlzlog import ColoredConsoleHandler
from frappy.gui.qt import QApplication
from frappy.gui.cfg_editor.mainwindow import MainWindow

38
frappy-server.spec Normal file
View File

@ -0,0 +1,38 @@
# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
a = Analysis(['bin\\frappy-server'],
pathex=['.'],
binaries=[],
datas=[],
hiddenimports=['frappy.protocol', 'frappy.protocol.dispatcher', 'frappy.protocol.interface', 'frappy.protocol.interface.tcp',
'frappy_psi.ppmssim', 'frappy_psi.ppmswindows', 'frappy_psi.ppms'],
hookspath=[],
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)
exe = EXE(pyz,
a.scripts,
[],
exclude_binaries=True,
name='frappy-server',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
console=True )
coll = COLLECT(exe,
a.binaries,
a.zipfiles,
a.datas,
strip=False,
upx=True,
upx_exclude=[],
name='frappy-server')

View File

@ -22,6 +22,7 @@
from frappy.core import Readable, Parameter, FloatRange, TupleOf, \
HasIO, StringIO, IntRange, BoolType, Writable, EnumType
from frappy.errors import RangeError
class SR_IO(StringIO):
@ -30,46 +31,65 @@ class SR_IO(StringIO):
def communicate(self, cmd): # remove dash from terminator
reply = super().communicate(cmd)
status = self._conn.readbytes(2, 0.1) # get the 2 status bytes
status = self._conn.readbytes(2, timeout=0.1) # get the 2 status bytes
return reply + ';%d;%d' % tuple(status)
class Ametek(StringIO, HasIO):
ioClass = SR_IO
def comm(self, cmd):
reply, status, overload = self.communicate(cmd).split(b';')
if overload != b'0':
self.status = (self.Status.WARN, f'overload {overload}')
self.status = (self.Status.IDLE, '')
return reply
class XY(Ametek, Readable):
class XY(HasIO, Readable):
value = Parameter('X, Y', datatype=TupleOf(FloatRange(unit='V'), FloatRange(unit='V')))
vmode = Parameter('control mode', EnumType(both_grounded=0, A=1, B=2, A_B_diff=3), readonly=False)
range = Parameter('sensitivity value', FloatRange(0.00, 1), unit='V', default=1)
autosen_on = Parameter('is auto sensitivity on', BoolType(), readonly=False)
noise_control = Parameter('noise control mode', BoolType(), readonly=False)
noise_control = Parameter('is noise control mode on', BoolType(), readonly=False)
phase = Parameter('reference phase control', FloatRange(-360, 360), unit='deg', readonly=False)
frequency = Parameter('oscill. frequen. control', FloatRange(0.001, 250e3), unit='Hz', readonly=False,
group='frequency')
amplitude = Parameter('oscill. amplit. control', FloatRange(0.00, 5), unit='V_rms', readonly=False)
#filter = Parameter('line frequency filter', unit='Hz')
sen_range = {name: value + 1 for value, name in enumerate(
['2nV', '5nV', '10nV', '20nV', '50nV', '100nV', '200nV', '500nV', '1uV',
'2uV', '5uV', '10uV', '20uV', '50uV', '100uV', '200uV', '500uV', '1mV',
'2mV', '5mV', '10mV', '20mV', '50mV', '100mV', '200mV', '500mV', '1V']
)}
irange = Parameter('sensitivity index', EnumType('sensitivity index range', sen_range), readonly=False)
time_const = {value: name for value, name in enumerate(
[('10us', 'N/A'), ('20us', 'N/A'), ('50us', 'N/A'), ('100us', 'N/A'),
('200us', 'N/A'), ('500us', '500us'), ('1ms', '1ms'), ('2ms', '2ms'),
('5ms', '5ms'), ('10ms', '10ms'), ('20ms', 'N/A'), ('50ms', 'N/A'),
('100ms', 'N/A'), ('200ms', 'N/A'), ('500ms', 'N/A'), ('1s', 'N/A'),
('2s', 'N/A'), ('5s', 'N/A'), ('10s', 'N/A'), ('20s', 'N/A'), ('50s', 'N/A'),
('100s', 'N/A'), ('200s', 'N/A'), ('500s', 'N/A'), ('1ks', 'N/A'),
('10ks', 'N/A'), ('20ks', 'N/A'), ('50ks', 'N/A'), ('100ks', 'N/A')]
time_const = {name: value for value, name in enumerate(
['10us', '20us', '50us', '100us', '200us', '500us', '1ms', '2ms', '5ms', '10ms',
'20ms', '50ms', '100ms', '200ms', '500ms', '1s', '2s', '5s', '10s', '20s', '50s',
'100s', '200s', '500s', '1ks', '10ks', '20ks', '50ks', '100ks']
)}
tc = Parameter('time const. value', FloatRange(0.00005, 100000), unit='s', readonly=False)
itc = Parameter('time const. index', EnumType('time const. index range', time_const), readonly=False)
ioClass = SR_IO
def comparison(self, curr_value, new_value, value_dict):
c_ind = None # closest index
c_diff = None # closets difference
for index, value in value_dict.items():
if c_diff is None or diff < c_diff:
c_ind = index
c_diff = c_diff
if abs(curr_value - new_value) < c_diff:
return c_ind
else:
for index, value in value_dict.items():
diff = abs(new_value - value)
if c_diff is None or diff < c_diff:
c_ind = index
c_diff = diff
return c_ind
def comm(self, cmd):
reply, status, overload = self.communicate(cmd).split(';')
if overload != '0':
self.status = (self.Status.WARN, f'overload {overload}')
self.status = (self.Status.IDLE, '')
return reply
def read_vmode(self):
return self.comm('VMODE')
@ -97,25 +117,11 @@ class XY(Ametek, Readable):
return self.comm('SEN.') # range value
def write_range(self):
self.comm(f'IMODE {0}')
self.comm(f'IMODE 0')
curr_value = self.read_range()
new_value = self.value
c_ind = None # closest parameters
c_diff = None
for index, value in self.sen_range.items():
diff = abs(curr_value - value)
if c_diff is None or diff < c_diff:
c_ind = index
c_diff = diff
if abs(curr_value - new_value) < c_diff:
return self.comm(f'SEN {c_ind}')
else:
for index, value in self.sen_range.items():
diff = abs(new_value - value)
if c_diff is None or diff < c_diff:
c_ind = index
c_diff = diff
return self.comm(f'SEN {c_ind}')
c_ind = self.comparison(curr_value, new_value, self.sen_range)
return self.comm(f'SEN {c_ind}')
def read_noise_control(self):
return self.comm('NOISEMODE')
@ -126,15 +132,24 @@ class XY(Ametek, Readable):
def read_tc(self):
return self.comm('TC.')
def read_itc(self):
return self.comm(f'TC')
def write_tc(self):
pass
# def write_tc(self, itc):
# if self.noise_control == 0:
# self.itc = self.
def read_itc(self):
return self.comm('TC')
def write_itc(self, new_itc):
curr_value = self.read_itc()
new_value = self.time_const[self.itc]
c_ind = self.comparison(curr_value, new_value, self.time_const)
if abs(curr_value - new_value) < c_diff:
if self.read_noise_control() == 1 and (5e-4 <= self.time_const[new_itc] <= 1e-2):
raise RangeError('not allowed with noisemode=1')
return self.comm(f'TC {new_itc}')
def read_value(self):
reply = self.comm('XY.').split(',')
reply = self.comm('XY.').split(b',')
x = float(reply[0])
y = float(reply[1])
return x, y
@ -142,68 +157,28 @@ class XY(Ametek, Readable):
def write_value(self, value):
return self.comm(f'XY {value}')
class Frequency(XY, Writable):
value = Parameter('oscill. frequen. control', FloatRange(0.001, 250e3), unit='Hz', readonly=False)
target = Parameter('target frequency', FloatRange(0.001, 250e3), unit='Hz', readonly=False)
def read_value(self):
def read_frequency(self):
return self.comm('OF.')
def write_target(self,):
target = self.target()
return self.comm(f'OF. {target}')
def write_frequency(self, frequency):
frequency = self.frequency
return self.comm(f'OF. {frequency}')
class Amplitude(XY, Writable):
value = Parameter('oscill. amplit. control', FloatRange(0.00, 5), unit='V_rms', readonly=False)
target = Parameter('target amplit.', FloatRange(0.00, 5), unit='V_rms', readonly=False)
# unify the following
# dac = Parameter('output DAC channel value', datatype=TupleOf(IntRange(1, 4), FloatRange(0.0, 5000, unit='mV')),
# readonly=False, initwrite=True, default=(3,0))
# dac = Parameter('output DAC channel value', FloatRange(-10000, 10000, unit='mV'),
# readonly=False, initwrite=True, default=0)
# oscillator amplitude module
def read_value(self):
def read_amplitude(self):
return self.comm('OA.')
def write_target(self):
target = self.target()
return self.comm(f'OA. {target}')
# external output DAC
# def read_dac(self):
# # reply = self.comm('DAC %g' % channel) # failed to add the DAC channel you want to control
# reply = self.comm('DAC 3') # stack to channel 3
# return reply
# def write_dac(self, value):
# # self.comm('DAC %g %g' % channel % value)
# self.comm('DAC 3 %g' % value)
# return value
def write_amplitude(self, amplitude):
return self.comm(f'OA. {amplitude}')
# phase and autophase
def read_phase(self):
reply = self.comm('REFP.')
return reply
return self.comm('REFP.')
def write_phase(self, value):
self.comm(f'REFP {round(1000 * value)}')
self.read_phase()
return value
return self.read_phase()
def aphase(self):
"""auto phase"""
self.read_phase()
return self.comm('AQN')
# class Comp(Ametek, Readable):
# enablePoll = False
# value = Parameter(datatype=FloatRange(unit='V'))
#
#
# class arg(Ametek, Readable):
# enablePoll = False
# value = Parameter(datatype=FloatRange(unit=''))

View File

@ -20,10 +20,10 @@
# *****************************************************************************
import math
from frappy.core import Readable, Parameter, IntRange, EnumType, FloatRange, \
from frappy.core import Readable, Parameter, IntRange, FloatRange, \
StringIO, HasIO, StringType, Property, Writable, Drivable, IDLE, ERROR, \
Attached, StructOf, WARN, Done, BoolType, Enum
StructOf, WARN, Done, BoolType, Enum
from frappy.errors import RangeError
from frappy_psi.convergence import HasConvergence
from frappy.mixins import HasOutputModule, HasControlledBy
@ -233,7 +233,7 @@ class HeaterOutput336(HeaterOutput):
else:
self._range = 1
user_current = max_current * math.sqrt(100)
self.set_par(f'HTRSET {self.loop}', <1 or 2>, 0, user_current, 1)
self.set_par(f'HTRSET {self.loop}', 1 if self.resistance < 50 else 2, 0, user_current, 1)
max_power = max_current ** 2 * self.resistance
self._max_power = max_power
self.set_range()

View File

@ -86,6 +86,29 @@ class ThermFishIO(StringIO):
class SensorA10(HasIO, Readable):
ioClass = ThermFishIO
value = Parameter('internal temperature', unit='degC')
status_messages = [
(ERROR, 'high tempr. cutout fault', 2, 0),
(ERROR, 'high RA tempr. fault', 2, 1),
(ERROR, 'high temperature fixed fault', 3, 7),
(ERROR, 'low temperature fixed fault', 3, 6),
(ERROR, 'high temperature fault', 3, 5),
(ERROR, 'low temperature fault', 3, 4),
(ERROR, 'low level fault', 3, 3),
(ERROR, 'circulator fault', 4, 5),
(ERROR, 'high press. cutout', 5, 2),
(ERROR, 'motor overloaded', 5, 1),
(ERROR, 'pump speed fault', 5, 0),
(WARN, 'open internal sensor', 1, 7),
(WARN, 'shorted internal sensor', 1, 6),
(WARN, 'high temperature warn', 3, 2),
(WARN, 'low temperature warn', 3, 1),
(WARN, 'low level warn', 3, 0),
(IDLE, 'max. heating', 5, 5),
(IDLE, 'heating', 5, 6),
(IDLE, 'cooling', 5, 4),
(IDLE, 'max cooling', 5, 3),
(IDLE, '', 4, 3),
]
def get_par(self, cmd):
"""
@ -112,37 +135,11 @@ class SensorA10(HasIO, Readable):
result_str = self.communicate('RUFS') # read unit fault status
values_str = result_str.strip().split()
values_int = [int(val) for val in values_str]
v1, v2, v3, v4, v5 = values_int #[:5]
status_messages = [
(ERROR, 'high tempr. cutout fault', 2, 0),
(ERROR, 'high RA tempr. fault', 2, 1),
(ERROR, 'high temperature fixed fault', 3, 7),
(ERROR, 'low temperature fixed fault', 3, 6),
(ERROR, 'high temperature fault', 3, 5),
(ERROR, 'low temperature fault', 3, 4),
(ERROR, 'low level fault', 3, 3),
(ERROR, 'circulator fault', 4, 5),
(ERROR, 'high press. cutout', 5, 2),
(ERROR, 'motor overloaded', 5, 1),
(ERROR, 'pump speed fault', 5, 0),
(WARN, 'open internal sensor', 1, 7),
(WARN, 'shorted internal sensor', 1, 6),
(WARN, 'high temperature warn', 3, 2),
(WARN, 'low temperature warn', 3, 1),
(WARN, 'low level warn', 3, 0),
(IDLE, 'max. heating', 5, 5),
(IDLE, 'heating', 5, 6),
(IDLE, 'cooling', 5, 4),
(IDLE, 'max cooling', 5, 3),
(IDLE, '', 4, 3),
]
for status_type, status_msg, vi, bit in status_messages:
for status_type, status_msg, vi, bit in self.status_messages:
if values_int[vi-1] & (1 << bit):
print(status_type, status_msg, vi, bit)
return status_type, status_msg
return WARN, 'circulation off'
return WARN, 'circulation off'
class TemperatureLoopA10(SensorA10, Drivable):

View File

@ -29,28 +29,28 @@ from os import listdir, path
from setuptools import find_packages, setup
import secop.version
import frappy.version
scripts = glob(path.join('bin', 'secop-*'))
scripts = glob(path.join('bin', 'frappy-*'))
uidir = path.join(path.dirname(__file__), 'secop', 'gui', 'ui')
uidir = path.join(path.dirname(__file__), 'frappy', 'gui', 'ui')
uis = [path.join('gui', 'ui', entry) for entry in listdir(uidir)]
setup(
name='secop-core',
version=secop.version.get_version(),
name='frappy-core',
version=frappy.version.get_version(),
license='GPL',
author='Enrico Faulhaber',
author_email='enrico.faulhaber@frm2.tum.de',
description='SECoP Playground core system',
packages=find_packages(exclude=['test']),
package_data={'secop': ['RELEASE-VERSION'] + uis},
package_data={'frappy': ['RELEASE-VERSION'] + uis},
data_files=[
('/lib/systemd/system-generators', ['etc/secop-generator']),
('/lib/systemd/system', ['etc/secop@.service',
'etc/secop.target',
('/lib/systemd/system-generators', ['etc/frappy-generator']),
('/lib/systemd/system', ['etc/frappy@.service',
'etc/frappy.target',
]),
('/var/log/secop', []),
('/var/log/frappy', []),
],
scripts=scripts,
classifiers=[