482 Commits
mirror ... tnmr

Author SHA1 Message Date
8b09b887f8 Reconciling file names with reference 2025-08-29 09:32:51 +02:00
69d63c4e11 Nevermind! Updated code reference 2025-08-29 09:20:00 +02:00
01dd256858 Minor changes, final backup. It's been real nice here at PSI. 2025-08-29 09:19:07 +02:00
0e01193240 Did some renaming to make things make sense 2025-08-27 14:49:12 +02:00
a590027c44 Added ease-of-access function update_parameters to OTFModule. Updated code reference 2025-08-27 14:26:11 +02:00
558bbfded9 Avoided setup-dependent error (file structuring). Implemented TNMR application search and re-open if it closes. This will not fix any particularly odd situations, but it will recover the majority of TNMR crashes and user error. 2025-08-15 11:15:10 +02:00
bee3f5615a Figured out the answer to a question posed by one of my comments in the past 2025-08-12 11:33:01 +02:00
f0d83e47d8 Merge remote-tracking branch 'refs/remotes/origin/tnmr' into tnmr 2025-08-12 11:24:04 +02:00
7e5b47d45f Can now change the number of acquired points. This, with the ability to change the acquisition length, allows one to control dwell time indirectly 2025-08-12 11:23:35 +02:00
97e52fd27c OTFModule: Forced some status updates 2025-08-06 14:13:06 +02:00
904db04447 Update 2025-08-05 14:31:48 +02:00
7a5694fbe2 Merge branch 'tnmr' of https://gitea.psi.ch/linse/frappy into tnmr 2025-08-05 10:34:02 +02:00
b3d243d831 safety 2025-08-05 10:33:59 +02:00
7bfc6b3cb8 Live data acquisition over SECoP 2025-07-30 13:56:25 +02:00
e77c48ace0 Added functionality for the TNMR module to write partial scans - useful for long experiments with many acquisitions, which might need to be terminated early. Also good for impatient people. Added functionality to the ZVL Network Analyser module to allow for use of inbuilt data correction (calibration). 2025-07-29 14:31:24 +02:00
d5d9d70713 Fixed weird bug where the length of pulse sequences could never increase. Now, they have a hard limit of 100 pulses. Not a big deal. 2025-07-24 11:24:56 +02:00
1777e4b7b1 debug 2025-07-24 10:41:02 +02:00
1990f906a3 debug 2025-07-24 10:39:03 +02:00
c2f4df30eb debug 2025-07-24 10:27:42 +02:00
1ded495e4a debug 2025-07-24 10:25:59 +02:00
bdf0d4f8ae Fix 2025-07-24 09:51:33 +02:00
ef769773f0 Prevented infinite loop 2025-07-24 09:39:25 +02:00
fc44f5597f Reversed removal of title property from otfmod 2025-07-23 11:47:05 +02:00
ff75c9ecbf Fixed a bug in the OTFModule 2025-07-23 11:42:30 +02:00
bfea1263ae Updated OTFModule config, added docstring 2025-07-22 11:20:30 +02:00
2194085e8e Merge branch 'tnmr' of https://gitea.psi.ch/linse/frappy into tnmr 2025-07-21 17:10:53 +02:00
7adf4bf452 on the fly 2025-07-21 17:10:50 +02:00
00e662a27f Added a message to the ZVL net analyser 2025-07-21 15:41:40 +02:00
d7b45cd163 Fixed a bug in tnmr interface, added functionality to load calibration files in ZVL net analyser 2025-07-21 15:38:39 +02:00
730aa61789 Cleaned up 2025-07-21 10:12:47 +02:00
ccd15f50e7 Added the capacitance reading device (based on TSSOP16, paired with an Arduino Nano V3, communication over serial) to the PSI NMR setup 2025-07-11 11:34:48 +02:00
44a4d921af Update to the NMR config file to make things make more sense. 2025-07-09 13:59:02 +02:00
5dfe929da5 Updates to OTF, and added RP100 strain cell power supply, as well as a couple network analysers. Results from the mRS network analyser are questionable at best, and nonsense at worst. Beware. 2025-07-09 13:02:24 +02:00
10acd4a188 TNMR updates: workaround for the hardware module error. Added more dashboard support. Added class definition auto-generated by pycom (NTNMR.py) 2025-06-30 13:55:21 +02:00
388748c995 Fixed hardware issue? 2025-06-24 11:35:32 +02:00
2fce39c381 frappy_psi: Added support for changing the observation frequency & number of scans. Further, added an automatic dashboard load on file setup, and a template dashboard for the Scout device. 2025-06-13 07:58:25 +02:00
365f0a2374 A few things: 1. Got it working again; 2. Renamed files to make more sense; 3. Replaced template tmp.tnt with an emptied out file that previously took data, now data is collected correctly (bug, I'm not sure where this need comes from but this is, as far as I know, a permanent workaround); 4. Added automatic COM interface restart on errors compiling; 5. Implemented variable acquisition times. 2025-06-12 11:04:57 +02:00
05324a8966 frappy_psi.tnmr: added a module (frappy_psi.tnmr.OTFModule) to interface with the Tecmag NMR (TNMR) program from a frappy server. 2025-06-11 08:50:21 +02:00
2c5d5da773 frappy.client.interactive: no pathlib needed here
allow the argument of the run function to be a simple string

Change-Id: I1d5de3802b6adc22a01a262d4cb017bf7dd084c5
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/36343
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
2025-05-16 15:35:44 +02:00
6f599d569c config: add 'include' and 'override'
including a config file and overriding some properties is
helpful when we do not want to modify the original config
but run it with sligthly different properties.

this involves some redesign a.o.:
- modules are collected in a dict instead of a list in
  order for 'override' to find the related module
- checking for duplicates happens in the Collector

Do not warn when included file does not end with '_cfg.py',
as this may be intentional, in case a file is only used
via 'include' and not as cfg file alone.

+ remove unused method Collector.append
+ complain with specific error message when Node is not given

Change-Id: Id568f04d6d84622ef2547412eb6f288fcebf986f
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/36357
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2025-05-16 15:35:22 +02:00
Jenkins system
f725a0f9d4 [deb] Release v0.20.5 2025-05-12 14:03:23 +02:00
abed998e43 frappy.client.interactive: improve updates while driving
- instead to show first current 'value' and 'status', and then
  the changes, show changes only - this way updates appear
  in the expected order
- for this SecopClient.register_callback needs a 'callimmediately'
  argument

Change-Id: I3e91c2c15bca7fee2eba3b1bf1dd27313da3ae29
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/36291
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
2025-05-12 10:32:09 +02:00
29004f7ac5 client: add SecopClient.execCommandFromString
analogous to setParameterFromString
to be used in simple clients where values of structured datatypes
are just python literals

Change-Id: I4936a3c5c0cac45bd7e875c938ce2700b4f4a979
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/36262
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
2025-05-07 14:05:38 +02:00
5436e34179 frappy_psi/ls370res: various bug fixes
- avoid some error messages on disabled channels
- update value of channel switcher properly
- fix bug in set_param method

Change-Id: I16f5cf2d7abce0c0fae17266f0c8e949e8416b7a
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/36263
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
2025-05-06 14:55:16 +02:00
f3fa2ac53a frappy.client.SecopClient: fix setParameterFromString
add missing datatype.export_value

Change-Id: I824d922fdda1ab548e4625982e1485ec4b758cb9
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/36172
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2025-04-28 13:44:06 +02:00
Konstantin Kholostov
2040d7d021 installer: add recipe to build macOS app bundle
Change-Id: Ief4401626db293fecc37f1d1ec72cf295b55fccf
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/36060
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2025-04-28 10:24:50 +02:00
50fc0fd038 follow-up change to 35931: make Proxy a Module
Proxy must be a class, because of the new check for configured
'cls' inheriting from Module. Use Proxy.__new__ to implement
this.

Change-Id: I4bb036afc2ce92187a9049dff0a6f22b20c3a260
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/36104
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
2025-04-24 11:13:03 +02:00
0df7fe4013 change to new visibility spec
+ visibiliy is no longer an EnumType, as this would break
  the specs

Change-Id: I1197c82f31c33c210fdcda0b49a0c38027880d77
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/36088
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
2025-04-22 15:37:19 +02:00
b2eb4fb663 make sure unexported modules are initialized
take the opportunity for a small redesign:

- create a new method build_descriptive_data which
  calls secnode.get_modules also on unexported modules.

+ cache descriptive data

Change-Id: I4a0b8ac96108463dc0c800bb11a404206c26b092
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/36089
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
2025-04-22 15:37:09 +02:00
0706ffa66d improve error messages on module creation
- add name when target and value datatype are incompatible
- check that module class inherits from Module

Change-Id: I4edbdff1c250b64b74b1adf7287f9659dff69b26
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/35931
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
2025-04-01 08:49:55 +02:00
27acfa46ab fix overriding Parameter with value
a property declared in a base class may be overriden
with a parameter in a subclass. this is already allowed.
if then, in the subsubclass it is overridden by a bare value,
it fails.

Patchset 1: add a test for this
Patchset 4: add the fix

Change-Id: Ia5a26076a9ee98439932643a03878342d56f8396
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/35932
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
2025-04-01 08:49:43 +02:00
3295be396c stop poller threads on shutdown
make sure module methods are not called after shutdownModule

+ fix: when mod.enablePoll is False, pollInfo is None
  therefore we have to check before access

Change-Id: I150eb366c013bc3819b612011e292761d801b3ff
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/35869
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2025-03-17 17:24:07 +01:00
75c00f8c07 config: Mod() should return config dict
this helps for coded configuration

Change-Id: I07bdf72f77082f31ee86192faec63df706dcbf56
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/35803
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2025-03-06 16:24:22 +01:00
2d01ca60c8 config: validate value and default of parameters
The Parameter Properties 'value', 'default' and 'constant'
have ValueType, so they are not checked in the setProperty call.
We have to do this explicitly in Module._add_accessible.

Change-Id: I1e35adf2fe539411b4aebacd813adb07497de95b
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/35797
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2025-03-06 16:24:10 +01:00
Georg Brandl
bd2bbea1c8 remove wrong <weight> from fonts on Qt6
Change-Id: Ib94b2ed74598b9f54c2361e61bfa940e60bd7c62
2025-02-28 18:40:12 +01:00
Georg Brandl
9cdfac7450 debian: update compat
Change-Id: I172dff4e0239ce90fe7b1c19fc800ba98f116270
2025-02-25 10:07:06 +01:00
0466e5b10e core: simplify test for methods names
The test for method names 'read_<param>' and 'write_<param>'
without a defined parameter is simplified. We do not check
anymore method names from base classes. Base classes
inheriting from HasAccessible are checked anyway at the
place they are defined.

+ add a test for it
+ move some tests to a new file test_all_modules.py, as
  test_modules.py is getting too long
+ fix missing doc string (frappy.simulation.SimDrivable.stop)

Change-Id: Id8a9afe5c977ae3b1371bd40c6da52be2fc79eb9
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/35503
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2025-01-30 09:36:02 +01:00
0e673a3ed0 core: alternative approach for optional accessibles
This is meant to replace change 33375.
Optional commands and parameters may be declared with the argument
optional=True. In principle, optional commands are not really needed
to be declared, but doing so is nice for documentation reasons
and for inherited accessible properties.

Optional parameters and commands can not be used and are not
exported als long as they are not overridden in subclasses.

- add a test for this
+ fix an issue with checking for methods like read_<param> without
  <param> being a parameter

Change-Id: Ide5021127a02778e7f2f7162555ec8826f1471cb
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/35495
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
2025-01-29 08:59:14 +01:00
f7e04231b6 equipment_id for merged configs and routed nodes
Add a new custom module property 'original_id' indicating
the equipment_id the modules originally belongs to.
This property is only given, when distinct from the equipment_id
of the SEC node.
It happens when multiple config files are given, for all modules
but the ones given in the first file, and for routed modules,
when  multiple nodes are routed or own modules are given.

+ fix an issue in router: additional modules were ignore in case
of a single node.

+ small cosmetic changes in config.py reducing IDE complains

Change-Id: If846c47a06158629cef807d22b91f69e4f416563
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/35396
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2025-01-17 14:33:50 +01:00
23f724e110 config: do not override equipment_id with name
In the previous code, the equipment_id was overridden by the
server name when the interface argument was given over
the commandline. This was leftover from the previous config
file format, where the config files not neccessarly needed
an equipment_id.

Change-Id: I2fc248372a7d2f61cc0690804268d6d066a0a9fa
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/35391
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2025-01-17 14:33:39 +01:00
56204b2ece make UPD listener work when 'tcp://' is omitted on interface
'tcp://' may be omitted on interfaces
add missing 'tcp://' earlier in code, so we do not need to check
for missing 'tcp://' again.

Change-Id: Ie9b4dbd168aebdb6edfe71dbd2cfc25e9229fe67
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/35321
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
2024-12-18 09:08:05 +01:00
30495db0c2 fix bug in change 35001 (better error message)
fix bug in error message

Change-Id: I8151d20f840818fc26d42348f73e740cdb20e03d
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/35287
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2024-12-10 16:27:09 +01:00
7376b39c27 an error on a write must not send an error update
Change-Id: I07a991bcf26e87121160a2e604f8842eba23ebaf
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/35281
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2024-12-10 09:16:19 +01:00
6d2a53acbf pylint: increase max number of positional arguments
Change-Id: Id88270b3c3c1efb56f47def733c1e9c745f1ab18
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/35282
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
2024-12-09 15:54:02 +01:00
3e3c1b51af better message when a parameter is overridden by an invalid value
happens e.g. then writing status = StatusType(...) instead of
status = Parameter(datatype=StatusType(...)) on the class level

+ improve doc strings

Change-Id: I05a0b0b0da4438a40b525da40018bb5b09fd5303
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/35001
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2024-12-09 13:08:03 +01:00
78dfedfe3d follow up change for 'better order of accessibles' (34904)
slight change to make it compatible with py 3.6/3.7, where
reversed(<dict>) was not allowed.

Change-Id: Id440870b5523a866b3afb470ba5db9cd6a9bb0ec
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/35002
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2024-11-27 16:25:02 +01:00
4ad77798c4 frappy.server: remove comment about opts in SecNode/Dispatcher
The options given in the node configuration may be used
for both SecNode (equipment_id) and Dispatcher (when the
frappy.protocol.router.Router is used as dispatcher).
It is correct that both remove the options known to them.

Change-Id: I2a34073e4e5490dcf8db577d9cb74788c0cb657b
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34989
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2024-11-22 08:48:06 +01:00
b3cfa85478 frappy.server: use server name for SecNode name
no need to configure the name of SecNode and Dispatcher

Change-Id: I5199bbd77c74e4fe56b527a5a565a8285b0d831e
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34988
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
2024-11-22 08:45:39 +01:00
53bea83f3e frappy.server bug fix: server name must not be a list
followup error from change 34893
this bug appears in HasComlog, only when comlog is switched on

Change-Id: Ic0db5ae0b0af9981b0c91ebacf2eb6cd704aaa58
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34987
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2024-11-19 14:34:57 +01:00
e9a61be0a4 fix bug when overriding a property with bare value
the bare value must be converted to a updated property.
add also a test for this

Change-Id: I261daaaa8e12d7f739d8b2e8389c1b871b26c5b3
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34985
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
2024-11-19 13:59:13 +01:00
21b8fd6518 add sim-server again based on socketserver
- fix ls370test config file
+ fix issues with frappy_psi.ls370res
+ add frappy_psi.ls370sim

Change-Id: Ie61e3ea01c4b9c7c1286426504e50acf9413a8ba
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34957
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
2024-11-19 08:54:40 +01:00
Jenkins system
3bf1a838d4 [deb] Release v0.20.4 2024-11-14 14:43:54 +01:00
Jens Krüger
a772c00d91 Lib/config: Create a list of pathes only for confdir
Under some condition (no general config file) it's possible that the
piddir and logdir as well are lists of pathes which creates some errors
during the server start

This problems occurs at least in NICOS test suite where no general
config file is defined.

Change-Id: I94c5db927923834c1546dbc34e2490b07b0bf111
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34952
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Jens Krueger <jens.krueger@tum.de>
2024-11-14 14:42:10 +01:00
3fca02e549 frappy.client: catch all errors in handleError callback
put try/execpt around handleError callback

Change-Id: I3d97f085556665189da848e52a7148248f55eb0e
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34955
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2024-11-14 10:15:28 +01:00
Jens Krüger
a9636572bb PSI: Fix import error on ThermoFisher module
Change-Id: I691d8f5057fdb19ba14c109399417a7ee9962637
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34954
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2024-11-14 08:16:50 +01:00
7232bc7e1f frappy.lib.multievent: avoid deadlock
use RLock instead of Lock, as queued actions might call
the set/clear methods recursively

Change-Id: Id43aa8669955e6be9f61379d039a4f65eb7b2dc4
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34950
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
2024-11-13 13:16:54 +01:00
Georg Brandl
623a4f4ef7 remove unused file
Change-Id: I969bfb22f2196227abe8c5ecef628a15e6eb75f1
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34939
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
2024-11-07 11:20:28 +01:00
Jenkins system
febb08dafb [deb] Release v0.20.3 2024-11-07 10:57:12 +01:00
Alexander Zaft
948411e041 add generalConfig to etc
Change-Id: I768b136c803d5e197e3653d1b84e147b62a97676
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34924
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2024-11-07 10:54:25 +01:00
Georg Brandl
9f35a7a7b9 fixup test for cfg_editor utils to run from non-checkout, and fix names, and remove example code
Change-Id: I6224244392e2a2d0928065ba24abcbe822096084
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34934
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2024-11-07 10:54:09 +01:00
Jenkins system
78cc236f55 [deb] Release v0.20.2 2024-11-06 10:40:26 +01:00
Alexander Zaft
ed1d693008 fix frappy-server cfgfiles command
frappy-server <name> errors after 34893

Change-Id: Ifba758fbabc3aef32e20b683f1c1edbfea711a75
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34913
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
2024-11-05 15:45:58 +01:00
Georg Brandl
fb883f64de server: better handling of cfgfile argument
No reason to keep stringly-typed data on that level

Change-Id: Iba8d88301bf36ef6051031d1916d1bac84ede546
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34893
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
2024-10-31 17:17:01 +01:00
7ab062a449 generalConfig: fix the case when confdir is a list of paths
convert all env variable values containing ':' into a list of paths
+ fix one case where an env variable is not converted to a Path
+ remove unused _gcfg_help

Change-Id: Ibc51ab4606ca51e0e87d0fedfac1aca4952f3270
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34872
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2024-10-31 10:11:11 +01:00
Alexander Zaft
16d5749d9e server: service discovery over UDP.
implement RFC-005
- server broadcasts once on startup and answers to broadcasts
- small tool for listening on the port and sending broadcasts

Change-Id: I02d1184d6be62bef6f964eb9d238220aef062e94
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34851
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
2024-10-31 08:19:30 +01:00
Georg Brandl
e0cff7f81c systemd: enable indication of reloading/stopping
Change-Id: I6dd1b3a50234fb0304fb1a5318f2f22d35d464ec
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34896
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
2024-10-30 15:53:00 +01:00
Alexander Zaft
dbb4ed6e97 server: fix windows ctrl-c
thread.join() blocks indefinetely, not allowing python to handle the
interrupt. Same is true for sleep on windows, but when we only sleep a
second, this is fine. Instead of joining the threads, keep track of them
manually.

Change-Id: I559fe06d9ce005a15388c881e4f076d996aea9dc
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34894
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
2024-10-30 15:52:57 +01:00
ae11d0b33f better order of accessibles: 'value' 'status' and 'target' first
- predefined parameters/commands appear first, in the order
  defined in frappy.params.PREDEFINED_ACCESSIBLES
- other (custom) parameters by inheritance order
- remove paramOrder attribute (not used currently)

Change-Id: If4c43189e4837dba057dc0a430ac6c3d1ae10829
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34904
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
2024-10-30 15:37:40 +01:00
Alexander Zaft
4a332532e7 generalconfig: streamlined config discovery
determine generalconfig file location in order:
  - command line argument
  - environment variable
  - git location (../cfg)
  - local location (cwd)
  - global location (/etc/frappy)

Change-Id: Ie34bcbd5188837075ee7bb7d5029d676ae72378e
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34839
Reviewed-by: Bjoern Pedersen <bjoern.pedersen@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
2024-10-29 14:03:00 +01:00
Alexander Zaft
2ece560ad7 Revert "config: allow using Prop(...)"
This reverts commit ba59bd5498.

Reason for revert: unnecessary

Change-Id: I4bf46a1de2e699049572f376e84fa39db5dae76c
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34888
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
2024-10-28 14:19:39 +01:00
Alexander Zaft
512f95eafd config: fix typo
Change-Id: Ie90993d9b2d387780fa3faa28fd8d4523f7fc866
2024-10-28 11:10:34 +01:00
Alexander Zaft
ba59bd5498 config: allow using Prop(...)
Still maps to the same logic, but it might be a bit confusing to
configure properties with prop = Param(...)

Change-Id: I6bde6a0b015095a8b765d98cb2780f0d42de7e6e
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34886
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2024-10-28 11:07:21 +01:00
f5e46d82fb fix playground
- fix initialization
- add description

Change-Id: Ic210c26edfec709bafa902e32eae04350d571acd
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34874
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
2024-10-25 09:37:56 +02:00
ccc976984d frappy_psi.sea: bugfix: revert change of updateEvent to udpateItem
revert some of change 34813
SeaClient is based on ProxyClient, not SecopClient
-> updateItem is not defined there

Change-Id: Ib3049038481917ec7a11b9fb2d285cedff5febbb
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34873
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
2024-10-24 14:59:00 +02:00
Alexander Zaft
d1930868aa core: fix Dispatcher and SECNode opts handling
both tried to consume everything before, also making the check for
unknown options afterwards pointless

Change-Id: I7e44c088163e0b99ac509a2c0f757270807d97ab
Fixes: #4912
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34837
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
2024-10-21 15:20:08 +02:00
Alexander Zaft
51fe236a63 server: show interfaces as custom property
Change-Id: I129be1228b8a04386db5fe370ebdc2ec6ce8050a
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34838
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
2024-10-21 15:16:20 +02:00
Alexander Zaft
29ec5c16aa server: fix positional argument lint
Change-Id: Ib718826e7bbce2c6fcc9b39879c30baec1ecaa5a
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34845
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
2024-10-21 14:47:36 +02:00
Alexander Zaft
11ea75bedf sim: make amagnet sim cfg startable again
Change-Id: I1e7b7dd6e4069c616f49edbe4e223f501a000398
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34844
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2024-10-21 14:03:15 +02:00
Alexander Zaft
323581075b simulation: fix extra_params default, ccidu1 cfg
Change-Id: I80672f1c070054871708961bc6641457f8e409ec
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34843
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
2024-10-21 14:03:10 +02:00
Alexander Zaft
ea1d08e669 test_server: basic description checks
Change-Id: I732ac2349f7e7ab2579f67cc6e51989703531087
2024-10-21 10:19:14 +02:00
Georg Brandl
baa0946e9d pylint: do not try to infer too much
Change-Id: I1aabf4c59fc47e888e8cd096a8228842f35ff769
2024-10-21 10:07:45 +02:00
Jenkins system
1c69abfd45 [deb] Release v0.20.1 2024-10-17 16:31:27 +02:00
Georg Brandl
d4c6a4d6d4 lib: there might be no confdir in "cfg"
Change-Id: I0832de4564a2c1ff439c486ae6cbaa776ebf1e59
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34833
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
2024-10-17 16:31:10 +02:00
Georg Brandl
79cbf87da8 remove sim-server
asyncore is deprecated for a long time and now removed in 3.12

Change-Id: I32eb18797dd13663de08ebedc38ce3de4b5ede93
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34830
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
2024-10-17 16:12:29 +02:00
Georg Brandl
e8a7825f6e remove old unused parse module
Change-Id: Ie94217504a65c21a7a8aa7221f9028a689476ffd
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34831
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2024-10-17 16:05:30 +02:00
Georg Brandl
fa75fe9da8 remove unused test class
Change-Id: I887a66befa834a72bc684dc5edbcb5862a0d0b71
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34832
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
2024-10-17 16:00:34 +02:00
Georg Brandl
b7ededef24 gui: do not add a console logger when there is no sys.stdout
Change-Id: Icfd39bd508b5d482c902e6e781cbc557085b0c2e
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34829
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
2024-10-17 15:57:35 +02:00
Jenkins system
2101bb727b [deb] Release v0.20.0 2024-10-17 14:24:29 +02:00
Georg Brandl
1d609deab6 setup: fill long_description and url
Change-Id: Ib5db4d9c33f205d181ed78c65265601caf23a53d
2024-10-17 14:22:47 +02:00
Georg Brandl
63ec5b6cb4 setup: fix classifiers
Change-Id: I473785df9c1157a77d02c3e1114bb6633d01149f
2024-10-17 14:12:21 +02:00
Georg Brandl
035472a707 update declared version to 1.0 final
Change-Id: Iec2564a5c95baf95de5f7e63ed1890334477c70f
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34793
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
2024-10-17 14:01:53 +02:00
2a99aa73e0 add more datatype tests
check from_string and to_string are counterparts
redesign standard value checks for this

Change-Id: I825cdba5955596096fd11ab52de571f05845d7ae
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34737
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2024-10-17 08:03:09 +02:00
cd20011437 add Datatype.to_string as counterpart of .from_string
This allows simple UIs using stringified versions in
text input.

- add frappy.client.SecopClient.setParameterFromString
- fix datatype tests
+ add updateItem to CallbackObject (for doc)

Change-Id: Ic7792bdc51ba0884637b2d4acc0e9433c669314d
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34736
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2024-10-17 08:03:02 +02:00
28603aed5d do not fail when generalConfig.init() is called twice
Change-Id: I7132b71f906fc8a77b6fedcdcc2c7d4a3e48830a
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34818
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
2024-10-16 15:43:01 +02:00
Enrico Faulhaber
d50718a121 add test for importing custom modules
related: #4882

Change-Id: I605de7fd43be146c84f4324d2a8eebe0aa11da79
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34814
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Tested-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2024-10-16 15:41:17 +02:00
Georg Brandl
d4668d904f install libgl1 for pyqt6
Change-Id: I873f97fb497364d9c647797a899cf348c430214b
2024-10-16 15:18:08 +02:00
Georg Brandl
5d74042fc9 install pytango for testing
Change-Id: I04e0dbc6d59b388dbcf6657b8815642fcdc25094
2024-10-16 15:15:51 +02:00
Georg Brandl
bd4519db4c new setuptools needs new importlib_metadata
Change-Id: Ie4220f7ec2c11b3dcf64c65b3ed97a3d9129af5c
2024-10-16 15:11:53 +02:00
Georg Brandl
084529d5fb ci/Dockerfile: do no use pytango from upstream
Change-Id: Ie002aff67e0fb4d6daf6f621c58be8c5ab71af9d
2024-10-16 15:06:14 +02:00
Georg Brandl
3bbde105f8 remove old "buffer" message
Change-Id: I010f535ec746ef15ccfc2929a2e62ccb83894c33
2024-10-16 15:06:14 +02:00
Enrico Faulhaber
831d74b993 ci: also install gui requirements for additional tests
Change-Id: Idc40699d470fb6449366a1cd75a3207cabcdd4a4
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34815
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
2024-10-16 14:43:22 +02:00
ffe5f52790 frappy_psi.sea: avoid error on import
the previous code raised an error when generalConfig.init() was
not called before importing. defer evaluation of seaconfdir to
the time it is used

+ use updateItem instead of updateEvent to avoid pylint complaint

Change-Id: I0da0891a8d4091102d2a149705f5546e2f6fd187
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34813
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
2024-10-16 11:15:27 +02:00
Georg Brandl
6ac25c7504 fix descriptive data
- remove unspecified "version" and "interface" properties
- add frappy version to "firmware" property
- keep custom node props with underscores

Change-Id: Ib047e4765a90f2833f9e41af69a665554dd20737
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34792
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
2024-10-15 10:17:15 +02:00
Alexander Zaft
e1458471a8 psi: change open calls in sea
Change-Id: I4fe235027df4ea935d84e29895eb280f620afbdf
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34665
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
2024-09-23 08:07:23 +02:00
Alexander Zaft
c550721e2d generalConfig, config: use pathlib
- switch to pathlib
- represent multiple confdirs as list of Paths internally, not string
  with pathsep

Change-Id: I1418e561641e27cd904af0762be056cd66ee1919
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34464
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2024-09-19 13:34:14 +02:00
Alexander Zaft
90d49355fa all: start using pathlib
Change-Id: I2b0d6ff8f534382913414fa9b35150d6f697acb4
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34463
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
2024-09-19 13:32:15 +02:00
116ad54ac1 GUI: allow enums to be plotted
numpy.finite() does not accept enums -> convert to float first

Change-Id: Ib740800a7410ada38fb48711d4da676af8b64b17
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34608
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2024-09-13 09:02:45 +02:00
8660d83a67 GUI: avoid space needed for closed groups
the empty QLabel in widgets for readonly parameters was not hidden
with the group.

Change-Id: I0e5ad49c3b693483a3cabf849e7962925cfcc434
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34607
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
2024-09-10 15:21:37 +02:00
Alexander Zaft
235e0f5820 bin: remove make_doc
relic from markdown documentation

Change-Id: I8cb1913e6b6d1b8efe77d4d7f982f95e75166707
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34465
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2024-08-27 11:12:42 +02:00
Jenkins system
a7b763713b [deb] Release v0.19.10 2024-08-07 17:00:07 +02:00
Georg Brandl
4c77b0b923 remove walrus
So far, frappy is still supposed to be 3.6 compatible

Change-Id: Ieb56c6500d58cdc1fe2f34b1448b05ba74b0fa6e
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34326
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
2024-08-07 15:32:12 +02:00
Alexander Zaft
3cd63119a3 debian: let frappy-core replace frappy-demo
Fixes: #4888
Change-Id: I32781773cbce9e29381df482b8bd9ba992dcb9e4
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34323
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
2024-08-07 13:25:03 +02:00
Jenkins system
19f6e8ed43 [deb] Release v0.19.9 2024-08-06 16:02:50 +02:00
Georg Brandl
6e56c19b77 debian: fix missing install dir
Change-Id: Id865c58b66af71dbb6631e5856f1f8563946fa40
2024-08-06 16:02:42 +02:00
Jenkins system
359fb4e69b [deb] Release v0.19.8 2024-08-06 15:58:20 +02:00
Georg Brandl
6479134e6a debian: move demo into core
Change-Id: I545850163f0fd6e560dcf62a008cb9f1aa544af9
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34309
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
2024-08-06 15:55:01 +02:00
Jenkins system
63bb34cf51 [deb] Release v0.19.7 2024-08-06 15:04:07 +02:00
Alexander Zaft
dacae94408 lib: GeneralConfig fix missing keys logic
Change-Id: I814511fff6fbf7c94e30a052bff0712fad9805b5
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34306
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
2024-08-06 14:59:27 +02:00
Jenkins system
f9f0eda937 [deb] Release v0.19.6 2024-08-06 13:56:51 +02:00
Alexander Zaft
768d758efa lib: Fix GeneralConfig defaults handling
overwriting defaults before init() had no effect, as the values were
replaced there.
Now, only unset defaults are updated, keeping the overrides.
Also fix unconditionally taking the values from environment variables.

Change-Id: Idf1c5e2338403e061d20c11ed9c4803d535eb188
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34304
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2024-08-06 13:56:25 +02:00
Georg Brandl
1b40b77fd4 gui: save/restore window geometry
Change-Id: I98008fc12479206018416d57ef248a9942b73490
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34297
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
2024-08-05 17:22:56 +02:00
Georg Brandl
54782bdbad GUI: allow starting in detailed view by cmdline flag
Change-Id: I4248bfee47d807833e02a35ce8dd85fa6b297e77
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34296
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2024-08-05 10:52:33 +02:00
Jens Krüger
fb9e713043 SINQ/SEA: Fix import error due to None value
If the environment variable isn't set a None value is returned. Now an
empty string will be returned

Fixes: #4882

Change-Id: I3e319daebf10e2d8ea3ee00f6094e6896e54f51b
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34234
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Reviewed-by: Jens Krueger <jens.krueger@tum.de>
2024-08-05 10:12:38 +02:00
Jenkins system
bcfb4ae474 [deb] Release v0.19.5 2024-08-05 09:30:53 +02:00
Alexander Zaft
e30d2544d2 pass logger parameter only for mlzlogger
The mlzlogger has an extra argument we want to keep using.
To keep compatibility, check if we got the mlzlogger or something else.

Change-Id: I1a4f4e7651370dd71124ab7c3608c6573a585dd9
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34292
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2024-08-05 09:29:50 +02:00
Alexander Zaft
48de238dbc add RemoteLogHandler independent of MainLogger
installing a custom logger was not possible, since the RemoteLogHandler
was not installed.
Additionally, search for the RemoteLogHandler recursively upwards, since
not all loggers copy their Hanlders to their children.

Change-Id: If3e19966d9289cacd926648582e9718b7eab279c
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34288
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
2024-08-05 09:29:45 +02:00
Alexander Zaft
1d71445440 add missing requirements to setup.py
Change-Id: Ie0d3eae3a7aeb1f28983476b00fe012c916051d7
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34287
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2024-08-02 09:36:57 +02:00
Alexander Zaft
9ed1f29e68 client: fix how to raise error on wrong ident
leftover error_map from long ago, turned into direct raising of
HardwareError

Change-Id: I8772e20133502bb0a997d5317a74e2bd16b780c6
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34279
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
2024-08-01 09:17:33 +02:00
Jenkins system
ba1d4c3a9e [deb] Release v0.19.4 2024-07-26 11:46:10 +02:00
Georg Brandl
c5bb0c37b1 actually exclude cfg-editor
Change-Id: I1a31fd96eb8962cff92cda349201ebff4a0dddbc
2024-07-26 11:46:02 +02:00
Jenkins system
1d49577f9a [deb] Release v0.19.3 2024-07-26 08:36:44 +02:00
Enrico Faulhaber
f055ae20c2 remove cfg_editor for now
as it was not functional...

fixes: #4881
related: #4882

Change-Id: Ic8c5ee06fcdd48b8b0562b5b1275296d2b155f06
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34226
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Jens Krueger <jens.krueger@tum.de>
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
2024-07-26 08:36:16 +02:00
Jens Krüger
bb5459243c Update copyright year
Change-Id: I7fe65e46639c2d8948fa93303ee9b14393e8bfca
2024-07-24 08:35:14 +02:00
Alexander Zaft
c4ad2ec83d mlz seop: add pylint
Change-Id: I096dff796c88bf1b23778aa57c73f9aa77712372
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34127
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
2024-07-12 15:24:54 +02:00
Alexander Zaft
abee1cc463 mlz: fix delayed import of he3cell
Change-Id: Ia15693a11f9d1526b4a50be4adbad19640eafe93
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34126
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
2024-07-12 15:16:23 +02:00
e0e90c4000 frappy_psi.sea: use raise from
this was complained by Jenkins after merging (1)

Change-Id: I9e4eb57004d218021978d6e9e06e1cbd42ec5e9c
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34024
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
2024-06-24 17:03:47 +02:00
81002c2568 frappy_psi.sea: use ReadFailedError
change error class on reading parameters in SEA from HardwareError
to ReadFailed. This is in most cases more appropriate.

TODO: find errors in SEA that should be should be HardwareErrors
and a mechanism to indicate this

+ for errors related to disabled modules use the DISABLED status

Change-Id: I0342a34185a66dcf874c6ca034b7cefc98bf9c8a
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/34022
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2024-06-24 13:40:33 +02:00
2598e94cb7 better behaviour on startup in case of errors
- fix a bug then TcpServer can not start dye to address in use
- report errors when restarting interfaces
- increase timeout. the timeout for waiting all interfaces
  starting up must be higher than a potential successful
  startup of TcpServer, which is currently ~ 10 sec
  (might be reduced, but at both places)

Change-Id: I88b967c4baff79fdf94f4c849dd713d2cba6fabc
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/33985
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2024-06-19 17:02:21 +02:00
67611d6d23 frappy_psi.extparams.StructParam: fix doc + simplify
- the doc string contained wrong, obsolete information
+ simplify: remove customizeable mapping member name -> param name

Change-Id: I0ffdcb336f45001d45f68238b56e1e257d98dd3d
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/33993
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2024-06-19 17:02:06 +02:00
Jenkins system
3c7c883538 [deb] Release v0.19.2 2024-06-18 15:21:43 +02:00
Enrico Faulhaber
22d016bd59 frappy_mlz/entangle: fix missing status enum
finally!

Change-Id: I5be4ded7c8ee87a09be44ba474e26cd023c917c6
2024-06-18 15:20:13 +02:00
185b47a471 frappy_psi.triton: fix heater output issue
when output_module is not HeaterOutputWith range, the heater limit
can not be changed

Change-Id: If25a609e9f9667dc111cb220024388a51df993ec
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/33913
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2024-06-12 11:26:58 +02:00
7dc4cf7029 frappy_psi.sea: various improvments
- always open asynio and syncio connections (conenctions for
  update and command)
- better synchronization when reconnecting using threading.Event
- nicer error messages

Change-Id: Ia435c3ccfa2732be4aa9f24a3b6e8484fab715a3
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/33909
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2024-06-12 10:54:00 +02:00
924a9a2c7f frappy_psi.triton: bug fixes
- fix channel numbers
- make sure some channels are selected

Change-Id: I11c553805ed5ee6235e54ce56a5ea68160d1d212
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/33911
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
2024-06-12 10:53:41 +02:00
36dd7598cc frappy_psi.picontrol: software control loop
example usage: use a temperature controller without changing
the calibration setting:
reading the raw sensor, calibrate by software and use 'manual'
heater output

Change-Id: I3dbcf37e7726b48a0516d7aa30758be52b80fe58
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/33910
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2024-06-12 10:53:18 +02:00
0641bc22c3 frappy_psi.ah2700: auto create loss module with Pinata
the loss angle is a separate quantity, which is preferred to
be an extra module. create this automatically.

Change-Id: I97f6be48f3411d8143f2ff85c2c61711fc71e8d6
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/33908
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2024-06-12 10:52:50 +02:00
Alexander Zaft
3d27a805d4 add option for delayed imports
will make setup checking easier, although it does not work for all cases
(from imports for example)

Change-Id: I2e5cf9b427a6f8e6f603d9662cdb9700d5f9ad9a
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/33893
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
2024-06-12 10:33:31 +02:00
fa007e4f1c bug fix in frappy_psi.convergence
+ various doc improvements

Change-Id: I8ce2a1f006a5e4870285ce1f6015510e21d01a13
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/33906
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2024-06-11 17:56:51 +02:00
e74192d45e HasControlledBy: update target without switching to self control
when a HeaterOutput module is used e.g. from a software loop,
a method is needed to update the output without switching to
self-controlled

Change-Id: I9c83b4e172e14812a405e836757491622ff5f949
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/33903
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
2024-06-11 16:08:44 +02:00
516e0c7a59 frappy.lib.asynconn: handle ConnectionResetError nicely
Change-Id: Icba24ffb82369aa78e431d12260f4f3cc795e511
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/33902
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
2024-06-11 16:08:34 +02:00
l_samenv
a53eebe2f3 fix missing update after error on parameter
the main error was a suppressed update when the value does not
change, but the readerror gets None

this error was the reason for strange behaviour in frappy.proxy
while finding the cause, other improvements were done:

- nodeStateChange: add 'activating' to the possible online states
- improve status handling in proxy

Change-Id: I2a1873065ab051bdba2200f50e6ad09ae55e168e
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/33901
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2024-06-11 16:08:25 +02:00
Jenkins system
91d50ae703 [deb] Release v0.19.1 2024-06-07 16:50:34 +02:00
Alexander Zaft
878f4774e4 mlz: derive Digitaloutput from Drivable
as the underlying entangle *DigitalOutput may be BUSY and frappy.Writable
disallows this.

Change-Id: I6e4861c6d014f59ad4cc2355a438130173bf6569
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/33849
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Bjoern Pedersen <bjoern.pedersen@frm2.tum.de>
2024-06-07 16:48:14 +02:00
Alexander Zaft
d77a7da606 datatypes: add more detail to error messages
the error messages for tuple and array swallow all details useful for
debugging. add the original exception for some context

Change-Id: I8e1036bfab10c09d5f9c8af05ac3306af89f54c4
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/33850
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
2024-06-05 14:02:25 +02:00
d3f1fdce4a frappy.client.readParameter: handle connection errors correctly
update cache in case of connection errors, as they are not handled
in the rx thread

Change-Id: Icf3377020ec314fcef2982a4e6dc64356f787273
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/33744
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2024-05-28 17:24:06 +02:00
d357a9695b SecopClient.online must be True while activating
as callbacks trigger by updates while activating may check for
online state

+ remove unused imports

Change-Id: I37df839abf6b7225389b803347234a3d0bc8d799
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/33745
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
2024-05-28 17:21:49 +02:00
Jenkins system
09e7f9e532 [deb] Release v0.19.0 2024-05-16 11:31:26 +02:00
Georg Brandl
cdab83368a fix LimitsType to be actually used and validated
Change-Id: Id0f67e91f4ff57d4c29c33960e736c8c3ae77209
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/33683
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
2024-05-16 11:29:45 +02:00
Jens Krüger
216f96cc04 Fix abslimits reading from entangle device
Fixes: #4864
Related: #4866

Change-Id: I393a35784766c0e09367a90debfc8b59b290626e
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/33672
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
2024-05-16 11:29:36 +02:00
Georg Brandl
46bdd6dd99 add config for the Entangle simulation server
Change-Id: I9e7564707fc98d3b5dc3182d7837b222aefef582
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/33692
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
2024-05-16 10:42:50 +02:00
cb9b0f0c8b frappy.client: avoid shutdown callback sent twice
in case th rx thread crashes, the shutdown callback is called twice
-> improve cleanup code in __rxthread

Change-Id: I0d20aa4304d94b17565b018ad8528d61bbbcbc83
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/33614
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2024-05-02 14:19:54 +02:00
23b60703dc SecopClient.__del__ must not call callbacks
otherwise a nasty deadlock might happen in NICOS

Change-Id: Ie1a333979b77683ce35683aede042ce86159fe65
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/33583
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2024-05-02 08:36:40 +02:00
d5448118e4 frappy.client.SecopClient: add the option to use no logging at all
using a dummy NullLogger

Change-Id: I1f12c7307d3d8e37243488b8a11c6abcf087af86
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/33582
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2024-05-02 08:31:32 +02:00
81a345f61d frappy.client.interactive: improve logging and error handling
- redesign logging, using python logging
- stop watching when an erro happens during update

Change-Id: Ibe96569ecc45df429b571232374c451de3f82f1f
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/33431
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2024-04-09 12:29:07 +02:00
4c4b565ad0 frappy.client: improve error handling more
- implement a 'handleError' callback
- SecopClient.handleError is registered as a callback and by default
  logs errors up to a limited number of times
- the cache is customized to return an item indicating an undefined value,
  helping to avoid follow up errors.
+ frappy.errors: cosmetic fix
+ frappy.client: cosmetic changes

Change-Id: I4614e1d27c7aea3a1a722176c6be55f8563597cd
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/33429
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2024-04-09 12:28:56 +02:00
5d5c1cfcf6 frappy.client: catch errors on callbacks
buggy updates or errors in callbacks are now converted into
error updates, buggy error updates are skipped.

-> the receive thread should no longer crash

Change-Id: I97e3999db73e64f73dfbc380fac3d7685b6ca31c
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/33386
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2024-04-05 09:13:44 +02:00
Alexander Zaft
2962b8aef5 test: add uri attach test
Change-Id: I8a021c53c9987ed03ce31c8481f73573b943d1f3
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/33417
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2024-04-04 11:22:30 +02:00
Alexander Zaft
c1cfea4cc2 gui: more specialized input widgets
Change-Id: I8b768b2069ae28a58d540165bd95f31ad7e984e0
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/33390
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2024-04-04 08:45:35 +02:00
e416878990 frappy.client: cleanup properly after a reply timeout
when a reply to a request is not received within 10 s a timeout
error is raised, but any further requests with the same identifier
will be blocked - fix this

Change-Id: Id2fbc8bb6e6ecfd54bba1fa57b62e626e49b54c8
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/33385
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2024-03-27 17:21:29 +01:00
Alexander Zaft
1375072f1e gui: sort qt imports
Change-Id: Id8dfdd7b07bff6e337eb71a436dd51762f9b5fa7
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/33389
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2024-03-27 10:49:01 +01:00
Alexander Zaft
ee61224fc6 gui: catch invalid inputs
Change-Id: Ie0525e4ef9a94085da811e7eaa2e0b7430bade95
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/33388
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2024-03-27 10:48:56 +01:00
Georg Brandl
c496a42830 dispatcher: consistent handling of missing timestamps
Like in `read` replies (line 193), `update` now omits the timestamp
instead of returning {"t": 0}.

Change-Id: Iaee0fccae81040cdd6075b0e4a8600c032aec03d
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/33382
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2024-03-26 09:41:36 +01:00
Alexander Zaft
9aba3db8a6 core: add websocket interface
Change-Id: Ic62abeef6fb73f4a1b3d29f9225ba164de9e3e93
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/33240
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2024-03-11 15:29:10 +01:00
08f889e6a3 follow up fix: handler export=True correctly
this seems to be broken in change 33266

Change-Id: I4da78f297976daeac0a0709b9c86e6e28fc122bf
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/33268
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2024-03-11 10:47:36 +01:00
93be8c9ba1 follow up fix for change 33168
triggerPoll must be set on attached io

Change-Id: If3fa1016efa6047371380790f60db246d87b3628
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/33269
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2024-03-11 08:24:23 +01:00
45871bd3ca fix command doc string handling and change default stop doc string
- fix inheritance of command description
- when no stop method is given, then the description should indicate
  that stop is a no-op -> add missing doc strings to stop methods
- add test to make sure stop command doc strings are given
  when implemented

Change-Id: If891359350e8dcdec39a706841d61d4f8ec8926f
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/33266
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2024-03-08 15:18:50 +01:00
Alexander Zaft
ee5a945e11 core: cover errors in handler setup()
Change-Id: I0bb2f07e26717205c013dfedec6e1beca2947d17
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/33239
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2024-03-07 13:32:42 +01:00
Alexander Zaft
ec58bd4d58 core: introduce common handler class
- make RequestHanlder based on socketserver.BaserequestHandler
- split handle() into subfunctions
- rework TCPRequestHandler

Change-Id: I62452e21c03b9cb9937673ce9c8663765798f863
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/32984
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2024-03-05 15:55:44 +01:00
63f7a31480 fix docstring in frappy.error.OutOfRangeError
Change-Id: I006c061a5d88ac7c97808efd56faece927916e78
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/33183
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2024-03-01 16:22:19 +01:00
65cc7f7d32 simplify callbacks
on Module, use one single callback list 'paramsCallback' instead of
'valueCallbacks', 'errorCallbacks'. Redesign the mechanism to
avoid most of the closures.

Change-Id: Ie7f68f6bf97ab3f3cd961faa20b0e77730e5b37d
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/33118
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
2024-03-01 11:34:51 +01:00
6cddb2d0c4 fixes for proxy modules
- for the case when the remote module name does not match,
  'read', 'change' and 'do' does not work
- a proxy to an IO class has enablePoll == False, but it needs
  a triggerPoll for modules relying on it to work
- a proxy on a communicator module has a status even when the
  remote does not - this needs 2 fixes

Change-Id: Icd44da4c2984f27ce7147dec633739f9176012ec
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/33168
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2024-03-01 11:33:35 +01:00
38a2151771 bugfix in automatic creation if attached io
srv.modules does no longer exist

Change-Id: Ibc52fe35f27ad110e60947702d97ee40f359b7c5
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/33167
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2024-03-01 09:17:34 +01:00
96e4d7bb75 move StructParam to frappy/extparams.py
+ typos and fixes in doc strings

Change-Id: Ib3e9add84ce2a6fb5c33770cae7f2da3f5655506
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/33033
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2024-02-14 08:47:46 +01:00
7fdd0204d2 add FloatEnumParam
for the use case where a parameter is a selection of discrete
float parameters

declaring a parameter as FloatEnumParam will create effectively
two parameters, one with datatype FloatRange and another with
datatype Enum, influencing each other automatically.

in a later change StructParam should be moved from
frappy/structparam.py to frappy/extparams.py

Change-Id: Ica3fd8dcaf6e9439e8178390f220dec15e52cc86
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/32975
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2024-02-12 10:09:49 +01:00
b0518e7bd4 simulation: extra_params might be a list
- still accept comma separated string
- remove legacy naming '.extra_params'

Change-Id: I497cf7722d0b39dd31c516383449a4cc4e7dcb7d
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/32968
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2024-01-29 14:25:01 +01:00
Jenkins system
d2d45e8253 [deb] Release v0.18.1 2024-01-24 14:59:21 +01:00
Alexander Zaft
5bfe97a1a6 mlz: entangle fix limit check
Change-Id: Ib430262057026054ac71053d25dfda340b48227a
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/32921
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Tested-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
2024-01-24 14:58:15 +01:00
Alexander Zaft
6bb6071561 mlz: Zapf fix unit handling and small errors
Change-Id: Iaa5ed175582d8399cc0c69ba72c3ab8e6e51ecf6
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/32920
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Tested-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
2024-01-24 14:57:21 +01:00
Jenkins system
72dc30b8df [deb] Release v0.18.0 2024-01-17 12:35:01 +01:00
a43b6ae65b bug fix in frappy.io.BytesIO.checkHWIdent
missing f for f string

Change-Id: Ie67384e5b7e514728041a72bd08c850abb31639e
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/32786
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-12-18 10:07:45 +01:00
d2862c9cb2 remove py35 compatibility code
as f-strings are heavily used now, compatibility to py35
can be removed

Change-Id: I1ae4912ad4cbde8419b74845217943bd061053f3
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/32754
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-12-15 16:58:30 +01:00
376def0410 fix playground after change 32249
as modules are now stored on secnode instead of dispatcher

Change-Id: Iccda3d97269693a893c06a4e094a9c1dbcf7df0b
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/32746
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-12-12 11:15:12 +01:00
9c286943f8 frappy.secnode: fix strange error message
when get_module_instance is called a second time after
it failed, the 'cls' element in opts is missing:

move opts dict copy from create_modules to get_module_instance

Change-Id: Ie046f133a8fdbbb1c39643ca16dc5447a9d2d065
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/32745
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-12-12 11:14:59 +01:00
b4cfd7cd4f modify arguments of Dispatcher.announce_update
- 'pname' argument is not needed
- change 'modulename' argument to 'moduleobj'
  (needed for further change)

Change-Id: Ib21f8ad06d9b2be4005ff3513088a85e29785c94
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/32744
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-12-12 11:14:22 +01:00
adabf5c4b1 fix missing import in change message
Transported values in a change must be converted first.
As this is only relevant for the exotic "scaled" and "blob"
datatypes, this was not detected yet.

- add tests
- suppress warning PytestUnhandledThreadExceptionWarning in tests
+ change import_value methods to raise no other exceptions than
  WrongTypeError and RangeError
+ simplify Command.do: as import_value already raises the
  appropriate error, no more try/except is needed

Change-Id: I299e511468dc0fcecff4c20cf8a917da38b70786
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/32743
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-12-11 16:36:44 +01:00
Alexander Zaft
dbacac71f9 core: better error on export of internal type
more descriptive error when trying to export OrType, NoneOr, ValueType
and DataTypeType

Change-Id: If13815e9d2b177042b24a1bb62b1ad1d1d88b502
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/32737
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-12-11 13:30:45 +01:00
c5c479f424 frappy_psi.sea: workaround for bug in sea
hdb path should not contain duble slash. replace double slash
by single slash

Change-Id: Ia2ce3be9a75d68fcc7efe3eb3dbd19a7907a73ff
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/32705
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-12-07 08:18:57 +01:00
Alexander Zaft
2de9a3ab43 core: better command handling
* check argument of do
* automatically set optional struct members from function signature

Change-Id: I95684f1826c1318ea92fad2bd4c9681d85ea72f5
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/32501
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-11-29 07:13:06 +01:00
Alexander Zaft
96b56ca411 datatypes: fix optional struct export
Change-Id: Ia2758dfba75f36a91bf1676e8ead555cec3ead53
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/32500
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-11-29 07:04:47 +01:00
Alexander Zaft
ca236d2064 mlz: handle unconfigured abslimits
- if there are no abslimits configured, get them from the hardware.
- check if the ranges are compatible

Change-Id: If72e31a56c299cb628ed8ff66d4340a87d4bd1d4
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/32625
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-11-27 10:46:03 +01:00
Alexander Zaft
748c31c774 core: formatting and update server docstring
Change-Id: Ic0dd4c5239f27679c89f6b3742b9c5f8b71f33f6
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/32514
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-11-10 08:45:05 +01:00
Alexander Zaft
acbd424ae1 core: allow multiple interfaces
Change-Id: Ib8c0baef85a6dd69cddafe1c4973e42136d1588b
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/32489
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
2023-11-10 07:56:23 +01:00
c0b8699ccf implement pfeiffer TPG vacuum reading
this is an example where StringIO.communicate has to be extended

Change-Id: Iff6bb426ee7960904993574531de84793152e21d
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/32385
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-10-26 08:58:34 +02:00
677a3bddae add StringIO.writeline, improve StringIO.multicomm
- StringIO.writeline sends a command and does not expect a reply
- StringIO.multicomm and BytesIO.multicomm is improved in order
  to insert individual delays in between lines and individual
  noreply flags

+ fix a bug in tutorial_t_control
+ improve readability of frappy.lib.classdoc.indent_description

Change-Id: I9dea113e19147684ec41aca5267a79816bbf202c
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/32267
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-10-26 08:57:59 +02:00
c8ed47df48 doc: drop latex support, add pdf support
latexpdf fails with error message "Too deply nested".
We want to avoid reducing the nesting level of doc strings
in frappy.lib.classdoc (less nice output) or a level of
nesting in method doc strings.

- latex removed from Jenkinsfile
- added support for rst2pdf

Change-Id: Ieb3355ef506e636e7e43a726c68327e3b1154469
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/32406
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-10-26 08:55:48 +02:00
39fd6e0be3 frappy.client: fix the case then timestamp is missing
the previous version failed when timestamp was missing

Change-Id: I77e1fb81b19fb4ee2749d731bafacbac46132f8e
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/32404
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-10-25 13:05:24 +02:00
Alexander Zaft
69bb896ebb mlz/demo: move old examples to Attached
change very early version of module attachments in GarfieldMagnet and
MagnetigField to use Attached

Change-Id: I616ad17bc72cd93d86e1b3e3609543cfe90edcd8
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/32250
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
2023-10-11 14:42:01 +02:00
Alexander Zaft
757e96e7c0 core: move module handling out of dispatcher
Split module handling code from the dispatcher.
The new class for managing Modules is called SecNode.

* change logging to no longer need a reference to modobj
* modules get a reference to the secnode obj instead of the
  dispatcher
* intermediate usage fixes for frappy_psi/sea

Change-Id: Ifee4bb47aa7a4508bb4a47c9a5873b7e2d5faf67
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/32249
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
2023-10-11 14:41:49 +02:00
8d26ab4fe2 frappy.io: change default to retry_first_idn=True
Looked at this code again, and wondered why the default is not True.
It is far more probable that the programmer just forgets to set
this property to True than it would harm to do so.

Change-Id: I439aedbdfc9c2b12737e3ce1694e90550ddf0e78
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/32270
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-10-06 15:27:43 +02:00
Alexander Zaft
a3651f71f2 psi: fix Done import in sea
Wasn't caught during change 31697. Imports Done from modulebase instead
of modules

Change-Id: I54389f83092fef7847867a7e6681fc36c42ff446
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/32265
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-10-05 16:04:10 +02:00
Alexander Zaft
48c9853b37 all: remove coding cookies
Change-Id: I53a4d79c3ebc50b8aed43a5ef1fa6538f8059a47
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/32251
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-10-05 10:43:39 +02:00
Alexander Zaft
c68529d42d server: handle signals during startup
previously, the signal handler would ignore SIGINTs and SIGTERMs during
server startup, so if there would be e.g. non-respoinding hardware, the
program could not be exited until a timeout occured.

For now, the default signal handler will be called. Later, we should
consider cleaning up the partial started modules.

Change-Id: I5bb802b5d996bb03dfa2679c1497e298fde1dd17
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/32247
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-10-04 10:32:27 +02:00
4b5e02c957 proxy: fix command wrapper
bugfix: return only value of execCommand result, not qualifiers
Change-Id: Iff14779050daa9886e9f7d0396317c5a41695cd1
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/32235
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-10-02 13:38:37 +02:00
Alexander Zaft
7d85d85963 core: factor out accessibles from init
* factor out adding of accessibles

Change-Id: I02c9d5ebc234f37be33ff0803248d05c65440c0a
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/32206
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-09-26 15:00:44 +02:00
Alexander Zaft
d7ab35a461 core: split module code
* split base and interface classes for Module into separate files.
* fix some imports

Change-Id: I92035863f138849c683bab9190df96a82b86143a
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31697
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-09-26 14:58:49 +02:00
dd67c48c9e bug in Attached (fix after change 31470)
An attached property may be defined with mandatory=False.
In this case, when no value or an empty string is given,
<modobj>.<attached_mod> must return None after initialisation.

+ remove 'dispatcher' level from the logger hierarchy on modules

Change-Id: Icee3ae3f9142cd7a910c579ae1ffaa35f93cee03
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/32187
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-09-22 10:32:36 +02:00
4f86fc5c3c frappy_psi.sea: small fixes
- changes in return value of frappy_config command in sea
- do not store sea manager

Change-Id: I5bc1d9a281ad2285b90d3649b4c702a3501d451d
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/32166
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-09-19 10:57:01 +02:00
4db1421b52 phytron.py: improve status
better analysis of hardware status code

Change-Id: I667b443649db43ff3e572e0a50685aabc9ba2ca2
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/32165
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-09-19 10:56:50 +02:00
81279d3b61 introduce FrozenParam
For the case when the readback of a parameter does not reflect the
change immediately.

May also be used on Writable.target or Drivable.target with a short
BUSY period.

+ bug fix in an error message in frappy.datatypes.IntRange

Change-Id: I5e1c871629f9e3940ae80f35cb6307f404202b4a
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31981
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-09-15 13:20:25 +02:00
ebb076a485 improve client shutdown time
in SecopClient.disconnect joinng the reconnect thread may take
up to 10 s, because of the time.sleep(10) call in the reconnect
thread.

change the _shutdown attribute from bool to an Event, and
use Event.wait instead of time.sleep

Change-Id: Icea6a14ad73df0b3d26ef45806f4c05e6bf18492
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/32137
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-09-14 08:59:50 +02:00
98f9b2b8ad change FloatRange arguments minval/maxval to min/max
in the previous version FloatRange(max=100) was neither working
properly nor complaining, because the maxval=None default was
overriding the value for max.

possible fixes:
  - raise an error when min/max used as argument (confusing for
    the programmer, as it is a property)
  - allow both versions minval/maxval and min/max (more code)
  - use min/max and a pylint directive here (the only thing to
    take care is not to use the min/max builtin in __init__)

this change uses the last option for the fix

Change-Id: Iff0e0c4d0d7b165003bdeffa67a93a1cd7f29eea
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31982
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-09-14 08:59:34 +02:00
e416a657fd fix frappy_demo.lakeshore
reading back the target does not work properly, because
  a) the readback value might be delayed
  b) there is no command to read back the target, SETP?1
     is returning the working setpoint, which might be distinct
     in case of a ramp

Change-Id: I0da2dbfc1a8ddbecbae6d0456ff64e008bc56336
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31983
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-09-14 08:59:13 +02:00
19c0bcdf14 psi: improve sea interface
- get return value from teh frappy-config script in order
  to detect failures
- call config_check not more than once within 1 sec

Change-Id: Ibe42e846521206463f2761d452aea7e558a36854
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/32139
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-09-14 08:48:16 +02:00
0d2c677de3 fix missing .poll attribute in simulation
using super() in SimBase.__new__ fixes the problem

Change-Id: I18d0ba6ac476c2edb0d973090bcb09508a983d6a
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/32136
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-09-13 14:39:46 +02:00
c7c6d60a99 further fixes after change 31470
- get_module is to be called when io is autocreated
- register_module is missing in playground

Change-Id: I28884575b71320667107c494473b0fc5d4363a50
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/32123
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-09-12 09:41:01 +02:00
20b6d3e953 frappy_psi.phytron: further improvements
unfortunaely, sometimes communication errors happen.
workaround: try several times reading the status

Change-Id: I2788c6c9b4145246cdd51c31b246abffee60f93b
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/32032
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-08-25 08:18:59 +02:00
Alexander Zaft
d946efa629 frappy_mlz seop: add count to ampl and phase cmds
Change-Id: Id7faca31269bb481ec4010f1e0aec2591f0299d6
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/32030
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-08-23 08:54:17 +02:00
3b95277152 fix frappy/playground.py after change 31470
assumptions about dispatcher in playground.py are no longer
valid.

- let Dispatcher class in playground inherit from real dispatcher
+ improve log messages

Change-Id: I2a9a9d532dabadc590543660c445c021dd2f2891
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31967
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-08-22 08:06:31 +02:00
2e74172869 interactive client: improve keyboard interrupt
- when driving a module with <module>(<target>),
  keyboard interrupt should send stop()

- make sure keyboard interrupt does not only stop
  the current driving, but also skips other code
  on the same command line

Change-Id: Ib4d2c4111dc0f23bf07385065766fb9b4a611454
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31926
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-08-14 14:35:13 +02:00
501b781144 frappy_psi.phytron: stop motor before restart
restarting the phytron motor without prior stop leads
to funny behaviour.

- send stop before restart
- stop motor when moving but status not busy
- restart when motor drives the wrong way

+ better status text when stopping

Change-Id: I82cd59297b3c79a354a4eeb5ba03fc65bedf755f
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31929
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-08-14 14:28:09 +02:00
2272aecf0f frappy/protocol/interface/tcp.py: use SECoP_DEFAULT_PORT
import SECoP_DEFAULT_PORT instead of defining DEF_PORT

Change-Id: I02ee420d200f90b61f8c79e1cb5ee3e0913955e9
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31913
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-08-07 16:13:05 +02:00
3569876bfc improve error message on client when host/port is bad
for host name without port, None was used for the port
leading to a confusing error message

- do not call parse_host_port with None as defaultport argument
- improve error message when connection fails

+ fix an error in last line of parse_ipv6_host_and_port
+ fix some issues breaking PEP 8 rules

Change-Id: I437360be96449c164f0080e3c60f1685825d4780
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31911
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-08-07 15:11:53 +02:00
Alexander Zaft
4d3d78ad3c frappy_mlz: fix one-off error in barcode reader
cut of one byte too much in barcode decode

Change-Id: I5f1f8475f197b13af836d685dc6da5a9ee824dc2
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31728
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-07-21 10:13:47 +02:00
Alexander Zaft
5b95a0ccca add zapf to requirements-dev
Change-Id: I6dddd8d4c590253f1039b89edae561fa90b40811
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31725
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-07-20 15:29:00 +02:00
Alexander Zaft
8232b106a7 Revert "add zapf to requirements-dev.txt"
This reverts commit e67a46cd01.

Reason for revert: required version available from pypi

Change-Id: Ib4f8b0cf62da58e84545511c7521ea93b7ff1342
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31724
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-07-20 15:22:35 +02:00
Alexander Zaft
bc652f00bc frappy_mlz: Add Zapf PLC
adds a zapf-based PLC connection scanner.

Change-Id: Icc0ded7e7a8cc5a83d7527d9b26b37c49e9b8674
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31471
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-07-20 09:27:25 +02:00
Alexander Zaft
e67a46cd01 add zapf to requirements-dev.txt
Change-Id: Ia4de696051cee1e00676e777b7dd2c0a90a0c504
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31719
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-07-20 09:05:46 +02:00
Alexander Zaft
a974f85a41 core: do not call register_module on error
Dispatcher.get_module_instance returns None on failure.
If that is the case, the dispatcher should not try to register the
None value as a module.

Change-Id: Ie33b8debc2a829d480d56cafc1eb0ab610181d67
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31713
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
2023-07-20 07:46:06 +02:00
Alexander Zaft
819e2c5381 dispatcher: change logging calls to debug
Some logging calls should not have landed as log.info in the dynamic
modules patch. This fixes that.

Change-Id: I666fc7c9b5c65ddbed1c26ea456becce7870e744
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31707
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-07-18 10:38:05 +02:00
Alexander Zaft
c6796a1199 frappy_mlz: Zebra fixes after basic test
Some fixes after the device was tested with socat ptys and NICOS.

Change-Id: I3e9dba2be2547d493c435d1da9844c932a2df4e6
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31662
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-07-13 07:19:40 +02:00
Alexander Zaft
2a769bbb40 mlz: Add Zebra Barcode Reader
Adds a Barcode reader device (for now, only for ANTARES). Not yet
tested with real hardware.

Change-Id: I25f097466be89d152f47b9d05ece8f562e4b34d6
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31412
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-07-11 14:58:49 +02:00
7ee65f47ee frappy.client.interactive: bug fixes
- correct behaviour with the following untypical message sequence:
  - send change target
  - receive status idle
  - receive status busy
  - receive changed target

- add 'exception' to Logger

Change-Id: I614b2a2c2e09ef1b43544838ccb2fa43357dd50d
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31632
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-07-11 09:02:39 +02:00
285df89d4d frappy_psi.sea: further bug fixes
- in SEA, it is not guaranteed that the is_running state is set
  before the run command returns. as a consequence, we have to
  wait in SeaDrivable.write_target for is_running being set
- syncio has always to be reconnected after asynio

Change-Id: Ia46cff11de86868ce0627faaf6f776282bd7a8f4
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31631
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-07-10 18:32:52 +02:00
78e8b9127f frappy_psi.sea: avoid multiple connections
the _connect method was sometimes started in parallel
from startModules and the first call to doPoll.
remove the first one, and protect the second one
with a lock

Change-Id: I079439e150efd5d005130cef475f6326f933ecbd
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31611
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-07-07 15:49:18 +02:00
8647814220 frappy.io: make error reporting consistent
- fix mechanism to avoid multiple error messages in log files

Change-Id: I688071f9b06da1a81eb12d63adb549042171c7c8
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31610
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-07-07 15:48:59 +02:00
9935546efd add frappy_psi.thermofisher to the doc
Change-Id: Iae7a611485446c80d831949f74f449520319729e
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31582
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-07-06 16:51:21 +02:00
830b5b3be0 add frappy_psi.thermofisher
ThermoScientific A10 bath thermostat

Change-Id: I7ce1ac8845ac539ff7cb1fcca84d0abebba61f07
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31408
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-07-03 08:39:01 +02:00
fd2d05d7b5 add StructParam
adds a generic solution for creating parameters with struct datatype
with their members linked to individual parameters.

main use case: ctrlpars

read_*/write_* methods are either created for the main (structed)
parameter based on the corresponding methods of the individual
parameters or the methods for the individual parameters are created
based on the methods of the main parameter

+ disable pylint use-dict-literal

Change-Id: I7f1d9fb3d3b2226b548c2999bbfebe2ba5ac285e
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31405
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-07-03 08:29:53 +02:00
Alexander Zaft
01348e0c7c server: add option to dynamically create devices
add module which scans a connection and registers new devices depending
on the answer.
* change module initialization to demand-based
* move code from server to dispatcher
- remove intermediate step in Attached __get__

TODO:
  factor out dispatcher (regards to playground)
  discuss factoring out of module creation code from server AND
  dispatcher

Change-Id: I7af959b99a84c291c526aac067a4e2bf3cd741d4
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31470
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-07-03 07:23:30 +02:00
fdf82c3989 pylint: disable use-dict-literal
sometimes it is nicer to use dict(...) instead of {}
an objections against removing this check from pylint?

Change-Id: Ib08d3016b7ec3512111021a82685253cdcd42916
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31505
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-06-30 08:15:11 +02:00
9ece4f797b frappy_psi.sea: try to reconnect on failure
both .asynio and .syncio connection should be tried to reopen.

Change-Id: I836ede1e5fff6f7ac670c92e769da8ec834d2b12
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31449
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-06-28 17:33:40 +02:00
b47e5d270c fix frappy.lib.merge_status
merge_status should consider that the status text in arguments
is already composed. add test for this.

Change-Id: Ia000d1e1d8e97a5c2b5ef9d1569cc123232016ae
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31378
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-06-28 11:49:38 +02:00
Alexander Zaft
cffe301c26 add test cases for server and config
Change-Id: I36427cab769785a9495851348f5e2ed1f20bcbc9
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31324
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-06-22 09:56:40 +02:00
Alexander Zaft
83d11da5ae server: Add signal handling
previously, no cleanup would be performed, SIGINTs being catched above
the server.run() function
+ signal handler for SIGINT, SIGTERM
* put serve_forever in its own thread, to be able to call shutdown() on
  the server

Change-Id: Ia5c021f3d6fd60ff2b9012c10e30715f93104977
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31340
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-06-21 08:33:22 +02:00
4c911d58b7 frappy_psi.convergence: bug fixes and improvements
- consider that super().read_status() might not exist
- use empty status text instead of 'approaching' for simple busy
- test for tolerance should use <=

Change-Id: Idfd59fcec02827e0eb0105a9ff3b9efb54e41d71
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31379
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-06-20 16:59:24 +02:00
Alexander Zaft
d079bd15e7 Add shutdownModule function
Add and call shutdownModule function, in order to allow modules to clean
up.
use shutdownModule instead of shutdown to avoid confusion with
severs/dispatchers shutdown and to make it consistent with initModule
etc.
Try to resolve module dependencies

Change-Id: I2a091bf74ecadc2395fcdf92c599f1c49eb120f5
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31339
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-06-20 16:16:08 +02:00
Jenkins system
0c45755170 [deb] Release v0.17.13 2023-06-20 14:38:00 +02:00
Alexander Zaft
b91905fc04 server: fix systemd variable scope
Change 31280 introduced an error where an import was overridden, which
leads python to consider it a local variable, preventing access to the
systemd import. (TODO: a better way to handle the systemd import?)

Fixes: #4732
Change-Id: I5188a8737392bd8befcdfa9af044a21be9af908a
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31386
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-06-20 14:35:48 +02:00
5727ecbc7f frappy_psi.sea: bug fixes
- left over fixes from config file format change
- sea enums might be texts - create SeaEnum datatype for this

Change-Id: I1f1baeeb4d6a0b13b5ec42d651bc0fc37b0fdf2c
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31380
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-06-20 09:39:02 +02:00
27b8deeb2e frappy_psi.magfield: bug fix
Change-Id: I8c004fe6ab840b3b6f270702a636a96ebba8c0b8
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31381
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-06-20 09:38:40 +02:00
98c8600117 frappy_psi.triton: fix HeaterOutput.limit
+ fix handling of control_active

Change-Id: Ic11933f6c1c4d9df07aa9d06ae4dca40b755e4ed
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31377
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-06-20 07:50:20 +02:00
f7129f6a00 add a hook for reads to be done initially
inital reads from HW should be done in the thread started by
startModule, not in startModule itself.

- add a hook method 'initialReads' for this
+ add doc for init methods
+ fix some errors in doc

Change-Id: I914e3b7ee05050eea1ee8aff3461030adf08a461
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31374
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-06-20 07:41:47 +02:00
2feff36077 frappy_psi.mercury: proper handling of control_active
Change-Id: I31e846fa6fdf6d642184e3736a66ffd53033bccf
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31376
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-06-19 17:04:55 +02:00
04b6ad09ba frappy.mixins.HasOutputModule
add 'set_control_active' method for overriding by subclasses

Change-Id: Ib344319862a4a0bf29efef16a63db09d1f314a82
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31375
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-06-19 16:50:57 +02:00
06175da887 frappy_psi.phytron: rename reset_error to clear_errors
use the command 'clear_errors' to return from an error state

+ make sure target is valid after clear_errors

Change-Id: I3c180500a05836d52bbb9a8ecbdb397adea03d0d
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31337
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-06-19 16:50:38 +02:00
9306596cb2 frappy_psi.mercury/triton: add control_off command
frappy_psi.triton.TemperatureLoop has not output module to
deactivate control -> add control_off also to loops in
frappy_psi.mercury

Change-Id: I4dc4333134da34a8d3ae0f3c037a1e5b108c95a1
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31341
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-06-19 10:36:10 +02:00
666ebf5719 GUI bugfix: use isChecked instead of checkState in BoolInput
Change-Id: I4896df13c117c6eeaaaaba80ca3da4b1982c3d9b
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31346
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-06-15 16:36:12 +02:00
Alexander Zaft
3783210b81 add egg-info to gitignore
Change-Id: I33e8987e552383776717e6176567988702be092a
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31338
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Reviewed-by: Bjoern Pedersen <bjoern.pedersen@frm2.tum.de>
2023-06-14 13:36:13 +02:00
Jenkins system
18f2fa05c9 [deb] Release v0.17.12 2023-06-13 06:51:28 +02:00
Alexander Zaft
b0e23466cc entangle: fix tango guards for pytango 9.3
Change-Id: I666969f9c798971d5cd8a0c2f6564067ac3cde72
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31327
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
2023-06-13 06:50:51 +02:00
Alexander Zaft
6802e8f9d3 io: followup fix for retry-first-ident
followup fix: no error was raised ever for the first identification
message.

Change-Id: I80f0f431add6dfd7b37d750b9fc661174aa8f217
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31318
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-06-12 14:02:47 +02:00
Alexander Zaft
ff9f7239cf config: fix merge_modules
Change-Id: I31d05afe300443e08fb08f9e6645401f52cfae39
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31323
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-06-12 14:02:22 +02:00
Alexander Zaft
15ca3c984d io: add option to retry first ident request
Change-Id: I524c15387eaf2461e3dfe690250a55f058467b0b
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31291
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Bjoern Pedersen <bjoern.pedersen@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-06-07 10:25:34 +02:00
68d74347c6 silently catches error in systemd.daemon.notify
our version of systemd installed does not accept
a string as argument for systemd.daemon.notify

anyway, whether systemd notifications are sent or not
should not depend only on the presence of a package,
but should be configurable.

Change-Id: I466d1ed2b969301a287dd532ab4d0743a74045fa
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31280
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-06-02 16:50:11 +02:00
Alexander Zaft
a11b8cf2d1 seop: fix fitparam command
Change-Id: I75589f4c9d954ebb189bd9c785e9f307767fa69d
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31273
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-06-02 09:47:45 +02:00
Alexander Zaft
4a80b4e45d Typo in influences description
Change-Id: If834790c2d269a5c988703da2fcc1764202b5021
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31269
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-06-01 15:56:18 +02:00
Alexander Zaft
d3c9666593 Add SEOP He3-polarization device
Change-Id: Ifd85584da154b629fdb88c1f4a8605bd788c82e6
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31176
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-06-01 14:32:28 +02:00
fa4349784c frappy.client: dummy logger is missing 'exception' method
Change-Id: Id22fe73f3c507e626602ddf045f7a02ed8873f91
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31241
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-05-31 16:19:16 +02:00
Alexander Zaft
815e91ae26 Add influences property to parameters/commands
Change-Id: Ica1cc40155cae9b6f52788c8559399030c07d379
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31234
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-05-31 09:14:18 +02:00
Alexander Zaft
3b92688b84 Warn about duplicate module definitions in a file
check for each file, if every module definition occurs only once

Change-Id: I4f37f67c07d68068cbced718908927a594defc88
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31194
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-05-25 14:12:07 +02:00
Jenkins system
37337ac959 [deb] Release v0.17.11 2023-05-25 09:38:25 +02:00
Alexander Zaft
af0f9b39b5 Fix rstrip misuse in frappy-generator
rstrip uses its argument as a set of characters to strip from the
string. Cut the last four characters with a slice if applicable.

Change-Id: Ia2198acf43f92d6f5d687122301f4a5e5324ac31
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31181
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-05-25 09:31:16 +02:00
a643093934 client: timestamps must never lie in the future
+ use log.exception for error in callback
  (nicer when called from nicos)

Change-Id: If6d3036d9876457e57b996e5b20343d28f99451b
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31160
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-05-24 09:08:07 +02:00
d8c0a1c507 phytron motor driver
an example for HasOffset and limits

+ cosmetic improvement of HasStates.start_machine

Change-Id: I34cbfa65dc04947285d8c901715899915f28fdaf
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31070
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-05-23 16:19:58 +02:00
bda0afe042 client.interactive: fix error when interface_classes empty
Change-Id: I7a4f3052d4c666186930b3b6dceca5f18d89d4e3
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31078
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-05-23 16:19:27 +02:00
4b307fe92a add unit=s to pollinterval
Change-Id: Ie352b3c044cafacbf2e3516284ea8bd1a68f23cc
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31071
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-05-23 16:16:06 +02:00
04d7d0249a move more code from bin/frappy-cli to frappy/client/interactive.py
allow to call console client easier from outside frappy

Change-Id: If08c5a27ca371a96d9ceedac2e2a7ea576740a60
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31083
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-05-23 16:15:01 +02:00
Georg Brandl
386e5d241e debian: add new executable
Change-Id: If0faae7aff20a75d1aa327d7da3ddcc48854238c
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31152
Tested-by: Georg Brandl <g.brandl@fz-juelich.de>
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
2023-05-23 07:30:47 +02:00
ccb33b81b3 add sea driver
+ fix a bug in frappy.client.ProxyClient: move CacheItem stuff to
  frappy.client.SecopClient.updateValue, as ProxyClient is used by
  SeaClient and does not know Frappy datatypes

Change-Id: I3aef9fdddbdd2bbef0c56a10c8a8031e4acc5993
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31065
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-05-09 14:49:21 +02:00
37e18a8a5b driver for mercury IPS
OI mercury series magnet power supply

Change-Id: I1ec20435a9e585c543afc736355e39da72eff879
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31009
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-05-09 14:49:12 +02:00
dfe0038494 improve traceback while processing config file
the filename of the executed config file has to
be known to 'exec' for a meaningfull traceback

Change-Id: I3403740dc9198ce5f64741fbb112cb908159c704
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31055
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-05-09 13:03:53 +02:00
Alexander Zaft
259970249a Fix lower limit checking of FloatRange
compatible used sys.float_info.min (smallest representable positive
float) instead of -sys.float_info.max.
so FloatRanges -500,10 and -10,10 were two-way compatible
Since it is correctly set in __init__, no need for the guard here

Change-Id: If693fa69a8b2de1aa52ce702bd282a84a8f4c55a
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31056
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-05-09 08:49:41 +02:00
3a3ca0372b fix interplay mercury.TemperatureLoop and HasConvergence
frappy_psi.convergence.HasConvergence:
- no need to inherit HasStates (should be independent)
- trigger current state then tolerance or settling_time is changed

frappy_psi.mercury:
- improve readback checks
- fix interplay with HasControlledBy
- fix interplay with HasConvergence

Change-Id: I6efedbe6bbfba5a66ddd22ac441ebf38af11eda6
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31047
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-05-08 14:41:30 +02:00
bc2b860f31 mixins should not inherit Module
else conflicts building MRO may arise

Change-Id: Ifdfc5000884d5d815a55eca6dbb5198b19410890
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31046
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-05-08 14:39:07 +02:00
Alexander Zaft
e20986c65b Fix interface class list
Communicator Modules were exported with the interface class Module
instead of the correct Communicator interface. Modules that combine
Drivable etc. and Communicator also did not have Communicator listed
as a second valid interface class.

Change-Id: Ib74d866cf97631f7fbc29ea9914b2968010cf226
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31037
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-05-08 10:32:48 +02:00
0153975d32 add HasOffset feature
+ remove all other unused features

Change-Id: Ifb276562a50c656b887cd9bbd5c865cae514d5ff
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31022
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-05-05 13:06:51 +02:00
e4bb28aa09 improve and fix errors with parameter limits
- in order to work properly, readonly=True in limit parameters
  has to be set before creating the write_* method
- more explicit: Use e.g. target_max=Limit()
- fix an error in the loop over the base classes when creating
  the check_* method
- more concise error message when a limit is violated
+ fix an error in playground when using persistent parameters

Change-Id: Ibd557b55d6c0d9a2612cda4460b16e3c70e1bc9e
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31017
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-05-05 13:06:24 +02:00
761b7b4cf8 fixes on HasConvergence and HasOutputModule
- HasConvergence must inherit from HasStates
- control_active should have a default

Change-Id: Ic8b430003fdb746bf76782b74fa04e43c700c2e2
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31023
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-05-04 16:29:52 +02:00
ed61a2f7ce driver for the triton dilution refrigerator
using the trion software on a windows PC.
the interface ist similar to the IO mercury series

Change-Id: I148f03bf2dfa91023432d1317a93a24e9f849e44
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31011
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-05-04 15:49:00 +02:00
f48a742bb5 improve mercury driver
less fancy but more readable commands

Change-Id: Ifcc6a03199167179d984235c9b1bc7e14c60b51b
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31008
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-05-04 15:48:38 +02:00
6d7fbda286 fix in frappy_psi.historywriter
Change-Id: I85266c2761c3d015098129bd9b5d604c05d85bde
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31021
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-05-04 15:35:08 +02:00
Alexander Zaft
5283b06cb7 Add Stopgap handling of cfg files in cfg-editor
Basic parsing and writing of python config files.
Does not preserve comments, can't transform the
old format to the new one.

This is just so the executable that is delivered
actually does something with the new config files.

Change-Id: I4bb8310e1af7a05f90dd426dfa629080583aff66
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30935
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-05-03 14:51:35 +02:00
Alexander Zaft
f491625dd1 Improve address and connection handling
* improve address checking
+ add ipv6 capabilities

Change-Id: I5369336bec449c27d79d857018f319266dfd4d0e
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30885
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-05-03 13:28:03 +02:00
Jens Krüger
a49d64953c MLZ/Entangle: Fix user limits handling
The user limits should always inside the absolute limits.

Change-Id: Ib678b52b6fd1e6badaec72a59eb18dc65a883c9e
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30970
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Jens Krueger <jens.krueger@frm2.tum.de>
2023-05-03 09:57:02 +02:00
Jens Krüger
507a941459 MLZ/Entangle: Add unit init in AnalogOutput
The init of the units in AnalogOutput should follow the same algorithm
as the AnalogInput branch

Change-Id: Ica5349f389d28fef2c97037d2b61266bc395b2f7
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30969
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Jens Krueger <jens.krueger@frm2.tum.de>
2023-05-03 09:53:36 +02:00
Jens Krüger
02c20f5296 Server: add missing 'restart_hook' missing
Change-Id: Iac6349c86ee7cc5c55177e881a51a240df260d6f
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31004
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Reviewed-by: Jens Krueger <jens.krueger@frm2.tum.de>
2023-05-03 09:52:55 +02:00
54c0a6062a improve interactive client
- remove irrelevant traceback on remote errors
- add run() function to execute scripts
- when started with bin/frappy-cli, use separate namespace

Change-Id: Ic808a76fa76ecd8d814d52b15a6d7d2203c6a2f3
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30957
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-05-02 15:48:46 +02:00
140a3e9e8a improve mercury temperature loop
- remove appearance of Done
- add auto flow
- try up to 3 times in 'change' method if read back does not match

Change-Id: I98928307bda87190d34aed663023b157311d4495
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30981
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-05-02 15:27:36 +02:00
3cea8580ae issues with StructOf
- depending whether client or server side, handling of optional is different
- fix issues when struct is used as keyworded command arguments

Change-Id: I72b347b1a96ee3bce1f67dace4862c313c12c7a9
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30972
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-05-02 15:27:25 +02:00
65ff0c0fc3 a playground for debugging drivers
playgound for trying out drivers by calling methods read_*
and write_* directly without starting a real SECoP server

Change-Id: Ia7d2366920d29794a4eda5d7bfb2b62d4930eb65
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30944
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-05-02 15:27:12 +02:00
21427ca765 frappy_psi: two small fixes in k2601b/ppmssim
Change-Id: I5b3a333fd6e79d1f09d540726ce0a91580c63d08
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30983
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-05-02 09:46:21 +02:00
3929a37e93 fix issues with lakeshore 370
- simplify parsing/formatting of LakeShore commands
  -> allow 'g' as enum format
- HasIO: check missing io later
- ls370res.ResChannel: get io for channels from switcher
- rwhandler.CommonWriteHandler: return value in write method
- frappy_psi.channelswitcher: fix the case when default channel does not exist

Change-Id: I28dd94cdf922cde307b870d4ffdfc64664c3423b
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30949
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-05-02 07:56:14 +02:00
ea5cdbbe44 improve error handling on callbacks
errors in callback functions should be reported to log,
but not stop the callback chain

Change-Id: I4fc509b7121960ebe59e1ad4f4b4746dfb4d5ba3
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30950
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-05-02 07:48:05 +02:00
Jens Krüger
827d27ed59 MLZ/Entangle: Fix formatting issues
Change-Id: I33b90a202ef55260159d13de1ecda8ca107e5bf3
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30968
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Reviewed-by: Jens Krueger <jens.krueger@frm2.tum.de>
2023-04-28 10:14:06 +02:00
5f4e5d22b7 make io device visible as expert by default
Change-Id: I49204bd2f951413e660d701ed67c0c08bcc29e43
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30967
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-04-27 16:39:05 +02:00
Alexander Zaft
97083a4db5 specify minimum pyqt5 version
Change-Id: I06f169fc9fc8734a9284e3db570e58422c271c92
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30938
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-04-24 14:11:40 +02:00
1d97a422c2 fix error from manual %-format conversion
frappy_psi.ppms (line 263) was not correctly converted probably due
to the fact, that dict access with f-strings gets quite ugly.

As it seems we want to get rid of %-format, use str.format_map here.

Change-Id: Idf5b700554aa7a02a6647dc4672bf4a3856f92a5
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30933
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-04-20 17:17:31 +02:00
Alexander Zaft
4b2500a9d7 Add __format__ to EnumMember
Make the format specifier 'd' able to be used when formatting them
in f-strings as an alternative to an int()-cast.

Change-Id: I4083aa0f4b0d8d10e3e11a29591cfbf5e5aca03d
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30902
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-04-20 13:36:04 +02:00
Jenkins system
9e7a0a8c1d [deb] Release v0.17.10 2023-04-19 14:32:52 +02:00
Alexander Zaft
805df680da make entangle mapping a dict
Change-Id: I38d863a907469674001f0721140f88c17b53635b
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30911
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-04-19 14:29:11 +02:00
Alexander Zaft
0bf4b6cdf2 Manually convert most remaining format statements
%d accepts floats and other things, so manual fixes are needed after
conversion.

After flynt -ll 2000 --aggressive, each was manually checked if the
casts with int() are needed.

Two statements are still missing in ls370res

Change-Id: I2651ddbe60695aa19582882a97d0f71bcb05c1ef
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30901
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-04-19 13:59:54 +02:00
Alexander Zaft
32b6d6ffc2 Rebuild NodeWidget when the description changes
+ add descriptionChanged signal
* track detached of TabWidgetStorage correctly
* build new NodeWidget when the nodes description changes. the old one
  is replaced

Change-Id: I61e60c61b7c2c975819730cb98562657a66f16af
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30910
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-04-18 10:05:22 +02:00
Alexander Zaft
bbddb6c572 [WIP] gui: add specific input widgets
+ add bool, enum and generic input widgets

Change-Id: If6962ed6f2c96a319d4ed8c8ee5fb8c03f6e7f82
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30723
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-04-17 08:57:24 +02:00
Alexander Zaft
de1579c34a move unit into display label
TODO: decide if this is preferable to a dedicated label
Change-Id: I707fad5ab85bf2de53f82bc638a9fe20eb26f14e
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30786
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-04-17 08:50:34 +02:00
Alexander Zaft
34183453e0 Convert formatting automatically to f-strings
Automatically convert formatting with the following call:
flynt -ll 2000 -v frappy*
Result: 303/381 auto-converted.
Failing conversions will be looked at manually in a follow-up commit.

Change-Id: Icd996b27221202faccc15af78e0380cf52ee37f2
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30900
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-04-14 15:50:27 +02:00
Alexander Zaft
c114dbab26 Change leftover %-logging calls to lazy
Change-Id: I0bee8d02ac364ab93f77919cae78afa386b85c85
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30899
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-04-14 15:50:19 +02:00
Jenkins system
1dcd1db4eb [deb] Release v0.17.9 2023-04-11 16:09:04 +02:00
08071acbf9 interactive client: avoid messing up the input line
- trigger a redraw of the input line when asynchronous log
  messages arrive
+ do not print traceback on 'remote' errors
+ persistent readline history

Change-Id: If85fd064c1c09c44e0cb0ebccbfc1b6411ad5aac
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30793
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-04-05 10:43:06 +02:00
Jenkins system
4ad9669531 [deb] Release v0.17.8 2023-04-05 07:20:26 +02:00
Jens Krüger
33f9f39f3c Debian: Fix typo
Change-Id: Iba218600bd60ad663869cee7758d6d4ac1387908
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30864
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Jens Krueger <jens.krueger@frm2.tum.de>
2023-04-05 07:19:18 +02:00
Jenkins system
59131c7456 [deb] Release v0.17.7 2023-04-05 07:07:25 +02:00
Jens Krüger
5245779fd9 Debian: add pyqtgraph dependency
The pyqtgraph version should be >= 0.11.1 (tested on Debian 11), so the
buster installation won't run without manual interaction: Installation
of pyqtgraph via pip

Fixes: #4711

Change-Id: If785da5578ac7f3812d8d49bc36d055cde4a37f9
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30859
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Jens Krueger <jens.krueger@frm2.tum.de>
2023-04-05 07:06:16 +02:00
Jenkins system
fed071d74a [deb] Release v0.17.6 2023-04-04 08:42:26 +02:00
Jens Krüger
d79a24221b Fix debian GUI package dependency
The current python packages for Qt5 are called 'python3-pyqt5*'

Change-Id: I36bba2be50eb8769b01eeaf1202b32d3c849fc56
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30854
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-04-04 08:39:56 +02:00
bf83f9a185 improve error messages
- treat validation errors of the result of write_ and read_ messages
  properly
- add info about the called read_* and write_ methods to the error
  message, in case the error is not raised in the outmost method
- as subsequent errors in poll functions are logged only once, log an
  info when a poll function succeeds again
- remove DiscouragedConversion error

Change-Id: Ib66e001cc95de8225751a1464a92594c369ceb3f
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30788
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-04-04 08:15:26 +02:00
Alexander Zaft
c1d5b77e9c cli: add argparse and inlcudes before repl
+ add argparse to cli
+ add option for files that are executed after connection to the modules
  but before repl starts
+ add option to skip interactive mode after executing files

Change-Id: I8f01db84b2c91d4bf1a7b397e8fa1bf0c87ddf0d
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30823
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Tested-by: Markus Zolliker <markus.zolliker@psi.ch>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-04-03 11:30:53 +02:00
Alexander Zaft
9791f15807 add optional validation to ValueType
* add optional parameter for ValueType: validator
used for checking, if a value meets a criteria (e.g. is dict)
+ InternalParameter, which is not exported and can hold any python value

Change-Id: If39a7a4a8019f2aa1a930e42cbef4fca59163b78
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30787
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-04-03 10:09:26 +02:00
Alexander Zaft
2daa8d49bf add copyright headers where missing
Change-Id: Ie68ed439d084b4b79d7db81b58360967f5726d7c
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30768
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-03-24 08:11:34 +01:00
Alexander Zaft
1041fd58f3 gui: logwindow improvements
* make state consistent with menu action
* colorize
* add time to log message

Change-Id: I0c0800ddb1843b826a6adacf4e4b18d52598acf2
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30759
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-03-24 07:32:03 +01:00
Alexander Zaft
56c4e221bc gui: add console history
+ add HistorySerializer to merge histories in correct order
* move console to own file
* promote msgLineEdit to class based on NICOS-HistoryLineEdit

Change-Id: I853d49a70640f38275c8762ab345003db5ec5592
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30753
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-03-24 07:31:39 +01:00
Alexander Zaft
d654708060 gui: switch group button order, change text
* change order of name and toolbutton
* change text on click

Change-Id: I6efba544d0ba63fd8065483a566643372892cc00
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30750
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-03-23 11:01:20 +01:00
Alexander Zaft
2086259bb4 gui: full module description only in detailed mode
* take only the first line of the description, this makes the normal
  view more condensed if it is formatted like a git commit message or
  similar

Change-Id: I268dce0aa09d3ad5133815fe33577532bf0a2e96
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30749
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-03-23 11:01:14 +01:00
Alexander Zaft
205789a51d gui: show parameter properties again
* parameter properties shown with own button
* for now as a popup window

Change-Id: If3b51eb66a759c207591f1341126557f2c6e4a3d
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30748
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-03-23 11:01:04 +01:00
Jenkins system
6bb3104134 [deb] Release v0.17.5 2023-03-22 12:32:06 +01:00
Alexander Zaft
b6204d5fbc Fix generator
Change-Id: Ic332e9c130b56e446787af87718d4028f2aac714
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30746
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-03-22 12:31:45 +01:00
Jenkins system
bd7ecbe167 [deb] Release v0.17.4 2023-03-22 11:44:34 +01:00
Alexander Zaft
78ab28c6d3 Fix entangle integration bugs
found during ccr-box adaption
* missing param description DigitalOutput
* missing Writable baseclass in DigitalOutput
* rework ccr config file

Change-Id: Ie40f875caacd374b02e6f6175b5fb003619c5f4e
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30743
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-03-22 10:18:23 +01:00
Jenkins system
013d20e8af [deb] Release v0.17.3 2023-03-21 15:55:10 +01:00
Jenkins system
2a4b94aa3b [deb] Release v0.17.2 2023-03-21 15:49:08 +01:00
bf809b4b9a format unit properly in the case of nested arrays
The unit is shown at the end of nested arrays.

Change-Id: I235bc40e61161e09a7b00cd1e186d8d8c1769d89
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30734
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-03-21 14:36:16 +01:00
7186759435 fix issues when closing tabs
- catch error on AsynTcp.shutdown (when already disconnected)
- avoid opening duplicate tabs
- shorten try except in mainWindow._handleTabClose to the minimum
+ fix an issue with frappy.client.CacheItem.formatted

Change-Id: Ice4086373a89a969f02e08ec90a173edbd5b0585
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30730
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-03-21 14:35:35 +01:00
Alexander Zaft
2722a0a40f gui: more greeter interactions
+ double click item to open node
+ Enter key while recent nodes are focused opens selected

Change-Id: I397f743faec70e623b5ef9a86d61625f8db7e933
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30736
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-03-21 14:18:19 +01:00
Alexander Zaft
df7dc2e612 Add SECoP link to readme
Change-Id: I5990b59e26060f9c9a2457f455537a0af28e28bb
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30735
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-03-21 13:27:20 +01:00
fb3a31761c fix generalConfig defaults
bin/frappy-server:
- the default for omit_unchanged_within must not be overriden
+ remove no longer used disable_value_range_check

Change-Id: I5c0620e44dc7df3ae2ca48f7ab6371189acae489
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30727
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-03-21 09:15:03 +01:00
80297963d2 remove UNKNOWN, UNSTABLE and DISABLED from Readable.status
- re-add them where needed (epics, entangle ...)

Change-Id: I2b8af9f5f86285f081d5418211f6940e80a1dbd7
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30718
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-03-21 08:29:49 +01:00
ace85026e0 improve frappy.errors
- include all secop errors from spec
- add doc strings
- make conversion to and from error report nicer
- move all error classes to frappy.errors
- rename errors clashing with built-in errors

Change-Id: I4d882173b020cd4baf862c5891375b691e67e24a
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30721
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-03-21 08:29:20 +01:00
a15cfc87bf simplify status type declaration
- StatusType: simpler inheritance (inherit from module instead of Enum)
- StatusType: more robust for standard codes, give names only
- <Module>.Status is automatically extended
- Enum: accept duplicates with same name and value

Change-Id: Iad1dacf14c31fe6f4ae48e7560b29e49838e4f23
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30716
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-03-21 08:18:40 +01:00
670fc39821 enhanced parameter range checks
- check for <param>_min and <param>_max
- customized checks with check_<param> method

the inherited customized check functions are all called in
a sequence, with the possibilty to return True to quit earlier,
no need to use super calls here

Change-Id: I903081abbbad2586c1e8237e303abaa3683ac419
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30632
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-03-21 07:51:28 +01:00
b80d39773b make return value 'Done' unneccessary
'Done' was introduced in order to suppress unneccessary
duplicate updates. However, since super calls on access methods are
allowed, it is not nice when such a method returns Done, as this
is not automagically replaced by the current parameter value.
As a consequence:

- using Done is discouraged, but not (yet) removed in all code
- the 'omit_unchanged_within' property is moved from Module to an
  internal Parameter property 'update_unchanged'
- its default is moved from a SEC node property to generalConfig
- the 'update_unchanged' parameter property may be set to
  'never' for parameters where duplicate updates make no sense
- this property might be set to 'always', for measurements, where
  even unchanged values taken from HW should be transmitted

Change-Id: I2847c983ca09c2c4098e402edd08d0c96c3913f4
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30672
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-03-20 14:31:56 +01:00
Alexander Zaft
c41eefba51 check configured names for spaces
reject equipment_ids and module names which contain spaces

Change-Id: I0ffe8fee13122ddfff6715863d0a82f72b5cb9f6
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30711
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-03-20 12:19:28 +01:00
Alexander Zaft
4ab33fc0fc gui: terminate connection on tab close
+ add method to explicitly terminate connection on qsecnode
* disconnect explicitly when closing tabs

Change-Id: I00af5fb296e1499b88eafc033f62fdcc1131a145
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30677
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-03-17 12:40:16 +01:00
Alexander Zaft
c6d588c881 fix README typo
Change-Id: I545835243959c9feb6781f3ed400bff53d0eb428
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30705
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-03-16 16:25:47 +01:00
e0b2747821 central point for status codes
Put status code definitions into frappy.datatypes.StatusType.
frappy.datatypes is anyway imported in servers and clients,
so this is a better place than frappy.modules.

Change-Id: I81dfc8a066f598fbd20854ed1a13b937b7facc8c
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30703
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-03-16 14:42:42 +01:00
8f9b2902d9 gui: support proper formatting of values
- use Datatype.format_value to convert all values
- frappy.client.ProxyClient: use CacheItem instead of 3-tuple
- CacheItem has built in formatting
- adapt gui to use it instead of stopgap

As it is now easy to convert to string including values, it may
be better to move the unit in the modulewidget into the value field.
This would simplyfy the code.

Change-Id: I5c06da4a24706fcbc83ebcbf8c0ea6a8eb6d7890
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30680
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-03-16 14:40:47 +01:00
Alexander Zaft
0ce1e7d8ca fix importing AsynCon without serial
importing HasIO without serial being installed fails, as the import
guard sets Serial to None, which is then called for AsyncSerials
SETTINGS attribute

Change-Id: I94a9eb5c2ff8de1a1b31f31700358d5d2226eadd
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30700
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-03-16 10:14:21 +01:00
Georg Brandl
5a182acf2d demo: fixup Switch class
Target and value are not emitting an update event upon changing target.

Change-Id: Ic01d17fd8529dc0b0a720fbc79d98c7a61fc572b
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30645
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
2023-03-16 08:47:45 +01:00
0560668b91 split BadValue into WrongType and RangeError
in order to match SECoP specification

fixes #4668

Change-Id: Ica73a8171536ccc324cf8db915347a6263c2d736
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30625
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-03-16 07:51:13 +01:00
Enrico Faulhaber
20506a8393 handle connection close more gracefully
Change-Id: Iea12e95e88fa3638f91edc2e99abb5ece3f75b4d
fixes: #4705
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30685
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
2023-03-15 18:39:15 +01:00
Alexander Zaft
c4de1d4db6 gui: Logo in greeter
+ add SECoP logo resources (3 dark text, 1 light text)
+ Add logo to greeter
TODO: when there is a frappy-logo, replace this

Change-Id: I37eb8946d291b2f5dde0b5000251a4ac363fb01f
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30596
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-03-14 14:24:11 +01:00
Alexander Zaft
80a4a123b0 gui: make module details button checkable
Change-Id: I22e5591e87e84a86ecbaf47d86d5885cf0a569be
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30676
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-03-14 09:24:54 +01:00
Georg Brandl
7be0ed5c65 isort: add firstparty
Change-Id: I38d2ee3bf617accc97069167c408b1cd1b9ef6b1
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30675
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
2023-03-14 08:20:03 +01:00
Georg Brandl
e186442084 Jenkinsfile: isort does not fail the build
Change-Id: Ide31346f35ecef3030f306698cfe4586010df020
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30674
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
2023-03-14 08:19:58 +01:00
Alexander Zaft
44f171aa72 Fix doubled module info
Change-Id: Ic406471a28f0c891323b990760ffd721ed419e12
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30667
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-03-13 10:03:07 +01:00
a72038e18c treat returning None from write_<param> properly
as intended originally, returning None should be the same
as returning the new value from the argument

Change-Id: I5596d2b6f6f525efd4dc410bbe22dad6f1fb2017
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30659
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-03-13 09:37:13 +01:00
Alexander Zaft
81f9e89402 Short background Color animation on scroll
When the tree selection changes, trigger a short animation of the
background color of the name-label of the selected module/parameter

Change-Id: Ia56619a7e73458a5ac63ef821b5ac7ab5f7451df
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30651
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
2023-03-10 15:19:06 +01:00
Georg Brandl
aa43254b55 gui: always show scrollbar in nodewidget
To avoid content jumping around when expanding.

Change-Id: I81a80f2ed11057bab2d4f0c1a21f9f29c4053c36
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30648
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
2023-03-10 14:10:16 +01:00
Georg Brandl
bc7975f4e5 gui: cleanup code in modulewidget
- line length
- spacing style
- copyright header

Change-Id: Ib402baf271868e82010e9acdfad4087164d91714
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30647
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
2023-03-10 14:10:12 +01:00
Georg Brandl
5983a4ac9d gui: better display of protocol version
Change-Id: I987aa7bf4b0cb1395425590655739fd4b28bd282
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30646
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-03-10 09:12:45 +01:00
Alexander Zaft
3afd0b07ed Remove Modulectrl Widget
Change-Id: I172227f01c8de494477050414e8cdd02bebafdbc
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30639
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-03-10 09:12:30 +01:00
Alexander Zaft
af57d92e99 Scroll Module area instead of replacing widgets
Change-Id: Id06eaabee294e032a71e7b28255a9b818763737e
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30638
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-03-10 09:12:20 +01:00
Alexander Zaft
16a3b1dc35 Extend Node and Module widgets
- put nodeinfo elements into ui file
- add per-module detailed view
- add first version of grouping (cleanup in a follow-up commit)

Change-Id: If35bc4a8f4ed0a313e97f88797e70186d7c0d9bc
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30631
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-03-09 13:42:02 +01:00
Alexander Zaft
1b38a989d8 Merge resource files
- move config editor files into resources
- merge both qrc files into one

Change-Id: I3089b0e1c7784683964d3e0b6e87c8a5cbd62ad2
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30593
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-03-08 15:59:30 +01:00
Alexander Zaft
e820e1a822 [Needs Feedback] Add PyQt6. Remove PyQt4
- fully qualify enum values for Qt6
- add resource file per Qt version
- TabWidget: use QPointF instead of QPoint for constructing mouse event

Change-Id: I07da61c36c4228a60f6b5b9dacbead27c0a2409d
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30585
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-03-08 15:59:15 +01:00
f6ee2f8d27 refresh logging when reconnected while watching
when a connection is reconnected, send 'logging' has to
be resent when watching

Change-Id: I13bb0075811151d93bd20f390b4c0745b9ad5418
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30604
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-03-08 08:43:49 +01:00
be24ea882b improve online help of frappy-cli
- help text shown exactly once (even with no or more arguments)
- automatically generated client object names
+ stay in interactive mode even when not all clients succeded

Change-Id: Iefcac66df92f47363e43bc9b97bb2082f153e5df
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30583
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-03-07 14:57:50 +01:00
Alexander Zaft
a8711f9706 Always make a greeter tab
Change-Id: If6a8cf55d29508645e4a731277ad341de23ca37d
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30587
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-03-07 07:16:24 +01:00
Georg Brandl
4ca3d5ba22 gui: better label for param set button
Change-Id: Ied1eb2851b755fa63289dcc19ba8b2aff803f13e
2023-03-06 12:51:21 +01:00
Georg Brandl
8c916eb7aa gui: remove unused ui file
Change-Id: I2b73cb7e65d12f5b053274e50d2fcf5f0b01c6d0
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30581
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
2023-03-06 12:50:45 +01:00
5a23c5af37 AsynConn.uri: better handling for missing scheme
- check roughly for hostname being a valid address
- allow missing 'tcp' scheme even with missing port number

Change-Id: Ia3ce4cb7b8d2a4b339421eafe21f06fba6d938e6
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30582
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-03-06 10:35:55 +01:00
Alexander Zaft
d48ab55909 Make input field more distinct
* different color for value fields
* placeholder text in input fields

Change-Id: Ibb94eb09ab7bfd7c2807f27226b7e2825ac3ea5d
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30579
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-03-06 09:45:26 +01:00
Alexander Zaft
47b1268ceb Remove unneeded constants
Change-Id: I1bfb213bb6c58af311d4f1af7af18abbdb82c269
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30575
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-03-03 15:52:18 +01:00
Alexander Zaft
e4a60863b5 Fix Node adding logic
* Unify _addNode calls
* introduce addNode for error catching
* set parent for Nodewidget only after successful creation (otherwise
  this results in Bug #4694

Change-Id: I82a5d867b45e766cd7dd33e7144e57a9f66a73b3
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30572
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-03-03 15:47:34 +01:00
Georg Brandl
a9257b2a0c gui: isort
Change-Id: Ic1c1d54a9577c1774024aefd5464b6e4b8e1fe07
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30570
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
2023-03-03 15:43:05 +01:00
Georg Brandl
9e6afffbec gui: move QSECNode to separate module
Change-Id: Iaba98c6c74adec7c3de952cc703430c5756dfbe4
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30569
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
2023-03-03 15:15:10 +01:00
Georg Brandl
33f4bb98d9 gui: add about dialog, remove "about Qt" menu entry
Change-Id: I483cc8cbe67cff6d0e14ff9ce198cc50bebb7cf8
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30567
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
2023-03-03 15:14:04 +01:00
Georg Brandl
d449e715c5 readme: fix make call
Change-Id: I58f31d53a2a4c67680c848f9e81068daabfa6cd4
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30568
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
2023-03-03 14:38:23 +01:00
Alexander Zaft
c0dca1e753 Add reconnect Action
* add reconnect method to QSECNode
* Rename File Menu to Node
* Add Button to 'Node' Menu

Fixes: #4687
Change-Id: I04ee55ddbc13253255f0099a9f4d2f8d4d0da77c
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30566
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-03-03 14:23:13 +01:00
67d72245ff make doc should not fail when version is not available
Fixes: #4665
Change-Id: Ief312e86b64ec1290d3410e1374ad1a71b5a3e4e
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30536
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
2023-03-03 14:08:43 +01:00
Georg Brandl
4f54423be5 installer: add config for frappy gui exe
Change-Id: I1abc325f685f8e95fac281b419be3defcc1e4485
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30508
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
2023-03-03 14:01:18 +01:00
Georg Brandl
25df2cffd1 cfg editor: fixes
Change-Id: I1ea9f96f6c39c25ff8d4c51163aabccc5698dace
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30507
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
2023-03-03 14:00:15 +01:00
4fe5ddeaa7 demo lakeshore with simulation
- example for lakeshore tutorial
- lakeshore simulator (merge with frappy_psils370sim)
- rename stringio-server to sim-server

Change-Id: I33a9c75ea268349573f8a8387910921e19f242eb
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30516
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-03-02 10:54:17 +01:00
731ecbeb32 default settings on the IO class
allow to define default settings on the IO class:
- a default 'port' may be given for tcp
- defaults like 'baudrate' or 'parity' might be given
  for serial connections

this avoids explicit settings in the config file in case
the settings can not be changed or have a typical value
other than the defaults in serial.Serial

Change-Id: I990f47d63e785f8cc48c4af197944a8eebe91fb4
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30555
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-03-02 10:53:44 +01:00
9796a25fe5 fix ppms with proxy
- proxy: remote parameter status should overddide datatype from
  ProxyModule.status
- ppms: create PpmsDrivable instead of importing from
  (PpmsBase, Drivable). Order matters for status parameter!
- update cfg files

Change-Id: If8fc263cffb903d8b3c1a93a089dcac3597d13a0
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30512
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-03-01 11:12:56 +01:00
2e9ed3ddea better guess for cfg file location
check for existence of repodir+'/cfg' instead of repodir+'/.git'

fixes #4692

Change-Id: Ida841cd31eba851305bcfc0d96019710340c3140
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30510
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-03-01 11:12:01 +01:00
Alexander Zaft
4b42d72bc6 Fix forge link in README
Change-Id: Ie428f1814edc2685d03590da4e0635d0b100bbdf
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30538
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-02-28 13:39:16 +01:00
Georg Brandl
25618a6264 version.py: sync with other projects
Change-Id: I0e8b1502a9d1e8efa3ee1e0798ec5a85bf9d0f35
2023-02-28 08:15:55 +01:00
bb82179191 do not reuse address on Windows
socketserver.ThreadingTCPServer.allow_reuse_address must be False on
Windows systems, else several servers might be started on the same
port, and unspecified behaviour will happen

Fixes: #4695
Change-Id: Ic9f193e23854f9cd3413ab6e664ca8029a7c9c76
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30523
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-02-28 07:45:53 +01:00
Alexander Zaft
578a412de1 Remove auto-connect to 10767 on startup
* not necessary with greeter
* Port is default in greeter text field

Change-Id: If89cb72ec6af20fd4d83488af85b942c5f54b105
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30531
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-02-28 07:02:06 +01:00
Alexander Zaft
7428634297 Add recent SECNodes to Drop down menu
Fixes: #4686

Change-Id: I864e8dd407b23c8af0f0633d3be477e222df6c40
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30525
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-02-28 06:59:43 +01:00
Alexander Zaft
aa7ba84425 Add greeter tab to UI
* adds a tab on startup that shows last connected secnodes
* last nodes saved with qsettings

Change-Id: I2b663a408dc46bd0a0135e723b55d5ef3661bec8
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30524
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-02-28 06:55:27 +01:00
a3a963721a allow super calls on read_/write_ methods
instead of wrapping the access methods on the class directly,
create a wrapper class with the wrapped methods.

Change-Id: I93f3985bd06d6956b42a6690c087fb125e460ef9
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30448
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-02-24 10:24:38 +01:00
Georg Brandl
367ecda9d6 add pyqtgraph to gui dependencies
Change-Id: Ic75d395e683c4c4e92162a287ef9beeb1c68df53
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30509
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
2023-02-24 07:13:47 +01:00
549980d9cd cfg path quick fix for hands-on session
Change-Id: If79f76ed17dce6a5587deaae2eae4eda77546306
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30503
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
2023-02-23 08:45:08 +01:00
Alexander Zaft
0bbf3337b2 Fix Simulation and Proxy
Combination of changes 30188 and 30194 leads to simulation and proxy
still reading 'default' instead of 'value'

Change-Id: I176a42f534a4eb04916b57bb3b54e880a2531ed3
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30502
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
2023-02-22 17:28:20 +01:00
Jenkins system
43b5f707e8 [deb] Release v0.17.1 2023-02-21 17:44:57 +01:00
Georg Brandl
612695b644 gui: make plot windows children of the node, so they close automatically
Change-Id: I025bff02bc566be8bbaa8d90bf0035d1e2bf2a69
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30494
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
2023-02-21 17:29:39 +01:00
Georg Brandl
cb8366105d gui: clear tree selection by clicking into empty space
Change-Id: Ib065feeffa8636ee0b3160d7612f069057ef6b0e
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30492
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
2023-02-21 17:29:35 +01:00
Georg Brandl
5de9ff2901 gui: as a stopgap measure, apply %g format to floats
Needs to be properly fixed by sharing the code to format
parameter values everywhere.

Change-Id: I766e4d2cb644153f99f9f40ce0414aa314b47307
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30491
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
2023-02-21 17:29:31 +01:00
Georg Brandl
35fce652b7 gui console: better formatting of input/output
Change-Id: I2ffb3712bb4ef5dcdfbcae869e4971bdc7a116ad
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30490
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
2023-02-21 17:29:26 +01:00
eb46733c86 fix links in doc/introduction
Change-Id: I9f613c77835472c79be2850265126686cb57e8b9
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30493
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2023-02-21 17:17:52 +01:00
Georg Brandl
318f33961a gui: make spacing more consistent
Change-Id: I5bb44c440b33cb0b5de0f5e2457c9226afe74a50
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30489
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
2023-02-21 17:01:45 +01:00
Georg Brandl
d641784104 cfg: repair demo cfg after conversion
Change-Id: I00b4e92d8e10842e9b2ae1ae904402473e77107f
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30488
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
2023-02-21 16:47:18 +01:00
Georg Brandl
97a9e6624b config: demo config fixes
Change-Id: I380e101065179bf0d784bacfe6b79731b40af4c5
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30487
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
2023-02-21 16:47:14 +01:00
Georg Brandl
72a28b198b gitignore: ignore demo PID file
Change-Id: Iab6bd32c51772f5bcf256802c9bb7082be5e7873
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30486
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Reviewed-by: Georg Brandl <g.brandl@fz-juelich.de>
2023-02-21 16:47:01 +01:00
Jenkins system
86f97f0492 [deb] Release v0.17.0 2023-02-21 13:52:17 +01:00
Alexander Zaft
9a91f28413 Merge "Rework GUI." 2023-02-21 12:35:53 +01:00
Georg Brandl
9c17f09bdf doc: fix trailing comma in authors
Change-Id: Ie611a3258a5b1acbdcbdfa55aad5198c4613f647
2023-02-21 12:06:12 +01:00
Georg Brandl
7465824423 ci: remove duplicate variable
Change-Id: I839ac4d9eda36082ba24c7c06df234a78798be2c
2023-02-21 12:03:36 +01:00
Alexander Zaft
a36d875fae Rework GUI.
Work-in-progress state of the new gui.

Change-Id: Ib5e9ad2178b372fbd2914077096a9c73f025ecb7
2023-02-21 11:41:23 +01:00
Jenkins system
12f21996e4 [deb] Release v0.16.1 2023-02-21 08:44:29 +01:00
Jenkins system
879267aad1 [deb] Release v0.16.4 2023-02-21 08:09:20 +01:00
Jenkins system
7081976612 [deb] Release v0.16.3 2023-02-21 08:00:15 +01:00
Jenkins system
ea98023c28 [deb] Release v0.16.2 2023-02-21 07:50:13 +01:00
Enrico Faulhaber
167294aad8 Merge "gui: move icon resources for the cfg editor to its subdirectory" 2023-02-20 21:45:32 +01:00
Jenkins system
716fd0df2c [deb] Release v0.16.1 2023-02-20 17:17:23 +01:00
Enrico Faulhaber
d168384d0c add frappy-cli to package
Change-Id: I8697f05517935470a7c867ebddd63f5d28be21c3
2023-02-20 17:15:23 +01:00
Jenkins system
56454b9d9a [deb] Release v0.16.0 2023-02-20 16:15:11 +01:00
4000371b97 Merge "README: add link to doc on forge.frm2.tum.de" 2023-02-20 16:02:48 +01:00
1b18337d2a Merge "do proper value import on the client side" 2023-02-20 16:01:48 +01:00
55077e2417 README: add link to doc on forge.frm2.tum.de
Change-Id: I4a183202590a7e73ee1a905538c35af175f6c82d
2023-02-20 15:53:50 +01:00
Alexander Zaft
127f1712ee Convert example configs to python
Fixes: #4627

Change-Id: I1049af9fa2f3f9ec06e55811dc9ecfa5f359c805
2023-02-20 15:41:56 +01:00
c4fbd8a7bf Merge "T controller tutorial and improve documentation" 2023-02-20 08:44:45 +01:00
Alexander Zaft
4a7294679b Change Readme title
Change-Id: Id8b07e76cb5748aa595fb484d78ffcc43f9cdddf
2023-02-16 12:00:51 +01:00
Alexander Zaft
5c3d09288b Add initial README
Change-Id: I314b6bf527ba6bb7011804a3768e7785ed4046e3
2023-02-16 11:51:46 +01:00
365476256e do proper value import on the client side
json values were not converted properly, resulting in integers
instead of enums at the client side

+ add log.debug in rx thread

Change-Id: Ifc3c3b28540eb6a516d77387a3f83711f34b7480
2023-02-15 15:33:58 +01:00
a2cd6051f2 Merge "HasStates: fix status code inheritance" 2023-02-14 08:25:22 +01:00
5b060d1b1c Merge "HasControlledBy and HasOutputModule mixins" 2023-02-14 08:24:51 +01:00
10a61aa760 T controller tutorial and improve documentation
add tutorial for Berlin hands-on workshop

+ improve the documentation (hints for structure welcome)
+ remove 'optional' parameter property
  (is not yet used - should not appear in doc)
+ added test property in frappy_demo.cryo alters Parameter class
  ('test' property appears in Parameter doc)

Change-Id: I3ea08f955a92f72451fd23a5ff00d1185c7fb00e
2023-02-13 15:58:39 +01:00
60f6c2dda5 Merge "interactive client: improve watch function" 2023-02-02 17:35:10 +01:00
a72c2b685d add lakeshore demo for hands-on workshop
- a simple LakeShore model 336 driver

a tutorial follows

Change-Id: I291a615efa5bd58a0dd908949210086d2f82c2ca
2023-02-02 15:18:44 +01:00
6b751f845f interactive client: improve watch function
- watch is now a command, not a module method
- finish watching with ctrl-C
- watching an io module logs communication
- add bin/frappy-cli to start interactive client
+ remove sorted function from StructOf.format_value

Change-Id: I7dd707473e4534f2d39c5d6afc533c2d872380f8
2023-01-31 13:11:07 +01:00
12ef37504a Merge "adapt tutorial to new config file format" 2023-01-31 11:44:45 +01:00
Alexander Zaft
3c1f4b0bc1 Merge "Add .desktop file" 2023-01-31 07:29:07 +01:00
ada9e53a4d raise ProtcolError when specifier is missing
- fixed this for 'read', 'change' and 'do' message
+ fix an error in frappy.client.SecopClient closing the connection
  when the identifier is None

fixes: #4672

Change-Id: Iaba0f9ed86b6eb6ef7588403ba640ded552dded6
2023-01-30 17:15:27 +01:00
66d363cc07 adapt tutorial to new config file format
Change-Id: Iafd8a2dbed8cd1283ce97b6559138c7bc02714c7
2023-01-26 16:43:56 +01:00
ddd16f4ed4 HasControlledBy and HasOutputModule mixins
for supporting coupled modules (output - input case)

Change-Id: I58488faa0d52b3b984a3dc70ff44ee4a9a218d7a
2023-01-25 10:25:31 +01:00
a4ebcb9bb7 HasStates: fix status code inheritance
use mro for status code inheritance
- as a consequence, the decorator class 'StatusCode' is now a
  decorator function 'status_code'. snake case is anyway more
  common for decorators.
- adapt tests
+ fix an error message

Change-Id: Ib409b963c51e0fe807397ff1d73d77d0147b8580
2023-01-25 08:49:02 +01:00
878bb6f892 do not throw ZeroDivisonError when pollinterval is 0
fast_interval might be 0, indicating to poll as fast as possible
- this should not throw a zero division error

Change-Id: I26e18f5a656c943b906c6ffff65361e1fcf16d50
2023-01-24 15:37:45 +01:00
e571abdb18 improve persistent parameters
A value given in config overrides values read from the persistent data file.
To let the loaded parameter have precedence, configure a default only.
The write_<param> method of a persistent parameter is now always called
on startup.

- add tests for persistent behaviour
+ simplify Modules.writeInitParams: remove started_callback argument

Change-Id: I08b49de52e9d9a2ed0918018eb2fe538141a4f5e
2023-01-24 15:35:50 +01:00
Alexander Zaft
ec16ee7e8b Add .desktop file
Fixes: #4632
Change-Id: Ie0f07049462ed6664cca4062bced09c15bdd5a56
2023-01-24 10:56:39 +01:00
Georg Brandl
401447ffd6 gui: move icon resources for the cfg editor to its subdirectory
Change-Id: Iebda39c73d9886701a58fe58b91ef54b70a4fd73
2023-01-24 09:29:55 +01:00
37ca162ae2 fix copy method of Attached
a copy of 'Attached' must also copy the basecls

Change-Id: Ia80cc458b241cb1f224f4c24f0241ed1d4ec1060
2023-01-24 08:22:58 +01:00
314 changed files with 44056 additions and 16833 deletions

10
.gitignore vendored
View File

@@ -1,13 +1,15 @@
frappydemo.PID
log/*
html/*
*.pyc
pid/*
# ide
# ide
.idea
RELEASE-VERSION
build
*.egg-info
# Sphinx
doc/_build
@@ -21,4 +23,8 @@ doc/_build
._*
# pyinstaller
dist/
dist/
*.cfg
*.bk.tnt
*.tps

8
.isort.cfg Normal file
View File

@@ -0,0 +1,8 @@
[settings]
multi_line_output=2
combine_as_imports=True
known_qt=frappy.gui.qt
known_core=frappy
sections=FUTURE,STDLIB,QT,THIRDPARTY,CORE,FIRSTPARTY,LOCALFOLDER

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
@@ -40,6 +40,7 @@ disable=missing-docstring
,locally-disabled
,fixme
,no-member
,not-callable
,wrong-import-position
,ungrouped-imports
,import-self
@@ -53,6 +54,8 @@ disable=missing-docstring
,unidiomatic-typecheck
,undefined-loop-variable
,consider-using-f-string
,use-dict-literal
[REPORTS]
# Set the output format. Available formats are text, parseable, colorized, msvs
@@ -199,7 +202,10 @@ max-branches=50
max-statements=150
# Maximum number of parents for a class (see R0901).
max-parents=15
max-parents=20
# Maximum number of positional arguments
max-positional-arguments=10
# Maximum number of attributes for a class (see R0902).
max-attributes=50

33
README.md Normal file
View File

@@ -0,0 +1,33 @@
Frappy: Framework for programming secnodes in Python
====================================================
Frappy is a Python-framework for writing [SECoP](https://github.com/SampleEnvironment/SECoP) servers (called SECNodes or Nodes) and Clients.
It comes with its own Graphical client and a collection of example Nodes.
It is able to use TCP and Serial connections.
To get started, look at the provided demo, the provided examples, or have a look
at the INTRODUCTION section.
Main development is done
[here](https://forge.frm2.tum.de/review/q/project:secop%252Ffrappy)
and a readonly GitHub-mirror for easier access is available
[here](https://github.com/SampleEnvironment/frappy).
Requirements
------------
See `requirements.txt`.
Demo
----
Use the following command after installing the dependencies:
```
$ make demo
```
Documentation
-------------
[See here for documentation of Frappy](https://forge.frm2.tum.de/public/doc/frappy/html/)

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
# pylint: disable=invalid-name
# -*- coding: utf-8 -*-
# *****************************************************************************
# Copyright (c) 2015-2024 by the authors, see LICENSE
#
# 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
@@ -29,6 +29,9 @@ from os import path
# Add import path for inplace usage
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,9 +41,13 @@ def main(argv=None):
parser.add_argument('-f', '--file', help='Configuration file to open.')
args = parser.parse_args()
app = QApplication(argv)
window = MainWindow(args.file)
logger = logging.getLogger('gui')
console = ColoredConsoleHandler()
console.setLevel(logging.INFO)
logger.addHandler(console)
window = MainWindow(args.file, log=logger)
window.show()
return app.exec_()
return app.exec()
if __name__ == '__main__':

66
bin/frappy-cli Executable file
View File

@@ -0,0 +1,66 @@
#!/usr/bin/env python3
# *****************************************************************************
# Copyright (c) 2015-2024 by the authors, see LICENSE
#
# 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 Lenz <alexander.lenz@frm2.tum.de>
# Markus Zolliker <markus.zolliker@psi.ch>
#
# *****************************************************************************
import sys
import argparse
from pathlib import Path
# Add import path for inplace usage
sys.path.insert(0, str(Path(__file__).absolute().parents[1]))
from frappy.client.interactive import init, run, clientenv, interact
def parseArgv(argv):
parser = argparse.ArgumentParser()
parser.add_argument('-i', '--include',
help='file to execute after connecting to the clients', metavar='file',
type=Path, action='append', default=[])
parser.add_argument('-o', '--only-execute',
help='Do not go into interactive mode after executing files. \
Has no effect without --include.', action='store_true')
parser.add_argument('node',
help='Nodes the client should connect to.\n', metavar='host:port',
nargs='*', type=str, default=[])
return parser.parse_args(argv)
args = parseArgv(sys.argv[1:])
success = init(*args.node)
run_error = ''
file_success = False
try:
for file in args.include:
run(file)
file_success = True
except Exception as e:
run_error = f'\n{clientenv.short_traceback()}'
if success:
if args.include and file_success and args.only_execute:
print('skipping interactive mode')
exit()
interact(run_error)

View File

@@ -1,8 +1,7 @@
#!/usr/bin/env python3
# pylint: disable=invalid-name
# -*- coding: utf-8 -*-
# *****************************************************************************
# Copyright (c) 2015-2016 by the authors, see LICENSE
# Copyright (c) 2015-2024 by the authors, see LICENSE
#
# 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
@@ -27,10 +26,10 @@ from __future__ import print_function
import sys
import argparse
from os import path
from pathlib import Path
# Add import path for inplace usage
sys.path.insert(0, path.abspath(path.join(path.dirname(__file__), '..')))
sys.path.insert(0, str(Path(__file__).absolute().parents[1]))
import logging
from mlzlog import ColoredConsoleHandler
@@ -47,9 +46,12 @@ def parseArgv(argv):
loggroup.add_argument('-q', '--quiet',
help='Supress everything but errors',
action='store_true', default=False)
parser.add_argument('-D', '--detailed',
help='Start in detailed mode',
action='store_true', default=False)
parser.add_argument('node',
help='Nodes the Gui should connect to.\n', metavar='host[:port]',
nargs='*', type=str, default=['localhost:10767'])
help='Nodes the GUI should connect to.\n', metavar='host[:port]',
nargs='*', type=str, default=[])
return parser.parse_args(argv)
@@ -62,16 +64,18 @@ def main(argv=None):
loglevel = logging.DEBUG if args.debug else (logging.ERROR if args.quiet else logging.INFO)
logger = logging.getLogger('gui')
logger.setLevel(logging.DEBUG)
console = ColoredConsoleHandler()
console.setLevel(loglevel)
logger.addHandler(console)
if sys.stdout is not None:
console = ColoredConsoleHandler()
console.setLevel(loglevel)
logger.addHandler(console)
app = QApplication(argv)
win = MainWindow(args.node, logger)
win = MainWindow(args, logger)
app.aboutToQuit.connect(win._onQuit)
win.show()
return app.exec_()
return app.exec()
if __name__ == '__main__':

42
bin/frappy-play Executable file
View File

@@ -0,0 +1,42 @@
#!/usr/bin/env python3
# *****************************************************************************
# Copyright (c) 2015-2024 by the authors, see LICENSE
#
# 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>
#
# *****************************************************************************
import sys
from pathlib import Path
from frappy.lib import generalConfig
from frappy.logging import logger
# Add import path for inplace usage
sys.path.insert(0, str(Path(__file__).absolute().parents[1]))
from frappy.client.interactive import Console
from frappy.playground import play, USAGE
generalConfig.init()
logger.init()
if len(sys.argv) > 1:
play(sys.argv[1])
else:
print(USAGE)
Console('play', sys.modules['__main__'].__dict__)

128
bin/frappy-scan Executable file
View 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)

View File

@@ -1,6 +1,5 @@
#!/usr/bin/env python3
# pylint: disable=invalid-name
# -*- coding: utf-8 -*-
# *****************************************************************************
#
# This program is free software; you can redistribute it and/or modify it under
@@ -23,12 +22,12 @@
#
# *****************************************************************************
import sys
import argparse
from os import path
import sys
from pathlib import Path
# Add import path for inplace usage
sys.path.insert(0, path.abspath(path.join(path.dirname(__file__), '..')))
sys.path.insert(0, str(Path(__file__).absolute().parents[1]))
from frappy.lib import generalConfig
from frappy.logging import logger
@@ -36,7 +35,15 @@ from frappy.server import Server
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.add_argument("-v", "--verbose",
help="Output lots of diagnostic information",
@@ -61,8 +68,9 @@ def parseArgv(argv):
action='store',
help="comma separated list of cfg files,\n"
"defaults to <name_of_the_instance>.\n"
"cfgfiles given without '.cfg' extension are searched in the configuration directory, "
"else they are treated as path names",
"If a config file contains a slash, it is treated as a"
"path, otherwise the file is searched for in the "
"configuration directory.",
default=None)
parser.add_argument('-g',
'--gencfg',
@@ -90,20 +98,21 @@ def main(argv=None):
args = parseArgv(argv[1:])
loglevel = 'debug' if args.verbose else ('error' if args.quiet else 'info')
generalConfig.defaults = {k: args.relaxed for k in (
'lazy_number_validation', 'disable_value_range_check', 'legacy_hasiodev', 'tolerate_poll_property')}
generalConfig.set_default('lazy_number_validation', args.relaxed)
generalConfig.set_default('legacy_hasiodev', args.relaxed)
generalConfig.set_default('tolerate_poll_property', args.relaxed)
generalConfig.init(args.gencfg)
logger.init(loglevel)
srv = Server(args.name, logger.log, cfgfiles=args.cfgfiles, interface=args.port, testonly=args.test)
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)
if args.daemonize:
srv.start()
else:
try:
srv.run()
except KeyboardInterrupt:
pass
srv.run()
if __name__ == '__main__':

View File

@@ -1,64 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# *****************************************************************************
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation; either version 2 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# Module authors:
# Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
#
# *****************************************************************************
import os
from os import path
import markdown
BASE_PATH = path.abspath(path.join(path.dirname(__file__), '..'))
DOC_SRC = path.join(BASE_PATH, 'doc')
DOC_DST = path.join(BASE_PATH, 'html')
conv = markdown.Markdown()
for dirpath, dirnames, filenames in os.walk(DOC_SRC):
# re-create the dir-structure of DOC_SRC into DOC_DST
dst_path = path.join(DOC_DST, path.relpath(dirpath, DOC_SRC))
try:
os.mkdir(dst_path)
except OSError:
pass
for fn in filenames:
full_name = path.join(dirpath, fn)
sub_name = path.relpath(full_name, DOC_SRC)
final_name = path.join(DOC_DST, sub_name)
if not fn.endswith('md'):
# just copy everything else
with open(full_name, 'rb') as fi:
with open(final_name, 'wb') as fo:
# WARNING: possible Memory hog!
fo.write(fi.read())
continue
# treat .md files special
final_sub_name = path.splitext(sub_name)[0] + '.html'
final_name = path.join(DOC_DST, final_sub_name)
print("Converting %s to %s" %(sub_name, final_sub_name))
# transform one file
conv.reset()
conv.convertFile(input=full_name,
output=final_name,
encoding="utf-8")

197
bin/sim-server Executable file
View File

@@ -0,0 +1,197 @@
#!/usr/bin/env python3
# pylint: disable=invalid-name
# *****************************************************************************
# 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>
# *****************************************************************************
"""server for a string communicator
Usage:
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.
Use cases, mainly for test purposes:
- 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 argparse
from pathlib import Path
import socket
import time
import os
from ast import literal_eval
from socketserver import BaseRequestHandler, ThreadingTCPServer
# Add import path for inplace usage
sys.path.insert(0, str(Path(__file__).absolute().parents[1]))
from frappy.lib import get_class, formatException, mkthread
class Logger:
def debug(self, *args):
pass
def log(self, level, *args):
pass
def info(self, *args):
print(*args)
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):
parser = argparse.ArgumentParser(description="Relay to a communicator (simulated HW or other)")
parser.add_argument("-v", "--verbose",
help="output full communication",
action='store_true', default=False)
parser.add_argument("cls",
type=str,
help="communicator class.\n",)
parser.add_argument('-p',
'--port',
action='store',
help='server port or uri',
default=2089)
parser.add_argument('-o',
'--options',
action='store',
nargs='*',
help='options in the form key=value',
default=None)
return parser.parse_args(argv)
def main(argv=None):
if argv is None:
argv = sys.argv
args = parse_argv(argv[1:])
options = {'description': ''}
for item in args.options or ():
key, eq, value = item.partition('=')
if not eq:
raise ValueError(f"missing '=' in {item}")
try:
value = literal_eval(value)
except Exception:
pass
options[key] = value
srv = Server(int(args.port), args.cls, options, args.verbose)
srv.serve_forever()
if __name__ == '__main__':
sys.exit(main(sys.argv))

View File

@@ -1,154 +0,0 @@
#!/usr/bin/env python3
# pylint: disable=invalid-name
# -*- coding: utf-8 -*-
# *****************************************************************************
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# 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>
# *****************************************************************************
"""server for a string communicator
Usage:
bin/stringio-server <communciator> <server port>
open a server on <server port> to communicate with the string based <communicator> over TCP/IP.
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
"""
import sys
from os import path
import asyncore
import socket
import ast
# Add import path for inplace usage
sys.path.insert(0, path.abspath(path.join(path.dirname(__file__), '..')))
from frappy.lib import get_class, formatException
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_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, host, port, lineHandlerClass):
asyncore.dispatcher.__init__(self)
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
self.set_reuse_addr()
self.bind((host, port))
self.listen(5)
self.lineHandlerClass = lineHandlerClass
def handle_accept(self):
pair = self.accept()
if pair is not None:
sock, addr = pair
print("Incoming connection from %s" % repr(addr))
self.lineHandlerClass(sock)
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.dispatcher = self.Dispatcher()
class Handler(LineHandler):
def handle_line(self, line):
try:
reply = module.do_communicate(line.strip())
if verbose:
print('%-40s | %s' % (line, reply))
except Exception:
print(formatException(verbose=True))
self.send_line(reply)
class Logger:
def debug(self, *args):
print(*args)
info = exception = debug
opts = {'description': 'simulator'}
args = []
for arg in sys.argv[1:]:
k, sep, v = arg.partition('=')
if not k:
args.append(v)
try:
v = ast.literal_eval(v)
except Exception:
pass
opts[k] = v
verbose = opts.pop('verbose', False)
opts['cls'] = 'frappy_psi.ls370sim.Ls370Sim'
opts['port'] = 4567
if len(args) > 2:
raise ValueError('do not know about: %s' % ' '.join(args[2:]))
if len(args) == 2:
opts['port'] = int(args[1])
if len(args) > 0:
opts['cls'] = args[0]
args.append(opts)
cls = opts.pop('cls')
port = opts.pop('port')
srv = Server('localhost', int(port), Handler)
module = get_class(cls)(cls, Logger(), opts, srv)
module.earlyInit()
srv.loop()

View File

@@ -1,17 +0,0 @@
[node AH2700Test.psi.ch]
description = AH2700 capacitance bridge test
[interface tcp]
type = tcp
bindto = 0.0.0.0
bindport = 5000
[module cap]
class = frappy_psi.ah2700.Capacitance
description = capacitance
uri=ldmse3-ts:3015
#[module ahcom]
#class = frappy_psi.ah2700.StringIO
#uri=ldmse3-ts:3015
#description = serial communicator to an AH2700

10
cfg/ah2700test_cfg.py Normal file
View File

@@ -0,0 +1,10 @@
Node('AH2700Test.psi.ch',
'AH2700 capacitance bridge test',
'tcp://5000',
)
Mod('cap',
'frappy_psi.ah2700.Capacitance',
'capacitance',
uri='ldmse3-ts:3015',
)

View File

@@ -1,111 +0,0 @@
[node MLZ_amagnet(Garfield)]
description=MLZ-Amagnet
.
Water cooled magnet from ANTARES@MLZ.
.
Use module to control the magnetic field.
Don't forget to select symmetry first (can be moved only at zero field!).
.
Monitor T1..T4 (Coil temps), if they get to hot, field will ramp down!
.
In case of Problems, contact the ANTARES people at MLZ.
visibility=expert
foo=bar
[interface tcp]
type=tcp
bindto=0.0.0.0
bindport=10767
[module enable]
class=frappy_mlz.entangle.NamedDigitalOutput
tangodevice='tango://localhost:10000/box/plc/_enable'
value.datatype=["enum", {'On':1,'Off':0}]
target.datatype=["enum", {'On':1,'Off':0}]
.description='Enables to Output of the Powersupply'
.visibility='advanced'
[module polarity]
class=frappy_mlz.entangle.NamedDigitalOutput
tangodevice=tango://localhost:10000/box/plc/_polarity
value.datatype=["enum", {'+1':1,'0':0,'-1':-1}]
target.datatype=["enum", {'+1':1,'0':0,'-1':-1}]
.description=polarity (+/-) switch
.
there is an interlock in the plc:
if there is current, switching polarity is forbidden
if polarity is short, powersupply is disabled
.visibility=advanced
comtries=50
[module symmetry]
class=frappy_mlz.entangle.NamedDigitalOutput
tangodevice=tango://localhost:10000/box/plc/_symmetric
value.datatype=["enum",{'symmetric':1,'short':0, 'asymmetric':-1}]
target.datatype=["enum",{'symmetric':1,'short':0, 'asymmetric':-1}]
.description=par/ser switch selecting (a)symmetric mode
.
symmetric is ser, asymmetric is par
.visibility=advanced
[module T1]
class=frappy_mlz.entangle.AnalogInput
tangodevice=tango://localhost:10000/box/plc/_t1
.description=Temperature1 of the coils system
#warnlimits=(0, 50)
value.unit='degC'
[module T2]
class=frappy_mlz.entangle.AnalogInput
tangodevice=tango://localhost:10000/box/plc/_t2
.description=Temperature2 of the coils system
#warnlimits=(0, 50)
value.unit='degC'
[module T3]
class=frappy_mlz.entangle.AnalogInput
tangodevice=tango://localhost:10000/box/plc/_t3
.description=Temperature3 of the coils system
#warnlimits=(0, 50)
value.unit='degC'
[module T4]
class=frappy_mlz.entangle.AnalogInput
tangodevice=tango://localhost:10000/box/plc/_t4
.description=Temperature4 of the coils system
#warnlimits=(0, 50)
value.unit='degC'
[module currentsource]
class=frappy_mlz.entangle.PowerSupply
tangodevice=tango://localhost:10000/box/lambda/curr
.description=Device for the magnet power supply (current mode)
abslimits=(0,200)
speed=1
ramp=60
precision=0.02
current=0
voltage=10
#unit=A
.visibility=advanced
[module mf]
class=frappy_mlz.amagnet.GarfieldMagnet
.description=magnetic field module, handling polarity switching and stuff
subdev_currentsource=currentsource
subdev_enable=enable
subdev_polswitch=polarity
subdev_symmetry=symmetry
target.unit='T'
value.unit='T'
userlimits=(-0.35, 0.35)
calibrationtable={'symmetric':[0.00186517, 0.0431937, -0.185956, 0.0599757, 0.194042],
'short': [0.0, 0.0, 0.0, 0.0, 0.0],
'asymmetric':[0.00136154, 0.027454, -0.120951, 0.0495289, 0.110689]}
.meaning=The magnetic field
.priority=100
.visibility=user
abslimits.default=-0.4,0.4

91
cfg/amagnet_cfg.py Normal file
View File

@@ -0,0 +1,91 @@
Node('MLZ_amagnet(Garfield)',
'MLZ-Amagnet\n'
'\n'
'Water cooled magnet from ANTARES@MLZ.\n'
'\n'
'Use module to control the magnetic field.\n'
'Don\'t forget to select symmetry first (can be moved only at zero field!).\n'
'\n'
'Monitor T1..T4 (Coil temps), if they get to hot, field will ramp down!\n'
'\n'
'In case of Problems, contact the ANTARES people at MLZ.',
'tcp://10767',
visibility = 'expert',
foo = 'bar',
)
Mod('enable',
'frappy_mlz.entangle.NamedDigitalOutput',
'Enables to Output of the Powersupply',
tangodevice = 'tango://localhost:10000/box/plc/_enable',
value = Param(datatype=["enum", {'On':1,'Off':0}]),
target = Param(datatype=["enum", {'On':1,'Off':0}]),
visibility = 'advanced',
)
Mod('polarity',
'frappy_mlz.entangle.NamedDigitalOutput',
'polarity (+/-) switch\n'
'\n'
'there is an interlock in the plc:\n'
'if there is current, switching polarity is forbidden\n'
'if polarity is short, powersupply is disabled',
tangodevice = 'tango://localhost:10000/box/plc/_polarity',
value = Param(datatype=["enum", {'+1':1,'0':0,'-1':-1}]),
target = Param(datatype=["enum", {'+1':1,'0':0,'-1':-1}]),
visibility = 'advanced',
comtries = 50,
)
Mod('symmetry',
'frappy_mlz.entangle.NamedDigitalOutput',
'par/ser switch selecting (a)symmetric mode\n'
'\n'
'symmetric is ser, asymmetric is par',
tangodevice = 'tango://localhost:10000/box/plc/_symmetric',
value = Param(datatype=["enum",{'symmetric':1,'short':0, 'asymmetric':-1}]),
target = Param(datatype=["enum",{'symmetric':1,'short':0, 'asymmetric':-1}]),
visibility = 'advanced',
)
for i in range(1,5):
Mod('T%d' % i,
'frappy_mlz.entangle.AnalogInput',
'Temperature %d of the coils system' % i,
tangodevice = 'tango://localhost:10000/box/plc/_t%d' % i,
#warnlimits=(0, 50),
value = Param(unit='degC'),
)
Mod('currentsource',
'frappy_mlz.entangle.PowerSupply',
'Device for the magnet power supply (current mode)',
tangodevice = 'tango://localhost:10000/box/lambda/curr',
abslimits = (0,200),
speed = 1,
ramp = 60,
precision = 0.02,
current = 0,
voltage = 10,
#value=Param(unit='A')
visibility = 'advanced',
)
Mod('mf',
'frappy_mlz.amagnet.GarfieldMagnet',
'magnetic field module, handling polarity switching and stuff',
currentsource = 'currentsource',
enable = 'enable',
polswitch = 'polarity',
symmetry = 'symmetry',
target = Param(unit='T'),
value = Param(unit='T'),
userlimits = (-0.35, 0.35),
calibrationtable = {'symmetric':[0.00186517, 0.0431937, -0.185956, 0.0599757, 0.194042],
'short': [0.0, 0.0, 0.0, 0.0, 0.0],
'asymmetric':[0.00136154, 0.027454, -0.120951, 0.0495289, 0.110689]},
meaning = ['The magnetic field', 1],
#priority=100,
visibility = 'user',
abslimits = (-0.4,0.4,),
)

View File

@@ -1,150 +0,0 @@
[node MLZ_ccr12]
description = CCR box of MLZ Sample environment group
.
Contains a Lakeshore 336 and an PLC controlling the compressor
and some valves.
[interface tcp]
type=tcp
bindto=0.0.0.0
bindport=10767
[module automatik]
class=frappy_mlz.entangle.NamedDigitalOutput
tangodevice=tango://localhost:10000/box/plc/_automatik
mapping=dict(Off=0,p1=1,p2=2)
description="controls the (simple) pressure regulation
.
selects between off, regulate on p1 or regulate on p2 sensor"
[module compressor]
class=frappy_mlz.entangle.NamedDigitalOutput
tangodevice=tango://localhost:10000/box/plc/_cooler_onoff
mapping=dict(Off=0,On=1)
description=control the compressor (on/off)
[module gas]
class=frappy_mlz.entangle.NamedDigitalOutput
tangodevice=tango://localhost:10000/box/plc/_gas_onoff
mapping=dict(Off=0,On=1)
description=control the gas inlet into the ccr (on/off)
.
note: this switches off automatically after 15 min.
note: activation de-activates the vacuum inlet
note: if the pressure regulation is active, it enslave this device
[module vacuum]
class=frappy_mlz.entangle.NamedDigitalOutput
tangodevice=tango://localhost:10000/box/plc/_vacuum_Onoff
mapping=dict(Off=0,On=1)
description=control the vacuum inlet into the ccr (on/off)
.
note: activation de-activates the gas inlet
note: if the pressure regulation is active, it enslave this device
[module p1]
class=frappy_mlz.entangle.AnalogInput
tangodevice=tango://localhost:10000/box/plc/_p1
value.unit='mbar'
description=pressure sensor 1 (linear scale)
[module p2]
class=frappy_mlz.entangle.AnalogInput
tangodevice=tango://localhost:10000/box/plc/_p2
value.unit='mbar'
description=pressure sensor 2 (selectable curve)
[module curve_p2]
class=frappy_mlz.entangle.NamedDigitalInput
tangodevice=tango://localhost:10000/box/plc/_curve
value.default=0
description=calibration curve for pressure sensor 2
mapping="{'0-10V':0, '0-1000mbar':1, '1-9V to 0-1 mbar':2,
'DI200':3, 'DI2000':4, 'TTR100':7, 'PTR90':8,
'PTR225/237':9, 'ITR90':10, 'ITR100-D':11,
'ITR100-2':12, 'ITR100-3':13, 'ITR100-4':14,
'ITR100-5':15, 'ITR100-6':16, 'ITR100-7':17,
'ITR100-8':18, 'ITR100-9':19, 'ITR100-A':20,
'CMR361':21, 'CMR362':22, 'CMR363':23,
'CMR364':24, 'CMR365':25}"
# sensors
[module T_sample]
class=frappy_mlz.entangle.Sensor
tangodevice=tango://localhost:10000/box/sample/sensora
value.unit='K'
description=sample temperature
[module T_stick]
class=frappy_mlz.entangle.Sensor
tangodevice=tango://localhost:10000/box/stick/sensorb
value.unit='K'
description=temperature at bottom of sample stick
[module T_coldhead]
class=frappy_mlz.entangle.Sensor
tangodevice=tango://localhost:10000/box/coldhead/sensorc
value.unit='K'
description=temperature at coldhead
[module T_tube]
class=frappy_mlz.entangle.Sensor
tangodevice=tango://localhost:10000/box/tube/sensord
value.unit='K'
description=temperature at thermal coupling tube <-> stick
# regulations
[module T_stick_regulation]
class=frappy_mlz.entangle.TemperatureController
tangodevice=tango://localhost:10000/box/stick/control2
heateroutput.default=0
description=regulation of stick temperature
ramp.default=6
speed.default=0.1
setpoint.default=0
pid.default=(40,10,1)
p.default=40
i.default=10
d.default=1
abslimits=(0,500)
value.unit='K'
# OMG! a NamedDigitalOutput, but with float'ints' 0..3
[module T_stick_regulation_heaterrange]
class=frappy_mlz.entangle.AnalogOutput
tangodevice=tango://localhost:10000/box/stick/range2
precision.default=1
abslimits=(0,3)
description=heaterrange for stick regulation
[module T_tube_regulation]
class=frappy_mlz.entangle.TemperatureController
tangodevice=tango://localhost:10000/box/tube/control1
description=regulation of tube temperature
heateroutput.default=0
ramp.default=6
speed.default=0.1
setpoint.default=0
pid.default=(40,10,1)
p.default=40
i.default=10
d.default=1
abslimits=(0,500)
value.unit='K'
# OMG! a NamedDigitalOutput, but with float'ints' 0..3
#[module T_tube_regulation_heaterrange]
#class=frappy_mlz.entangle.AnalogOutput
#tangodevice=tango://localhost:10000/box/tube/range1
#precision.default=1
#abslimits=(0,3)
[module T_tube_regulation_heaterrange]
class=frappy_mlz.entangle.NamedDigitalOutput
tangodevice=tango://localhost:10000/box/tube/range1
mapping=dict(Off=0, Low=1, Medium=2, High=3)
description=heaterrange for tube regulation

148
cfg/ccr_cfg.py Normal file
View File

@@ -0,0 +1,148 @@
desc = '''CCR box of MLZ Sample environment group
Contains a Lakeshore 336 and an PLC controlling the compressor
and some valves.'''
Node('MLZ_ccr',
desc,
'tcp://10767',
)
Mod('automatik',
'frappy_mlz.entangle.NamedDigitalOutput',
'controls the (simple) pressure regulation\n'
'\n'
'selects between off, regulate on p1 or regulate on p2 sensor',
tangodevice = 'tango://localhost:10000/box/plc/_automatik',
mapping={'Off':0,'p1':1,'p2':2},
)
Mod('compressor',
'frappy_mlz.entangle.NamedDigitalOutput',
'control the compressor (on/off)',
tangodevice = 'tango://localhost:10000/box/plc/_cooler_onoff',
mapping={'Off':0,'On':1},
)
Mod('gas',
'frappy_mlz.entangle.NamedDigitalOutput',
'control the gas inlet into the ccr (on/off)\n'
'\n'
'note: this switches off automatically after 15 min.\n'
'note: activation de-activates the vacuum inlet\n'
'note: if the pressure regulation is active, it enslave this device',
tangodevice = 'tango://localhost:10000/box/plc/_gas_onoff',
mapping={'Off':0,'On':1},
)
Mod('vacuum',
'frappy_mlz.entangle.NamedDigitalOutput',
'control the vacuum inlet into the ccr (on/off)\n'
'\n'
'note: activation de-activates the gas inlet\n'
'note: if the pressure regulation is active, it enslave this device',
tangodevice = 'tango://localhost:10000/box/plc/_vacuum_onoff',
mapping={'Off':0,'On':1},
)
Mod('p1',
'frappy_mlz.entangle.AnalogInput',
'pressure sensor 1 (linear scale)',
tangodevice = 'tango://localhost:10000/box/plc/_p1',
value = Param(unit='mbar')
)
Mod('p2',
'frappy_mlz.entangle.AnalogInput',
'pressure sensor 2 (selectable curve)',
tangodevice = 'tango://localhost:10000/box/plc/_p2',
value = Param(unit='mbar'),
)
Mod('curve_p2',
'frappy_mlz.entangle.NamedDigitalInput',
'calibration curve for pressure sensor 2',
tangodevice = 'tango://localhost:10000/box/plc/_curve',
value = 0,
mapping = {'0-10V':0, '0-1000mbar':1, '1-9V to 0-1 mbar':2,
'DI200':3, 'DI2000':4, 'TTR100':7, 'PTR90':8,
'PTR225/237':9, 'ITR90':10, 'ITR100-D':11,
'ITR100-2':12, 'ITR100-3':13, 'ITR100-4':14,
'ITR100-5':15, 'ITR100-6':16, 'ITR100-7':17,
'ITR100-8':18, 'ITR100-9':19, 'ITR100-A':20,
'CMR361':21, 'CMR362':22, 'CMR363':23,
'CMR364':24, 'CMR365':25},
)
Mod('T_tube_regulation',
'frappy_mlz.entangle.TemperatureController',
'regulation of tube temperature',
tangodevice = 'tango://localhost:10000/box/tube/control1',
value = Param(unit = 'K'),
heateroutput = 0,
ramp = 6,
speed = 0.1,
setpoint = 0,
pid = (40, 10, 1),
p = 40,
i = 10,
d = 1,
abslimits = (0, 500),
)
Mod('T_stick_regulation',
'frappy_mlz.entangle.TemperatureController',
'regualtion of stick temperature',
tangodevice = 'tango://localhost:10000/box/stick/control2',
value = Param(unit = 'K'),
heateroutput = 0,
ramp = 6,
speed = 0.1,
setpoint = 0,
pid = (40, 10, 1),
p = 40,
i = 10,
d = 1,
abslimits = (0, 500),
)
Mod('T_sample',
'frappy_mlz.entangle.Sensor',
'sample temperature',
tangodevice = 'tango://localhost:10000/box/sample/sensora',
value = Param(unit = 'K'),
)
Mod('T_stick',
'frappy_mlz.entangle.Sensor',
'temperature at bottom of sample stick',
tangodevice = 'tango://localhost:10000/box/stick/sensorb',
value = Param(unit = 'K'),
)
Mod('T_coldhead',
'frappy_mlz.entangle.Sensor',
'temperature at coldhead',
tangodevice = 'tango://localhost:10000/box/coldhead/sensorc',
value = Param(unit = 'K'),
)
Mod('T_tube',
'frappy_mlz.entangle.Sensor',
'temperature at thermal coupling tube <-> stick',
tangodevice = 'tango://localhost:10000/box/tube/sensord',
value = Param(unit = 'K'),
)
# THIS IS A HACK: due to entangle (in controller)
Mod('T_tube_regulation_heaterrange',
'frappy_mlz.entangle.NamedDigitalOutput',
'heaterrange for tube regulation',
tangodevice = 'tango://localhost:10000/box/tube/range1',
mapping={'Off':0,'Low':1,'Medium':2, 'High':3},
)
Mod('T_stick_regulation_heaterrange',
'frappy_mlz.entangle.NamedDigitalOutput',
'heaterrange for stick regulation',
tangodevice = 'tango://localhost:10000/box/stick/range2',
mapping={'Off':0,'Low':1,'Medium':2, 'High':3},
)

View File

@@ -3,19 +3,17 @@
#####################################################################
Node('cryo_7.frappy.demo',
'short description' \
'' \
'' \
'This is a very long description providing all the glory details in all the ' \
'glory details about the stuff we are describing',
'short description\n\n'
'This is a very long description providing all the gory details '
'about the stuff we are describing.',
'tcp://10769',
more="blub",
)
Mod('cryo',
'frappy_demo.cryo.Cryostat',
'A simulated cc cryostat with heat-load, specific heat for the sample and a ' \
'temperature dependend heat-link between sample and regulation.',
'A simulated cc cryostat with heat-load, specific heat for the sample and a '
'temperature dependent heat-link between sample and regulation.',
group='very important/stuff',
jitter=0.1,
T_start=10.0,

View File

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

View File

@@ -1,50 +0,0 @@
[node see_demo_equipment]
description=Do not use, it needs to be rewritten....
[interface testing]
type=tcp
bindto=0.0.0.0
bindport=10767
[module tc1]
class=frappy_demo.modules.CoilTemp
sensor="X34598T7"
[module tc2]
class=frappy_demo.modules.CoilTemp
sensor="X39284Q8'
[module sensor1]
class=frappy_ess.epics.EpicsReadable
epics_version="v4"
.group="Lakeshore336"
value_pv="DEV:KRDG1"
[module loop1]
class=frappy_ess.epics.EpicsTempCtrl
epics_version="v4"
.group="Lakeshore336"
value_pv="DEV:KRDG1"
target_pv="DEV:SETP_S1"
heaterrange_pv="DEV:RANGE_S1"
[module sensor2]
class=frappy_ess.epics.EpicsReadable
epics_version="v4"
.group="Lakeshore336"
value_pv="DEV:KRDG2"
[module loop2]
class=frappy_ess.epics.EpicsTempCtrl
epics_version="v4"
.group="Lakeshore336"
value_pv="DEV:KRDG2"
target_pv="DEV:SETP_S2"
heaterrange_pv="DEV:RANGE_S2"

36
cfg/epics_cfg.py Normal file
View File

@@ -0,0 +1,36 @@
Node('see_demo_equipment',
'Do not use, it needs to be rewritten....',
'tcp://10767',
)
Mod('tc1',
'frappy_demo.modules.CoilTemp',
'',
sensor="X34598T7",
)
Mod('tc2',
'frappy_demo.modules.CoilTemp',
'',
sensor="X39284Q8",
)
for i in [1,2]:
Mod('sensor%d' % i,
'frappy_ess.epics.EpicsReadable',
'',
epics_version="v4",
value_pv="DEV:KRDG%d" % i,
group="Lakeshore336",
)
Mod('loop%d' % i,
'frappy_ess.epics.EpicsTempCtrl',
'',
epics_version="v4",
group="Lakeshore336",
value_pv="DEV:KRDG%d" % i,
target_pv="DEV:SETP_S%d" % i,
heaterrange_pv="DEV:RANGE_S%d" % i,
)

7
cfg/frappy_test_cfg.py Normal file
View File

@@ -0,0 +1,7 @@
import frappy.core as fc
import TNMRExt.FlexibleModule as mod
Node('example_TNMR.psi.ch', 'The NMR system running the Scout and controlled with TNMR', interface='tcp://5000')
Mod('sequence0', mod.flexible_module('D:\\Users\\Garrad\\sequence_0.tps', 's0'), 'The zeroth sequence')
Mod('sequence1', mod.flexible_module('D:\\Users\\Garrad\\sequence_1.tps', 's1'), 'The first sequence')

23
cfg/ls336_cfg.py Normal file
View File

@@ -0,0 +1,23 @@
from os import environ
# either change the uri or set the environment variable 'LS_URI'
lakeshore_uri = environ.get('LS_URI', 'tcp://<host>:7777')
Node('example_cryo.psi.ch', # a globally unique identification
'this is an example cryostat for the Frappy tutorial', # describes the node
interface='tcp://10767') # you might choose any port number > 1024
Mod('io', # the name of the module
'frappy_demo.lakeshore.LakeshoreIO', # the class used for communication
'communication to main controller', # a description
uri=lakeshore_uri, # the serial connection
)
Mod('T',
'frappy_demo.lakeshore.TemperatureLoop',
'Sample Temperature',
io='io',
channel='A', # the channel on the LakeShore for this module
loop=1, # the loop to be used
value=Param(max=470), # set the maximum expected T
target=Param(max=420), # set the maximum allowed target T
heater_range=3, # 5 for model 350
)

View File

@@ -1,28 +0,0 @@
[NODE]
id = LscSIM.psi.ch
description = Lsc Simulation at PSI
[INTERFACE]
uri = tcp://5000
[lscom]
class = frappy_psi.ls370sim.Ls370Sim
description = simulated serial communicator to a LS 370
visibility = 3
[sw]
class = frappy_psi.ls370res.Switcher
description = channel switcher for Lsc controller
io = lscom
[a]
class = frappy_psi.ls370res.ResChannel
channel = 1
description = resistivity
switcher = sw
[b]
class = frappy_psi.ls370res.ResChannel
channel = 3
description = resistivity
switcher = sw

30
cfg/ls370sim_cfg.py Normal file
View File

@@ -0,0 +1,30 @@
Node('LscSIM.psi.ch',
'Lsc Simulation at PSI',
'tcp://5000',
)
Mod('lscom',
'frappy_psi.ls370sim.Ls370Sim',
'simulated serial communicator to a LS 370',
visibility = 3
)
Mod('sw',
'frappy_psi.ls370res.Switcher',
'channel switcher for Lsc controller',
io = 'lscom',
)
Mod('a',
'frappy_psi.ls370res.ResChannel',
'resistivity',
channel = 1,
switcher = 'sw',
)
Mod('b',
'frappy_psi.ls370res.ResChannel',
'resistivity',
channel = 3,
switcher = 'sw',
)

View File

@@ -1,21 +0,0 @@
[node LscSIM.psi.ch]
description = Lsc370 Test
[interface tcp]
type = tcp
bindto = 0.0.0.0
bindport = 5000
[module lsmain]
class = frappy_psi.ls370res.Main
description = main control of Lsc controller
uri = localhost:4567
[module res]
class = frappy_psi.ls370res.ResChannel
vexc = '2mV'
channel = 3
description = resistivity
main = lsmain
# the auto created iodev from lsmain:
iodev = lsmain_iodev

29
cfg/ls370test_cfg.py Normal file
View File

@@ -0,0 +1,29 @@
Node('LscSIM.psi.ch',
'Lsc370 Test',
'tcp://5000',
)
Mod('io',
'frappy_psi.ls370res.StringIO',
'io for Ls370',
uri = 'localhost:2089',
)
Mod('sw',
'frappy_psi.ls370res.Switcher',
'channel switcher',
io = 'io',
)
Mod('res1',
'frappy_psi.ls370res.ResChannel',
'resistivity chan 1',
vexc = '2mV',
channel = 1,
switcher = 'sw',
)
Mod('res2',
'frappy_psi.ls370res.ResChannel',
'resistivity chn 3',
vexc = '2mV',
channel = 3,
switcher = 'sw',
)

View File

@@ -1,8 +0,0 @@
[NODE]
class = protocol.router.Router
id = multiplexer
description = multiplexer node
nodes = ['localhost:5000', 'localhost:10769']
[INTERFACE]
uri = tcp://5000

6
cfg/multiplexer_cfg.py Normal file
View File

@@ -0,0 +1,6 @@
Node('multiplexer',
'multiplexer node',
'tcp://5000',
cls = 'protocol.router.Router',
nodes = ['localhost:10768', 'localhost:10769'],
)

View File

@@ -0,0 +1,5 @@
import frappy.core as fc
Node('example_NA.psi.ch', 'A demo system showing how to connect network analysers', interface='tcp://5000')
Mod('ZVLNode', 'frappy_psi.network_analysers.ZVL.ZVLNode.ZVLNode', 'ZVL Network Analyser', analyser_ip=Param('169.254.150.182')) # must be connected on the same ethernet network

14
cfg/nmr_scout_cfg.py Normal file
View File

@@ -0,0 +1,14 @@
import frappy.core as fc
docstring = 'NMR pulse sequence.\
Each pulse ``block`` consists of first a pulse with parameters pulse_width (microseconds), pulse_height (amplitude; for the SCOUT, percentage of max), and phase_cycle, and then a delay with parameter delay_time (microseconds).\
\
Please use the custom commands, ``generate_pulse``, ``scan_sequence``, and ``scan_sequences``. There exist example scripts in your NICOS install location/nicos_sinq/tnmr/example_scripts.\
Durations are in microseconds, excepting post_acquisition_time (ms), and frequencies are in MHz.\
'
Node('example_TNMR.psi.ch', 'The NMR system running the Scout and controlled with TNMR', interface='tcp://5000')
Mod('daq_scout', 'frappy_psi.tnmr.TNMRModule.TNMRModule', 'Tecmag SCOUT-based NMR System')
print('TNMR Module loaded - please refer to https://www.psi.ch/en/lin/nmr-spectroscopy for help and documentation')

View File

@@ -1,124 +0,0 @@
[NODE]
id = PPMS.psi.ch
description = PPMS at PSI
[INTERFACE]
uri = tcp://5000
[tt]
class = frappy_psi.ppms.Temp
description = main temperature
io = ppms
[mf]
class = frappy_psi.ppms.Field
target.min = -9
target.max = 9
description = magnetic field
io = ppms
[pos]
class = frappy_psi.ppms.Position
description = sample rotator
io = ppms
[lev]
class = frappy_psi.ppms.Level
description = helium level
io = ppms
[chamber]
class = frappy_psi.ppms.Chamber
description = chamber state
io = ppms
[r1]
class = frappy_psi.ppms.BridgeChannel
description = resistivity channel 1
no = 1
value.unit = Ohm
io = ppms
[r2]
class = frappy_psi.ppms.BridgeChannel
description = resistivity channel 2
no = 2
value.unit = Ohm
io = ppms
[r3]
class = frappy_psi.ppms.BridgeChannel
description = resistivity channel 3
no = 3
value.unit = Ohm
io = ppms
[r4]
class = frappy_psi.ppms.BridgeChannel
description = resistivity channel 4
no = 4
value.unit = Ohm
io = ppms
[i1]
class = frappy_psi.ppms.Channel
description = current channel 1
no = 1
value.unit = uA
io = ppms
[i2]
class = frappy_psi.ppms.Channel
description = current channel 2
no = 2
value.unit = uA
io = ppms
[i3]
class = frappy_psi.ppms.Channel
description = current channel 3
no = 3
value.unit = uA
io = ppms
[i4]
class = frappy_psi.ppms.Channel
description = current channel 4
no = 4
value.unit = uA
io = ppms
[v1]
class = frappy_psi.ppms.DriverChannel
description = voltage channel 1
no = 1
value.unit = V
io = ppms
[v2]
class = frappy_psi.ppms.DriverChannel
description = voltage channel 2
no = 2
value.unit = V
io = ppms
[tv]
class = frappy_psi.ppms.UserChannel
description = VTI temperature
enabled = 1
value.unit = K
io = ppms
[ts]
class = frappy_psi.ppms.UserChannel
description = sample temperature
enabled = 1
value.unit = K
io = ppms
[ppms]
class = frappy_psi.ppms.Main
description = the main and poller module
class_id = QD.MULTIVU.PPMS.1
visibility = 3
pollinterval = 2

93
cfg/ppms_cfg.py Normal file
View File

@@ -0,0 +1,93 @@
Node('PPMS.psi.ch',
'PPMS at PSI',
'tcp://5000',
)
Mod('tt',
'frappy_psi.ppms.Temp',
'main temperature',
io = 'ppms',
)
Mod('mf',
'frappy_psi.ppms.Field',
'magnetic field',
target = Param(min=-9, max=9),
io = 'ppms',
)
Mod('pos',
'frappy_psi.ppms.Position',
'sample rotator',
io = 'ppms',
)
Mod('lev',
'frappy_psi.ppms.Level',
'helium level',
io = 'ppms',
)
Mod('chamber',
'frappy_psi.ppms.Chamber',
'chamber state',
io = 'ppms',
)
for i in range(1,5):
Mod('r%d' % i,
'frappy_psi.ppms.BridgeChannel',
'resistivity channel %d' % i,
no = i,
value = Param(unit = 'Ohm'),
io = 'ppms',
)
for i in range(1,5):
Mod('i%d' % i,
'frappy_psi.ppms.Channel',
'current channel %d' % i,
no = i,
value = Param(unit = 'uA'),
io = 'ppms',
)
Mod('v1',
'frappy_psi.ppms.DriverChannel',
'voltage channel 1',
no = 1,
value = Param(unit = 'V'),
io = 'ppms',
)
Mod('v2',
'frappy_psi.ppms.DriverChannel',
'voltage channel 2',
no = 2,
value = Param(unit = 'V'),
io = 'ppms',
)
Mod('tv',
'frappy_psi.ppms.UserChannel',
'VTI temperature',
enabled = 1,
value = Param(unit = 'K'),
io = 'ppms',
)
Mod('ts',
'frappy_psi.ppms.UserChannel',
'sample temperature',
enabled = 1,
value = Param(unit = 'K'),
io = 'ppms',
)
Mod('ppms',
'frappy_psi.ppms.Main',
'the main and poller module',
class_id = 'QD.MULTIVU.PPMS.1',
visibility = 3,
pollinterval = 2,
)

View File

@@ -1,22 +0,0 @@
[node filtered.PPMS.psi.ch]
description = filtered PPMS at PSI
[interface tcp]
type = tcp
bindto = 0.0.0.0
bindport = 5002
[module secnode]
class = frappy.SecNode
description = a SEC node
uri = tcp://localhost:5000
[module mf]
class = frappy.Proxy
remote_class = frappy_psi.ppms.Field
description = magnetic field
iodev = secnode
value.min = -0.1
value.max = 0.1
target.min = -8
target.max = 8

View File

@@ -0,0 +1,21 @@
Node('filtered.PPMS.psi.ch',
'filtered PPMS at PSI',
'tcp://5002',
)
Mod('secnode',
'frappy.proxy.SecNode',
'a SEC node',
uri = 'tcp://localhost:5000',
)
Mod('mf',
'frappy.proxy.Proxy',
'magnetic field',
remote_class = 'frappy_psi.ppms.Field',
io = 'secnode',
value = Param(),
target = Param(min=-0.1, max=0.1),
)

34
cfg/psi_nmr_setup_cfg.py Normal file
View File

@@ -0,0 +1,34 @@
import frappy.core as fc
enabled_modules = [ 'TNMR', 'Razorbill', 'Capacitance', 'NetAnalyser' ] # default
#enabled_modules = [ 'Capacitance' ]
Node('uniaxial_nmr.psi.ch',
'The NMR system running the Scout and controlled with TNMR. Also contains a uniaxial cell (Razorbill RP100), a network analyser (ZVL), and a capacitance reader (for more direct measurements of the strain cell\'s status) (TSSOP16 with Arduino Nano V3)',
interface='tcp://5000')
# TNMR
if('TNMR' in enabled_modules):
Mod('tnmr_otf_module', 'frappy_psi.tnmr.OTFModule.ProgrammedSequence', 'NMR Sequence')
# Razorbill RP100
if('Razorbill' in enabled_modules):
Mod('io_razorbill',
'frappy_psi.uniaxial_cell.RP100.RP100IO',
'communication',
uri='serial://COM3?baudrate=9600+bytesize=8+parity=none+stopbits=1')
Mod('RP100Node_CH1', 'frappy_psi.uniaxial_cell.RP100.VoltageChannel', 'Razorbill RP100 PSU (CH1)', channel=1, io='io_razorbill')
Mod('RP100Node_CH2', 'frappy_psi.uniaxial_cell.RP100.VoltageChannel', 'Razorbill RP100 PSU (CH2)', channel=2, io='io_razorbill')
# Capacitance readings (TSSOP16 with Arduino Nano V3)
if('Capacitance' in enabled_modules):
Mod('io_capacitance',
'frappy_psi.capacitance_readings.TSSOP16.TSSOP16_IO',
'communication',
uri='serial://COM5?baudrate=9600+bytesize=8+parity=none+stopbits=1')
Mod('TSSOP16', 'frappy_psi.capacitance_readings.TSSOP16.TSSOP16', 'Capacitance-reading Arduino (with TSSOP16)', io='io_capacitance')
# ZVL Network Analyser
if('NetAnalyser' in enabled_modules):
Mod('ZVLNode', 'frappy_psi.network_analysers.ZVL.ZVLNode.ZVLNode', 'ZVL Network Analyser', analyser_ip=Param('129.129.156.201')) # must be connected on the same ethernet network

View File

@@ -0,0 +1,12 @@
import frappy.core as fc
import serial
Node('example_RP100.psi.ch', 'A demo system showing how to connect the Razorbill PSU', interface='tcp://5000')
Mod('io1',
'frappy_psi.uniaxial_cell.RP100.RP100IO',
'communication',
uri='serial://COM10?baudrate=9600+bytesize=8+parity=none+stopbits=1')
Mod('RP100Node_CH1', 'frappy_psi.uniaxial_cell.RP100.VoltageChannel', 'Razorbill RP100 PSU (CH1)', channel=1, io='io1')
Mod('RP100Node_CH2', 'frappy_psi.uniaxial_cell.RP100.VoltageChannel', 'Razorbill RP100 PSU (CH2)', channel=2, io='io1')

View File

@@ -1,8 +0,0 @@
[NODE]
id = router
class = protocol.router.Router
description = router node
node = localhost:5000
[INTERFACE]
uri=tcp://5002

6
cfg/router_cfg.py Normal file
View File

@@ -0,0 +1,6 @@
Node('router',
'router node',
'tcp://5002',
cls = 'protocol.router.Router',
node = 'localhost:5000',
)

43
cfg/seop_cfg.py Normal file
View File

@@ -0,0 +1,43 @@
description = """
3He system in Lab ...
"""
Node('mlz_seop',
description,
'tcp://10767',
)
Mod('cell',
'frappy_mlz.seop.Cell',
'interface module to the driver',
config_directory = '/home/jcns/daemon/config',
)
Mod('afp',
'frappy_mlz.seop.Afp',
'controls the afp flip of the cell',
cell = 'cell'
)
Mod('nmr',
'frappy_mlz.seop.Nmr',
'controls the ',
cell = 'cell'
)
fitparams = [
('amplitude', 'V'),
('T1', 's'),
('T2', 's'),
('b', ''),
('frequency', 'Hz'),
('phase', 'deg'),
]
for param, unit in fitparams:
Mod(f'nmr_{param.lower()}',
'frappy_mlz.seop.FitParam',
f'fittet parameter {param} of NMR',
cell = 'cell',
value = Param(unit=unit),
sigma = Param(unit=unit),
param = param,
)

View File

@@ -1,23 +0,0 @@
[node test config]
description=description of the simulation sec-node
.
Testing simulation dummy setup.
[interface tcp]
type=tcp
bindto=0.0.0.0
bindport=10767
[module sim]
class=frappy.simulation.SimDrivable
.description=simulation stuff
.extra_params=param3,param4,jitter,ramp
param3.datatype={"type":"bool"}
param3.default=True
param3.readonly=False
jitter.default=1
ramp.default=60
value.default=123
target.default=42

18
cfg/sim_cfg.py Normal file
View File

@@ -0,0 +1,18 @@
Node('sim.test.config',
'description of the simulation sec-node\n'
'\n'
'Testing simulation dummy setup.',
'tcp://10767',
)
Mod('sim',
'frappy.simulation.SimDrivable',
'simulation stuff',
extra_params = 'param3,param4,jitter,ramp',
param3 = Param(default=True, datatype={'type': 'bool'}, readonly=False),
jitter = 1,
ramp = 60,
value = 123,
target = 42,
)

View File

@@ -1,116 +0,0 @@
[node SIM_MLZ_amagnet(Garfield)]
description=MLZ-Amagnet
.
Water cooled magnet from ANTARES@MLZ.
.
Use module to control the magnetic field.
Don't forget to select symmetry first (can be moved only at zero field!).
.
Monitor T1..T4 (Coil temps), if they get to hot, field will ramp down!
.
In case of Problems, contact the ANTARES people at MLZ.
visibility=expert
foo=bar
[interface tcp]
type=tcp
bindto=0.0.0.0
bindport=10767
[module enable]
class=frappy.simulation.SimWritable
value.datatype={"type":"enum", "members":{'On':1,'Off':0}}
target.datatype={"type":"enum", "members":{'On':1,'Off':0}}
.description='Enables to Output of the Powersupply'
.visibility='advanced'
[module polarity]
class=frappy.simulation.SimWritable
value.datatype={"type":"enum", "members":{'+1':1,'0':0,'-1':-1}}
target.datatype={"type":"enum", "members":{'+1':1,'0':0,'-1':-1}}
.description=polarity (+/-) switch
.
there is an interlock in the plc:
if there is current, switching polarity is forbidden
if polarity is short, powersupply is disabled
.visibility=advanced
[module symmetry]
class=frappy.simulation.SimWritable
value.datatype={"type":"enum", "members":{'symmetric':1,'short':0, 'asymmetric':-1}}
target.datatype={"type":"enum", "members":{'symmetric':1,'short':0, 'asymmetric':-1}}
.description=par/ser switch selecting (a)symmetric mode
.
note: on the front panel symmetric is ser, asymmetric is par
.visibility=advanced
value.default = 'symmetric'
[module T1]
class=frappy.simulation.SimReadable
.description=Temperature1 of the coils system
value.unit='degC'
value.default = 23.45
[module T2]
class=frappy.simulation.SimReadable
.description=Temperature2 of the coils system
value.unit='degC'
value.default = 23.45
[module T3]
class=frappy.simulation.SimReadable
.description=Temperature3 of the coils system
value.unit='degC'
value.default = 23.45
[module T4]
class=frappy.simulation.SimReadable
.description=Temperature4 of the coils system
value.unit='degC'
value.default = 23.45
[module currentsource]
class=frappy.simulation.SimDrivable
.description=Device for the magnet power supply (current mode)
abslimits=(0,200)
speed=1
ramp=60
precision=0.02
current=0
voltage=10
.visibility=advanced
.extra_params = abslimits, speed, ramp, precision, current, voltage, window
abslimits.datatype = {"type":"limit", "members":{"type":"double", "min":0, "max":200, "unit":"A"}}
abslimits.default = (0, 200)
speed.datatype = {"type":"double", "min":0, "max":10, "unit":"A/s"}
speed.default = 10
ramp.datatype = {"type":"double", "min":0, "max":600, "unit":"A/min"}
ramp.default = 600
precision.datatype = {"type":"double", "unit":"A"}
precision.default = 0.1
current.datatype = {"type":"double", "min":0, "max":200, "unit":"A"}
current.default = 0
voltage.datatype = {"type":"double", "min":0, "max":10, "unit":"V"}
voltage.default = 0
window.datatype = {"type":"double", "min":0, "max":120, "unit":"s"}
window.default = 10
[module mf]
class=frappy_mlz.amagnet.GarfieldMagnet
.description=magnetic field module, handling polarity switching and stuff
subdev_currentsource=currentsource
subdev_enable=enable
subdev_polswitch=polarity
subdev_symmetry=symmetry
target.unit='T'
value.unit='T'
userlimits=(-0.35, 0.35)
calibrationtable={'symmetric':[0.00186517, 0.0431937, -0.185956, 0.0599757, 0.194042],
'short': [0.0, 0.0, 0.0, 0.0, 0.0],
'asymmetric':[0.00136154, 0.027454, -0.120951, 0.0495289, 0.110689]}
.meaning=["magneticfield", 20]
.visibility=user
abslimits.default=-0.4,0.4

116
cfg/sim_mlz_amagnet_cfg.py Normal file
View File

@@ -0,0 +1,116 @@
Node('SIM_MLZ_amagnet(Garfield)',
'MLZ-Amagnet\n'
'\n'
'Water cooled magnet from ANTARES@MLZ.\n'
'\n'
' Use module to control the magnetic field.\n'
'Don\'t forget to select symmetry first (can be moved only at zero field!).\n'
'\n'
'Monitor T1..T4 (Coil temps), if they get to hot, field will ramp down!\n'
'\n'
'In case of Problems, contact the ANTARES people at MLZ.',
'tcp://10767',
visibility = 'expert',
foo = 'bar',
)
Mod('enable',
'frappy.simulation.SimWritable',
'Enables to Output of the Powersupply',
value = Param(datatype={"type":"enum", "members":{'On':1,'Off':0}}),
target = Param(datatype={"type":"enum", "members":{'On':1,'Off':0}}),
visibility = 'advanced',
)
Mod('polarity',
'frappy.simulation.SimWritable',
'polarity (+/-) switch\n'
'\n'
'there is an interlock in the plc:\n'
'if there is current, switching polarity is forbidden\n'
'if polarity is short, powersupply is disabled',
value = Param(datatype={"type":"enum", "members":{'+1':1,'0':0,'-1':-1}}),
target = Param(datatype={"type":"enum", "members":{'+1':1,'0':0,'-1':-1}}),
visibility = 'advanced',
)
Mod('symmetry',
'frappy.simulation.SimWritable',
'par/ser switch selecting (a)symmetric mode\n'
'\n'
'note: on the front panel symmetric is ser, asymmetric is par',
value = Param(
datatype={"type":"enum", "members":{'symmetric':1,'short':0, 'asymmetric':-1}},
default = 'symmetric'
),
target = Param(datatype={"type":"enum", "members":{'symmetric':1,'short':0, 'asymmetric':-1}}),
visibility = 'advanced',
)
for i in range(1,5):
Mod('T%d' % i,
'frappy.simulation.SimReadable',
'Temperature%d of the coils system' % i,
value = Param(default = 23.45, unit='degC'),
)
Mod('currentsource',
'frappy.simulation.SimDrivable',
'Device for the magnet power supply (current mode)',
value = 0,
#abslimits = (0,200),
#speed = 1,
#ramp = 60,
#precision = 0.02,
#current = 0,
#voltage = 10,
visibility = 'advanced',
extra_params = 'abslimits, speed, ramp, precision, current, voltage, window',
abslimits = Param(
default = (0, 200),
datatype = {"type":"limit", "members":{"type":"double", "min":0, "max":200, "unit":"A"}}
),
speed = Param(
default = 10,
datatype = {"type":"double", "min":0, "max":10, "unit":"A/s"}
),
ramp = Param(
default = 600,
datatype = {"type":"double", "min":0, "max":600, "unit":"A/min"}
),
precision = Param(
default = 0.1,
datatype = {"type":"double", "unit":"A"}
),
current = Param(
default = 0,
datatype = {"type":"double", "min":0, "max":200, "unit":"A"}
),
voltage = Param(
default = 0,
datatype = {"type":"double", "min":0, "max":10, "unit":"V"}
),
window = Param(
default = 10,
datatype = {"type":"double", "min":0, "max":120, "unit":"s"}
)
)
Mod('mf',
'frappy_mlz.amagnet.GarfieldMagnet',
'magnetic field module, handling polarity switching and stuff',
currentsource='currentsource',
enable='enable',
polswitch='polarity',
symmetry='symmetry',
target = Param(unit='T'),
value = Param(unit='T'),
userlimits=(-0.35, 0.35),
calibrationtable={'symmetric':[0.00186517, 0.0431937, -0.185956, 0.0599757, 0.194042],
'short': [0.0, 0.0, 0.0, 0.0, 0.0],
'asymmetric':[0.00136154, 0.027454, -0.120951, 0.0495289, 0.110689]},
meaning=("magneticfield", 20),
visibility='user',
abslimits=(-0.4,0.4),
)

View File

@@ -1,93 +0,0 @@
[node cci3he1]
description = [sim] cci3he box of MLZ Sample environment group
.
Controls an 3He insert with an ls370 and an PLC controlling
the compressor and the valves of the gas handling.
[interface tcp]
type=tcp
bindto=0.0.0.0
bindport=10767
[module T_cci3he1]
class=frappy.simulation.SimDrivable
.description=Main temperature control node of cci3he1.
.
Controls the regulation loop of the ls370.
value.datatype={"type":"double","unit":"K"}
value.default=300
target.datatype={"type":"double", "min":0, "max":300, "unit":"K"}
target.default=300
.extra_params=ramp
ramp.datatype={"type":"double","min":0,"max":600,"unit":"K/min"}
ramp.description=target ramping speed in K/min.
ramp.default=60
.meaning=["temperature_regulation",40]
[module T_cci3he1_A]
class=frappy.simulation.SimReadable
.description=3He pot temperature sensor. Also used for the regulation.
.visibility=expert
value.default=300
value.datatype={"type":"double","unit":"K"}
.meaning=["temperature",38]
[module T_cci3he1_B]
class=frappy.simulation.SimReadable
.description=(optional) sample temperature sensor close to sample.
.visibility=user
value.default=300
value.datatype={"type":"double","unit":"K"}
.meaning=["temperature",39]
[module cci3he1_p1]
class=frappy.simulation.SimReadable
.description=Pressure at turbo pump inlet.
.visibility=expert
value.default=2e-3
value.datatype={"type":"double","unit":"mbar"}
[module cci3he1_p2]
class=frappy.simulation.SimReadable
.description=Pressure at turbo pump outlet.
.visibility=expert
value.default=9.87
value.datatype={"type":"double","unit":"mbar"}
[module cci3he1_p3]
class=frappy.simulation.SimReadable
.description=Pressure at compressor inlet.
.visibility=expert
value.default=19.99
value.datatype={"type":"double","unit":"mbar"}
[module cci3he1_p4]
class=frappy.simulation.SimReadable
.description=Pressure at compressor outlet.
.visibility=expert
value.default=999
value.datatype={"type":"double","unit":"mbar"}
[module cci3he1_p5]
class=frappy.simulation.SimReadable
.description=Pressure in dump tank.
.visibility=expert
value.default=567
value.datatype={"type":"double","unit":"mbar"}
[module cci3he1_p6]
class=frappy.simulation.SimReadable
.description=Pressure in the vacuum dewar (ivc).
.visibility=expert
value.default=1e-3
value.datatype={"type":"double","unit":"mbar"}
[module cci3he1_flow]
class=frappy.simulation.SimReadable
.description=Gas Flow (condensing line).
.visibility=expert
value.default=12.34
value.datatype={"type":"double","unit":"mln/min"}
# note: all valves and switches are missing: use VNC to control them

View File

@@ -0,0 +1,88 @@
Node('cci3he1',
'[sim] cci3he box of MLZ Sample environment group\n'
'\n'
'Controls an 3He insert with an ls370 and an PLC controlling \n'
'the compressor and the valves of the gas handling.',
'tcp://10767',
)
Mod('T_cci3he1',
'frappy.simulation.SimDrivable',
'Main temperature control node of cci3he1.\n'
'\n'
'Controls the regulation loop of the ls370.',
value = Param(default=300, datatype={"type":"double","unit":"K"}),
target = Param(default=300, datatype={"type":"double", "min":0, "max":300, "unit":"K"}),
extra_params='ramp',
ramp = Param(default=60,
datatype={"type":"double","min":0,"max":600,"unit":"K/min"},
description='target ramping speed in K/min.',
),
meaning=["temperature_regulation",40]
)
Mod('T_cci3he1_A',
'frappy.simulation.SimReadable',
'3He pot temperature sensor. Also used for the regulation.',
visibility='expert',
value = Param(default=300, datatype={"type":"double","unit":"K"}),
meaning=["temperature",38]
)
Mod('T_cci3he1_B',
'frappy.simulation.SimReadable',
'(optional) sample temperature sensor close to sample.',
visibility='user',
value = Param(default=300, datatype={"type":"double","unit":"K"}),
meaning=["temperature",39]
)
Mod('cci3he1_p1',
'frappy.simulation.SimReadable',
'Pressure at turbo pump inlet.',
value = Param(default=2e-3, datatype={"type":"double","unit":"mbar"}),
visibility='expert',
)
Mod('cci3he1_p2',
'frappy.simulation.SimReadable',
'Pressure at turbo pump outlet.',
value = Param(default=9.87, datatype={"type":"double","unit":"mbar"}),
visibility='expert',
)
Mod('cci3he1_p3',
'frappy.simulation.SimReadable',
'Pressure at compressor inlet.',
value = Param(default=19.99, datatype={"type":"double","unit":"mbar"}),
visibility='expert',
)
Mod('cci3he1_p4',
'frappy.simulation.SimReadable',
'Pressure at compressor outlet.',
value = Param(default=999, datatype={"type":"double","unit":"mbar"}),
visibility='expert',
)
Mod('cci3he1_p5',
'frappy.simulation.SimReadable',
'Pressure in dump tank.',
value = Param(default=567, datatype={"type":"double","unit":"mbar"}),
visibility='expert',
)
Mod('cci3he1_p6',
'frappy.simulation.SimReadable',
'Pressure in the vacuum dewar (ivc).',
value = Param(default=1e-3, datatype={"type":"double","unit":"mbar"}),
visibility='expert',
)
Mod('cci3he1_flow',
'frappy.simulation.SimReadable',
'Gas Flow (condensing line).',
value = Param(default=12.34, datatype={"type":"double","unit":"mln/min"}),
visibility='expert',
)
# note: all valves and switches are missing: use VNC to control them

View File

@@ -1,107 +0,0 @@
[node ccidu1]
description = [sim] ccidu box of MLZ Sample environment group
.
Controls an 3He/4He dilution insert with an ls372 and an PLC controlling
the compressor and the valves of the gas handling.
[interface tcp]
type=tcp
bindto=0.0.0.0
bindport=10767
[module T_ccidu1]
class=frappy.simulation.SimDrivable
.description=Main temperature control node of ccidu1.
.
Controls the regulation loop of the ls372.
value.unit='K'
value.default=300
target.datatype={"type":"double", "min":0, "max":300, "unit":"K"}
target.default=300
.extra_params=ramp
ramp.datatype={"type":"double", "min":0, "max":600, "unit":"K/min"}
ramp.description=target ramping speed in K/min.
ramp.default=60
.meaning=["temperature_regulation",40]
[module T_ccidu1_A]
class=frappy.simulation.SimReadable
.description=mixing chamber temperature sensor. Also used for the regulation.
.visibility=expert
value.default=300
value.datatype={"type":"double", "unit":"K"}
.meaning=["temperature",38]
[module T_ccidu1_B]
class=frappy.simulation.SimReadable
.description=(optional) sample temperature sensor close to sample.
.visibility=user
value.default=300
value.datatype={"type":"double", "unit":"K"}
.meaning=["temperature",39]
[module ccidu1_pstill]
class=frappy.simulation.SimReadable
.description=Pressure at the still/turbo pump inlet.
.visibility=expert
value.default=999
value.datatype={"type":"double", "unit":"mbar"}
[module ccidu1_pinlet]
class=frappy.simulation.SimReadable
.description=Pressure at forepump inlet/turbo pump outlet.
.visibility=expert
value.default=999
value.datatype={"type":"double", "unit":"mbar"}
[module ccidu1_poutlet]
class=frappy.simulation.SimReadable
.description=Pressure at forepump outlet/compressor inlet.
.visibility=expert
value.default=999
value.datatype={"type":"double", "unit":"mbar"}
[module ccidu1_pkond]
class=frappy.simulation.SimReadable
.description=Pressure at condensing line/compressor outlet.
.visibility=expert
value.default=999
value.datatype={"type":"double", "unit":"mbar"}
[module ccidu1_ptank]
class=frappy.simulation.SimReadable
.description=Pressure in dump tank.
.visibility=expert
value.default=999
value.datatype={"type":"double", "unit":"mbar"}
[module ccidu1_pvac]
class=frappy.simulation.SimReadable
.description=Pressure in the vacuum dewar (ivc).
.visibility=expert
value.default=999
value.datatype={"type":"double", "unit":"mbar"}
[module ccidu1_flow]
class=frappy.simulation.SimReadable
.description=Gas Flow (condensing line).
.visibility=expert
value.default=999
value.datatype={"type":"double", "unit":"mbar"}
# note: all valves and switches are missing: use VNC to control them
[module ccidu1_V6]
class=frappy.simulation.SimDrivable
.description=Needle valve
.visibility=expert
value.default=99
value.datatype={"type":"double", "min":0, "max":100, "unit":"%%"}
[module ccidu1_V3]
class=frappy.simulation.SimWritable
.description=Dump Valve
.visibility=expert
value.default="OFF"
value.datatype={"type":"enum", "members":{"on": 1, "OFF":0}}
target.datatype={"type":"enum", "members":{"on": 1, "OFF":0}}

107
cfg/sim_mlz_ccidu1_cfg.py Normal file
View File

@@ -0,0 +1,107 @@
Node('ccidu1',
'[sim] ccidu box of MLZ Sample environment group\n'
'\n'
'Controls an 3He/4He dilution insert with an ls372 and an PLC controlling\n'
'the compressor and the valves of the gas handling.',
'tcp://10767',
)
Mod('T_ccidu1',
'frappy.simulation.SimDrivable',
'Main temperature control node of ccidu1.\n'
'\n'
'Controls the regulation loop of the ls372.',
value = Param(default=300, unit='K'),
target = Param(default=300, datatype={"type":"double", "min":0, "max":300, "unit":"K"}),
extra_params='ramp',
ramp = Param(default=60,
datatype={"type":"double", "min":0, "max":600, "unit":"K/min"},
description='target ramping speed in K/min.',
),
meaning=["temperature_regulation",40]
)
Mod('T_ccidu1_A',
'frappy.simulation.SimReadable',
'mixing chamber temperature sensor. Also used for the regulation.',
value = Param(default=300, datatype={"type":"double", "unit":"K"}),
visibility='expert',
meaning=["temperature",38],
)
Mod('T_ccidu1_B',
'frappy.simulation.SimReadable',
'(optional) sample temperature sensor close to sample.',
value = Param(default=300, datatype={"type":"double", "unit":"K"}),
visibility='user',
meaning=["temperature",39],
)
Mod('ccidu1_pstill',
'frappy.simulation.SimReadable',
'Pressure at the still/turbo pump inlet.',
value = Param(default=999, datatype={"type":"double", "unit":"mbar"}),
visibility='expert',
)
Mod('ccidu1_pinlet',
'frappy.simulation.SimReadable',
'Pressure at forepump inlet/turbo pump outlet.',
value = Param(default=999, datatype={"type":"double", "unit":"mbar"}),
visibility='expert',
)
Mod('ccidu1_poutlet',
'frappy.simulation.SimReadable',
'Pressure at forepump outlet/compressor inlet.',
value = Param(default=999, datatype={"type":"double", "unit":"mbar"}),
visibility='expert',
)
Mod('ccidu1_pkond',
'frappy.simulation.SimReadable',
'Pressure at condensing line/compressor outlet.',
value = Param(default=999, datatype={"type":"double", "unit":"mbar"}),
visibility='expert',
)
Mod('ccidu1_ptank',
'frappy.simulation.SimReadable',
'Pressure in dump tank.',
value = Param(default=999, datatype={"type":"double", "unit":"mbar"}),
visibility='expert',
)
Mod('ccidu1_pvac',
'frappy.simulation.SimReadable',
'Pressure in the vacuum dewar (ivc).',
value = Param(default=999, datatype={"type":"double", "unit":"mbar"}),
visibility='expert',
)
Mod('ccidu1_flow',
'frappy.simulation.SimReadable',
'Gas Flow (condensing line).',
value = Param(default=999, datatype={"type":"double", "unit":"mbar"}),
visibility='expert',
)
# note: all valves and switches are missing: use VNC to control them
Mod('ccidu1_V6',
'frappy.simulation.SimDrivable',
'Needle valve',
value = Param(default=99, datatype={"type":"double", "min":0, "max":100, "unit":"%%"}),
target = Param(min=0, max=100),
visibility='expert',
)
Mod('ccidu1_V3',
'frappy.simulation.SimWritable',
'Dump Valve',
value = Param(
default="OFF",
datatype={"type":"enum", "members":{"on": 1, "OFF":0}}
),
target = Param(datatype={"type":"enum", "members":{"on": 1, "OFF":0}}),
visibility='expert',
)

View File

@@ -1,164 +0,0 @@
[node ccr12]
description = [sim] CCR12 box of MLZ Sample environment group
.
Contains a Lakeshore 336 and an PLC controlling the compressor
and some valves.
.
This is how we use it now.
[interface tcp]
type=tcp
bindto=0.0.0.0
bindport=10767
[module T_ccr12]
class=frappy.simulation.SimDrivable
.description=Main temperature control node of CCR12.
.
Switches between regulation on stick and regulation on tube depending on temperature requested.
May also pump gas for higher temperatures, if configured.
.
Note: in nicos this is handled by its own class which manages T_ccr12_stick and T_ccr12_tube.
in this simulation this module is isolated.
.extra_params=ramp
ramp.datatype={"type":"double", "min":0,"max":60, "unit":"K/min"}
ramp.default=60
value.datatype={"type":"double", "min":0,"max":600, "unit":"K"}
value.default=300
target.datatype={"type":"double", "min":0,"max":600, "unit":"K"}
target.default=300
.meaning=["temperature_regulation", 20]
[module T_ccr12_stick]
class=frappy.simulation.SimDrivable
.description=Temperature regulation for the sample stick in ccr12.
.extra_params=ramp
ramp.datatype={"type":"double", "min":0,"max":60, "unit":"K/min"}
ramp.default=60
value.datatype={"type":"double", "min":0,"max":600, "unit":"K"}
value.default=300
target.datatype={"type":"double", "min":0,"max":600, "unit":"K"}
target.default=300
.meaning=["temperature_regulation", 15]
[module T_ccr12_tube]
class=frappy.simulation.SimDrivable
.description=Temperature regulation for the tube of ccr12.
.extra_params=ramp
ramp.datatype={"type":"double", "min":0,"max":60, "unit":"K/min"}
ramp.default=60
value.datatype={"type":"double", "min":0,"max":600, "unit":"K"}
value.default=300
target.datatype={"type":"double", "min":0,"max":600, "unit":"K"}
target.default=300
.meaning=["temperature_regulation", 10]
[module T_ccr12_A]
class=frappy.simulation.SimReadable
.description=(optional) Sample temperature sensor.
value.datatype={"type":"double", "unit":"K"}
value.default=300
.meaning=["temperature", 9]
[module T_ccr12_B]
class=frappy.simulation.SimReadable
.description=(regulation) temperature sensor on stick.
value.datatype={"type":"double", "unit":"K"}
value.default=300
.meaning=["temperature", 10]
[module T_ccr12_C]
class=frappy.simulation.SimReadable
.description=Temperature at the coldhead.
value.datatype={"type":"double", "unit":"K"}
value.default=70
.meaning=["temperature", 1]
[module T_ccr12_D]
class=frappy.simulation.SimReadable
.description=(regulation) temperature at coupling to stick.
value.datatype={"type":"double", "unit":"K"}
value.default=80
.meaning=["temperature", 2]
[module ccr12_pressure_regulate]
class=frappy.simulation.SimWritable
.description=Selects on which Sensor the pressure regulation works, or switches it off.
.visibility=expert
value.datatype={"type":"enum", "members":{'off':0,'p1':1,'p2':2}}
value.default='off'
target.datatype={"type":"enum", "members":{'off':0,'p1':1,'p2':2}}
target.default='off'
[module ccr12_compressor]
class=frappy.simulation.SimDrivable
.description=Switches the compressor for the cooling stage on or off.
.
Note: This should always be on, except for fast heatup for sample change.
value.datatype={"type":"enum", "members":{'off':0,'on':1}}
value.default='on'
target.datatype={"type":"enum", "members":{'off':0,'on':1}}
target.default='on'
[module ccr12_gas_switch]
class=frappy.simulation.SimWritable
.description=Switches the gas inlet on or off.
.
note: in reality this switches itself off after 15min.
note: in reality this is interlocked with ccr12_vacuum_switch, only one can be on!
note: in this simulation this module is isolated.
value.datatype={"type":"enum", "members":{'off':0,'on':1}}
value.default='off'
target.datatype={"type":"enum", "members":{'off':0,'on':1}}
target.default='off'
[module ccr12_vacuum_switch]
class=frappy.simulation.SimWritable
.description=Switches the vacuum pumping valve on or off.
.
note: in reality this is interlocked with ccr12_gas_switch, only one can be on!
note: in this simulation this module is isolated.
value.datatype={"type":"enum", "members":{'off':0,'on':1}}
value.default='off'
target.datatype={"type":"enum", "members":{'off':0,'on':1}}
target.default='off'
[module ccr12_p1]
class=frappy.simulation.SimReadable
.description=Default pressure Sensor, linear scale 0..1000mbar
value.datatype={"type":"double", "unit":"mbar"}
value.default=999
[module ccr12_p2]
class=frappy.simulation.SimReadable
.description=Auxillary pressure Sensor.
value.datatype={"type":"double", "unit":"mbar"}
value.default=1e-6
[module ccr12_curve_p2]
class=frappy.simulation.SimWritable
.description=Curve for Aux pressure Sensor p2
.visibility=expert
value.default='TTR100'
value.datatype={"type":"enum", "members":{'0..10V':0,'default':1,'0..9V':2,'DI200':3,'DI2000':4,'TTR100':7,'PTR90':8,'PTR225/PTR237':9,'ITR90':10,'ITR100 curve D':11, 'ITR100 curve 2':12, 'ITR100 curve 3':13,'ITR100 curve 4':14,'ITR100 curve 5':15, 'ITR100 curve 6':16, 'ITR100 curve 7':17, 'ITR100 curve 8':18, 'ITR100 curve 9':19, 'ITR100 curve A':20,'CMR361':21, 'CMR362':22, 'CMR363':23, 'CMR364':24, 'CMR365':25}}
target.datatype={"type":"enum", "members":{'0..10V':0,'default':1,'0..9V':2,'DI200':3,'DI2000':4,'TTR100':7,'PTR90':8,'PTR225/PTR237':9,'ITR90':10,'ITR100 curve D':11, 'ITR100 curve 2':12, 'ITR100 curve 3':13,'ITR100 curve 4':14,'ITR100 curve 5':15, 'ITR100 curve 6':16, 'ITR100 curve 7':17, 'ITR100 curve 8':18, 'ITR100 curve 9':19, 'ITR100 curve A':20,'CMR361':21, 'CMR362':22, 'CMR363':23, 'CMR364':24, 'CMR365':25}}
[module ccr12_p1_limits]
class=frappy.simulation.SimWritable
.description=Limits for pressure regulation in P1.
.visibility=expert
value.datatype={"type":"limit","members":{"type":"double", "min":0,"max":1000, "unit":"mbar"}}
value.default=[0,10]
target.datatype={"type":"limit","members":{"type":"double", "min":0,"max":1000, "unit":"mbar"}}
target.default=[0,10]
[module ccr12_p2_limits]
class=frappy.simulation.SimWritable
.description=Limits for pressure regulation in P2.
.visibility=expert
value.datatype={"type":"limit","members":{"type":"double", "min":0,"max":1000, "unit":"mbar"}}
value.default=[1e-5,1e-3]
target.datatype={"type":"limit","members":{"type":"double", "min":0,"max":1000, "unit":"mbar"}}
target.default=[1e-5,1e-3]

View File

@@ -1,155 +0,0 @@
[node ccr12]
description = [sim] CCR12 box of MLZ Sample environment group
.
Contains a Lakeshore 336 and an PLC controlling the compressor
and some valves.
.
This is an improved version, how we think it should be.
[interface tcp]
type=tcp
bindto=0.0.0.0
bindport=10767
[module T_ccr12]
class=frappy.simulation.SimDrivable
.description=Main temperature control node of CCR12.
.
Switches between regulation on stick and regulation on tube depending on temperature requested.
May also pump gas for higher temperatures, if configured.
Manual switching of the regulation node is supported via the regulationmode parameter.
value.datatype={"type":"double", "min":0, "max":600, "unit":"K"}
value.default=300
target.datatype={"type":"double", "min":0, "max":600, "unit":"K"}
target.default=300
.extra_params=ramp,regulationmode,abslimits,userlimits
ramp.datatype={"type":"double", "min":0, "max":60, "unit":"K/min"}
ramp.description=target ramping speed in K/min.
ramp.default=60
ramp.readonly=False
regulationmode.datatype={"type":"enum","members":{"stick":1,"tube":2,"both":3}}
regulationmode.default='both'
regulationmode.description=regulate only stick, tube or select based upon the target value.
regulationmode.readonly=False
abslimits.datatype={"type":"limit","members":{"type":"double", "min":0,"max":600, "unit":"K"}}
abslimits.default=[0,600]
abslimits.description=currently active absolute limits for the setpoint. depend on the regulationmode parameter (both/stick->0..600, tube->0..300K).
userlimits.datatype={"type":"limit","members":{"type":"double", "min":0,"max":600, "unit":"K"}}
userlimits.default=[0,300]
userlimits.description=current user set limits for the setpoint. must be inside abslimits.
userlimits.readonly=False
.meaning=["temperature_regulation", 20]
[module T_ccr12_A]
class=frappy.simulation.SimReadable
.description=(optional) Sample temperature sensor.
.visibility=expert
value.datatype={"type":"double", "min":0, "unit":"K"}
value.default=300
.meaning=["temperature", 9]
[module T_ccr12_B]
class=frappy.simulation.SimReadable
.description=(regulation) temperature sensor on stick.
.visibility=expert
value.datatype={"type":"double", "min":0, "unit":"K"}
value.default=300
.meaning=["temperature", 10]
[module T_ccr12_C]
class=frappy.simulation.SimReadable
.description=Temperature at the coldhead.
.visibility=expert
value.datatype={"type":"double", "min":0, "unit":"K"}
value.default=70
.meaning=["temperature", 1]
[module T_ccr12_D]
class=frappy.simulation.SimReadable
.description=(regulation) temperature at coupling to stick.
.visibility=expert
value.datatype={"type":"double", "min":0, "unit":"K"}
value.default=80
.meaning=["temperature", 2]
[module ccr12_pressure_regulation]
class=frappy.simulation.SimReadable
.description=Simple two-point presssure regulation. the mode parameter selects the readout on which to regulate, or 'none' for no regulation.
.visibility=user
.extra_params=switchpoints, mode
mode.datatype={"type":"enum", "members":{"none":0,"p1":1,"p2":2}}
mode.description=Select pressure sensor to regulate on, or 'none' to disable regulation.
mode.default='none'
# struct is more explicit, but ugly to read....
switchpoints.datatype={"type":"struct", "members":{"lower":{"type":"double", "unit":"mbar"},"upper":{"type":"double", "unit":"mbar"}}, "optional":["upper","lower"]}
switchpoints.description=Switching points for regulation. If the selected pressure is below 'lower' value, the gas valve is opened, above 'upper' the value vacuum valve is openend, else both are closed. values for switchpoints are taken from the selected pressure sensors userlimits.
switchpoints.default={'lower':1e-6,'upper':1e-3}
switchpoints.readonly=True
value.datatype={"type":"double", "min":0, "max":1000, "unit":"mbar"}
value.default = 1e-5
[module ccr12_compressor]
class=frappy.simulation.SimDrivable
.description=Switches the compressor for the cooling stage on or off.
.
Note: This should always be on, except for fast heatup for sample change.
.visibility=user
value.datatype={"type":"enum", "members":{'off':0,'on':1}}
value.default='off'
target.datatype={"type":"enum", "members":{'off':0,'on':1}}
[module ccr12_gas_switch]
class=frappy.simulation.SimWritable
.description=Switches the gas inlet on or off.
.
note: in reality this switches itself off after 15min.
note: in reality this is interlocked with ccr12_vacuum_switch, only one can be on!
note: in this simulation this module is isolated.
value.datatype={"type":"enum", "members":{'off':0,'on':1}}
value.default='off'
target.datatype={"type":"enum", "members":{'off':0,'on':1}}
target.default='off'
[module ccr12_vacuum_switch]
class=frappy.simulation.SimWritable
.description=Switches the vacuum pumping valve on or off.
.
note: in reality this is interlocked with ccr12_gas_switch, only one can be on!
note: in this simulation this module is isolated.
value.datatype={"type":"enum", "members":{'off':0,'on':1}}
value.default='off'
target.datatype={"type":"enum", "members":{'off':0,'on':1}}
target.default='off'
[module ccr12_p1]
class=frappy.simulation.SimReadable
.description=Default pressure Sensor, linear scale 0..1000 mbar
.
Good candidate for a 'Sensor' Interface class!
value.default=999
value.unit=mbar
.extra_params=curve, userlimits
curve.datatype={"type":"enum", "members":{'0..10V':0,'default':1,'0..9V':2,'DI200':3,'DI2000':4,'TTR100':7,'PTR90':8,'PTR225/PTR237':9,'ITR90':10,'ITR100 curve D':11, 'ITR100 curve 2':12, 'ITR100 curve 3':13,'ITR100 curve 4':14,'ITR100 curve 5':15, 'ITR100 curve 6':16, 'ITR100 curve 7':17, 'ITR100 curve 8':18, 'ITR100 curve 9':19, 'ITR100 curve A':20,'CMR361':21, 'CMR362':22, 'CMR363':23, 'CMR364':24, 'CMR365':25}}
curve.description=Calibration curve for pressure sensor
curve.default='TTR100'
userlimits.datatype={"type":"limit","members":{"type":"double", "min":0,"max":1000, "unit":"mbar"}}
userlimits.default=[1, 100]
userlimits.description=current user set limits for the pressure regulation.
userlimits.readonly=False
[module ccr12_p2]
class=frappy.simulation.SimReadable
.description=Auxillary pressure Sensor.
value.default=1e-6
value.unit=mbar
.extra_params=curve,userlimits
curve.datatype={"type":"enum", "members":{'0..10V':0,'default':1,'0..9V':2,'DI200':3,'DI2000':4,'TTR100':7,'PTR90':8,'PTR225/PTR237':9,'ITR90':10,'ITR100 curve D':11, 'ITR100 curve 2':12, 'ITR100 curve 3':13,'ITR100 curve 4':14,'ITR100 curve 5':15, 'ITR100 curve 6':16, 'ITR100 curve 7':17, 'ITR100 curve 8':18, 'ITR100 curve 9':19, 'ITR100 curve A':20,'CMR361':21, 'CMR362':22, 'CMR363':23, 'CMR364':24, 'CMR365':25}}
curve.description=Calibration curve for pressure sensor
curve.default='PTR90'
userlimits.datatype={"type":"limit","members":{"type":"double", "min":0,"max":1000, "unit":"mbar"}}
userlimits.default=[1e-6, 1e-3]
userlimits.description=current user set limits for the pressure regulation.
userlimits.readonly=False
pollinterval.visibility='expert'

177
cfg/sim_mlz_ccr12_v2_cfg.py Normal file
View File

@@ -0,0 +1,177 @@
# pylint: skip-file
Node('ccr12',
'[sim] CCR12 box of MLZ Sample environment group'
''
'Contains a Lakeshore 336 and an PLC controlling the compressor'
'and some valves.'
''
'This is an improved version, how we think it should be.',
'tcp://10767',
)
Mod('T_ccr12',
'frappy.simulation.SimDrivable',
'Main temperature control node of CCR12.'
''
'Switches between regulation on stick and regulation on tube depending on temperature requested.'
'May also pump gas for higher temperatures, if configured.'
'Manual switching of the regulation node is supported via the regulationmode parameter.',
value = Param(default=300,
datatype={"type":"double", "min":0, "max":600, "unit":"K"}),
target = Param(default=300,
datatype={"type":"double", "min":0, "max":600, "unit":"K"}),
extra_params='ramp,regulationmode,abslimits,userlimits',
ramp = Param(
default=60,
datatype={"type":"double", "min":0, "max":60, "unit":"K/min"},
description='target ramping speed in K/min.',
readonly=False,
),
regulationmode = Param(
default='both',
datatype={"type":"enum","members":{"stick":1,"tube":2,"both":3}},
description='regulate only stick, tube or select based upon the target value.',
readonly=False,
),
abslimits = Param(
default=[0,600],
datatype={"type":"limit","members":{"type":"double", "min":0,"max":600, "unit":"K"}},
description='currently active absolute limits for the setpoint. depend on the regulationmode parameter (both/stick->0..600, tube->0..300K).',
),
userlimits = Param(
default=[0,300],
datatype={"type":"limit","members":{"type":"double", "min":0,"max":600, "unit":"K"}},
description='current user set limits for the setpoint. must be inside abslimits.',
readonly=False,
),
meaning=["temperature_regulation", 20],
)
Mod('T_ccr12_A',
'frappy.simulation.SimReadable',
'(optional) Sample temperature sensor.',
value = Param(default=300,
datatype={"type":"double", "min":0, "unit":"K"}),
visibility='expert',
meaning=["temperature", 9],
)
Mod('T_ccr12_B',
'frappy.simulation.SimReadable',
'(regulation) temperature sensor on stick.',
value = Param(default=300, datatype={"type":"double", "min":0, "unit":"K"}),
visibility='expert',
meaning=["temperature", 10],
)
Mod('T_ccr12_C',
'frappy.simulation.SimReadable',
'Temperature at the coldhead.',
value = Param(default=70, datatype={"type":"double", "min":0, "unit":"K"}),
visibility='expert',
meaning=["temperature", 1],
)
Mod('T_ccr12_D',
'frappy.simulation.SimReadable',
'(regulation) temperature at coupling to stick.',
value = Param(default=80, datatype={"type":"double", "min":0, "unit":"K"}),
visibility='expert',
meaning=["temperature", 2],
)
Mod('ccr12_pressure_regulation',
'frappy.simulation.SimReadable',
'Simple two-point presssure regulation. the mode parameter selects the readout on which to regulate, or, \'none\' for no regulation.',
value = Param(default = 1e-5,
datatype={"type":"double", "min":0, "max":1000, "unit":"mbar"}),
extra_params='switchpoints, mode',
mode = Param(
default='none',
datatype={"type":"enum", "members":{"none":0,"p1":1,"p2":2}},
description='Select pressure sensor to regulate on, or \'none\' to disable regulation.',
),
switchpoints = Param(
default={'lower':1e-6,'upper':1e-3},
# struct is more explicit, but ugly to read....
datatype={"type":"struct", "members":{"lower":{"type":"double", "unit":"mbar"},"upper":{"type":"double", "unit":"mbar"}}, "optional":["upper","lower"]},
description='Switching points for regulation. If the selected pressure is below \'lower\' value, the gas valve is opened, above \'upper\' the value vacuum valve is openend, else both are closed. values for switchpoints are taken from the selected pressure sensors userlimits.',
readonly=True,
),
visibility='user',
)
Mod('ccr12_compressor',
'frappy.simulation.SimDrivable',
'Switches the compressor for the cooling stage on or off.\n'
'\n'
'Note: This should always be on, except for fast heatup for sample change.',
value = Param(default='off',
datatype={"type":"enum", "members":{'off':0,'on':1}}),
target = Param(datatype={"type":"enum", "members":{'off':0,'on':1}}),
visibility='user',
)
Mod('ccr12_gas_switch',
'frappy.simulation.SimWritable',
'Switches the gas inlet on or off.\n'
'\n'
'note: in reality this switches itself off after 15min.\n'
'note: in reality this is interlocked with ccr12_vacuum_switch, only one can be on!\n'
'note: in this simulation this module is isolated.',
value = Param(default='off',
datatype={"type":"enum", "members":{'off':0,'on':1}}),
target = Param(default='off',
datatype={"type":"enum", "members":{'off':0,'on':1}}),
)
Mod('ccr12_vacuum_switch',
'frappy.simulation.SimWritable',
'Switches the vacuum pumping valve on or off.\n'
'\n'
'note: in reality this is interlocked with ccr12_gas_switch, only one can be on!\n'
'note: in this simulation this module is isolated.',
value = Param(default='off',
datatype={"type":"enum", "members":{'off':0,'on':1}}),
target = Param(default='off',
datatype={"type":"enum", "members":{'off':0,'on':1}}),
)
Mod('ccr12_p1',
'frappy.simulation.SimReadable',
'Default pressure Sensor, linear scale 0..1000 mbar\n'
'\n'
'Good candidate for a \'Sensor\' Interface class!',
value = Param(default=999, unit='mbar'),
extra_params='curve, userlimits',
curve = Param(
default='TTR100',
datatype={"type":"enum", "members":{'0..10V':0,'default':1,'0..9V':2,'DI200':3,'DI2000':4,'TTR100':7,'PTR90':8,'PTR225/PTR237':9,'ITR90':10,'ITR100 curve D':11, 'ITR100 curve 2':12, 'ITR100 curve 3':13,'ITR100 curve 4':14,'ITR100 curve 5':15, 'ITR100 curve 6':16, 'ITR100 curve 7':17, 'ITR100 curve 8':18, 'ITR100 curve 9':19, 'ITR100 curve A':20,'CMR361':21, 'CMR362':22, 'CMR363':23, 'CMR364':24, 'CMR365':25}},
description='Calibration curve for pressure sensor',
),
userlimits = Param(
default=[1, 100],
datatype={"type":"limit","members":{"type":"double", "min":0,"max":1000, "unit":"mbar"}},
description='current user set limits for the pressure regulation.',
readonly=False,
),
)
Mod('ccr12_p2',
'frappy.simulation.SimReadable',
'Auxillary pressure Sensor.',
value = Param(default=1e-6, unit='mbar'),
extra_params='curve,userlimits',
curve = Param(
default='PTR90',
datatype={"type":"enum", "members":{'0..10V':0,'default':1,'0..9V':2,'DI200':3,'DI2000':4,'TTR100':7,'PTR90':8,'PTR225/PTR237':9,'ITR90':10,'ITR100 curve D':11, 'ITR100 curve 2':12, 'ITR100 curve 3':13,'ITR100 curve 4':14,'ITR100 curve 5':15, 'ITR100 curve 6':16, 'ITR100 curve 7':17, 'ITR100 curve 8':18, 'ITR100 curve 9':19, 'ITR100 curve A':20,'CMR361':21, 'CMR362':22, 'CMR363':23, 'CMR364':24, 'CMR365':25}},
description='Calibration curve for pressure sensor',
),
userlimits = Param(
default=[1e-6, 1e-3],
datatype={"type":"limit","members":{"type":"double", "min":0,"max":1000, "unit":"mbar"}},
description='current user set limits for the pressure regulation.',
readonly=False,
),
pollinterval = Param(visibility='expert'),
)

View File

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

View File

@@ -1,33 +0,0 @@
[node htf02]
description = [sim] htf02 box of MLZ Sample environment group
.
Controls an High Temperature Furnace with an eurotherm controller and an PLC checking the cooing water.
[interface tcp]
type=tcp
bindto=0.0.0.0
bindport=10767
[module T_htf02]
class=frappy.simulation.SimDrivable
.description=Main temperature control node of htf02.
.
Controls the regulation loop of the Eurotherm.
value.datatype={"type":"double", "min":0, "unit":"degC"}
value.default=300
target.datatype={"type":"double", "min":0, "max": 2000, "unit":"degC"}
target.default=300
.extra_params=ramp
ramp.datatype={"type":"double", "min":0, "max": 600, "unit":"K/min"}
ramp.description=target ramping speed in K/min.
ramp.default=60
ramp.readonly=False
.meaning=["temperature", 10]
[module htf02_p]
class=frappy.simulation.SimReadable
.description=Pressure Sensor at sample space (ivc).
value.datatype={"type":"double", "min":0, "unit":"mbar"}
value.default=989

30
cfg/sim_mlz_htf02_cfg.py Normal file
View File

@@ -0,0 +1,30 @@
Node('htf02',
'[sim] htf02 box of MLZ Sample environment group\n'
'\n'
'Controls an High Temperature Furnace with an eurotherm controller and an PLC checking the cooing water.',
'tcp://10767',
)
Mod('T_htf02',
'frappy.simulation.SimDrivable',
'Main temperature control node of htf02.\n'
'\n'
'Controls the regulation loop of the Eurotherm.',
value = Param(default=300,
datatype={"type":"double", "min":0, "unit":"degC"}),
target = Param(default=300,
datatype={"type":"double", "min":0, "max": 2000, "unit":"degC"}),
extra_params='ramp',
ramp = Param(default=60,
datatype={"type":"double", "min":0, "max": 600, "unit":"K/min"},
description='target ramping speed in K/min.',
readonly=False,
),
meaning=["temperature", 10],
)
Mod('htf02_p',
'frappy.simulation.SimReadable',
'Pressure Sensor at sample space (ivc).',
value = Param(default=989, datatype={"type":"double", "min":0, "unit":"mbar"}),
)

View File

@@ -1,73 +0,0 @@
[node stressihtf2]
description = [sim] Stressihtf2 box of MLZ Sample environment group
.
Controls an High Temperature Furnace with an Eurotherm and an PLC controlling some valves and checking cooling water.
[interface tcp]
type=tcp
bindto=0.0.0.0
bindport=10767
[module T_stressihtf2]
class=frappy.simulation.SimDrivable
.description=Main temperature control node of Stressihtf2.
value.datatype={"type":"double", "min":0, "unit":"degC"}
value.default=20
target.datatype={"type":"double", "min":0, "max":2000, "unit":"degC"}
target.default=20
.extra_params=ramp,regulationmode,abslimits,userlimits
ramp.datatype={"type":"double", "min":0, "max":600, "unit":"K/min"}
ramp.description=target ramping speed in K/min.
ramp.default=60
abslimits.datatype={"type":"limit", "members":{"type":"double", "min":0, "max":2000, "unit":"degC"}}
abslimits.default=[0,2000]
abslimits.description=currently active absolute limits for the setpoint. depend on the regulationmode parameter (both/stick->0..600, tube->0..300K).
userlimits.datatype={"type":"limit", "members":{"type":"double", "min":0, "max":2000, "unit":"degC"}}
userlimits.default=[0,300]
userlimits.description=current user set limits for the setpoint. must be inside abslimits.
userlimits.readonly=False
.meaning=['temperature_regulation', 10]
[module T_stressihtf2_sample]
class=frappy.simulation.SimReadable
.description=(optional) Sample temperature sensor.
.visibility=expert
value.default=300
value.datatype={"type":"double", "min":0, "unit":"degC"}
.meaning=["temperature", 9]
[module stressihtf2_n2]
class=frappy.simulation.SimWritable
.description=Switches the N2 gas inlet on or off.
.visibility=expert
value.default='off'
value.datatype={"type":"enum", "members":{'off':0,'on':1}}
target.datatype={"type":"enum", "members":{'off':0,'on':1}}
target.default='off'
[module stressihtf2_he]
class=frappy.simulation.SimWritable
.description=Switches the He gas inlet on or off.
.visibility=expert
value.default='off'
value.datatype={"type":"enum", "members":{'off':0,'on':1}}
target.datatype={"type":"enum", "members":{'off':0,'on':1}}
target.default='off'
[module stressihtf2_lamps]
class=frappy.simulation.SimWritable
.description=Switches the heating lamps on or off.
.visibility=expert
value.default='on'
value.datatype={"type":"enum", "members":{'off':0,'on':1}}
target.datatype={"type":"enum", "members":{'off':0,'on':1}}
target.default='on'
[module stressihtf2_water_ok]
class=frappy.simulation.SimReadable
.description=Readout of the cooling water state.
.visibility=expert
value.default='ok'
value.datatype={"type":"enum", "members":{'failed':0,'ok':1}}

View File

@@ -1,73 +0,0 @@
[node stressihtf2_v2]
description = [sim] Stressihtf2 box of MLZ Sample environment group
.
Controls an High Temperature Furnace with an Eurotherm and an PLC controlling some valves and checking cooling water.
[interface tcp]
type=tcp
bindto=0.0.0.0
bindport=10767
[module T]
class=frappy.simulation.SimDrivable
.description=Main temperature control node of Stressihtf2.
value.datatype={"type":"double", "min":0, "unit":"degC"}
value.default=20
target.datatype={"type":"double", "min":0, "max":2000, "unit":"degC"}
target.default=20
.extra_params=ramp,regulationmode,abslimits,userlimits
ramp.datatype={"type":"double", "min":0, "max":600, "unit":"K/min"}
ramp.description=target ramping speed in K/min.
ramp.default=60
abslimits.datatype={"type":"limit", "members":{"type":"double", "min":0, "max":2000, "unit":"degC"}}
abslimits.default=[0,2000]
abslimits.description=currently active absolute limits for the setpoint. depend on the regulationmode parameter (both/stick->0..600, tube->0..300K).
userlimits.datatype={"type":"limit", "members":{"type":"double", "min":0, "max":2000, "unit":"degC"}}
userlimits.default=[0,300]
userlimits.description=current user set limits for the setpoint. must be inside abslimits.
userlimits.readonly=False
.meaning=['temperature_regulation', 10]
[module T_sample]
class=frappy.simulation.SimReadable
.description=(optional) Sample temperature sensor.
.visibility=expert
value.default=300
value.datatype={"type":"double", "min":0, "unit":"degC"}
.meaning=["temperature", 9]
[module N2]
class=frappy.simulation.SimWritable
.description=Switches the N2 gas inlet on or off.
.visibility=expert
value.default='off'
value.datatype={"type":"enum", "members":{'off':0,'on':1}}
target.datatype={"type":"enum", "members":{'off':0,'on':1}}
target.default='off'
[module He]
class=frappy.simulation.SimWritable
.description=Switches the He gas inlet on or off.
.visibility=expert
value.default='off'
value.datatype={"type":"enum", "members":{'off':0,'on':1}}
target.datatype={"type":"enum", "members":{'off':0,'on':1}}
target.default='off'
[module lamps]
class=frappy.simulation.SimWritable
.description=Switches the heating lamps on or off.
.visibility=expert
value.default='on'
value.datatype={"type":"enum", "members":{'off':0,'on':1}}
target.datatype={"type":"enum", "members":{'off':0,'on':1}}
target.default='on'
[module water_ok]
class=frappy.simulation.SimReadable
.description=Readout of the cooling water state.
.visibility=expert
value.default='ok'
value.datatype={"type":"enum", "members":{'failed':0,'ok':1}}

View File

@@ -0,0 +1,82 @@
Node('stressihtf2_v2',
'[sim] Stressihtf2 box of MLZ Sample environment group\n'
'\n'
'Controls an High Temperature Furnace with an Eurotherm and an PLC controlling some valves and checking cooling water.',
'tcp://10767',
)
Mod('T',
'frappy.simulation.SimDrivable',
'Main temperature control node of Stressihtf2.',
value = Param(default=20,
datatype={"type":"double", "min":0, "unit":"degC"}),
target = Param(default=20,
datatype={"type":"double", "min":0, "max":2000, "unit":"degC"}),
extra_params='ramp,regulationmode,abslimits,userlimits',
ramp = Param(
default=60,
datatype={"type":"double", "min":0, "max":600, "unit":"K/min"},
description='target ramping speed in K/min.',
),
abslimits = Param(
default=[0,2000],
datatype={"type":"limit", "members":{"type":"double", "min":0, "max":2000, "unit":"degC"}},
description='currently active absolute limits for the setpoint. depend \
on the regulationmode parameter (both/stick->0..600, tube->0..300K).',
),
userlimits = Param(
default=[0,300],
datatype={"type":"limit", "members":{"type":"double", "min":0, "max":2000, "unit":"degC"}},
description='current user set limits for the setpoint. must be inside abslimits.',
readonly=False,
),
meaning=['temperature_regulation', 10],
)
Mod('T_sample',
'frappy.simulation.SimReadable',
'(optional) Sample temperature sensor.',
value = Param(default=300,
datatype={"type":"double", "min":0, "unit":"degC"}),
visibility='expert',
meaning=["temperature", 9],
)
Mod('N2',
'frappy.simulation.SimWritable',
'Switches the N2 gas inlet on or off.',
value = Param(default='off',
datatype={"type":"enum", "members":{'off':0,'on':1}}),
target = Param(default='off',
datatype={"type":"enum", "members":{'off':0,'on':1}}),
visibility='expert',
)
Mod('He',
'frappy.simulation.SimWritable',
'Switches the He gas inlet on or off.',
value = Param(default='off',
datatype={"type":"enum", "members":{'off':0,'on':1}}),
target = Param(default='off',
datatype={"type":"enum", "members":{'off':0,'on':1}}),
visibility='expert',
)
Mod('lamps',
'frappy.simulation.SimWritable',
'Switches the heating lamps on or off.',
value = Param(default='on',
datatype={"type":"enum", "members":{'off':0,'on':1}}),
target = Param(default='on',
datatype={"type":"enum", "members":{'off':0,'on':1}}),
visibility='expert',
)
Mod('water_ok',
'frappy.simulation.SimReadable',
'Readout of the cooling water state.',
value = Param(default='ok',
datatype={"type":"enum", "members":{'failed':0,'ok':1}}),
visibility='expert',
)

View File

@@ -1,12 +0,0 @@
[r3]
class = frappy.core.Proxy
remote_class = frappy.core.Readable
description = temp sensor on 3He system
uri = tcp://pc12694:5000
export = False
[t3]
class = frappy_psi.softcal.Sensor
rawsensor = r3
calib = X131346
value.unit = K

20
cfg/softcal_cfg.py Normal file
View File

@@ -0,0 +1,20 @@
Node('softcal.demo.example',
'convert r2 from PPMS to a temperature',
'tcp://5001',
)
Mod('r2',
'frappy.core.Proxy',
'convert r2 from PPMS to a temperature',
remote_class = 'frappy.core.Readable',
uri = 'tcp://localhost:5000',
export = False,
)
Mod('T2',
'frappy_psi.softcal.Sensor',
'',
value = Param(unit = 'K'),
rawsensor = 'r2',
calib = 'X131346',
)

View File

@@ -1,83 +0,0 @@
[node stressihtf2]
description = Stressihtf2 box of MLZ Sample environment group
.
Controls an High Temperature Furnace with an Eurotherm and an PLC controlling some valves and checking cooling water.
meaning={'T_regulation':{'T':100}, 'T_sample':{'T_sample':100}}
[interface tcp]
type=tcp
bindto=0.0.0.0
bindport=10767
[module T]
class=frappy_mlz.entangle.TemperatureController
tangodevice=tango://localhost:10000/box/eurotherm/ctrl
.description=Main temperature control node of Stressihtf2.
value.unit='degC'
target.datatype=["double", 0, 2000]
ramp.datatype=["double",0,9999]
ramp.description=target ramping speed in K/min.
ramp.default=60
ramp.unit=K/min
abslimits.datatype=["tuple",[["double"],["double"]]]
abslimits.default=[0,2000]
abslimits.description=currently active absolute limits for the setpoint. depend on the regulationmode parameter (both/stick->0..600, tube->0..300K).
abslimits.unit='degC'
abslimits.readonly=True
userlimits.datatype=["tuple",[["double"],["double"]]]
userlimits.default=[0,300]
userlimits.description=current user set limits for the setpoint. must be inside abslimits.
userlimits.unit='degC'
heateroutput.datatype=["double",0,100]
heateroutput.description=output to the heater
heateroutput.unit='%%'
heateroutput.default=0
setpoint.default=0
p.default=1
i.default=0
d.default=0
pid.default=[1,0,0]
speed.default=0
[module T_sample_a]
class=frappy_mlz.entangle.Sensor
tangodevice=tango://localhost:10000/box/eurotherm/sensora
.description=Regulation temperature sensor.
.visibility=user
value.unit='degC'
[module T_sample_b]
class=frappy_mlz.entangle.Sensor
tangodevice=tango://localhost:10000/box/eurotherm/sensorb
.description=(optional) Sample temperature sensor.
.visibility=expert
value.unit='degC'
[module N2]
class=frappy_mlz.entangle.NamedDigitalOutput
tangodevice=tango://localhost:10000/box/plc/_gas1
.description=Switches the N2 gas inlet on or off.
.visibility=expert
mapping=dict(off=0,on=1)
[module He]
class=frappy_mlz.entangle.NamedDigitalOutput
tangodevice=tango://localhost:10000/box/plc/_gas2
.description=Switches the He gas inlet on or off.
.visibility=expert
mapping=dict(off=0,on=1)
[module lamps]
class=frappy_mlz.entangle.NamedDigitalOutput
tangodevice=tango://localhost:10000/box/plc/_onoff
.description=Switches the heating lamps on or off.
.visibility=expert
mapping=dict(off=0,on=1)
[module water_ok]
class=frappy_mlz.entangle.NamedDigitalInput
tangodevice=tango://localhost:10000/box/plc/_waterok
.description=Readout of the cooling water state.
.visibility=expert
mapping=dict(failed=0,ok=1)

96
cfg/stressihtf2_cfg.py Normal file
View File

@@ -0,0 +1,96 @@
Node('stressihtf2',
'Stressihtf2 box of MLZ Sample environment group\n'
'\n'
'Controls an High Temperature Furnace with an Eurotherm and an PLC controlling some valves and checking cooling water.',
'localhost:10767',
meaning={'T_regulation':{'T':100}, 'T_sample':{'T_sample':100}},
)
Mod('T',
'frappy_mlz.entangle.TemperatureController',
'Main temperature control node of Stressihtf2.',
tangodevice='tango://localhost:10000/box/eurotherm/ctrl',
value = Param(unit='degC'),
target = Param(datatype=["double", 0, 2000]),
ramp = Param(
default=60,
datatype=["double",0,9999],
unit='K/min',
description='target ramping speed in K/min.',
),
abslimits = Param(
default=[0,2000],
datatype=["tuple",[["double"],["double"]]],
unit='degC',
description='currently active absolute limits for the setpoint.\
depend on the regulationmode parameter (both/stick->0..600, tube->0..300K).',
readonly=True,
),
userlimits = Param(
default=[0,300],
datatype=["tuple",[["double"],["double"]]],
unit='degC',
description='current user set limits for the setpoint. must be inside abslimits.',
),
heateroutput = Param(
default=0,
datatype=["double",0,100],
unit='%%',
description='output to the heater',
),
setpoint = 0,
p = 1,
i = 0,
d = 0,
pid = [1,0,0],
speed = 0,
)
Mod('T_sample_a',
'frappy_mlz.entangle.Sensor',
'Regulation temperature sensor.',
tangodevice='tango://localhost:10000/box/eurotherm/sensora',
value = Param(unit='degC'),
visibility='user',
)
Mod('T_sample_b',
'frappy_mlz.entangle.Sensor',
'(optional) Sample temperature sensor.',
tangodevice='tango://localhost:10000/box/eurotherm/sensorb',
value = Param(unit='degC'),
visibility='expert',
)
Mod('N2',
'frappy_mlz.entangle.NamedDigitalOutput',
'Switches the N2 gas inlet on or off.',
tangodevice='tango://localhost:10000/box/plc/_gas1',
mapping={'off':0,'on':1},
visibility='expert',
)
Mod('He',
'frappy_mlz.entangle.NamedDigitalOutput',
'Switches the He gas inlet on or off.',
tangodevice='tango://localhost:10000/box/plc/_gas2',
mapping={'off':0,'on':1},
visibility='expert',
)
Mod('lamps',
'frappy_mlz.entangle.NamedDigitalOutput',
'Switches the heating lamps on or off.',
tangodevice='tango://localhost:10000/box/plc/_onoff',
mapping={'off':0,'on':1},
visibility='expert',
)
Mod('water_ok',
'frappy_mlz.entangle.NamedDigitalInput',
'Readout of the cooling water state.',
tangodevice='tango://localhost:10000/box/plc/_waterok',
mapping={'failed':0,'ok':1},
visibility='expert',
)

View File

@@ -1,7 +1,7 @@
Node('test.config.frappy.demo',
'''short description of the testing sec-node
This description for the Nodecan be as long as you need if you use a multiline string.
This description for the node can be as long as you need if you use a multiline string.
Very long!
The needed fields are Equipment id (1st argument), description (this)
@@ -10,6 +10,22 @@ The needed fields are Equipment id (1st argument), description (this)
'tcp://10768',
)
Mod('attachtest',
'frappy_demo.test.WithAtt',
'test attached',
att = 'LN2',
)
Mod('pinata',
'frappy_demo.test.Pin',
'scan test',
)
Mod('recursive',
'frappy_demo.test.RecPin',
'scan test',
)
Mod('LN2',
'frappy_demo.test.LN2',
'random value between 0..100%',
@@ -44,3 +60,15 @@ Mod('Lower',
'frappy_demo.test.Lower',
'something else',
)
Mod('Decision',
'frappy_demo.test.Mapped',
'Random value from configured property choices. Config accepts anything ' \
'that can be converted to a list',
choices = ['Yes', 'Maybe', 'No'],
)
Mod('c',
'frappy_demo.test.Commands',
'a command test',
)

11
cfg/tssop16_cfg.py Normal file
View File

@@ -0,0 +1,11 @@
import frappy.core as fc
import serial
Node('example_TSSOP16.psi.ch', 'A demo system showing how to connect the TSSOP16 Arduino', interface='tcp://5000')
Mod('io1',
'frappy_psi.capacitance_readings.TSSOP16.TSSOP16_IO',
'communication',
uri='serial://COM11?baudrate=9600+bytesize=8+parity=none+stopbits=1')
Mod('TSSOP16', 'frappy_psi.capacitance_readings.TSSOP16.TSSOP16', 'Capacitance-reading Arduino (with TSSOP16)', io='io1')

View File

@@ -9,10 +9,11 @@ RUN apt-get update && \
openssh-client \
make \
locales \
libgl1 \
python3 \
python3-dev \
python3-tango \
python3-venv python3-setuptools \
python3-venv \
python3-setuptools \
virtualenv
@@ -35,8 +36,10 @@ RUN virtualenv /home/jenkins/tools2 && \
RUN virtualenv -p /usr/bin/python3 --system-site-packages /home/jenkins/secopvenv && \
git clone https://forge.frm2.tum.de/review/secop/frappy /home/jenkins/frappy && \
. /home/jenkins/secopvenv/bin/activate && \
pip install -U pip wheel setuptools && \
pip install -r /home/jenkins/frappy/requirements-dev.txt -r /home/jenkins/frappy/requirements.txt pylint pytest && \
pip install -U pip wheel setuptools importlib_metadata && \
pip install -r /home/jenkins/frappy/requirements-dev.txt \
-r /home/jenkins/frappy/requirements-gui.txt \
-r /home/jenkins/frappy/requirements.txt pylint pytest && \
rm -rf /home/jenkins/frappy

21
ci/Jenkinsfile vendored
View File

@@ -13,11 +13,6 @@ properties([
choice(choices: '''\
patchset-created
ref-updated
change-merged''',
description: '', name: 'GERRIT_EVENT'),
choice(choices: '''\
patchset-created
ref-updated
change-merged''',
description: '', name: 'GERRIT_EVENT_TYPE')])
])
@@ -41,6 +36,7 @@ git diff HEAD~1... --name-only --diff-filter=ARCM -- \\*.py
#!/bin/bash -x
. /home/jenkins/secopvenv/bin/activate
pip install -r requirements-dev.txt
pip install -r requirements-gui.txt
pip install -r requirements.txt
pip install isort pylint
pip install -e .
@@ -50,7 +46,7 @@ echo "$changedFiles"
if [[ -n "$changedFiles" ]]; then
set -o pipefail
pylint $changedFiles | tee pylint_results.txt
isort --df $changedFiles | tee isort_results.txt
isort --df $changedFiles || true | tee isort_results.txt
fi
"""
withCredentials([string(credentialsId: 'GERRITHTTP',
@@ -99,6 +95,7 @@ addopts = --junit-xml=pytest.xml --junit-prefix=''' + pyver
#!/bin/bash
. /home/jenkins/secopvenv/bin/activate
pip install -r requirements-dev.txt
pip install -r requirements-gui.txt
pip install -r requirements.txt
pip install -e .
make test
@@ -119,6 +116,7 @@ def run_docs() {
sh '''
. /home/jenkins/secopvenv/bin/activate
pip install -r requirements-dev.txt
pip install -r requirements-gui.txt
pip install -r requirements.txt
pip install -e .
'''
@@ -146,12 +144,23 @@ def run_docs() {
'''
}
/* does not work with too many quote levels
* alternatively use pdf (based on rst2pdf)
* or singlehtml converted to pdf manually from a browser (may produce nicer output)
stage('build latexpdf') {
sh '''
. /home/jenkins/secopvenv/bin/activate
make -C doc latexpdf
'''
}
*/
stage('build pdf') {
sh '''
. /home/jenkins/secopvenv/bin/activate
make -C doc pdf
'''
}
stage('build man') {
sh '''

932
debian/changelog vendored
View File

@@ -1,4 +1,912 @@
frappy-core (0.15.0) focal; urgency=medium
frappy-core (0.20.5) stable; urgency=medium
[ Markus Zolliker ]
* add sim-server again based on socketserver
* fix bug when overriding a property with bare value
* frappy.server bug fix: server name must not be a list
* frappy.server: use server name for SecNode name
* frappy.server: remove comment about opts in SecNode/Dispatcher
* follow up change for 'better order of accessibles' (34904)
* better message when a parameter is overridden by an invalid value
* pylint: increase max number of positional arguments
* an error on a write must not send an error update
* fix bug in change 35001 (better error message)
* make UPD listener work when 'tcp://' is omitted on interface
* config: do not override equipment_id with name
* equipment_id for merged configs and routed nodes
* core: alternative approach for optional accessibles
* core: simplify test for methods names
[ Georg Brandl ]
* debian: update compat
* remove wrong <weight> from fonts on Qt6
[ Markus Zolliker ]
* config: validate value and default of parameters
* config: Mod() should return config dict
* stop poller threads on shutdown
* fix overriding Parameter with value
* improve error messages on module creation
* make sure unexported modules are initialized
* change to new visibility spec
* follow-up change to 35931: make Proxy a Module
[ Konstantin Kholostov ]
* installer: add recipe to build macOS app bundle
[ Markus Zolliker ]
* frappy.client.SecopClient: fix setParameterFromString
* frappy_psi/ls370res: various bug fixes
* client: add SecopClient.execCommandFromString
* frappy.client.interactive: improve updates while driving
-- Markus Zolliker <jenkins@frm2.tum.de> Mon, 12 May 2025 14:03:22 +0200
frappy-core (0.20.4) stable; 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) stable; 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) stable; 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) stable; urgency=medium
* gui: do not add a console logger when there is no sys.stdout
* remove unused test class
* remove old unused parse module
* remove sim-server
* lib: there might be no confdir in "cfg"
-- Georg Brandl <jenkins@frm2.tum.de> Thu, 17 Oct 2024 16:31:27 +0200
frappy-core (0.20.0) stable; urgency=medium
[ Alexander Zaft ]
* bin: remove make_doc
[ Markus Zolliker ]
* GUI: avoid space needed for closed groups
* GUI: allow enums to be plotted
[ Alexander Zaft ]
* all: start using pathlib
* generalConfig, config: use pathlib
* psi: change open calls in sea
[ Georg Brandl ]
* fix descriptive data
[ Markus Zolliker ]
* frappy_psi.sea: avoid error on import
[ Enrico Faulhaber ]
* ci: also install gui requirements for additional tests
[ Georg Brandl ]
* remove old "buffer" message
* ci/Dockerfile: do no use pytango from upstream
* new setuptools needs new importlib_metadata
* install pytango for testing
* install libgl1 for pyqt6
[ Enrico Faulhaber ]
* add test for importing custom modules
[ Markus Zolliker ]
* do not fail when generalConfig.init() is called twice
* add Datatype.to_string as counterpart of .from_string
* add more datatype tests
[ Georg Brandl ]
* update declared version to 1.0 final
* setup: fix classifiers
* setup: fill long_description and url
-- Alexander Zaft <jenkins@frm2.tum.de> Thu, 17 Oct 2024 14:24:29 +0200
frappy-core (0.19.10) stable; urgency=medium
[ Alexander Zaft ]
* debian: let frappy-core replace frappy-demo
[ Georg Brandl ]
* remove walrus
-- Alexander Zaft <jenkins@frm2.tum.de> Wed, 07 Aug 2024 17:00:06 +0200
frappy-core (0.19.9) stable; urgency=medium
* debian: fix missing install dir
-- Georg Brandl <jenkins@frm2.tum.de> Tue, 06 Aug 2024 16:02:50 +0200
frappy-core (0.19.8) stable; urgency=medium
* debian: move demo into core
-- Georg Brandl <jenkins@frm2.tum.de> Tue, 06 Aug 2024 15:58:20 +0200
frappy-core (0.19.7) stable; urgency=medium
* lib: GeneralConfig fix missing keys logic
-- Alexander Zaft <jenkins@frm2.tum.de> Tue, 06 Aug 2024 15:04:07 +0200
frappy-core (0.19.6) stable; urgency=medium
[ Jens Krüger ]
* SINQ/SEA: Fix import error due to None value
[ Georg Brandl ]
* GUI: allow starting in detailed view by cmdline flag
* gui: save/restore window geometry
[ Alexander Zaft ]
* lib: Fix GeneralConfig defaults handling
-- Jens Krüger <jenkins@frm2.tum.de> Tue, 06 Aug 2024 13:56:51 +0200
frappy-core (0.19.5) stable; urgency=medium
* client: fix how to raise error on wrong ident
* add missing requirements to setup.py
* add RemoteLogHandler independent of MainLogger
* pass logger parameter only for mlzlogger
-- Alexander Zaft <jenkins@frm2.tum.de> Mon, 05 Aug 2024 09:30:53 +0200
frappy-core (0.19.4) stable; urgency=medium
* actually exclude cfg-editor
-- Georg Brandl <jenkins@frm2.tum.de> Fri, 26 Jul 2024 11:46:10 +0200
frappy-core (0.19.3) stable; urgency=medium
[ Markus Zolliker ]
* frappy_psi.extparams.StructParam: fix doc + simplify
* better behaviour on startup in case of errors
* frappy_psi.sea: use ReadFailedError
* frappy_psi.sea: use raise from
[ Alexander Zaft ]
* mlz: fix delayed import of he3cell
* mlz seop: add pylint
[ Jens Krüger ]
* Update copyright year
[ Enrico Faulhaber ]
* remove cfg_editor for now
-- Markus Zolliker <jenkins@frm2.tum.de> Fri, 26 Jul 2024 08:36:43 +0200
frappy-core (0.19.2) stable; urgency=medium
[ l_samenv ]
* fix missing update after error on parameter
[ Markus Zolliker ]
* frappy.lib.asynconn: handle ConnectionResetError nicely
* HasControlledBy: update target without switching to self control
* bug fix in frappy_psi.convergence
[ Alexander Zaft ]
* add option for delayed imports
[ Markus Zolliker ]
* frappy_psi.ah2700: auto create loss module with Pinata
* frappy_psi.picontrol: software control loop
* frappy_psi.triton: bug fixes
* frappy_psi.sea: various improvments
* frappy_psi.triton: fix heater output issue
[ Enrico Faulhaber ]
* frappy_mlz/entangle: fix missing status enum
-- l_samenv <jenkins@frm2.tum.de> Tue, 18 Jun 2024 15:21:43 +0200
frappy-core (0.19.1) stable; urgency=medium
[ Markus Zolliker ]
* SecopClient.online must be True while activating
* frappy.client.readParameter: handle connection errors correctly
[ Alexander Zaft ]
* datatypes: add more detail to error messages
* mlz: derive Digitaloutput from Drivable
-- Markus Zolliker <jenkins@frm2.tum.de> Fri, 07 Jun 2024 16:50:33 +0200
frappy-core (0.19.0) stable; urgency=medium
[ Markus Zolliker ]
* simulation: extra_params might be a list
* add FloatEnumParam
* move StructParam to frappy/extparams.py
* bugfix in automatic creation if attached io
* fixes for proxy modules
* simplify callbacks
* fix docstring in frappy.error.OutOfRangeError
[ Alexander Zaft ]
* core: introduce common handler class
* core: cover errors in handler setup()
[ Markus Zolliker ]
* fix command doc string handling and change default stop doc string
* follow up fix for change 33168
* follow up fix: handler export=True correctly
[ Alexander Zaft ]
* core: add websocket interface
[ Georg Brandl ]
* dispatcher: consistent handling of missing timestamps
[ Alexander Zaft ]
* gui: catch invalid inputs
* gui: sort qt imports
[ Markus Zolliker ]
* frappy.client: cleanup properly after a reply timeout
[ Alexander Zaft ]
* gui: more specialized input widgets
* test: add uri attach test
[ Markus Zolliker ]
* frappy.client: catch errors on callbacks
* frappy.client: improve error handling more
* frappy.client.interactive: improve logging and error handling
* frappy.client.SecopClient: add the option to use no logging at all
* SecopClient.__del__ must not call callbacks
* frappy.client: avoid shutdown callback sent twice
[ Georg Brandl ]
* add config for the Entangle simulation server
[ Jens Krüger ]
* Fix abslimits reading from entangle device
[ Georg Brandl ]
* fix LimitsType to be actually used and validated
-- Markus Zolliker <jenkins@frm2.tum.de> Thu, 16 May 2024 11:31:25 +0200
frappy-core (0.18.1) stable; urgency=medium
* mlz: Zapf fix unit handling and small errors
* mlz: entangle fix limit check
-- Alexander Zaft <jenkins@frm2.tum.de> Wed, 24 Jan 2024 14:59:21 +0100
frappy-core (0.18.0) stable; urgency=medium
[ Alexander Zaft ]
* Add shutdownModule function
[ Markus Zolliker ]
* frappy_psi.convergence: bug fixes and improvements
[ Alexander Zaft ]
* server: Add signal handling
* add test cases for server and config
[ Markus Zolliker ]
* fix frappy.lib.merge_status
* frappy_psi.sea: try to reconnect on failure
* pylint: disable use-dict-literal
[ Alexander Zaft ]
* server: add option to dynamically create devices
[ Markus Zolliker ]
* add StructParam
* add frappy_psi.thermofisher
* add frappy_psi.thermofisher to the doc
* frappy.io: make error reporting consistent
* frappy_psi.sea: avoid multiple connections
* frappy_psi.sea: further bug fixes
* frappy.client.interactive: bug fixes
[ Alexander Zaft ]
* mlz: Add Zebra Barcode Reader
* frappy_mlz: Zebra fixes after basic test
* dispatcher: change logging calls to debug
* core: do not call register_module on error
* add zapf to requirements-dev.txt
* frappy_mlz: Add Zapf PLC
* Revert "add zapf to requirements-dev.txt"
* add zapf to requirements-dev
* frappy_mlz: fix one-off error in barcode reader
[ Markus Zolliker ]
* improve error message on client when host/port is bad
* frappy/protocol/interface/tcp.py: use SECoP_DEFAULT_PORT
* frappy_psi.phytron: stop motor before restart
* interactive client: improve keyboard interrupt
* fix frappy/playground.py after change 31470
[ Alexander Zaft ]
* frappy_mlz seop: add count to ampl and phase cmds
[ Markus Zolliker ]
* frappy_psi.phytron: further improvements
* further fixes after change 31470
* fix missing .poll attribute in simulation
* psi: improve sea interface
* fix frappy_demo.lakeshore
* change FloatRange arguments minval/maxval to min/max
* improve client shutdown time
* introduce FrozenParam
* phytron.py: improve status
* frappy_psi.sea: small fixes
* bug in Attached (fix after change 31470)
[ Alexander Zaft ]
* core: split module code
* core: factor out accessibles from init
[ Markus Zolliker ]
* proxy: fix command wrapper
[ Alexander Zaft ]
* server: handle signals during startup
* all: remove coding cookies
* psi: fix Done import in sea
[ Markus Zolliker ]
* frappy.io: change default to retry_first_idn=True
[ Alexander Zaft ]
* core: move module handling out of dispatcher
* mlz/demo: move old examples to Attached
[ Markus Zolliker ]
* frappy.client: fix the case then timestamp is missing
* doc: drop latex support, add pdf support
* add StringIO.writeline, improve StringIO.multicomm
* implement pfeiffer TPG vacuum reading
[ Alexander Zaft ]
* core: allow multiple interfaces
* core: formatting and update server docstring
* mlz: handle unconfigured abslimits
* datatypes: fix optional struct export
* core: better command handling
[ Markus Zolliker ]
* frappy_psi.sea: workaround for bug in sea
[ Alexander Zaft ]
* core: better error on export of internal type
[ Markus Zolliker ]
* fix missing import in change message
* modify arguments of Dispatcher.announce_update
* frappy.secnode: fix strange error message
* fix playground after change 32249
* remove py35 compatibility code
* bug fix in frappy.io.BytesIO.checkHWIdent
-- Alexander Zaft <jenkins@frm2.tum.de> Wed, 17 Jan 2024 12:35:00 +0100
frappy-core (0.17.13) stable; urgency=medium
[ Alexander Zaft ]
* add egg-info to gitignore
[ Markus Zolliker ]
* GUI bugfix: use isChecked instead of checkState in BoolInput
* frappy_psi.mercury/triton: add control_off command
* frappy_psi.phytron: rename reset_error to clear_errors
* frappy.mixins.HasOutputModule
* frappy_psi.mercury: proper handling of control_active
* add a hook for reads to be done initially
* frappy_psi.triton: fix HeaterOutput.limit
* frappy_psi.magfield: bug fix
* frappy_psi.sea: bug fixes
[ Alexander Zaft ]
* server: fix systemd variable scope
-- Alexander Zaft <jenkins@frm2.tum.de> Tue, 20 Jun 2023 14:38:00 +0200
frappy-core (0.17.12) stable; urgency=medium
[ Alexander Zaft ]
* Warn about duplicate module definitions in a file
* Add influences property to parameters/commands
[ Markus Zolliker ]
* frappy.client: dummy logger is missing 'exception' method
[ Alexander Zaft ]
* Add SEOP He3-polarization device
* Typo in influences description
* seop: fix fitparam command
[ Markus Zolliker ]
* silently catches error in systemd.daemon.notify
[ Alexander Zaft ]
* io: add option to retry first ident request
* config: fix merge_modules
* io: followup fix for retry-first-ident
* entangle: fix tango guards for pytango 9.3
-- Alexander Zaft <jenkins@frm2.tum.de> Tue, 13 Jun 2023 06:51:27 +0200
frappy-core (0.17.11) stable; urgency=medium
[ Alexander Zaft ]
* Add __format__ to EnumMember
[ Markus Zolliker ]
* fix error from manual %-format conversion
[ Alexander Zaft ]
* specify minimum pyqt5 version
[ Markus Zolliker ]
* make io device visible as expert by default
[ Jens Krüger ]
* MLZ/Entangle: Fix formatting issues
[ Markus Zolliker ]
* improve error handling on callbacks
* fix issues with lakeshore 370
* frappy_psi: two small fixes in k2601b/ppmssim
* a playground for debugging drivers
* issues with StructOf
* improve mercury temperature loop
* improve interactive client
[ Jens Krüger ]
* Server: add missing 'restart_hook' missing
* MLZ/Entangle: Add unit init in AnalogOutput
* MLZ/Entangle: Fix user limits handling
[ Alexander Zaft ]
* Improve address and connection handling
* Add Stopgap handling of cfg files in cfg-editor
[ Markus Zolliker ]
* fix in frappy_psi.historywriter
* improve mercury driver
* driver for the triton dilution refrigerator
* fixes on HasConvergence and HasOutputModule
* improve and fix errors with parameter limits
* add HasOffset feature
[ Alexander Zaft ]
* Fix interface class list
[ Markus Zolliker ]
* mixins should not inherit Module
* fix interplay mercury.TemperatureLoop and HasConvergence
[ Alexander Zaft ]
* Fix lower limit checking of FloatRange
[ Markus Zolliker ]
* improve traceback while processing config file
* driver for mercury IPS
* add sea driver
[ Georg Brandl ]
* debian: add new executable
[ Markus Zolliker ]
* move more code from bin/frappy-cli to frappy/client/interactive.py
* add unit=s to pollinterval
* client.interactive: fix error when interface_classes empty
* phytron motor driver
* client: timestamps must never lie in the future
[ Alexander Zaft ]
* Fix rstrip misuse in frappy-generator
-- Alexander Zaft <jenkins@frm2.tum.de> Thu, 25 May 2023 09:38:24 +0200
frappy-core (0.17.10) stable; urgency=medium
* Change leftover %-logging calls to lazy
* Convert formatting automatically to f-strings
* move unit into display label
* [WIP] gui: add specific input widgets
* Rebuild NodeWidget when the description changes
* Manually convert most remaining format statements
* make entangle mapping a dict
-- Alexander Zaft <jenkins@frm2.tum.de> Wed, 19 Apr 2023 14:32:52 +0200
frappy-core (0.17.9) stable; urgency=medium
* interactive client: avoid messing up the input line
-- Markus Zolliker <jenkins@frm2.tum.de> Tue, 11 Apr 2023 16:09:03 +0200
frappy-core (0.17.8) stable; urgency=medium
* Debian: Fix typo
-- Jens Krüger <jenkins@frm2.tum.de> Wed, 05 Apr 2023 07:20:25 +0200
frappy-core (0.17.7) stable; urgency=medium
* Debian: add pyqtgraph dependency
-- Jens Krüger <jenkins@frm2.tum.de> Wed, 05 Apr 2023 07:07:24 +0200
frappy-core (0.17.6) stable; urgency=medium
[ Alexander Zaft ]
* gui: show parameter properties again
* gui: full module description only in detailed mode
* gui: switch group button order, change text
* gui: add console history
* gui: logwindow improvements
* add copyright headers where missing
* add optional validation to ValueType
* cli: add argparse and inlcudes before repl
[ Markus Zolliker ]
* improve error messages
[ Jens Krüger ]
* Fix debian GUI package dependency
-- Alexander Zaft <jenkins@frm2.tum.de> Tue, 04 Apr 2023 08:42:26 +0200
frappy-core (0.17.5) stable; urgency=medium
* Fix generator
-- Alexander Zaft <jenkins@frm2.tum.de> Wed, 22 Mar 2023 12:32:06 +0100
frappy-core (0.17.4) stable; urgency=medium
* Fix entangle integration bugs
-- Alexander Zaft <jenkins@frm2.tum.de> Wed, 22 Mar 2023 11:44:34 +0100
frappy-core (0.17.3) stable; urgency=medium
* UNRELEASED
-- Alexander Zaft <jenkins@frm2.tum.de> Tue, 21 Mar 2023 15:55:09 +0100
frappy-core (0.17.2) stable; urgency=medium
[ Alexander Zaft ]
* Fix Simulation and Proxy
[ Markus Zolliker ]
* cfg path quick fix for hands-on session
[ Georg Brandl ]
* add pyqtgraph to gui dependencies
[ Markus Zolliker ]
* allow super calls on read_/write_ methods
[ Alexander Zaft ]
* Add greeter tab to UI
* Add recent SECNodes to Drop down menu
* Remove auto-connect to 10767 on startup
[ Markus Zolliker ]
* do not reuse address on Windows
[ Georg Brandl ]
* version.py: sync with other projects
[ Alexander Zaft ]
* Fix forge link in README
[ Markus Zolliker ]
* better guess for cfg file location
* fix ppms with proxy
* default settings on the IO class
* demo lakeshore with simulation
[ Georg Brandl ]
* cfg editor: fixes
* installer: add config for frappy gui exe
[ Markus Zolliker ]
* make doc should not fail when version is not available
[ Alexander Zaft ]
* Add reconnect Action
[ Georg Brandl ]
* readme: fix make call
* gui: add about dialog, remove "about Qt" menu entry
* gui: move QSECNode to separate module
* gui: isort
[ Alexander Zaft ]
* Fix Node adding logic
* Remove unneeded constants
* Make input field more distinct
[ Markus Zolliker ]
* AsynConn.uri: better handling for missing scheme
[ Georg Brandl ]
* gui: remove unused ui file
* gui: better label for param set button
[ Alexander Zaft ]
* Always make a greeter tab
[ Markus Zolliker ]
* improve online help of frappy-cli
* refresh logging when reconnected while watching
[ Alexander Zaft ]
* [Needs Feedback] Add PyQt6. Remove PyQt4
* Merge resource files
* Extend Node and Module widgets
* Scroll Module area instead of replacing widgets
* Remove Modulectrl Widget
[ Georg Brandl ]
* gui: better display of protocol version
* gui: cleanup code in modulewidget
* gui: always show scrollbar in nodewidget
[ Alexander Zaft ]
* Short background Color animation on scroll
[ Markus Zolliker ]
* treat returning None from write_<param> properly
[ Alexander Zaft ]
* Fix doubled module info
[ Georg Brandl ]
* Jenkinsfile: isort does not fail the build
* isort: add firstparty
[ Alexander Zaft ]
* gui: make module details button checkable
* gui: Logo in greeter
[ Enrico Faulhaber ]
* handle connection close more gracefully
[ Markus Zolliker ]
* split BadValue into WrongType and RangeError
[ Georg Brandl ]
* demo: fixup Switch class
[ Alexander Zaft ]
* fix importing AsynCon without serial
[ Markus Zolliker ]
* gui: support proper formatting of values
* central point for status codes
[ Alexander Zaft ]
* fix README typo
* gui: terminate connection on tab close
* check configured names for spaces
[ Markus Zolliker ]
* make return value 'Done' unneccessary
* enhanced parameter range checks
* simplify status type declaration
* improve frappy.errors
* remove UNKNOWN, UNSTABLE and DISABLED from Readable.status
* fix generalConfig defaults
[ Alexander Zaft ]
* Add SECoP link to readme
* gui: more greeter interactions
[ Markus Zolliker ]
* fix issues when closing tabs
* format unit properly in the case of nested arrays
-- Alexander Zaft <jenkins@frm2.tum.de> Tue, 21 Mar 2023 15:49:06 +0100
frappy-core (0.17.1) stable; urgency=medium
[ Georg Brandl ]
* gitignore: ignore demo PID file
* config: demo config fixes
* cfg: repair demo cfg after conversion
* gui: make spacing more consistent
[ Markus Zolliker ]
* fix links in doc/introduction
[ Georg Brandl ]
* gui console: better formatting of input/output
* gui: as a stopgap measure, apply %g format to floats
* gui: clear tree selection by clicking into empty space
* gui: make plot windows children of the node, so they close automatically
-- Georg Brandl <jenkins@frm2.tum.de> Tue, 21 Feb 2023 17:44:56 +0100
frappy-core (0.17.0) stable; urgency=medium
[ Alexander Zaft ]
* Rework GUI.
[ Georg Brandl ]
* ci: remove duplicate variable
* doc: fix trailing comma in authors
-- Alexander Zaft <jenkins@frm2.tum.de> Tue, 21 Feb 2023 13:52:17 +0100
frappy-core (0.16.1) stable; urgency=medium
* UNRELEASED
-- Georg Brandl <jenkins@frm2.tum.de> Tue, 21 Feb 2023 08:44:28 +0100
frappy-core (0.16.4) stable; urgency=medium
* UNRELEASED
-- Georg Brandl <jenkins@frm2.tum.de> Tue, 21 Feb 2023 08:09:20 +0100
frappy-core (0.16.3) stable; urgency=medium
* UNRELEASED
-- Georg Brandl <jenkins@frm2.tum.de> Tue, 21 Feb 2023 08:00:15 +0100
frappy-core (0.16.2) stable; urgency=medium
* gui: move icon resources for the cfg editor to its subdirectory
-- Georg Brandl <jenkins@frm2.tum.de> Tue, 21 Feb 2023 07:50:13 +0100
frappy-core (0.16.1) stable; urgency=medium
* add frappy-cli to package
-- Enrico Faulhaber <jenkins@frm2.tum.de> Mon, 20 Feb 2023 17:17:23 +0100
frappy-core (0.16.0) stable; urgency=medium
[ Enrico Faulhaber ]
* fix sorce package name
[ Markus Zolliker ]
* interactive client: fix detection of overriding modules
[ Alexander Zaft ]
* Fix error Message for too large arrays
[ Markus Zolliker ]
* redesign of the state machine
[ Alexander Zaft ]
* Fix identification response
* GUI: add logging infra, switch to argparse
[ Bjoern Pedersen ]
* Improve jenkinsfile
[ Alexander Zaft ]
* Change config to Python
[ Markus Zolliker ]
* improve He level tutorial
* client: detect original frappy error class
* rework datatypes (setter should not check limits)
[ Alexander Zaft ]
* Bring demo up to date
* Revert limit change in demo
[ Markus Zolliker ]
* improve parameter initialisation
* fix copy method of Attached
[ Alexander Zaft ]
* Add .desktop file
[ Markus Zolliker ]
* improve persistent parameters
* do not throw ZeroDivisonError when pollinterval is 0
* HasStates: fix status code inheritance
* HasControlledBy and HasOutputModule mixins
* adapt tutorial to new config file format
* raise ProtcolError when specifier is missing
* interactive client: improve watch function
* add lakeshore demo for hands-on workshop
* T controller tutorial and improve documentation
* do proper value import on the client side
[ Alexander Zaft ]
* Add initial README
* Change Readme title
* Convert example configs to python
[ Markus Zolliker ]
* README: add link to doc on forge.frm2.tum.de
-- Enrico Faulhaber <jenkins@frm2.tum.de> Mon, 20 Feb 2023 16:15:10 +0100
frappy-core (0.15.0) stable; urgency=medium
[ Björn Pedersen ]
* Remove iohandler left-overs from docs
@@ -28,7 +936,7 @@ frappy-core (0.15.0) focal; urgency=medium
-- Björn Pedersen <jenkins@frm2.tum.de> Thu, 10 Nov 2022 14:46:01 +0100
secop-core (0.14.3) focal; urgency=medium
secop-core (0.14.3) stable; urgency=medium
[ Enrico Faulhaber ]
* change repo to secop/frappy
@@ -44,13 +952,13 @@ secop-core (0.14.3) focal; urgency=medium
-- Enrico Faulhaber <jenkins@frm2.tum.de> Thu, 03 Nov 2022 13:51:52 +0100
secop-core (0.14.2) focal; urgency=medium
secop-core (0.14.2) stable; urgency=medium
* systemd generator: adapt to changed config API
-- Georg Brandl <jenkins@frm2.tum.de> Thu, 20 Oct 2022 15:38:45 +0200
secop-core (0.14.1) focal; urgency=medium
secop-core (0.14.1) stable; urgency=medium
[ Markus Zolliker ]
* secop_psi.entangle.AnalogInput: fix main value
@@ -62,7 +970,7 @@ secop-core (0.14.1) focal; urgency=medium
-- Markus Zolliker <jenkins@frm2.tum.de> Thu, 20 Oct 2022 14:04:07 +0200
secop-core (0.14.0) focal; urgency=medium
secop-core (0.14.0) stable; urgency=medium
* add simple interactive python client
* fix undefined status in softcal
@@ -76,7 +984,7 @@ secop-core (0.14.0) focal; urgency=medium
-- Markus Zolliker <jenkins@frm2.tum.de> Wed, 19 Oct 2022 11:31:50 +0200
secop-core (0.13.1) focal; urgency=medium
secop-core (0.13.1) stable; urgency=medium
[ Markus Zolliker ]
* an enum with value 0 should be interpreted as False
@@ -87,7 +995,7 @@ secop-core (0.13.1) focal; urgency=medium
-- Markus Zolliker <jenkins@jenkins02.admin.frm2.tum.de> Tue, 02 Aug 2022 15:31:52 +0200
secop-core (0.13.0) focal; urgency=medium
secop-core (0.13.0) stable; urgency=medium
[ Georg Brandl ]
* debian: fix email addresses in changelog
@@ -150,13 +1058,13 @@ secop-core (0.13.0) focal; urgency=medium
-- Georg Brandl <jenkins@frm2.tum.de> Tue, 02 Aug 2022 09:47:06 +0200
secop-core (0.12.4) focal; urgency=medium
secop-core (0.12.4) stable; urgency=medium
* fix command inheritance
-- Markus Zolliker <jenkins@jenkins01.admin.frm2.tum.de> Thu, 11 Nov 2021 16:21:19 +0100
secop-core (0.12.3) focal; urgency=medium
secop-core (0.12.3) stable; urgency=medium
[ Georg Brandl ]
* Makefile: fix docker image
@@ -179,7 +1087,7 @@ secop-core (0.12.3) focal; urgency=medium
-- Georg Brandl <jenkins@jenkins01.admin.frm2.tum.de> Wed, 10 Nov 2021 16:33:19 +0100
secop-core (0.12.2) focal; urgency=medium
secop-core (0.12.2) stable; urgency=medium
[ Markus Zolliker ]
* fix issue with new syntax in simulation
@@ -191,13 +1099,13 @@ secop-core (0.12.2) focal; urgency=medium
-- Markus Zolliker <jenkins@jenkins01.admin.frm2.tum.de> Tue, 18 May 2021 10:29:17 +0200
secop-core (0.12.1) focal; urgency=medium
secop-core (0.12.1) stable; urgency=medium
* remove secop-console from debian *.install file
-- Enrico Faulhaber <jenkins@jenkins02.admin.frm2.tum.de> Tue, 04 May 2021 09:42:53 +0200
secop-core (0.12.0) focal; urgency=medium
secop-core (0.12.0) stable; urgency=medium
[ Markus Zolliker ]
* make datatypes immutable

1
debian/compat vendored
View File

@@ -1 +0,0 @@
11

24
debian/control vendored
View File

@@ -2,7 +2,7 @@ Source: frappy-core
Section: contrib/misc
Priority: optional
Maintainer: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Build-Depends: debhelper (>= 11~),
Build-Depends: debhelper-compat (= 13),
dh-python,
python3 (>=3.6),
python3-all,
@@ -20,7 +20,7 @@ Build-Depends: debhelper (>= 11~),
git,
markdown,
python3-daemon
Standards-Version: 4.1.4
Standards-Version: 4.6.2
X-Python3-Version: >= 3.6
Package: frappy-core
@@ -35,8 +35,10 @@ Depends: python3 (>= 3.6),
python3-mlzlog,
markdown,
python3-daemon
Replaces: secop-core (<= 0.14.3)
Breaks: secop-core (<= 0.14.3)
Replaces: secop-core (<= 0.14.3),
frappy-demo (<= 0.19.7)
Breaks: secop-core (<= 0.14.3),
frappy-demo (<= 0.19.7)
Description: Frappy SECoP core system
contains the core server and client libraries and the server binary
as well as the systemd integration
@@ -54,23 +56,13 @@ Architecture: all
Depends: frappy-core,
${misc:Depends},
${python3:Depends},
python3-pyqt (>=4)
python3-pyqtgraph (>=0.11.0),
python3-pyqt5 (>=5)
Replaces: secop-gui (<= 0.14.3)
Breaks: secop-gui (<= 0.14.3)
Description: Frappy SECoP gui client + cfgtool
contains the GUI client and the configurator
Package: frappy-demo
Architecture: all
Depends: frappy-core,
${misc:Depends},
${python3:Depends}
Replaces: secop-demo (<= 0.14.3)
Breaks: secop-demo (<= 0.14.3)
Recommends: frappy-gui
Description: SECoP demo files
for demonstration purposes
Package: frappy-ess
Architecture: all
Depends: frappy-core,

4
debian/copyright vendored
View File

@@ -5,11 +5,11 @@ Comment: FRAPPY is an implementation of the free SECoP protocol
see https://www.github.com/SampleEnvironment/SECoP
Files: *
Copyright: 2016-2022 by the FRAPPY-SECOP contributors (see AUTHORS)
Copyright: 2016-2024 by the FRAPPY-SECOP contributors (see AUTHORS)
License: GPL-2
Files: debian/*
Copyright: 2015-2022 Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Copyright: 2015-2024 Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
License: GPL-2
License: GPL-2

View File

@@ -1,9 +1,15 @@
usr/bin/frappy-cli
usr/bin/frappy-server
usr/bin/frappy-play
usr/bin/frappy-scan
usr/lib/python3.*/dist-packages/frappy/*.py
usr/lib/python3.*/dist-packages/frappy/__pycache__
usr/lib/python3.*/dist-packages/frappy/lib
usr/lib/python3.*/dist-packages/frappy/client
usr/lib/python3.*/dist-packages/frappy/protocol
usr/lib/python3.*/dist-packages/frappy_core-*
usr/lib/python3.*/dist-packages/frappy/RELEASE-VERSION
usr/lib/python3.*/dist-packages/frappy_demo
lib/systemd
var/log/frappy
etc/frappy/generalConfig.cfg

View File

@@ -1,2 +0,0 @@
usr/lib/python3.*/dist-packages/frappy_demo
usr/lib/python3.*/dist-packages/frappy/__pycache__

View File

@@ -1,3 +1,2 @@
usr/bin/frappy-gui
usr/bin/frappy-cfg-editor
usr/lib/python3.*/dist-packages/frappy/gui

1
debian/rules vendored
View File

@@ -11,6 +11,7 @@ override_dh_install:
rmdir debian/tmp
mv debian/python3-frappy debian/tmp
install -m644 -Dt debian/tmp/etc/frappy etc/generalConfig.cfg
dh_install -i -O--buildsystem=pybuild
dh_missing --fail-missing

View File

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

View File

@@ -0,0 +1,58 @@
Configuration File
..................
.. _node configuration:
:Node(equipment_id, description, interface, \*\*kwds):
Specify the SEC-node properties.
The arguments are SECoP node properties and additional internal node configurations
:Parameters:
- **equipment_id** - a globally unique string identifying the SEC node
- **description** - a human readable description of the SEC node
- **interface** - an uri style string indication the address for the server
- **kwds** - other SEC node properties
.. _mod configuration:
:Mod(name, cls, description, \*\*kwds):
Create a SECoP module.
Keyworded argument matching a parameter name are used to configure
the initial value of a parameter. For configuring the parameter properties
the value must be an instance of **Param**, using the keyworded arguments
for modifying the default values of the parameter properties. In this case,
the initial value may be given as the first positional argument.
In case command properties are to be modified **Command** has to be used.
:Parameters:
- **name** - the module name
- **cls** - a qualified class name or the python class of a module
- **description** - a human readable description of the module
- **kwds** - parameter, property or command configurations
.. _param configuration:
:Param(value=<undef>, \*\*kwds):
Configure a parameter
:Parameters:
- **value** - if given, the initial value of the parameter
- **kwds** - parameter or datatype SECoP properties (see :class:`frappy.param.Parameter`
and :class:`frappy.datatypes.Datatypes`)
.. _command configuration:
:Command(\*\*kwds):
Configure a command
:Parameters:
- **kwds** - command SECoP properties (see :class:`frappy.param.Commands`)

View File

@@ -8,3 +8,7 @@ Demo
.. automodule:: frappy_demo.test
:show-inheritance:
:members:
.. automodule:: frappy_demo.lakeshore
:show-inheritance:
:members:

View File

@@ -25,3 +25,10 @@ Calibrated sensors and control loop not yet supported.
:show-inheritance:
:members:
Bath Thermostat Thermofisher
............................
.. automodule:: frappy_psi.thermofisher
:show-inheritance:
:members:

View File

@@ -5,6 +5,10 @@ Frappy Programming Guide
:maxdepth: 2
introduction
structure
programming
magic
server
tutorial
reference
frappy_psi

View File

@@ -57,14 +57,30 @@ to provide to the user.
Programming a Driver
--------------------
Programming a driver means extending one of the base classes like :class:`frappy.modules.Readable`
or :class:`frappy.modules.Drivable`. The parameters are defined in the dict :py:attr:`parameters`, as a
class attribute of the extended class, using the :class:`frappy.params.Parameter` constructor, or in case
of altering the properties of an inherited parameter, :class:`frappy.params.Override`.
:ref:`Programming a driver <class_coding>` means:
- selecting a base class to be extended (e.g. :class:`frappy.modules.Readable`
or :class:`frappy.modules.Drivable`).
- defining the parameters
- coding the methods to retrieve and access these parameters
Support for Communication with the Hardware
-------------------------------------------
Often the access to the hardware has to be done over a serial communication over LAN,
RS232 or USB. The mixin :class:`frappy.io.HasIO` and the classes :class:`frappy.io.StringIO`
and :class:`frappy.io.BytesIO` have all the functionality needed for this.
Some hardware also requires calls to libraries offered by the manufacturers, certainly this
is also possible. In case there is no python package for this, but a C/C++ API, you might
use one of the following:
- `Ctypes (A foreign function library for Python) <https://docs.python.org/3/library/ctypes.html>`_
- `CFFI (C Foreign Function Interface for Python) <https://cffi.readthedocs.io/>`_
- `Extending Python with C or C++ <https://docs.python.org/3/extending/extending.html>`_
.. TODO: shift this to an extra section
Parameters usually need a method :meth:`read_<name>()`
implementing the code to retrieve their value from the hardware. Writeable parameters
(with the argument ``readonly=False``) usually need a method :meth:`write_<name>(<value>)`
implementing how they are written to the hardware. Above methods may be omitted, when
there is no interaction with the hardware involved.

78
doc/source/magic.rst Normal file
View File

@@ -0,0 +1,78 @@
Frappy Internals
----------------
Frappy is a powerful framework, which does everything behind the
scenes you need for getting a SEC node to work. This section describes
what the framwork does for you.
Startup
.......
On startup several methods are called. First :meth:`earlyInit` is called on all modules.
Use this to initialize attributes independent of other modules, if you can not initialize
as a class attribute, for example for mutable attributes.
Then :meth:`initModule` is called for all modules.
Use it to initialize things related to other modules, for example registering callbacks.
After this, :meth:`startModule` is called with a callback function argument.
:func:`frappy.modules.Module.startModule` starts the poller thread, calling
:meth:`writeInitParams` for writing initial parameters to hardware, followed
by :meth:`initialReads`. The latter is meant for reading values from hardware,
which are not polled continuously. Then all parameters configured for poll are polled
by calling the corresponding read_*() method. The end of this last initialisation
step is indicated to the server by the callback function.
After this, the poller thread starts regular polling, see next section.
When overriding one of above methods, do not forget to super call.
.. _polling:
Polling
.......
By default, a module inheriting from :class:`Readable <frappy.modules.Readable>` is
polled every :attr:`pollinterval` seconds. More exactly, the :meth:`doPoll`
method is called, which by default calls :meth:`read_value` and :meth:`read_status`.
The programmer might override the behaviour of :meth:`doPoll`, often it is wise
to super call the inherited method.
:Note:
Even for modules not inheriting from :class:`Readable <frappy.modules.Readable>`,
:meth:`doPoll` is called regularly. Its default implementation is doing nothing,
but may be overridden to do customized polling.
In addition, the :meth:`read_<param>` method is called every :attr:`slowinterval`
seconds for all parameters, in case the value was not updated since :attr:`pollinterval`
seconds.
The decorator :func:`nopoll <frappy.rwhandler.nopoll>` might be used on a :meth:`read_<param>`
method in order to indicate, that the value is not polled by the slow poll mechanism.
.. _client notification:
Client Notification
...................
Whenever a parameter is changed by assigning a value to the attribute or by
means of the access method, an ``update`` message is sent to all activated clients.
Frappy implements the extended version of the ``activate`` message, where single modules
and parameters might be activated.
.. _type check:
Type check and type conversion
..............................
Assigning a parameter to a value by setting the attribute via ``self.<param> = <value>``
or ``<module>.<param> = <value>`` involves a type check and possible a type conversion,
but not a range check for numeric types. The range check is only done on a ``change``
message.
TODO: error handling, logging

117
doc/source/programming.rst Normal file
View File

@@ -0,0 +1,117 @@
Coding
======
.. _class_coding:
Coding a Class for a SECoP Module
---------------------------------
A SECoP module is represented as an instance of a python class.
For programming such a class, typically you create a
subclass of one of the base classes :class:`Readable <frappy.modules.Readable>`,
:class:`Writable <frappy.modules.Writable>` or :class:`Drivable <frappy.modules.Drivable>`.
It is also quite common to inherit from classes created for similar modules,
and or to inherit from a mixin class like :class:`HasIO <frappy.io.HasIO>`.
For creating the :ref:`parameters <module structure parameters>`,
class attributes are used, using the name of
the parameter as the attribute name and an instantiation of :class:`frappy.params.Parameter`
for defining the parameter. If a parameter is already given by an inherited class,
the parameter declaration might be omitted, or just its altered properties
have to be given.
In addition, you might need one or several configurable items
(see :ref:`properties <module structure properties>`), declared in the same way, with
``<property name> =`` :class:`frappy.params.Property` ``(...)``.
For each of the parameters, the behaviour has to be programmed with the
following access methods:
def read\_\ *<parameter>*\ (self):
Called on a ``read`` SECoP message and whenever the internal poll mechanism
of Frappy tries to get a new value. The return value should be the
retrieved value.
This method might also be called internally, in case a fresh value of
the parameter is needed.
.. admonition:: polling
The Frappy framework has a built in :ref:`polling <polling>` mechanism,
which calls above method regularely. Each time ``read_<parameter>`` is
called, the Frappy framework ensures then that the value of the parameter
is updated and the activated clients will be notified by means of an
``update`` message.
def write\_\ *<parameter>*\ (self, value):
Called on a ``change`` SECoP message. The ``value`` argument is the value
given by the change message, and the method should implement the change,
typically by handing it over to the hardware. On success, the method must
return the accepted value. If the value may be read back
from the hardware, the readback value should be returned, which might be
slighly altered for example by rounding. The idea is, that the returned
value would be the same, as if it would be done by the ``read_<parameter>``
method. Often the easiest implementation is just returning the result of
a call to the ``read_<parameter>`` method.
.. admonition:: behind the scenes
Assigning a parameter to a value by setting the attribute via
``self.<param> = <value>`` or ``<module>.<param> = <value>`` includes
a :ref:`type check <type check>`, some type conversion and ensures that
a :ref:`notification <client notification>` with an
``update`` message is sent to all activated clients.
Example code:
.. code:: python
from frappy.core import HasIO, Drivable, Property, Parameter, StringType
class TemperatureLoop(HasIO, Drivable):
"""a temperature sensor with loop"""
# internal property to configure the channel
channel = Property('the Lakeshore channel', datatype=StringType())
# modifying a property of inherited parameters (unit is propagated to the FloatRange datatype)
value = Parameter(unit='K')
target = Parameter(unit='K')
def read_value(self):
# using the inherited HasIO.communicate method to send a command and get the reply
reply = self.communicate(f'KRDG?{self.channel}')
return float(reply)
def read_status(self):
... determine the status from the hardware and return it ...
return status_code, status_text
def read_target(self):
... read back the target value ...
return target
def write_target(self, target):
... write here the target to the hardware ...
# important: make sure that the status is changed to BUSY within this method:
self.status = BUSY, 'target changed'
return self.read_target() # return the read back value
Parameter Initialisation
------------------------
Initial values of parameters might be given by several different sources:
1) value argument of a Parameter declaration
2) read from HW
3) read from persistent data file
4) value given in config file
For (2) the programmer might decide for any parameter to poll it regularely from the
hardware. In this case changes from an other input, for example a keyboard or other
interface of the connected devices would be updated continuously in Frappy.
If there is no such other input, or if the programmer decides that such other
data sources are not to be considered, the hardware parameter might be read in just
once on startup, :func:`frappy.modules.Module.initialReads` may be overriden.
This method is called once on startup, before the regular polls start.
.. TODO: io, state machine, persistent parameters, rwhandler, datatypes, features, commands, proxies

View File

@@ -1,13 +1,18 @@
Reference
---------
Core
....
For convenience everything documented on this page may also be
imported from the frappy.core module.
Module Base Classes
...................
.. autodata:: frappy.modules.Done
.. autoclass:: frappy.modules.Module
:members: earlyInit, initModule, startModule
:members: earlyInit, initModule, startModule, initialReads
.. autoclass:: frappy.modules.Readable
:members: Status
@@ -27,21 +32,61 @@ Parameters, Commands and Properties
.. autoclass:: frappy.modules.Attached
:show-inheritance:
Access method decorators
........................
.. autofunction:: frappy.rwhandler.nopoll
.. _datatypes:
Datatypes
.........
.. autoclass:: frappy.datatypes.FloatRange
.. autoclass:: frappy.datatypes.IntRange
.. autoclass:: frappy.datatypes.BoolType
.. autoclass:: frappy.datatypes.ScaledInteger
.. autoclass:: frappy.datatypes.EnumType
.. autoclass:: frappy.datatypes.StringType
.. autoclass:: frappy.datatypes.TupleOf
.. autoclass:: frappy.datatypes.ArrayOf
.. autoclass:: frappy.datatypes.StructOf
.. autoclass:: frappy.datatypes.BLOBType
:members: __call__
.. autoclass:: frappy.datatypes.IntRange
:members: __call__
.. autoclass:: frappy.datatypes.BoolType
:members: __call__
.. autoclass:: frappy.datatypes.ScaledInteger
:members: __call__
.. autoclass:: frappy.datatypes.EnumType
:members: __call__
.. autoclass:: frappy.datatypes.StringType
:members: __call__
.. autoclass:: frappy.datatypes.TupleOf
:members: __call__
.. autoclass:: frappy.datatypes.ArrayOf
:members: __call__
.. autoclass:: frappy.datatypes.StructOf
:members: __call__
.. autoclass:: frappy.datatypes.BLOBType
:members: __call__
.. autoclass:: frappy.datatypes.DataTypeType
:members: __call__
.. autoclass:: frappy.datatypes.ValueType
:members: __call__
.. autoclass:: frappy.datatypes.NoneOr
:members: __call__
.. autoclass:: frappy.datatypes.OrType
:members: __call__
.. autoclass:: frappy.datatypes.LimitsType
:members: __call__
Communication
@@ -51,6 +96,10 @@ Communication
:show-inheritance:
:members: communicate
.. autoclass:: frappy.io.IOBase
:show-inheritance:
:members: default_settings
.. autoclass:: frappy.io.StringIO
:show-inheritance:
:members: communicate, multicomm
@@ -62,6 +111,12 @@ Communication
.. autoclass:: frappy.io.HasIO
:show-inheritance:
.. autoclass:: frappy.lib.asynconn.AsynTcp
:show-inheritance:
.. autoclass:: frappy.lib.asynconn.AsynSerial
:show-inheritance:
.. autoclass:: frappy.rwhandler.ReadHandler
:show-inheritance:
:members:
@@ -85,5 +140,4 @@ Exception classes
.. automodule:: frappy.errors
:members:
.. include:: server.rst
.. include:: configuration.rst

View File

@@ -1,47 +1,42 @@
Server
------
Configuration
.............
The configuration consists of a **NODE** section, an **INTERFACE** section and one
section per SECoP module.
The configuration code consists of a :ref:`Node() <node configuration>` section, and one
:ref:`Mod() <mod configuration>` section per SECoP module.
The **NODE** section contains a description of the SEC node and a globally unique ID of
the SEC node. Example:
The **Node** section contains a globally unique ID of the SEC node,
a description of the SEC node and the server interface uri. Example:
.. code::
.. code:: python
[NODE]
description = a description of the SEC node
id = globally.valid.identifier
Node('globally.valid.identifier',
'a description of the SEC node',
interface = 'tcp://5000')
The **INTERFACE** section defines the server interface. Currently only tcp is supported.
When the TCP port is given as an argument of the server start script, this section is not
needed or ignored. The main information is the port number, in this example 5000:
For the interface scheme currently only tcp is supported.
When the TCP port is given as an argument of the server start script, **interface** is not
needed or ignored. The main information is the port number, in this example 5000.
.. code::
[INTERFACE]
uri = tcp://5000
All other sections define the SECoP modules. The section name itself is the module name,
mandatory fields are **class** and **description**. **class** is a path to the Python class
from there the module is instantiated, separated with dots. In the following example the class
All other :ref:`Mod() <mod configuration>` sections define the SECoP modules.
Mandatory fields are **name**, **cls** and **description**. **cls** is a path to the Python class
from where the module is instantiated, separated with dots. In the following example the class
**HeLevel** used by the **helevel** module can be found in the PSI facility subdirectory
frappy_psi in the python module file ccu4.py:
.. code::
.. code:: python
[helevel]
class = frappy_psi.ccu4.HeLevel
description = this is the He level sensor of the main reservoir
empty = 380
empty.export = False
full = 0
full.export = False
Mod('helevel',
'frappy_psi.ccu4.HeLevel',
'this is the He level sensor of the main reservoir',
empty_length = Param(380, export=False),
full = Param(0, export=False))
It is highly recommended to use all lower case for the module name, as SECoP names have to be
unique despite of casing. In addition, parameters, properties and parameter properties might
be initialized in this section. In the above example **empty** and **full** are parameters,
be initialized in this section. In the above example **empty_length** and **full_length** are parameters,
the resistivity of the He Level sensor at the end of the ranges. In addition, we alter the
default property **export** of theses parameters, as we do not want to expose these parameters to
the SECoP interface.
@@ -54,12 +49,12 @@ The Frappy server can be started via the **bin/frappy-server** script.
.. parsed-literal::
usage: frappy-server [-h] [-v | -q] [-d] name
usage: bin/frappy-server [-h] [-v | -q] [-d] [-t] [-p port] [-c cfgfiles] name
Manage a Frappy server
positional arguments:
name name of the instance. Uses etc/name.cfg for configuration
name name of the instance. Uses <config path>/name_cfg.py for configuration
optional arguments:
-c, --cfgfiles config files to be used. Comma separated list.

83
doc/source/structure.rst Normal file
View File

@@ -0,0 +1,83 @@
Structure
---------
Node Structure
..............
Before starting to write the code for drivers, you have to think about
the node structure. What are the modules I want to create? What is to
be represented as a SECoP module, what as a parameter? At this point
you should not look what the hardware offers (e.g. channels A and B of
a temperature controller), but on what you need for doing an
experiment. Typically, each quantity you measure or control, has to
be represented by a module. You need module parameters for influencing
how you achieve or control the quantity. And you will need configurable
internal properties to configure the access to the hardware.
Examples:
- A temperature sensor, without an attached control loop, should inherit
from :class:`Readable <frappy.modules.Readable>`
- A temperature sensor with a control loop should inherit from
:class:`Drivable <frappy.modules.Drivable>`. You will need to implement a criterion for
deciding when the temperature is reached (e.g. tolerance and time window)
- If the heater power is a quantity of interest, it should be its own
module inheriting from :class:`Writable <frappy.modules.Writable>`.
- If it is a helium cryostat, you may want to implement a helium level
reading module inheriting from :class:`Readable <frappy.modules.Readable>`
.. _module structure parameters:
Module Structure: Parameters
............................
The next step is to determine which parameters we need in addition to
the standard ones given by the inherited class. As a temperature sensor
inherits from :class:`Readable <frappy.modules.Readable>`, it has already a ``value``
parameter representing the measured temperature. It has also a
``status`` parameter, indicating whether the measured temperature is
valid (``IDLE``), invalid (``ERROR``) or there might be a less
critical issue (``WARN``). In addition you might want additional
parameters, like an alarm threshold.
For the controlled temperature, in addition to above, inherited from
:class:`Drivable <frappy.modules.Drivable>` it has a writable ``target`` parameter.
In addition we might need control parameters or a changeable target limits.
For the heater you might want to have a changeable power limit or power range.
.. _module structure properties:
Module Structure: Properties
............................
For the access to the hardware, we will need internal properties for
configuring the hardware access. This might the IP address of a
LAN connection or the path of an internal serial device.
In Frappy, when inheriting from the mixin :class:`HasIO <frappy.io.HasIO>`,
either the property ``io`` referring to an explicitly configured
communicator or the ``uri`` property, generating a communicator with
the given uri can be used for this.
In addition, depending on the hardware probably you need a property to
configure the channel number or name assigned to the module.
For the heater output, you might need to configure the heater resistance.
Parameter Structure
...................
A parameter also has properties, which have to be set when declaring
the parameter. Even for the inherited parameters, often the properties
have to be overriden. For example, the ``unit`` property of the ``value``
parameter on the temperature sensor will be set to 'K', and the ``max``
property of the ``target`` parameter should be set to the maximum possible
value for the hardware. This value may then probably get more restricted
by an entry in the configuration file.

View File

@@ -5,3 +5,4 @@ Tutorial
:maxdepth: 2
tutorial_helevel
tutorial_t_control

View File

@@ -205,46 +205,50 @@ Before we continue coding, we may try out what we have coded and create a config
The directory tree of the Frappy framework contains the code for all drivers, but the
configuration file determines, which code will be loaded when a server is started.
We choose the name *example_cryo* and create therefore a configuration file
*example_cryo.cfg* in the *cfg* subdirectory:
*example_cryo_cfg.py* in the *cfg* subdirectory:
``cfg/example_cryo.cfg``:
``cfg/example_cryo_cfg.py``:
.. code:: ini
.. code:: python
[NODE]
description = this is an example cryostat for the Frappy tutorial
id = example_cryo.psi.ch
Node('example_cryo.psi.ch',
'this is an example cryostat for the Frappy tutorial',
interface='tcp://5000')
Mod('helev',
'frappy_psi.ccu4.HeLevel',
'He level of the cryostat He reservoir',
uri='linse-moxa-4.psi.ch:3001',
empty_length=380,
full_length=0)
[INTERFACE]
uri = tcp://5000
A configuration file contains a node configuration and one or several module configurations.
[helev]
description = He level of the cryostat He reservoir
class = frappy_psi.ccu4.HeLevel
uri = linse-moxa-4.psi.ch:3001
empty_length = 380
full_length = 0
*Node* describes the main properties of the SEC Node: an id and a description of the node
which should be globally unique, and an interface defining the address of the server,
usually the only important value here is the TCP port under which the server will be accessible.
Currently only tcp is supported.
A configuration file contains several sections with a header enclosed by rectangular brackets.
All the other sections define the SECoP modules to be used. This first arguments of *Mod(* are:
The *NODE* section describes the main properties of the SEC Node: a description of the node
and an id, which should be globally unique.
* the module name
* the python class to be used for the creation of the module
* a human readable description is its
The *INTERFACE* section defines the address of the server, usually the only important value
here is the TCP port under which the server will be accessible. Currently only tcp is
supported.
All the other sections define the SECoP modules to be used. A module section at least contains a
human readable *description*, and the Python *class* used. Other properties or parameter values may
follow, in this case the *uri* for the communication with the He level monitor and the values for
configuring the He Level sensor. We might also alter parameter properties, for example we may hide
Other properties or parameter values may follow, in this case the *uri* for the communication
with the He level monitor and the values for configuring the He Level sensor.
We might also alter parameter properties, for example we may hide
the parameters *empty_length* and *full_length* from the client by defining:
.. code:: ini
.. code:: python
empty_length.export = False
full_length.export = False
Mod('helev',
'frappy_psi.ccu4.HeLevel',
'He level of the cryostat He reservoir',
uri='linse-moxa-4.psi.ch:3001',
empty_length=Param(380, export=False),
full_length=Param(0, export=False))
However, we do not put this here, as it is nice to try out changing parameters for a test!
As we configure more than just an initial value, we have to call *Param* and give the
value as the first argument, and additional properties as keyworded arguments.
*to be continued*

View File

@@ -0,0 +1,412 @@
A Simple Temperature Controller
===============================
The Use Case
------------
Let us assume we have simple cryostat or furnace with one temperature sensor
and a heater. We want first to implement reading the temperature and then
add the control loop. Assume also we have a LakeShore temperature controller
to access the hardware.
Coding the Sensor Module
------------------------
A temperature sensor without control loop is to be implemented as a subclass
of :class:`Readable <frappy.modules.Readable>`. You create this example to be used in your
facility, so you add it to the subdirectory of your facility. You might need
to create it, if it is not already there. In this example, you may
replace *frappy_psi* by *frappy_<your facility>*. The name the python file
is chosen from the type of temperature controller *lakeshore.py*.
We assume that the temperature controller is already configured with input ``A``
being used, and the proper calibration curve assigned. In productive code
this configuration may also be done by Frappy, but this would extend the scope
of this tutorial too much.
So we define a class and define the parameter properties for the value:
``frappy_psi/lakeshore.py``:
.. code:: python
# the most common Frappy classes can be imported from frappy.core
from frappy.core import Readable, Parameter, FloatRange
class TemperatureSensor(Readable):
"""a temperature sensor (generic for different models)"""
# 1500 is the maximum T allowed for most of the lakeshore models
# this should be further restricted in the configuration (see below)
value = Parameter(datatype=FloatRange(0, 1500, unit='K'))
For the next step, we have to code how to retrieve the temperature
from the controller. For this we add the method ``read_value``.
In addition, we have to define a communicator class, and make
``TemperatureSensor`` inherit from :class:`HasIO <frappy.io.HasIO>`
in order to add the :meth:`communicate` method to the class.
See :ref:`lsc_manual_extract` for details of the needed commands.
.. code:: python
from frappy.core import Readable, Parameter, FloatRange, HasIO, StringIO, Property, StringType
class LakeshoreIO(StringIO):
wait_before = 0.05 # Lakeshore requires a wait time of 50 ms between commands
# '*IDN?' is sent on connect, and the reply is checked to match the regexp 'LSCI,.*'
identification = [('*IDN?', 'LSCI,.*')]
class TemperatureSensor(HasIO, Readable):
"""a temperature sensor (generic for different models)"""
# internal property to configure the channel
# see below for the difference of 'Property' and 'Parameter'
channel = Property('the Lakeshore channel', datatype=StringType())
# 0, 1500 is the allowed range by the LakeShore controller
# this should be further restricted in the configuration (see below)
value = Parameter(datatype=FloatRange(0, 1500, unit='K'))
def read_value(self):
# the communicate method sends a command and returns the reply
reply = self.communicate(f'KRDG?{self.channel}')
# convert to float
return float(reply)
This is the code to run a minimalistic SEC Node, which does just read a temperature
and nothing else.
.. Note::
A :class:`Property <frappy.properties.Property>` is used instead of a
:class:`Parameter <frappy.param.Parameter>`, for a configurable item not changing
on run time. A ``Property`` is typically only internal needed and by default not
visible by SECoP.
Before we start the frappy server for the first time, we have to create a configuration file.
The directory tree of the Frappy framework contains the code for all drivers but the
configuration file determines, which code will be loaded when a server is started.
We choose the name *example_cryo* and create therefore a configuration file
*example_cryo_cfg.py* in the *cfg* subdirectory:
``cfg/example_cryo_cfg.py``:
.. code:: python
Node('example_cryo.psi.ch', # a globally unique identification
'this is an example cryostat for the Frappy tutorial', # describes the node
interface='tcp://10767') # you might choose any port number > 1024
Mod('io', # the name of the module
'frappy_psi.lakeshore.LakeshoreIO', # the class used for communication
'communication to main controller', # a description
# the serial connection, including serial settings (see frappy.io.IOBase):
uri='serial://COM6:?baudrate=57600+parity=odd+bytesize=7',
)
Mod('T',
'frappy_psi.lakeshore.TemperatureSensor',
'Sample Temperature',
io='io', # refers to above defined module 'io'
channel='A', # the channel on the LakeShore for this module
value=Param(max=470), # alter the maximum expected T
)
The first section in the configuration file configures the common settings for the server.
:ref:`Node <node configuration>` describes the main properties of the SEC Node: an identifier,
which should be globally unique, a description of the node, and an interface defining the server address.
Usually the only important value in the server address is the TCP port under which the
server will be accessible. Currently only the tcp scheme is supported.
Then for each module a :ref:`Mod <mod configuration>` section follows.
We have to create the ``io`` module for communication first, with
the ``uri`` as its most important argument.
In case of a serial connection the prefix is ``serial://``. On a Windows machine, the full
uri is something like ``serial://COM6:?baudrate=9600`` on a linux system it might be
``serial:///dev/ttyUSB0?baudrate=9600``. In case of a LAN connection, the uri should
be something like ``tcp://129.129.138.78:7777`` or ``tcp://mydevice.psi.ch:7777``, where
7777 is the tcp port the LakeShore is listening to.
Now, we are ready to start our first server. In the main frappy directory, we
start it with:
.. code::
python bin/frappy-server example_cryo
If error messages appear, you have first to try to fix the errors.
Else you might open an other console or terminal, in order to start
a frappy client, for example the GUI client. The argument is
compose by the machine running the server and the server port chosen
in the configuration file:
.. code::
python bin/frappy-gui localhost:10767
A ``Readable`` SECoP module also has a status parameter. Until now, we completely
ignored it. As you may see, the value of status parameter is always ``(IDLE, '')``.
However, we should implement the status parameter to give information about the
validity of the sensor reading. The controller has a query command ``RDGST?<channel>``
returning a code describing error states. We implement this by adding a the
``read_status`` method to the class:
.. code:: python
from frappy.core import Readable, Parameter, FloatRange, HasIO, StringIO, Property, StringType,\
IDLE, ERROR
...
class TemperatureSensor(HasIO, Readable):
...
def read_status(self):
code = int(self.communicate(f'RDGST?{self.channel}'))
if code >= 128:
text = 'units overrange'
elif code >= 64:
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'
else:
return IDLE, ''
return ERROR, text
After a restart of the server and the client, the status should change to
``ERROR, '<some error message>'`` when the sensor is unplugged.
Extend the Class to a Temperature Loop
--------------------------------------
As we want to implement also temperature control, we have extend the class more.
Instead of adding just more methods to the ``TemperatureSensor`` class, we
create a new class ``TemperatureLoop`` inheriting from Temperature sensor.
This way, we would for example be able to create a node with a controlled
temperature on one channel, and a sensor module without control on an other channel.
Temperature control is represented by a subclass of :class:`Drivable <frappy.modules.Drivable>`.
So our new class will be based on ``TemperatureSensor`` where we have already
implemented the readable stuff. We need to define some properties of the ``target``
parameter and add a property ``loop`` indicating, which control loop and
heater output we use.
In addition, we have to implement the method ``write_target``. Remark: we do not
implement ``read_target`` here, because the lakeshore does not offer to read back the
real target. The SETP command is returning the working setpoint, which may be distinct
from target during a ramp.
.. code:: python
from frappy.core import Readable, Parameter, FloatRange, HasIO, StringIO, Property, StringType,\
IDLE, BUSY, WARN, ERROR, Drivable, IntRange
...
class TemperatureLoop(TemperatureSensor, Drivable):
# lakeshore loop number to be used for this module
loop = Property('lakeshore loop', IntRange(1, 2), default=1)
target = Parameter(datatype=FloatRange(unit='K', min=0, max=1500))
def write_target(self, target):
# we always use a request / reply scheme
self.communicate(f'SETP {self.loop},{target};*OPC?')
return target
In order to test this, we will need to change the entry module ``T`` in the
configuration file:
.. code:: python
Mod('T',
'frappy_psi.lakeshore.TemperatureLoop',
'Sample Temperature',
io='io',
channel='A', # the channel on the LakeShore for this module
loop=1, # the loop to be used
value=Param(max=470), # set the maximum expected T
target=Param(max=420), # set the maximum allowed target T
)
To test that this step worked, just restart the server and the client.
If the temperature controller is not yet configured for controlling the
temperature on channel A with loop 1, this has to be done first.
Especially the heater has to be switched on, setting the maximum heater
range.
There are two things still missing:
- We want to switch on the heater automatically, when the target is changed.
A property ``heater_range`` is added for this.
- We want to handle the status code correctly: set to ``BUSY`` when the
target is changed, and back to ``IDLE`` when the target temperature is reached.
The parameter ``tolerance`` is used for this. For the tutorial we use here
a rather simple mechanism. In reality, often over- or undershoot happens.
A better algorithm would not switch to IDLE before the temperature was within
tolerance for some given time.
.. code:: python
from frappy.core import Readable, Drivable, Parameter, FloatRange, \
HasIO, StringIO, IDLE, BUSY, WARN, ERROR
...
class TemperatureLoop(TemperatureSensor, Drivable):
...
heater_range = Property('heater power range', IntRange(0, 5)) # max. 3 on LakeShore 336
tolerance = Parameter('convergence criterion', FloatRange(0), default=0.1, readonly=False)
_driving = False
...
def write_target(self, target):
# reactivate heater in case it was switched off
self.communicate(f'RANGE {self.loop},{self.heater_range};RANGE?{self.loop}')
self.communicate(f'SETP {self.loop},{target};*OPC?')
self._driving = True
# Setting the status attribute triggers an update message for the SECoP status
# parameter. This has to be done before returning from this method!
self.status = BUSY, 'target changed'
return target
...
def read_status(self):
code = int(self.communicate(f'RDGST?{self.channel}'))
if code >= 128:
text = 'units overrange'
elif code >= 64:
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:
return BUSY, 'approaching setpoint'
return WARN, 'temperature out of tolerance'
else: # within tolerance: simple convergence criterion
self._driving = False
return IDLE, ''
return ERROR, text
Finally, the config file would be:
``cfg/example_cryo_cfg.py``:
.. code:: python
Node('example_cryo.psi.ch', # a globally unique identification
'this is an example cryostat for the Frappy tutorial', # describes the node
interface='tcp://10767') # you might choose any port number > 1024
Mod('io', # the name of the module
'frappy_psi.lakeshore.LakeshoreIO', # the class used for communication
'communication to main controller', # a description
uri='serial://COM6:?baudrate=57600+parity=odd+bytesize=7', # the serial connection
)
Mod('T',
'frappy_psi.lakeshore.TemperatureLoop',
'Sample Temperature',
io='io',
channel='A', # the channel on the LakeShore for this module
loop=1, # the loop to be used
value=Param(max=470), # set the maximum expected T
target=Param(max=420), # set the maximum allowed target T
heater_range=3, # 5 for model 350
)
Now, you should try again restarting the server and the client, if it works, you have done a good job!
If not, you might need to fix the code first ...
More Complex Configurations
...........................
Without coding any more class, much more complex situations might be realized just by
extending the configuration. Using a single LakeShore controller, you might add more
temperature sensors or (in the case of Model 336 or 350) even a second temperature loop,
just by adding more ``Mod(`` sections to the configuration file. In case more than 4 channels
are needed, an other module ``io2`` has to be added for the second controller and so on.
Appendix 1: The Solution
------------------------
You will find the full solution code via the ``[source]`` link in the automatic
created documentation of the class :class:`frappy_demo.lakeshore.TemperatureLoop`.
.. _lsc_manual_extract:
Appendix 2: Extract from the LakeShore Manual
---------------------------------------------
.. table:: commands used in this tutorial
====================== =======================
**Query Identification**
----------------------------------------------
Command \*IDN? *term*
Reply <manufacturer>,<model>,<instrument serial>/<option serial>, <firmware version> *term*
Example LSCI,MODEL336,1234567/1234567,1.0
**Query Kelvin Reading for an Input**
----------------------------------------------
Command KRDG?<input> *term*
Example KRDG?A
Reply <kelvin value> *term*
Example +273.15
**Query Input Status**
----------------------------------------------
Command RDGST?<input> *term*
Reply <status bit weighting> *term*
Description The integer returned represents the sum of the bit weighting \
of the input status flag bits. A “000” response indicates a valid reading is present.
Bit / Value Status
0 / 1 invalid reading
1 / 2 old reading (Model 340 only)
4 / 16 temperature underrange
5 / 32 temperature overrange
6 / 64 sensor units zero
7 / 128 sensor units overrange
**Set Control Loop Setpoint**
----------------------------------------------
Command SETP <loop>,<value> *term*
Example SETP 1,273.15
**Query Control Loop Setpoint**
----------------------------------------------
Command SETP?<loop> *term*
Reply <value> *term*
Example +273.15
**Set Heater Range**
----------------------------------------------
Command (340) RANGE <range number> *term*
Command (336/350) RANGE <loop>,<range number> *term*
Description 0: heater off, 1-5: heater range (Model 336: 1-3)
**Query Heater Range**
----------------------------------------------
Command (340) RANGE? *term*
Command (336/350) RANGE?<loop> *term*
Reply <range> *term*
**Operation Complete Query**
----------------------------------------------
Command \*OPC?
Reply 1
Description in Frappy, we append this command to request in order
to generate a reply
====================== =======================

View File

@@ -1,7 +1,6 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# *****************************************************************************
# Copyright (c) 2015-2019 by the authors, see LICENSE
# Copyright (c) 2015-2024 by the authors, see LICENSE
#
# 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
@@ -39,8 +38,8 @@ def main():
frappy_unit = '/lib/systemd/system/frappy@.service'
wants_dir = normal_dir + '/frappy.target.wants'
all_servers = [base for (base, ext) in
map(path.splitext, os.listdir(config_dir)) if ext == '.cfg']
all_servers = [base[:-4] if base.endswith('_cfg') else base for (base, ext) in
map(path.splitext, os.listdir(config_dir)) if ext == '.py']
all_servers.sort()
for srv in all_servers:

4
etc/generalConfig.cfg Normal file
View File

@@ -0,0 +1,4 @@
[FRAPPY]
logdir = /var/log
piddir = /var/run/frappy
confdir = /etc/frappy

View File

@@ -1,6 +1,5 @@
# -*- coding: utf-8 -*-
# *****************************************************************************
# Copyright (c) 2015-2016 by the authors, see LICENSE
# Copyright (c) 2015-2024 by the authors, see LICENSE
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# *****************************************************************************
#
# This program is free software; you can redistribute it and/or modify it under
@@ -23,33 +22,34 @@
# *****************************************************************************
"""general SECoP client"""
import re
import json
import queue
import re
import time
from collections import defaultdict
from threading import Event, RLock, current_thread
import frappy.errors
import frappy.params
from frappy.datatypes import get_datatype
from frappy.errors import HardwareError, SECoPError, WrongTypeError, \
make_secop_error
from frappy.lib import mkthread
from frappy.lib.asynconn import AsynConn, ConnectionClosed
from frappy.protocol.interface import decode_msg, encode_msg_frame
from frappy.protocol.messages import COMMANDREQUEST, \
DESCRIPTIONREQUEST, ENABLEEVENTSREQUEST, ERRORPREFIX, \
EVENTREPLY, HEARTBEATREQUEST, IDENTPREFIX, IDENTREQUEST, \
READREPLY, READREQUEST, REQUEST2REPLY, WRITEREPLY, WRITEREQUEST
from frappy.protocol.messages import COMMANDREQUEST, DESCRIPTIONREQUEST, \
ENABLEEVENTSREQUEST, ERRORPREFIX, EVENTREPLY, HEARTBEATREQUEST, \
IDENTPREFIX, IDENTREQUEST, READREPLY, READREQUEST, REQUEST2REPLY, \
WRITEREPLY, WRITEREQUEST
# replies to be handled for cache
UPDATE_MESSAGES = {EVENTREPLY, READREPLY, WRITEREPLY, ERRORPREFIX + READREQUEST, ERRORPREFIX + EVENTREPLY}
VERSIONFMT= re.compile(r'^[^,]*?ISSE[^,]*,SECoP,')
VERSIONFMT = re.compile(r'^[^,]*?ISSE[^,]*,SECoP,')
class UNREGISTER:
"""a magic value, used a returned value in a callback
to indicate it has to be unregistered
class UnregisterCallback(Exception):
"""raise in a callback to indicate it has to be unregistered
used to implement one shot callbacks
"""
@@ -66,7 +66,11 @@ class Logger:
pass
debug = noop
error = warning = critical = info
error = exception = warning = critical = info
class NullLogger(Logger):
error = exception = warning = critical = info = Logger.noop
class CallbackObject:
@@ -75,15 +79,23 @@ class CallbackObject:
this is mainly for documentation, but it might be extended
and used as a mixin for objects registered as a callback
"""
def updateEvent(self, module, parameter, value, timestamp, readerror):
def updateItem(self, module, parameter, item):
"""called whenever a value is changed
or when new callbacks are registered
:param module: the module name
:param parameter: the parameter name
:param item: a CacheItem object
"""
def unhandledMessage(self, action, ident, data):
"""called on an unhandled message"""
def handleError(self, exc):
"""called on errors handling messages
:param exc: the exception raised (= sys.exception())
"""
def nodeStateChange(self, online, state):
"""called when the state of the connection changes
@@ -98,57 +110,157 @@ class CallbackObject:
and on every changed module with module==<module name>
"""
def updateEvent(self, module, parameter, value, timestamp, readerror):
"""legacy method: called whenever a value is changed
or when new callbacks are registered
"""
class CacheItem(tuple):
"""cache entry
includes formatting information
inheriting from tuple: compatible with old previous version of cache
"""
def __new__(cls, value, timestamp=None, readerror=None, datatype=None):
obj = tuple.__new__(cls, (value, timestamp, readerror))
if datatype:
try:
# override default methods
obj.format_value = datatype.format_value
obj.to_string = datatype.to_string
except AttributeError:
pass
return obj
@property
def value(self):
return self[0]
@property
def timestamp(self):
return self[1]
@property
def readerror(self):
return self[2]
def __str__(self):
"""format value without unit
may be used in this form for SecopClient.setParameterFromString
"""
if self[2]: # readerror
return repr(self[2])
return self.to_string(self[0])
def formatted(self):
"""format value with using unit
nicer format for humans, hard to parse
"""
if self[2]: # readerror
return repr(self[2])
return self.format_value(self[0])
@staticmethod
def format_value(value):
"""typically overridden with datatype.format_value"""
return str(value)
@staticmethod
def to_string(value):
"""typically overridden with datatype.to_string"""
return str(value)
def __repr__(self):
args = (self.value,)
if self.timestamp:
args += (self.timestamp,)
if self.readerror:
args += (self.readerror,)
return f'CacheItem{args!r}'
class Cache(dict):
class Undefined(Exception):
def __repr__(self):
return '<undefined>'
undefined = CacheItem(None, None, Undefined())
def __missing__(self, key):
return self.undefined
class ProxyClient:
"""common functionality for proxy clients"""
CALLBACK_NAMES = ('updateEvent', 'descriptiveDataChange', 'nodeStateChange', 'unhandledMessage')
CALLBACK_NAMES = {'updateEvent', 'updateItem', 'descriptiveDataChange',
'nodeStateChange', 'unhandledMessage', 'handleError'}
online = False # connected or reconnecting since a short time
validate_data = False
state = 'disconnected' # further possible values: 'connecting', 'reconnecting', 'connected'
log = None
def __init__(self):
self.callbacks = {cbname: defaultdict(list) for cbname in self.CALLBACK_NAMES}
# caches (module, parameter) = value, timestamp, readerror (internal names!)
self.cache = {}
self.cache = Cache() # dict returning Cache.undefined for missing keys
def register_callback(self, key, *args, **kwds):
def register_callback(self, key, *args, callimmediately=True, **kwds):
"""register callback functions
- key might be either:
several callbacks might be registered within one call.
ProxyClient.CALLBACK_NAMES contains all names of valid callbacks
:param key: might be either:
1) None: general callback (all callbacks)
2) <module name>: callbacks related to a module (not called for 'unhandledMessage')
3) (<module name>, <parameter name>): callback for specified parameter (only called for 'updateEvent')
- all the following arguments are callback functions. The callback name may be
given by the keyword, or, for non-keyworded arguments it is taken from the
__name__ attribute of the function
3) (<module name>, <parameter name>): callback for specified parameter
(only called for 'updateEvent' and 'updateItem')
:param args: callback functions. the callback name is taken from the the __name__ attribute of the function
:param callimmediately: True (default): call immediately for updateItem and updateEvent callbacks
:param kwds: callback functions. the callback name is taken from the key
"""
for cbfunc in args:
kwds[cbfunc.__name__] = cbfunc
for cbname in self.CALLBACK_NAMES:
cbfunc = kwds.pop(cbname, None)
if not cbfunc:
continue
cbdict = self.callbacks[cbname]
cbdict[key].append(cbfunc)
for cbname, cbfunc in kwds.items():
if cbname not in self.CALLBACK_NAMES:
raise TypeError(f"unknown callback: {', '.join(kwds)}")
# immediately call for some callback types
if cbname == 'updateEvent':
if key is None:
for (mname, pname), data in self.cache.items():
cbfunc(mname, pname, *data)
# call immediately for some callback types
if cbname in ('updateItem', 'updateEvent') and callimmediately:
if key is None: # case generic callback
cbargs = [(m, p, d) for (m, p), d in self.cache.items()]
else:
data = self.cache.get(key, None)
if data:
cbfunc(*key, *data) # case single parameter
if data: # case single parameter
cbargs = [key + (data,)]
else: # case key = module
for (mname, pname), data in self.cache.items():
if mname == key:
cbfunc(mname, pname, *data)
cbargs = [(m, p, d) for (m, p), d in self.cache.items() if m == key]
if cbname == 'updateEvent':
# expand entry argument to (value, timestamp, readerror)
cbargs = [a[0:2] + a[2] for a in cbargs]
elif cbname == 'nodeStateChange':
cbfunc(self.online, self.state)
if kwds:
raise TypeError('unknown callback: %s' % (', '.join(kwds)))
cbargs = [(self.online, self.state)]
else:
cbargs = []
do_append = True
for args in cbargs:
try:
cbfunc(*args)
except UnregisterCallback:
do_append = False
except Exception as e:
if self.log:
self.log.error('error %r calling %s%r', e, cbfunc.__name__, args)
if do_append:
self.callbacks[cbname][key].append(cbfunc)
def unregister_callback(self, key, *args, **kwds):
"""unregister a callback
@@ -172,20 +284,21 @@ class ProxyClient:
key=(<module name>, <parameter name): callbacks for specified parameter
"""
cblist = self.callbacks[cbname].get(key, [])
self.callbacks[cbname][key] = [cb for cb in cblist if cb(*args) is not UNREGISTER]
for cbfunc in list(cblist):
try:
cbfunc(*args)
except UnregisterCallback:
cblist.remove(cbfunc)
except Exception as e:
if cbname != 'handleError':
try:
e.args = [f'error in callback {cbname}{args}: {e}']
self.callback(None, 'handleError', e)
except Exception:
pass
return bool(cblist)
def updateValue(self, module, param, value, timestamp, readerror):
if readerror:
assert isinstance(readerror, Exception)
if self.validate_data:
try:
# try to validate, reason: make enum_members from integers
datatype = self.modules[module]['parameters'][param]['datatype']
value = datatype(value)
except (KeyError, ValueError):
pass
self.cache[(module, param)] = (value, timestamp, readerror)
self.callback(None, 'updateEvent', module, param, value, timestamp, readerror)
self.callback(module, 'updateEvent', module, param, value, timestamp, readerror)
self.callback((module, param), 'updateEvent', module, param, value, timestamp, readerror)
@@ -195,7 +308,6 @@ class SecopClient(ProxyClient):
"""a general SECoP client"""
reconnect_timeout = 10
_running = False
_shutdown = False
_rxthread = None
_txthread = None
_connthread = None
@@ -204,8 +316,17 @@ class SecopClient(ProxyClient):
descriptive_data = {}
modules = {}
_last_error = None
_update_error_count = 0
_max_error_count = 10
def __init__(self, uri, log=Logger):
"""initialize SecopClient
:param uri: the uri to connect to
:param log: a logger.
when not given, the print command is used for messages with at least info level.
when None, nothing is logged at all
"""
super().__init__()
# maps expected replies to [request, Event, is_error, result] until a response came
# there can only be one entry per thread calling 'request'
@@ -213,14 +334,21 @@ class SecopClient(ProxyClient):
self.io = None
self.txq = queue.Queue(30) # queue for tx requests
self.pending = queue.Queue(30) # requests with colliding action + ident
self.log = log
self.log = log or NullLogger
self.uri = uri
self.nodename = uri
self._lock = RLock()
self._shutdown = Event()
self.cleanup = []
self.register_callback(None, self.handleError)
def __del__(self):
# make sure threads are stopping. this is needed in case
# a frappy client object is lost without calling .disconnect()
try:
self.disconnect()
# avoid callbacks when deleting. may cause deadlocks in NICOS
self.callbacks.clear()
self.disconnect(True)
except Exception:
pass
@@ -232,12 +360,17 @@ class SecopClient(ProxyClient):
with self._lock:
if self.io:
return
self._shutdown.clear()
self.txq = queue.Queue(30)
self.pending = queue.Queue(30)
self.active_requests.clear()
self.cleanup.clear()
if self.online:
self._set_state(True, 'reconnecting')
else:
self._set_state(False, 'connecting')
deadline = time.time() + try_period
while not self._shutdown:
while not self._shutdown.is_set():
try:
self.io = AsynConn(self.uri) # timeout 1 sec
self.io.writeline(IDENTREQUEST.encode('utf-8'))
@@ -245,16 +378,15 @@ class SecopClient(ProxyClient):
if reply:
self.secop_version = reply.decode('utf-8')
else:
raise self.error_map('HardwareError')('no answer to %s' % IDENTREQUEST)
raise HardwareError(f'no answer to {IDENTREQUEST}')
if not VERSIONFMT.match(self.secop_version):
raise self.error_map('HardwareError')('bad answer to %s: %r' %
(IDENTREQUEST, self.secop_version))
raise HardwareError(f'bad answer to {IDENTREQUEST}: {self.secop_version!r}')
# inform that the other party still uses a legacy identifier
# see e.g. Frappy Bug #4659 (https://forge.frm2.tum.de/redmine/issues/4659)
if not self.secop_version.startswith(IDENTPREFIX):
self.log.warning('SEC-Node replied with legacy identify reply: %s'
% self.secop_version)
self.log.warning('SEC-Node replied with legacy identify reply: %s',
self.secop_version)
# now its safe to do secop stuff
self._running = True
@@ -265,6 +397,7 @@ class SecopClient(ProxyClient):
self._init_descriptive_data(self.request(DESCRIPTIONREQUEST)[2])
self.nodename = self.properties.get('equipment_id', self.uri)
if self.activate:
self._set_state(True, 'activating')
self.request(ENABLEEVENTSREQUEST)
self._set_state(True, 'connected')
break
@@ -274,8 +407,8 @@ class SecopClient(ProxyClient):
# stay online for now, if activated
self._set_state(self.online and self.activate)
raise
time.sleep(1)
if not self._shutdown:
self._shutdown.wait(1)
if not self._shutdown.is_set():
self.log.info('%s ready', self.nodename)
def __txthread(self):
@@ -302,8 +435,15 @@ class SecopClient(ProxyClient):
def __rxthread(self):
noactivity = 0
shutdown = False
try:
while self._running:
while self.cleanup:
entry = self.cleanup.pop()
for key, prev in self.active_requests.items():
if prev is entry:
self.active_requests.pop(key)
break
# may raise ConnectionClosed
reply = self.io.readline()
if reply is None:
@@ -312,34 +452,42 @@ class SecopClient(ProxyClient):
# send ping to check if the connection is still alive
self.queue_request(HEARTBEATREQUEST, str(noactivity))
continue
self.log.debug('RX: %r', reply)
noactivity = 0
action, ident, data = decode_msg(reply)
if ident == '.':
ident = None
if action in UPDATE_MESSAGES:
module_param = self.internal.get(ident, None)
if module_param is None and ':' not in ident:
# allow missing ':value'/':target'
if action == WRITEREPLY:
module_param = self.internal.get(ident + ':target', None)
else:
module_param = self.internal.get(ident + ':value', None)
if module_param is not None:
if action.startswith(ERRORPREFIX):
timestamp = data[2].get('t', None)
readerror = frappy.errors.make_secop_error(*data[0:2])
value = None
else:
timestamp = data[1].get('t', None)
value = data[0]
readerror = None
module, param = module_param
try:
try:
action, ident, data = decode_msg(reply)
if ident == '.':
ident = None
if action in UPDATE_MESSAGES:
module_param = self.internal.get(ident, None)
if module_param is None and ':' not in (ident or ''):
# allow missing ':value'/':target'
if action == WRITEREPLY:
module_param = self.internal.get(f'{ident}:target', None)
else:
module_param = self.internal.get(f'{ident}:value', None)
if module_param is not None:
now = time.time()
if action.startswith(ERRORPREFIX):
timestamp = data[2].get('t', now)
readerror = make_secop_error(*data[0:2])
value = None
else:
timestamp = data[1].get('t', now)
value = data[0]
readerror = None
module, param = module_param
timestamp = min(now, timestamp) # no timestamps in the future!
self.updateValue(module, param, value, timestamp, readerror)
except KeyError:
pass # ignore updates of unknown parameters
if action in (EVENTREPLY, ERRORPREFIX + EVENTREPLY):
continue
if action in (EVENTREPLY, ERRORPREFIX + EVENTREPLY):
continue
except Exception as e:
e.args = (f'error handling SECoP message {reply!r}: {e}',)
try:
self.callback(None, 'handleError', e)
except Exception:
pass
continue
try:
key = action, ident
entry = self.active_requests.pop(key)
@@ -366,17 +514,19 @@ class SecopClient(ProxyClient):
except ConnectionClosed:
pass
except Exception as e:
self.log.error('rxthread ended with %r', e)
self._rxthread = None
self.disconnect(False)
if self._shutdown:
return
if self.activate:
self.log.info('try to reconnect to %s', self.uri)
self._connthread = mkthread(self._reconnect)
else:
self.log.warning('%s disconnected', self.uri)
self._set_state(False, 'disconnected')
shutdown = True
self.callback(None, 'handleError', e)
finally:
self._rxthread = None
self.disconnect(shutdown)
if self._shutdown.is_set():
pass
elif self.activate:
self.log.info('try to reconnect to %s', self.uri)
self._connthread = mkthread(self._reconnect)
else:
self.log.warning('%s disconnected', self.uri)
self._set_state(False, 'disconnected')
def spawn_connect(self, connected_callback=None):
"""try to connect in background
@@ -387,7 +537,7 @@ class SecopClient(ProxyClient):
self._connthread = mkthread(self._reconnect, connected_callback)
def _reconnect(self, connected_callback=None):
while not self._shutdown:
while not self._shutdown.is_set():
try:
self.connect()
if connected_callback:
@@ -407,15 +557,15 @@ class SecopClient(ProxyClient):
self.log.info('continue trying to reconnect')
# self.log.warning(formatExtendedTraceback())
self._set_state(False)
time.sleep(self.reconnect_timeout)
self._shutdown.wait(self.reconnect_timeout)
else:
time.sleep(1)
self._shutdown.wait(1)
self._connthread = None
def disconnect(self, shutdown=True):
self._running = False
if shutdown:
self._shutdown = True
self._shutdown.set()
self._set_state(False, 'shutdown')
if self._connthread:
if self._connthread == current_thread():
@@ -429,6 +579,8 @@ class SecopClient(ProxyClient):
self.txq.get(False)
except Exception:
pass
if self.io:
self.io.shutdown()
if self._txthread:
self.txq.put(None) # shutdown marker
self._txthread.join()
@@ -478,7 +630,7 @@ class SecopClient(ProxyClient):
iname = self.internalize_name(aname)
datatype = get_datatype(aentry['datainfo'], iname)
aentry = dict(aentry, datatype=datatype)
ident = '%s:%s' % (modname, aname)
ident = f'{modname}:{aname}'
self.identifier[modname, iname] = ident
self.internal[ident] = modname, iname
if datatype.IS_COMMAND:
@@ -486,8 +638,8 @@ class SecopClient(ProxyClient):
else:
parameters[iname] = aentry
properties = {k: v for k, v in moddescr.items() if k != 'accessibles'}
self.modules[modname] = dict(accessibles=accessibles, parameters=parameters,
commands=commands, properties=properties)
self.modules[modname] = {'accessibles': accessibles, 'parameters': parameters,
'commands': commands, 'properties': properties}
if changed_modules is not None:
done = done_main = self.callback(None, 'descriptiveDataChange', None, self)
for mname in changed_modules:
@@ -502,6 +654,13 @@ class SecopClient(ProxyClient):
if not self.callback(None, 'unhandledMessage', action, ident, data):
self.log.warning('unhandled message: %s %s %r', action, ident, data)
def handleError(self, exc):
if self._update_error_count < self._max_error_count:
self.log.exception('%s', exc)
self._update_error_count += 1
if self._update_error_count == self._max_error_count:
self.log.error('disabled reporting of further update errors')
def _set_state(self, online, state=None):
# remark: reconnecting is treated as online
self.online = online
@@ -522,13 +681,16 @@ class SecopClient(ProxyClient):
def get_reply(self, entry):
"""wait for reply and return it"""
if not entry[1].wait(10): # event
self.cleanup.append(entry)
raise TimeoutError('no response within 10s')
if not entry[2]: # reply
if self._shutdown.is_set():
raise ConnectionError('connection shut down')
# no cleanup needed as self.active_requests will be cleared on connect
raise ConnectionError('connection closed before reply')
action, _, data = entry[2] # pylint: disable=unpacking-non-sequence
if action.startswith(ERRORPREFIX):
errcls = self.error_map(data[0])
raise errcls(data[1])
raise make_secop_error(*data[0:2])
return entry[2] # reply
def request(self, action, ident=None, data=None):
@@ -543,9 +705,14 @@ class SecopClient(ProxyClient):
"""forced read over connection"""
try:
self.request(READREQUEST, self.identifier[module, parameter])
except frappy.errors.SECoPError:
# error reply message is already stored as readerror in cache
pass
except SECoPError as e:
result = self.cache[module, parameter]
if e == result.readerror:
# the update was already done in the rx thread
return result
# e was not originating from a secop error message e.g. a connection problem
# -> we have to do the error update
self.updateValue(module, parameter, None, time.time(), e)
return self.cache.get((module, parameter), None)
def getParameter(self, module, parameter, trycache=False):
@@ -564,6 +731,17 @@ class SecopClient(ProxyClient):
self.request(WRITEREQUEST, self.identifier[module, parameter], value)
return self.cache[module, parameter]
def setParameterFromString(self, module, parameter, formatted):
"""set parameter from string
formatted is a string in the form obtained by str(<cache item>)
"""
self.connect() # make sure we are connected
datatype = self.modules[module]['parameters'][parameter]['datatype']
value = datatype.export_value(datatype.from_string(formatted))
self.request(WRITEREQUEST, self.identifier[module, parameter], value)
return self.cache[module, parameter]
def execCommand(self, module, command, argument=None):
self.connect() # make sure we are connected
datatype = self.modules[module]['commands'][command]['datatype'].argument
@@ -571,7 +749,7 @@ class SecopClient(ProxyClient):
argument = datatype.export_value(argument)
else:
if argument is not None:
raise frappy.errors.BadValueError('command has no argument')
raise WrongTypeError('command has no argument')
# pylint: disable=unsubscriptable-object
data, qualifiers = self.request(COMMANDREQUEST, self.identifier[module, command], argument)[2]
datatype = self.modules[module]['commands'][command]['datatype'].result
@@ -579,17 +757,47 @@ class SecopClient(ProxyClient):
data = datatype.import_value(data)
return data, qualifiers
def execCommandFromString(self, module, command, formatted_argument=''):
"""call command from string argument
return data as CacheItem which allows to get
- result.value # the python value
- result.formatted() # a string (incl. units)
- result.timestamp
"""
self.connect()
datatype = self.modules[module]['commands'][command]['datatype'].argument
if datatype:
argument = datatype.from_string(formatted_argument)
else:
if formatted_argument:
raise WrongTypeError('command has no argument')
argument = None
# pylint: disable=unsubscriptable-object
data, qualifiers = self.request(COMMANDREQUEST, self.identifier[module, command], argument)[2]
datatype = self.modules[module]['commands'][command]['datatype'].result
value = datatype.import_value(data) if datatype else None
return CacheItem(value, qualifiers.get('t'), None, datatype)
def updateValue(self, module, param, value, timestamp, readerror):
datatype = self.modules[module]['parameters'][param]['datatype']
if readerror:
assert isinstance(readerror, Exception)
else:
value = datatype.import_value(value)
entry = CacheItem(value, timestamp, readerror, datatype)
self.cache[(module, param)] = entry
self.callback(None, 'updateItem', module, param, entry)
self.callback(module, 'updateItem', module, param, entry)
self.callback((module, param), 'updateItem', module, param, entry)
# TODO: change clients to use updateItem instead of updateEvent
super().updateValue(module, param, value, timestamp, readerror)
# the following attributes may be/are intended to be overwritten by a subclass
ERROR_MAP = frappy.errors.EXCEPTIONS
DEFAULT_EXCEPTION = frappy.errors.SECoPError
PREDEFINED_NAMES = set(frappy.params.PREDEFINED_ACCESSIBLES)
activate = True
def error_map(self, exc):
"""how to convert SECoP and unknown exceptions"""
return self.ERROR_MAP.get(exc, self.DEFAULT_EXCEPTION)
def internalize_name(self, name):
"""how to create internal names"""
if name.startswith('_') and name[1:] not in self.PREDEFINED_NAMES:

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# *****************************************************************************
#
# This program is free software; you can redistribute it and/or modify it under
@@ -24,54 +23,77 @@
import sys
import time
import re
from queue import Queue
from frappy.client import SecopClient
import code
import signal
import os
import traceback
import threading
import logging
from os.path import expanduser
from frappy.lib import delayed_import
from frappy.client import SecopClient, UnregisterCallback
from frappy.errors import SECoPError
from frappy.datatypes import get_datatype
from frappy.datatypes import get_datatype, StatusType
readline = delayed_import('readline')
USAGE = """
Usage:
{client_assign}
# for all SECoP modules objects are created in the main namespace
from frappy.client.interactive import Client
<module> # list all parameters
<module>.<param> = <value> # change parameter
<module>(<target>) # set target and wait until not busy
# 'status' and 'value' changes are shown every 1 sec
{client_name}.mininterval = 0.2 # change minimal update interval to 0.2 s (default is 1 s)
client = Client('localhost:5000') # start client.
# this connects and creates objects for all SECoP modules in the main namespace
<module> # list all parameters
<module>.<param> = <value> # change parameter
<module>(<target>) # set target and wait until not busy
# 'status' and 'value' changes are shown every 1 sec
client.mininterval = 0.2 # change minimal update interval to 0.2 sec (default is 1 second)
<module>.watch(1) # watch changes of all parameters of a module
<module>.watch(0) # remove all watching
<module>.watch(status=1, value=1) # add 'status' and 'value' to watched parameters
<module>.watch(value=0) # remove 'value' from watched parameters
"""
main = sys.modules['__main__']
watch(T) # watch changes of T.status and T.value (stop with ctrl-C)
watch(T='status target') # watch status and target parameters
watch(io, T=True) # watch io and all parameters of T
{tail}"""
class Logger:
def __init__(self, loglevel='info'):
func = self.noop
for lev in 'debug', 'info', 'warning', 'error':
if lev == loglevel:
func = self.emit
setattr(self, lev, func)
self._minute = 0
LOG_LEVELS = {
'debug': logging.DEBUG,
'comlog': logging.DEBUG+1,
'info': logging.INFO,
'warning': logging.WARN,
'error': logging.ERROR,
'off': logging.ERROR+1}
CLR = '\r\x1b[K' # code to move to the left and clear current line
def emit(self, fmt, *args, **kwds):
now = time.time()
minute = now // 60
if minute != self._minute:
self._minute = minute
print(time.strftime('--- %H:%M:%S ---', time.localtime(now)))
print('%6.3f' % (now % 60.0), str(fmt) % args)
@staticmethod
def noop(fmt, *args, **kwds):
pass
class Handler(logging.StreamHandler):
def emit(self, record):
super().emit(record)
if clientenv.sigwinch:
# SIGWINCH: 'window size has changed' -> triggers a refresh of the input line
os.kill(os.getpid(), signal.SIGWINCH)
class Logger(logging.Logger):
show_time = False
_minute = None
def __init__(self, name, loglevel='info'):
super().__init__(name, LOG_LEVELS.get(loglevel, logging.INFO))
handler = Handler()
handler.formatter = logging.Formatter('%(asctime)s%(message)s')
handler.formatter.formatTime = self.format_time
self.addHandler(handler)
def format_time(self, record, datefmt=None):
if self.show_time:
now = record.created
tm = time.localtime(now)
sec = f'{now % 60.0:6.3f}'.replace(' ', '0')
if tm.tm_min == self._minute:
return f'{CLR}{sec} '
self._minute = tm.tm_min
return f"{CLR}{time.strftime('--- %H:%M:%S ---', tm)}\n{sec} "
return ''
class PrettyFloat(float):
@@ -82,7 +104,7 @@ class PrettyFloat(float):
- always display a decimal point
"""
def __repr__(self):
result = '%.12g' % self
result = f'{self:.12g}'
if '.' in result or 'e' in result:
return result
return result + '.'
@@ -96,36 +118,35 @@ class Module:
self._secnode = secnode
self._parameters = list(secnode.modules[name]['parameters'])
self._commands = list(secnode.modules[name]['commands'])
self._running = None
if 'communicate' in self._commands:
self._watched_params = {}
self._log_level = 'comlog'
else:
self._watched_params = {'value', 'status'}
self._log_level = 'info'
self._is_driving = False
self._driving_event = threading.Event()
self._status = None
props = secnode.modules[name]['properties']
self._title = '# %s (%s)' % (props.get('implementation', ''), props.get('interface_classes', [''])[0])
self._title = f"# {props.get('implementation', '')} ({(props.get('interface_classes') or ['Module'])[0]})"
def _one_line(self, pname, minwid=0):
"""return <module>.<param> = <value> truncated to one line"""
param = getattr(type(self), pname)
try:
value = getattr(self, pname)
r = param.format(value)
except Exception as e:
r = repr(e)
result = param.formatted(self)
pname = pname.ljust(minwid)
vallen = 113 - len(self._name) - len(pname)
if len(r) > vallen:
r = r[:vallen - 4] + ' ...'
return '%s.%s = %s' % (self._name, pname, r)
if len(result) > vallen:
result = result[:vallen - 4] + ' ...'
return f'{self._name}.{pname} = {result}'
def _isBusy(self):
return 300 <= self.status[0] < 400
return self.status[0] // 100 == StatusType.BUSY // 100
def _status_value_update(self, m, p, status, t, e):
if self._running:
try:
self._running.put(True)
if self._running and not self._isBusy():
self._running.put(False)
except TypeError: # may happen when _running is removed during above lines
pass
def _status_update(self, m, p, status, t, e):
if self._is_driving and not self._isBusy():
self._is_driving = False
self._driving_event.set()
def _watch_parameter(self, m, pname, *args, forced=False, mininterval=0):
"""show parameter update"""
@@ -139,59 +160,111 @@ class Module:
pobj.prev = value
pobj.prev_time = now
def watch(self, *args, **kwds):
enabled = {}
for arg in args:
if arg == 1: # or True
enabled.update({k: True for k in self._parameters})
elif arg == 0: # or False
enabled.update({k: False for k in self._parameters})
def _set_watching(self, watch_list=None):
"""set parameters for watching and log levels
:param watch_list: items to be watched
True or 1: watch all parameters
a string from LOG_LEVELS: change the log level
any other string: convert space separated string to a list of strings
a list of string: parameters to be watched or log_level to be set
"""
if isinstance(watch_list, str):
if watch_list in LOG_LEVELS:
self._log_level = watch_list
watch_list = None
else:
enabled.update(arg)
enabled.update(kwds)
for pname, enable in enabled.items():
# accept also space separated list instead of list of strings
watch_list = watch_list.split()
elif isinstance(watch_list, int): # includes also True
watch_list = self._parameters if watch_list else ()
if watch_list is not None:
params = []
for item in watch_list:
if item in self._parameters:
params.append(item)
elif item in LOG_LEVELS:
self._log_level = item
else:
self._secnode.log.error('can not set %r on module %s', item, self._name)
self._watched_params = params
print(f"--- {self._name}:\nlog: {self._log_level}, watch: {' '.join(self._watched_params)}")
def _start_watching(self):
for pname in self._watched_params:
self._watch_parameter(self, pname, forced=True)
self._secnode.register_callback((self._name, pname), updateEvent=self._watch_parameter)
self._secnode.request('logging', self._name, self._log_level)
self._secnode.register_callback(None, nodeStateChange=self._set_log_level)
def _stop_watching(self):
for pname in self._watched_params:
self._secnode.unregister_callback((self._name, pname), updateEvent=self._watch_parameter)
if enable:
self._secnode.register_callback((self._name, pname), updateEvent=self._watch_parameter)
self._secnode.unregister_callback(None, nodeStateChange=self._set_log_level)
self._secnode.request('logging', self._name, 'off')
def _set_log_level(self, online, state):
if online and state == 'connected':
self._secnode.request('logging', self._name, self._log_level)
def read(self, pname='value'):
value, _, error = self._secnode.readParameter(self._name, pname)
if error:
raise error
clientenv.raise_with_short_traceback(error)
return value
def __call__(self, target=None):
if target is None:
return self.read()
self.target = target # this sets self._running
type(self).value.prev = None # show at least one value
show_final_value = True
watch_params = ['value', 'status']
for pname in watch_params:
self._secnode.register_callback((self._name, pname),
updateEvent=self._watch_parameter,
callimmediately=False)
self.target = target # this sets self._is_driving
def loop():
while self._is_driving:
self._driving_event.wait()
self._driving_event.clear()
try:
while self._running.get():
self._watch_parameter(self._name, 'value', mininterval=self._secnode.mininterval)
self._watch_parameter(self._name, 'status')
except KeyboardInterrupt:
loop()
except KeyboardInterrupt as e:
self._secnode.log.info('-- interrupted --')
self._running = None
self._watch_parameter(self._name, 'status')
self._secnode.readParameter(self._name, 'value')
self._watch_parameter(self._name, 'value', forced=show_final_value)
self.stop()
try:
loop() # wait for stopping to be finished
except KeyboardInterrupt:
# interrupted again while stopping -> definitely quit
pass
clientenv.raise_with_short_traceback(e)
finally:
self._secnode.readParameter(self._name, 'value')
for pname in watch_params:
self._secnode.unregister_callback((self._name, pname),
updateEvent=self._watch_parameter)
return self.value
def __repr__(self):
wid = max(len(k) for k in self._parameters)
return '%s\n%s\nCommands: %s' % (
return f'<module {self._name}>'
def showAll(self):
wid = max((len(k) for k in self._parameters), default=0)
return '%s\n%s%s' % (
self._title,
'\n'.join(self._one_line(k, wid) for k in self._parameters),
', '.join(k + '()' for k in self._commands))
'\nCommands: %s' % ', '.join(k + '()' for k in self._commands) if self._commands else '')
def logging(self, level='comlog', pattern='.*'):
def log_filter(self, pattern='.*'):
self._log_pattern = re.compile(pattern)
self._secnode.request('logging', self._name, level)
def handle_log_message_(self, data):
def handle_log_message_(self, loglevel, data):
if self._log_pattern.match(data):
self._secnode.log.info('%s: %r', self._name, data)
if loglevel == 'comlog':
self._secnode.log.info('%s%s', self._name, data)
else:
self._secnode.log.info('%s %s: %s', self._name, loglevel, data)
class Param:
@@ -206,20 +279,22 @@ class Param:
return self
value, _, error = obj._secnode.cache[obj._name, self.name]
if error:
raise error
clientenv.raise_with_short_traceback(error)
return value
def formatted(self, obj):
return obj._secnode.cache[obj._name, self.name].formatted()
def __set__(self, obj, value):
if self.name == 'target':
obj._running = Queue()
try:
obj._secnode.setParameter(obj._name, self.name, value)
if self.name == 'target':
obj._is_driving = obj._isBusy()
return
except SECoPError as e:
clientenv.raise_with_short_traceback(e)
obj._secnode.log.error(repr(e))
def format(self, value):
return self.datatype.format_value(value)
class Command:
def __init__(self, name, modname, secnode):
@@ -232,6 +307,8 @@ class Command:
if args:
raise TypeError('mixed arguments forbidden')
result, _ = self.exec(self.modname, self.name, kwds)
elif len(args) == 1:
result, _ = self.exec(self.modname, self.name, *args)
else:
result, _ = self.exec(self.modname, self.name, args or None)
return result
@@ -242,54 +319,228 @@ class Command:
return self.call
def show_parameter(modname, pname, *args, forced=False, mininterval=0):
"""show parameter update"""
mobj = clientenv.namespace[modname]
mobj._watch_parameter(modname, pname, *args)
def watch(*args, **kwds):
modules = []
for mobj in args:
if isinstance(mobj, Module):
if mobj._name not in kwds:
modules.append(mobj)
mobj._set_watching()
else:
print(f'do not know {mobj!r}')
for key, arg in kwds.items():
mobj = clientenv.namespace.get(key)
if mobj is None:
print(f'do not know {key!r}')
else:
modules.append(mobj)
mobj._set_watching(arg)
print('---')
try:
nodes = set()
for mobj in modules:
nodes.add(mobj._secnode)
mobj._start_watching()
close_event = threading.Event()
def close_node(online, state):
if online and state != 'shutdown':
return None
close_event.set()
return UnregisterCallback
def handle_error(*_):
close_event.set()
return UnregisterCallback
for node in nodes:
node.register_callback(None, nodeStateChange=close_node, handleError=handle_error)
close_event.wait()
except KeyboardInterrupt as e:
clientenv.raise_with_short_traceback(e)
finally:
for mobj in modules:
mobj._stop_watching()
print()
class Client(SecopClient):
activate = True
secnodes = {}
mininterval = 1
def __init__(self, uri, loglevel='info'):
def __init__(self, uri, loglevel='info', name=''):
if clientenv.namespace is None:
# called from a simple python interpeter
clientenv.init(sys.modules['__main__'].__dict__)
# remove previous client:
prev = self.secnodes.pop(uri, None)
log = Logger(name, loglevel)
removed_modules = []
if prev:
prev.log.info('remove previous client to %s', uri)
log.info('remove previous client to %s', uri)
for modname in prev.modules:
prevnode = getattr(getattr(main, modname, None), '_secnode', None)
prevnode = getattr(clientenv.namespace.get(modname), '_secnode', None)
if prevnode == prev:
prev.log.info('remove previous module %s', modname)
delattr(main, modname)
removed_modules.append(modname)
clientenv.namespace.pop(modname)
prev.disconnect()
self.secnodes[uri] = self
super().__init__(uri, Logger(loglevel))
if name:
log.info('\n>>> %s = Client(%r)', name, uri)
super().__init__(uri, log)
self.connect()
created_modules = []
skipped_modules = []
for modname, moddesc in self.modules.items():
prev = getattr(main, modname, None)
prev = clientenv.namespace.get(modname)
if prev is None:
self.log.info('create module %s', modname)
created_modules.append(modname)
else:
if getattr(prev, '_secnode', None) is None:
self.log.error('skip module %s overwriting a global variable' % modname)
skipped_modules.append(modname)
continue
self.log.info('overwrite module %s', modname)
removed_modules.append(modname)
created_modules.append(modname)
attrs = {}
for pname, pinfo in moddesc['parameters'].items():
attrs[pname] = Param(pname, pinfo['datainfo'])
for cname in moddesc['commands']:
attrs[cname] = Command(cname, modname, self)
mobj = type('M_%s' % modname, (Module,), attrs)(modname, self)
mobj = type(f'M_{modname}', (Module,), attrs)(modname, self)
if 'status' in mobj._parameters:
self.register_callback((modname, 'status'), updateEvent=mobj._status_value_update)
self.register_callback((modname, 'value'), updateEvent=mobj._status_value_update)
setattr(main, modname, mobj)
self.register_callback((modname, 'status'), updateEvent=mobj._status_update)
clientenv.namespace[modname] = mobj
if removed_modules:
self.log.info('removed modules: %s', ' '.join(removed_modules))
if skipped_modules:
self.log.info('skipped modules overwriting globals: %s', ' '.join(skipped_modules))
if created_modules:
self.log.info('created modules: %s', ' '.join(created_modules))
self.register_callback(None, self.unhandledMessage)
self.log.info('%s', USAGE)
log.show_time = True
def unhandledMessage(self, action, ident, data):
"""handle logging messages"""
if action == 'log':
modname = ident.split(':')[0]
modobj = getattr(main, modname, None)
modname, loglevel = ident.split(':')
modobj = clientenv.namespace.get(modname)
if modobj:
modobj.handle_log_message_(data)
modobj.handle_log_message_(loglevel, data)
return
self.log.info('module %s not found', modname)
self.log.info('unhandled: %s %s %r', action, ident, data)
def __repr__(self):
return f'Client({self.uri!r})'
def run(filepath):
clientenv.namespace.update({
"__file__": filepath,
"__name__": "__main__",
})
with open(filepath, 'rb') as file:
# pylint: disable=exec-used
exec(compile(file.read(), filepath, 'exec'), clientenv.namespace, None)
class ClientEnvironment:
namespace = None
last_frames = 0
sigwinch = False
def init(self, namespace=None):
self.nodes = []
self.namespace = namespace or {}
self.namespace.update(run=run, watch=watch, Client=Client)
def raise_with_short_traceback(self, exc):
# count number of lines of internal irrelevant stack (for remote errors)
self.last_frames = len(traceback.format_exception(*sys.exc_info()))
raise exc
def short_traceback(self):
"""cleanup traceback from irrelevant lines"""
lines = traceback.format_exception(*sys.exc_info())
# line 0: Traceback header
# skip line 1+2 (contains unspecific console line and exec code)
lines[1:3] = []
if ' exec(' in lines[1]:
# replace additional irrelevant exec line if needed with run command
lines[1:2] = []
# skip lines of client code not relevant for remote errors
lines[-self.last_frames-1:-1] = []
self.last_frames = 0
if len(lines) <= 2: # traceback contains only console line
lines = lines[-1:]
return ''.join(lines)
clientenv = ClientEnvironment()
class Console(code.InteractiveConsole):
def __init__(self, name='cli', namespace=None):
if namespace:
clientenv.namespace = namespace
super().__init__(clientenv.namespace)
history = None
if readline:
try:
history = expanduser(f'~/.frappy-{name}-history')
readline.read_history_file(history)
except FileNotFoundError:
pass
try:
self.interact('', '')
finally:
if history:
readline.write_history_file(history)
def raw_input(self, prompt=""):
clientenv.sigwinch = bool(readline) # activate refresh signal
line = input(prompt)
clientenv.sigwinch = False
if line.startswith('/'):
line = f"run('{line[1:].strip()}')"
module = clientenv.namespace.get(line.strip())
if isinstance(module, Module):
print(module.showAll())
line = ''
return line
def showtraceback(self):
self.write(clientenv.short_traceback())
def init(*nodes):
clientenv.init()
success = not nodes
for idx, node in enumerate(nodes):
client_name = '_c%d' % idx
try:
node = clientenv.namespace[client_name] = Client(node, name=client_name)
clientenv.nodes.append(node)
success = True
except Exception as e:
print(repr(e))
return success
def interact(usage_tail=''):
empty = '_c0' not in clientenv.namespace
print(USAGE.format(
client_name='cli' if empty else '_c0',
client_assign="\ncli = Client('localhost:5000')\n" if empty else '',
tail=usage_tail))
Console()

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# *****************************************************************************
#
# This program is free software; you can redistribute it and/or modify it under
@@ -17,24 +16,29 @@
#
# Module authors:
# Alexander Zaft <a.zaft@fz-juelich.de>
# Markus Zolliker <markus.zolliker@psi.ch>
#
# *****************************************************************************
import os
from pathlib import Path
import re
from frappy.errors import ConfigError
from frappy.lib import generalConfig
class Undef:
pass
class Node(dict):
def __init__(
self,
equipment_id,
description,
interface=None,
cls='protocol.dispatcher.Dispatcher',
omit_unchanged_within=1.1,
cls='frappy.protocol.dispatcher.Dispatcher',
**kwds
):
super().__init__(
@@ -42,20 +46,22 @@ class Node(dict):
description=description,
interface=interface,
cls=cls,
omit_unchanged_within=omit_unchanged_within,
**kwds
)
class Param(dict):
def __init__(self, value=Undef, **kwds):
if value is not Undef:
kwds['value'] = value
super().__init__(**kwds)
class Group(tuple):
def __new__(cls, *args):
return super().__new__(cls, args)
class Mod(dict):
def __init__(self, name, cls, description, **kwds):
super().__init__(
@@ -63,6 +69,11 @@ class Mod(dict):
cls=cls,
description=description
)
# matches name from spec
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?')
# Make parameters out of all keywords
groups = {}
for key, val in kwds.items():
@@ -77,16 +88,50 @@ class Mod(dict):
for member in members:
self[member]['group'] = group
def override(self, **kwds):
name = self['name']
warnings = []
for key, ovr in kwds.items():
if isinstance(ovr, Group):
warnings.append(f'ignore Group when overriding module {name}')
continue
param = self.get(key)
if param is None:
self[key] = ovr if isinstance(ovr, Param) else Param(ovr)
continue
if isinstance(param, Param):
if isinstance(ovr, Param):
param.update(ovr)
else:
param['value'] = ovr
else: # description or cls
self[key] = ovr
return warnings
class Collector:
def __init__(self, cls):
self.list = []
self.cls = cls
def __init__(self):
self.modules = {}
self.warnings = []
def add(self, *args, **kwds):
self.list.append(self.cls(*args, **kwds))
mod = Mod(*args, **kwds)
name = mod.pop('name')
if name in self.modules:
self.warnings.append(f'duplicate module {name} overrides previous')
self.modules[name] = mod
return mod
def append(self, mod):
self.list.append(mod)
def override(self, name, **kwds):
"""override properties/parameters of previously configured modules
this is useful together with 'include'
"""
mod = self.modules.get(name)
if mod is None:
self.warnings.append(f'try to override nonexisting module {name}')
return
self.warnings.extend(mod.override(**kwds))
class NodeCollector:
@@ -99,57 +144,77 @@ class NodeCollector:
else:
raise ConfigError('Only one Node is allowed per file!')
def override(self, **kwds):
if self.node is None:
raise ConfigError('node must be defined before overriding')
self.node.update(kwds)
class Config(dict):
def __init__(self, node, modules):
super().__init__(
node=node.node,
**{mod['name']: mod for mod in modules.list}
)
self.module_names = {mod.pop('name') for mod in modules.list}
super().__init__(node=node.node, **modules.modules)
self.module_names = set(modules.modules)
self.ambiguous = set()
def merge_modules(self, other):
""" merges only the modules from 'other' into 'self'"""
self.ambiguous |= self.module_names & other.module_names
equipment_id = other['node']['equipment_id']
for name, mod in other.items():
if name == 'node':
continue
if name not in self.module_names:
self.module_names.add(name)
self.modules.append(mod)
self[name] = mod
mod['original_id'] = equipment_id
def process_file(config_text):
class Include:
def __init__(self, namespace, log):
self.namespace = namespace
self.log = log
def __call__(self, cfgfile):
filename = to_config_path(cfgfile, self.log, '')
# pylint: disable=exec-used
exec(compile(filename.read_bytes(), filename, 'exec'), self.namespace)
def process_file(filename, log):
config_text = filename.read_bytes()
node = NodeCollector()
mods = Collector(Mod)
ns = {'Node': node.add, 'Mod': mods.add, 'Param': Param, 'Command': Param, 'Group': Group}
mods = Collector()
ns = {'Node': node.add, 'Mod': mods.add, 'Param': Param, 'Command': Param, 'Group': Group,
'override': mods.override, 'overrideNode': node.override}
ns['include'] = Include(ns, log)
# pylint: disable=exec-used
exec(config_text, ns)
exec(compile(config_text, filename, 'exec'), ns)
if mods.warnings:
log.warning('warnings in %s', filename)
for text in mods.warnings:
log.warning(text)
return Config(node, mods)
def to_config_path(cfgfile, log):
def to_config_path(cfgfile, log, check_end='_cfg.py'):
candidates = [cfgfile + e for e in ['_cfg.py', '.py', '']]
if os.sep in cfgfile: # specified as full path
filename = cfgfile if os.path.exists(cfgfile) else None
file = Path(cfgfile) if Path(cfgfile).exists() else None
else:
for filename in [os.path.join(d, candidate)
for d in generalConfig.confdir.split(os.pathsep)
for candidate in candidates]:
if os.path.exists(filename):
for file in [Path(d) / candidate
for d in generalConfig.confdir
for candidate in candidates]:
if file.exists():
break
else:
filename = None
if filename is None:
raise ConfigError("Couldn't find cfg file %r in %s"
% (cfgfile, generalConfig.confdir))
if not filename.endswith('_cfg.py'):
log.warning("Config files should end in '_cfg.py': %s", os.path.basename(filename))
log.debug('Using config file %s for %s', filename, cfgfile)
return filename
file = None
if file is None:
raise ConfigError(f"Couldn't find cfg file {cfgfile!r} in {generalConfig.confdir}")
if not file.name.endswith(check_end):
log.warning("Config files should end in %r: %s", check_end, file.name)
log.debug('Using config file %s for %s', file, cfgfile)
return file
def load_config(cfgfiles, log):
@@ -158,8 +223,8 @@ def load_config(cfgfiles, log):
Only the node-section of the first config file will be returned.
The others will be discarded.
Arguments
- cfgfiles : str
Comma separated list of config-files
- cfgfiles : list
List of config file paths
- log : frappy.logging.Mainlogger
Logger aquired from frappy.logging
Returns
@@ -167,16 +232,16 @@ def load_config(cfgfiles, log):
merged configuration
"""
config = None
for cfgfile in cfgfiles.split(','):
filename = to_config_path(cfgfile, log)
for cfgfile in cfgfiles:
filename = to_config_path(str(cfgfile), log)
log.debug('Parsing config file %s...', filename)
with open(filename, 'rb') as f:
config_text = f.read()
cfg = process_file(config_text)
cfg = process_file(filename, log)
if config:
config.merge_modules(cfg)
else:
config = cfg
if config.get('node') is None:
raise ConfigError(f'missing Node in {filename}')
if config.ambiguous:
log.warning('ambiguous sections in %s: %r',

View File

@@ -1,6 +1,5 @@
# -*- coding: utf-8 -*-
# *****************************************************************************
# Copyright (c) 2015-2016 by the authors, see LICENSE
# Copyright (c) 2015-2024 by the authors, see LICENSE
#
# 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
@@ -27,19 +26,36 @@
# pylint: disable=unused-import
from frappy.datatypes import ArrayOf, BLOBType, BoolType, EnumType, \
FloatRange, IntRange, ScaledInteger, StringType, StructOf, TupleOf
FloatRange, IntRange, ScaledInteger, StringType, StructOf, TupleOf, StatusType
from frappy.lib.enum import Enum
from frappy.modulebase import Done, Module, Feature
from frappy.modules import Attached, Communicator, \
Done, Drivable, Feature, Module, Readable, Writable, HasAccessibles
from frappy.params import Command, Parameter
Drivable, Readable, Writable
from frappy.params import Command, Parameter, Limit
from frappy.properties import Property
from frappy.proxy import Proxy, SecNode, proxy_class
from frappy.io import HasIO, StringIO, BytesIO, HasIodev # TODO: remove HasIodev (legacy stuff)
from frappy.persistent import PersistentMixin, PersistentParam
from frappy.persistent import PersistentMixin, PersistentParam, PersistentLimit
from frappy.rwhandler import ReadHandler, WriteHandler, CommonReadHandler, \
CommonWriteHandler, nopoll
ERROR = Drivable.Status.ERROR
WARN = Drivable.Status.WARN
BUSY = Drivable.Status.BUSY
IDLE = Drivable.Status.IDLE
DISABLED = StatusType.DISABLED
IDLE = StatusType.IDLE
STANDBY = StatusType.STANDBY
PREPARED = StatusType.PREPARED
WARN = StatusType.WARN
WARN_STANDBY = StatusType.WARN_STANDBY
WARN_PREPARED = StatusType.WARN_PREPARED
UNSTABLE = StatusType.UNSTABLE # no SECoP standard (yet)
BUSY = StatusType.BUSY
DISABLING = StatusType.DISABLING
INITIALIZING = StatusType.INITIALIZING
PREPARING = StatusType.PREPARING
STARTING = StatusType.STARTING
RAMPING = StatusType.RAMPING
STABILIZING = StatusType.STABILIZING
FINALIZING = StatusType.FINALIZING
ERROR = StatusType.ERROR
ERROR_STANDBY = StatusType.ERROR_STANDBY
ERROR_PREPARED = StatusType.ERROR_PREPARED
UNKNOWN = StatusType.UNKNOWN # no SECoP standard (yet)

File diff suppressed because it is too large Load Diff

41
frappy/dynamic.py Normal file
View File

@@ -0,0 +1,41 @@
# *****************************************************************************
#
# 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>
#
# *****************************************************************************
from .core import Module
class Pinata(Module):
"""Base class for scanning conections and adding modules accordingly.
Like a piñata. You poke it, and modules fall out.
To use it, subclass it for your connection type and override the function
'scanModules'. For each module you want to register, you should yield the
modules name and its config options.
The connection will then be scanned during server startup.
"""
export = False
# POKE
def scanModules(self):
"""yield (modname, options) for each module the Pinata should create.
Options has to include keys for class and the config for the module.
"""
raise NotImplementedError

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# *****************************************************************************
#
# This program is free software; you can redistribute it and/or modify it under
@@ -20,111 +19,235 @@
# Markus Zolliker <markus.zolliker@psi.ch>
#
# *****************************************************************************
"""Define (internal) SECoP Errors"""
"""Define (internal) SECoP Errors
all error classes inherited from SECoPError should be placed in this module,
else they might not be registered and can therefore not be rebuilt on the client side
"""
import re
from ast import literal_eval
class SECoPError(RuntimeError):
silent = False # silent = True indicates that the error is already logged
clsname2class = {} # needed to convert error reports back to classes
name = 'InternalError'
name2class = {}
report_error = True
raising_methods = None
def __init_subclass__(cls):
cls.clsname2class[cls.__name__] = cls
if 'name' in cls.__dict__:
cls.name2class[cls.name] = cls
def __init__(self, *args, **kwds):
super().__init__()
self.args = args
self.kwds = kwds
for k, v in list(kwds.items()):
setattr(self, k, v)
self.raising_methods = []
def __repr__(self):
args = ', '.join(map(repr, self.args))
kwds = ', '.join(['%s=%r' % i for i in list(self.__dict__.items())
if i[0] != 'silent'])
res = []
if args:
res.append(args)
if kwds:
res.append(kwds)
return '%s(%s)' % (self.name, ', '.join(res))
res.extend((repr(a) for a in self.args))
#res.extend(('%s=%r' % i for i in self.kwds.items()))
return f"{self.name or type(self).__name__}({', '.join(res)})"
@property
def name(self):
return self.__class__.__name__[:-len('Error')]
def __str__(self):
return self.format(True)
def format(self, stripped):
"""format with info about raising methods
class SECoPServerError(SECoPError):
name = 'InternalError'
:param stripped: strip last method.
:return: the formatted error message
Use stripped=True (or str()) for the following cases, as the last method can be derived from the context:
- stored in pobj.readerror: read_<pobj.name>
- error message from a change command: write_<pname>
- error message from a read command: read_<pname>
Use stripped=False for the log file, as the related parameter is not known
"""
mlist = self.raising_methods
if mlist and stripped:
mlist = mlist[:-1] # do not pop, as this would change self.raising_methods
prefix = '' if self.name2class.get(self.name) == type(self) else type(self).__name__
prefix += ''.join(' in ' + m for m in mlist).strip()
if prefix:
return f'{prefix}: {super().__str__()}'
return super().__str__()
def __eq__(self, other):
return type(self) is type(other) and self.args == other.args and self.kwds == other.kwds
def __ne__(self, other):
return not self == other
class InternalError(SECoPError):
"""uncatched error"""
name = 'InternalError'
class ProgrammingError(SECoPError):
name = 'InternalError'
"""catchable programming error"""
class ConfigError(SECoPError):
name = 'InternalError'
"""invalid configuration"""
class ProtocolError(SECoPError):
"""A malformed request or on unspecified message was sent
This includes non-understood actions and malformed specifiers.
Also if the message exceeds an implementation defined maximum size.
"""
name = 'ProtocolError'
class NoSuchModuleError(SECoPError):
"""missing module
The action can not be performed as the specified module is non-existent"""
name = 'NoSuchModule'
# pylint: disable=redefined-builtin
class NotImplementedError(NotImplementedError, SECoPError):
pass
class NotImplementedSECoPError(NotImplementedError, SECoPError):
"""not (yet) implemented
A (not yet) implemented action or combination of action and specifier
was requested. This should not be used in productive setups, but is very
helpful during development."""
name = 'NotImplemented'
class NoSuchParameterError(SECoPError):
pass
"""missing parameter
The action can not be performed as the specified parameter is non-existent.
Also raised when trying to use a command name in a 'read' or 'change' message.
"""
name = 'NoSuchParameter'
class NoSuchCommandError(SECoPError):
pass
"""The specified command does not exist
Also raised when trying to use a parameter name in a 'do' message.
"""
name = 'NoSuchCommand'
class ReadOnlyError(SECoPError):
pass
"""The requested write can not be performed on a readonly value"""
name = 'ReadOnly'
class BadValueError(ValueError, SECoPError):
pass
class BadValueError(SECoPError):
"""do not raise, but might used for instance checks (WrongTypeError, RangeError)"""
class RangeError(BadValueError, ValueError):
"""data out of range
The requested parameter change or Command can not be performed as the
argument value is not in the allowed range specified by the datainfo
property. This also happens if an unspecified Enum variant is tried
to be used, the size of a Blob or String does not match the limits
given in the descriptive data, or if the number of elements in an
array does not match the limits given in the descriptive data."""
name = 'RangeError'
class BadJSONError(SECoPError):
"""The data part of the message can not be parsed, i.e. the JSON-data is no valid JSON.
not used in Frappy, but might appear on the client side from a foreign SEC Node
"""
# TODO: check whether this should not be removed from specs!
name = 'BadJSON'
class WrongTypeError(BadValueError, TypeError):
"""Wrong data type
The requested parameter change or Command can not be performed as the
argument has the wrong type. (i.e. a string where a number is expected.)
It may also be used if an incomplete struct is sent, but a complete
struct is expected."""
name = 'WrongType'
class CommandFailedError(SECoPError):
pass
name = 'CommandFailed'
class CommandRunningError(SECoPError):
pass
"""The command is already executing.
request may be retried after the module is no longer BUSY
(retryable)"""
name = 'CommandRunning'
class CommunicationFailedError(SECoPError):
pass
"""Some communication (with hardware controlled by this SEC node) failed
(retryable)"""
name = 'CommunicationFailed'
class SilentCommunicationFailedError(CommunicationFailedError):
silent = True
class IsBusyError(SECoPError):
pass
"""The requested action can not be performed while the module is Busy
or the command still running"""
name = 'IsBusy'
class IsErrorError(SECoPError):
pass
"""The requested action can not be performed while the module is in error state"""
name = 'IsError'
class DisabledError(SECoPError):
pass
"""The requested action can not be performed while the module is disabled"""
name = 'Disabled'
class ImpossibleError(SECoPError):
"""The requested action can not be performed at the moment"""
name = 'Impossible'
class ReadFailedError(SECoPError):
"""The requested parameter can not be read just now"""
name = 'ReadFailed'
class OutOfRangeError(SECoPError):
"""The value read from the hardware is out of sensor or calibration range"""
name = 'OutOfRange'
class HardwareError(SECoPError):
"""The connected hardware operates incorrect or may not operate at all
due to errors inside or in connected components."""
name = 'HardwareError'
FRAPPY_ERROR = re.compile(r'(.*)\(.*\)$')
class TimeoutSECoPError(TimeoutError, SECoPError):
"""Some initiated action took longer than the maximum allowed time (retryable)"""
name = 'TimeoutError'
FRAPPY_ERROR = re.compile(r'(\w*): (.*)$')
def make_secop_error(name, text):
@@ -134,43 +257,25 @@ def make_secop_error(name, text):
:param text: the second item of a SECoP error report
:return: the built instance of SECoPError
"""
try:
# try to interprete the error text as a repr(<instance of SECoPError>)
# as it would be created by a Frappy server
cls, textarg = FRAPPY_ERROR.match(text).groups()
errcls = locals()[cls]
if errcls.name == name:
# convert repr(<string>) to <string>
text = literal_eval(textarg)
except Exception:
# probably not a Frappy server, or running a different version
errcls = EXCEPTIONS.get(name, InternalError)
return errcls(text)
match = FRAPPY_ERROR.match(text)
if match:
clsname, errtext = match.groups()
errcls = SECoPError.clsname2class.get(clsname)
if errcls:
return errcls(errtext)
return SECoPError.name2class.get(name, InternalError)(text)
def secop_error(exception):
if isinstance(exception, SECoPError):
return exception
return InternalError(repr(exception))
def secop_error(exc):
"""turn into InternalError, if not already a SECoPError"""
if isinstance(exc, SECoPError):
return exc
return InternalError(f'{type(exc).__name__}: {exc}')
EXCEPTIONS = dict(
NoSuchModule=NoSuchModuleError,
NoSuchParameter=NoSuchParameterError,
NoSuchCommand=NoSuchCommandError,
CommandFailed=CommandFailedError,
CommandRunning=CommandRunningError,
ReadOnly=ReadOnlyError,
BadValue=BadValueError,
CommunicationFailed=CommunicationFailedError,
HardwareError=HardwareError,
IsBusy=IsBusyError,
IsError=IsErrorError,
Disabled=DisabledError,
# TODO: check if these are really needed:
SECoPError.name2class.update(
SyntaxError=ProtocolError,
NotImplemented=NotImplementedError,
ProtocolError=ProtocolError,
InternalError=InternalError,
# internal short versions (candidates for spec)
Protocol=ProtocolError,
Internal=InternalError,

300
frappy/extparams.py Normal file
View File

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

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