Compare commits

...

167 Commits
wip ... mirror

Author SHA1 Message Date
dcd79506a9 Merge "improve parameter initialisation" 2023-01-23 08:25:36 +01:00
f4e974f46c improve parameter initialisation
- make 'value' a Parameter property instead of an attribute
- use 'value' instead of 'default' property for setting
  the initial value in the config file
- removal of initwrite parameter property

this change is the basis of a better implementation
for change 30041 (PersistentParam property 'override_cfg')

Change-Id: I2b82bdd54c2dacb87dcd2b3472004d2f0a730cf0
2023-01-20 16:55:06 +01:00
Alexander Zaft
d889401697 Revert limit change in demo
After 29724, the change in frappy_demo/modules.py from 30183 which was
made to run 'make demo' without errors can be reverted.

Change-Id: I00a6f512304a3159c10e44aef670ac0edd4703d7
2023-01-19 15:39:33 +01:00
85295a7d72 Merge "client: detect original frappy error class" 2023-01-19 12:29:37 +01:00
82957c287d Merge "rework datatypes (setter should not check limits)" 2023-01-19 08:28:30 +01:00
Alexander Zaft
05593d80f6 Bring demo up to date
* Add python config for test and demo server
* Remove old configs
* Fix issue with slow start of test server

Change-Id: If0e576f4e4dda8b03489fdbb79b209dfcdca29ff
2023-01-18 16:24:30 +01:00
7a870aa56c rework datatypes (setter should not check limits)
- use Datatype.validate for converting and checking limits
  (used also in properties)
- Datatype.__call__ converts and validates, but without checking
  limits (used in setter)
- Datatype.validate may be used to add missing optional struct elements
  from previous value (used in Dispatcher._setParameterValue)
- remove problematic range check
+ use shorter formula for converting float to int in ScaledInteger
  (leftover from python2 compatibility)
+ improve error messages (strip very long repr(value))

Change-Id: Ib85736fe558ec3370ebce4e1c43f957e3bb0497c
2023-01-16 10:18:15 +01:00
Alexander Zaft
09d48ea913 Merge "GUI: add logging infra, switch to argparse" 2023-01-12 13:12:09 +01:00
Alexander Zaft
8850edbc2d Merge "Change config to Python" 2023-01-12 13:10:37 +01:00
59cc981566 client: detect original frappy error class
The text part of the error report contains the original error
class - convert it to the frappy error class, if possible.
This makes the error messages on the client nicer, as the
error class would be duplicated in the error message on the
client side.

Change-Id: If2e0c3eb15ac2dd1b80a851ff42e4076557a325d
2022-12-22 13:44:08 +01:00
3cc9a75174 improve He level tutorial
values return from read_* methods should be converted
from string to float on float parameters

+ fix some wording

Change-Id: Ic80010c6fbe3eef23483ff69c8a43e25afb8bb6a
2022-12-22 13:39:47 +01:00
Alexander Zaft
52b77ba9e6 Change config to Python
- Change Configuration format to be python-based.
- move config logic to frappy/config.py
- Add first py-config: cryo_cfg.py
- Adapt test to new expected config format

Change-Id: Iaec484e0e1e21ebbb1e5c74b53be6231329ddf71
2022-12-20 09:48:14 +01:00
Bjoern Pedersen
db3b190c26 Improve jenkinsfile
Change-Id: I68efdd1a20135a0374fb9692e369a315824786ea
2022-12-19 14:34:48 +01:00
Alexander Zaft
c522c41654 GUI: add logging infra, switch to argparse
First part for #4662

Change-Id: I75877337e8ea35d4c4555471ee4518c942dac88a
2022-12-08 16:38:00 +01:00
Enrico Faulhaber
929e41ffff Merge "Fix identification response" 2022-12-06 18:00:10 +01:00
Alexander Zaft
8d99a8c536 Fix identification response
- fix header, but accept both responses
- warn when counterpart uses old behaviour

Fixes: #4659
Change-Id: Ib8869755898bf20edcbc7ae93157c943f816ebc1
2022-12-06 14:43:45 +01:00
a14c282993 redesign of the state machine
With the current implementation, we run into a deadlock with the lock
from the state machine interfering with the accessLock on the module.
We can not wait for the state machine to finish while having the
accessLock locked by write_target. As a consequence, when restarting
the state machine we should not wait, but remember the state function
to call and postpone the restart after the cleanup has finished.
For this, we want to know the status before calling the state function.

- create HasState mixin, using doPoll for driving the machine
- StatusCode decorator for assigning a status to a state function
- remove the state machines 'threaded' option
- 'Retry' is now a unique value instead of a class. The retry period
  is determined by the (fast) poll interval.
- return 'Finish' instead of None for finishing the machine. returning
  None for state function is now an error, as this might happen
  easily inadvertently.

Change-Id: Icb31367442f10e98be69af3e05a84f12ce5cc966
2022-12-06 10:18:50 +01:00
Alexander Zaft
d09634a55d Fix error Message for too large arrays
Change-Id: I69b6789ef9f463565918a395120b8f5ad3494b20
2022-11-28 09:28:37 +01:00
b17030afa2 Merge "interactive client: fix detection of overriding modules" 2022-11-10 17:01:34 +01:00
37c9efb27b interactive client: fix detection of overriding modules
+ add docstring to PrettyFloat

Change-Id: Idc92e169e94d0c2bd3f9b8958870393295c87b18
2022-11-10 15:58:28 +01:00
Enrico Faulhaber
4167ce7b00 fix sorce package name
Change-Id: I91cd5d5e6d2da00eedc3e2ff0ee2a1d3e9ed4b04
2022-11-10 15:00:27 +01:00
Jenkins system
2b7b2267d2 [deb] Release v0.15.0 2022-11-10 14:46:02 +01:00
Enrico Faulhaber
8071c21819 Merge "Fix typo in .description" 2022-11-10 14:43:32 +01:00
Enrico Faulhaber
e16ef3ae87 Merge "rename debian files" 2022-11-10 14:42:54 +01:00
Björn Pedersen
51147d8e09 Fix doc warnings/errors
Change-Id: Idd6feeb66d58bc562853d3a82831645ef2d5ccf6
2022-11-10 11:12:32 +02:00
Alexander Zaft
6909eb8541 rename debian files
Change-Id: Ib990ecb8ef5ad856eb32110e5448064acf9a5a12
2022-11-10 09:46:46 +01:00
Björn Pedersen
5d6b208671 CI build: upgrade base image
- use python 3.9 (3.9 bullseyse)
- add latex-fonts-extra to fix missing tgtermes.sty
- in bullseye python3-pytango has been renamend to python3-tango
 (https://packages.debian.org/stable/python/python3-tango)

Change-Id: I06c8d8e432644f657057d14bbe754f28e2c10dd4
2022-11-10 09:08:21 +01:00
Alexander Zaft
b3eebb6c6a rename debian package files
Change-Id: I376082a68ceacd6fda984dc8dc1d53fa4afbbfef
2022-11-09 16:31:40 +01:00
Alexander Zaft
7f166a5b8c Rename from secop to frappy
debian/ is still missing, will follow in next commit.

Fixes: #4626

Change-Id: Ia87c28c1c75b8402eedbfca47f888585a7881f44
2022-11-09 16:29:29 +01:00
Alexander Zaft
c1eb764b09 fixed pylint warnings
Change-Id: Ibb3da77e9a53b7293a280659defc029416e30e3b
2022-11-09 17:19:17 +02:00
Christian Felder
a9d798fabc Fix typo in .description
Change-Id: I84def1c25279a2492d39931590f32a3b6fea8856
2022-11-08 17:44:58 +01:00
Alexander Zaft
a928c95efd Merge "Add requirements-gui.txt and add PyQT5" 2022-11-03 15:50:19 +01:00
Enrico Faulhaber
7df4584150 Merge "Remove iohandler left-overs from docs" 2022-11-03 15:00:54 +01:00
Alexander Zaft
b7cebe2cd8 Add requirements-gui.txt and add PyQT5
Change-Id: I8e2cdcc2d0353f4384ba8ea026e02af65064ece9
2022-11-03 14:41:25 +01:00
Georg Brandl
b8b2dafaf8 Makefile: fix release target
Change-Id: I1cc94a91cbb03c046092a814163664a507c88bdc
2022-11-03 13:56:24 +01:00
Björn Pedersen
f66411dded Remove iohandler left-overs from docs
The iohandler module has been remove in 28526

Change-Id: I24c86f88c8a37f85018cfcdec48279a1438da408
2022-11-03 13:52:27 +01:00
Jenkins system
ce4bbec766 [deb] Release v0.14.3 2022-11-03 13:51:52 +01:00
Enrico Faulhaber
355810a887 MLZ/entangle: fix AnalogOutput.read_status()
Change-Id: I584cd8f559b6c57f3c73105b28bc533526f6f492
2022-11-03 12:59:58 +01:00
Bjoern Pedersen
aa98604f88 Upgrade for ci
fixes outdated options and macros in Jenkinsfile
fixes outdated options in pylintrc

Change-Id: Ib064cc8b4235536c21288733676438297e15736d
2022-11-03 12:27:37 +01:00
Georg Brandl
b0051ca3f0 secop_mlz/amagnet: formatting fixup
Change-Id: I05ec4568c87d58f32cf48479ac653075e2211ed3
2022-10-28 16:20:29 +02:00
Enrico Faulhaber
92edbb27ea change repo to secop/frappy
Change-Id: I515c0d958c87d555156861db83a7b22c60046ead
2022-10-21 12:40:33 +02:00
Jenkins system
20fc48ddf0 [deb] Release v0.14.2 2022-10-20 15:38:45 +02:00
Georg Brandl
340c031f46 systemd generator: adapt to changed config API
Change-Id: Idb2527b7007aca3a051c1ec9a2d8eecdb55cacef
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/29535
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>
2022-10-20 15:13:29 +02:00
Jenkins system
3ac8b4e255 [deb] Release v0.14.1 2022-10-20 14:04:07 +02:00
Georg Brandl
6ffc73a1e1 Makefile: fix Jenkins host
Change-Id: I1ae3c27d0839b8dffde4cf9da5a13fa00f88a9d3
2022-10-20 14:03:59 +02:00
Georg Brandl
4ef0b0c01d mlz: avoid error on import due to consistency check
Change-Id: I43751a93b16a0cd9a64ae79da7045fd4e879b065
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/29529
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2022-10-20 10:39:08 +02:00
Georg Brandl
1fc805a5a2 gui: clarify needed input for "add sec node" dialog
Change-Id: Ia34eef4df50d545fa779979dd25a239803af0a8e
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/29528
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2022-10-20 07:54:05 +02:00
05edf98dfe secop_psi.entangle.AnalogInput: fix main value
when the unit of parameter 'value' is taken from tango, the
'$' units of other parameters are already replaced by the configured
value and are not updated. this change fixes this.

not yet tested on entangle, but a test with similar code works

Change-Id: I87ad112b0965b39bb204d6c3d1fc1de6d4e14f60
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/29357
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>
2022-10-19 17:27:29 +02:00
Jenkins system
e09c365ea5 [deb] Release v0.14.0 2022-10-19 11:31:51 +02:00
64cb297a06 HasIO: automatic creation of io from uri fails
attached io in HasIO must not be mandatory - either uri or io
has to be given

Change-Id: Id39e40f98020d4051c1ad8105f6af6018aafaea8
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/29349
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>
2022-09-22 15:37:42 +02:00
eaefa1ce87 apply main unit also in structured types
Change-Id: I5a3efb167f2b460b847d8e7ac75a21848976b5f8
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/29350
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>
2022-09-22 14:59:24 +02:00
71aaf7187a improvements on interactive client
- fix handling of exceptions
- add selective logging
- improve formatting of values

Change-Id: I69c11e95aca1cdd222800fd3fd192a6b12b38411
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/29348
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>
2022-09-22 14:59:10 +02:00
0a28192c15 improve general config
for easier configuration of multiple servers on the same machine,
FRAPPY_* env. variables are overriding the values from the
general config file

+ apply expanduser where approporiate

Change-Id: Icb73543402f5fb1b8a248a8b8d7fb470971492f4
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/29351
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>
2022-09-22 14:58:47 +02:00
1b9cac04b1 fix bug when restarting statemachine
- fixed bad if clause
+ better debug message on restart/stop

Change-Id: I4c2327593c014749a32377dac45f0f46c680df2b
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/29352
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>
2022-09-22 14:58:20 +02:00
2b1986ad8f fix bug in persistent.py
- use dirname instead of basename

Change-Id: Id563794a8e5f5c9e4d31750f089eb3b9c3150d94
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/29353
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>
2022-09-22 14:58:05 +02:00
270152d503 improve HasConvergence mixin
- add stop command
- fix bug in cleanup
- reset time spent on write_target

Change-Id: Iaa76cb7a9c6b4a2ccb08313f9880006ab14afe2b
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/29355
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Tested-by: Markus Zolliker <markus.zolliker@psi.ch>
2022-09-22 14:57:52 +02:00
1922578dfa fix undefined status in softcal
when the status of the rawsensor is not changed, the
status of the calibrated module was not initialized
properly.

Change-Id: I2c23e245226ffb7643060e486c9dfde250a79ce9
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/29356
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>
2022-09-22 14:56:23 +02:00
43880346d6 add simple interactive python client
- SECoP modules are accessible as objects in the main python module
- parameters are accessed as attributes of these objects
- __repr__ is used for listing all parameters
- __call__ is used for 'change target and wait until no more busy'

typically used from a python interpreter or in a jupyter notebook

Change-Id: Idb55684eeff6d1262e5d1517a3ff934f1c1bf208
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/28980
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2022-08-11 11:15:40 +02:00
Jenkins system
d0794a7803 [deb] Release v0.13.1 2022-08-02 15:31:52 +02:00
Enrico Faulhaber
dc76ac92de secop_mlz: minor rework entangle client
Change-Id: Ie406b4220c22cdbf302a1fd36f2d7407d81a47fa
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/28951
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>
2022-08-02 15:30:53 +02:00
8579368259 make startup faster in case of errors
When the io of one SECoP module fails, it takes ages to startup
because each parameter poll takes the time to wait for a timeout.
After the first communication error on an io, no more startup polls
are tried on the modules using this io.

Change-Id: I0d250953dfe91a7d68d2d2b108395cc25d471afe
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/28588
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>
2022-08-02 11:52:57 +02:00
cd90385e6c an enum with value 0 should be interpreted as False
for example: bool(Enum(off=0, on=1)('off')) is False

Change-Id: Ieb200b4ecf0eed50b657ecc00f73a69810ad828f
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/28586
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>
2022-08-02 11:37:56 +02:00
Jenkins system
3acea5f7c7 [deb] Release v0.13.0 2022-08-02 09:47:07 +02:00
Enrico Faulhaber
c564ae392c default unit to UTF8
Change-Id: Ic958346beb1a3b164c8d7b2826d59cf7e3991e15
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/28946
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Tested-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
2022-08-02 09:46:02 +02:00
1357ead435 remove IOHandler stuff
as all code using IO handlers has been changed to use
secop.rwhandler, IO handlers can be removed

Change-Id: Id57fbc4ce2744dbe73bb8792fd45449373f76bb5
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/28526
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>
2022-05-30 09:58:00 +02:00
6a0261c728 allow to convert numpy arrays to ArrayOf
accept all sequences instead of just tuple / list
+ change Module.announceUpdate to convert value before
  comparing with previous one (comparing will not work with numpy arrays)

Change-Id: I5eceef4297607107e2dde688af2833d3651a8775
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/28525
Tested-by: Markus Zolliker <markus.zolliker@psi.ch>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2022-05-25 14:22:30 +02:00
d717a481d7 feature implementation
implement features including two proposed features
HasOffset and HasLimits

Change-Id: I7949f12dc8abe28fb2ee040e64e7db19d1b23b9a
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/28485
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>
2022-05-25 14:21:21 +02:00
4c94580cb9 channel switcher for Lakeshore 370 with scanner
- add a general channel switcher module
- change ls370res code from IOHandler to rwhandlers
+ fix an issue with the poller when io module is placed below
  using modules in cfg file

after this, IOHandler stuff may be removed from Frappy

Change-Id: I787101fc1e365ae3e0453bfe59291e2011a1fe53
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/28512
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>
2022-05-25 07:47:32 +02:00
8eee7ab3b0 fix keithley 2601b after tests
- add missing super call in initModule
- change mode before writing levels
- fix MEASURE_DCVOLTS instead of MEASURE_VOLTS

Change-Id: Id93187e082db9868f443d4ef8cbdc85acd11be2b
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/28256
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>
2022-04-27 15:46:58 +02:00
478075c545 allow a configfile path as single argument to secop-server
when a full path is given as single argument to secop-server,
the server name has to be sanitized

Change-Id: I1d11f076157548e90877f380f0cab3a6a3f96784
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/28232
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2022-04-26 08:35:34 +02:00
b7d16d2e16 add 'ts' to the ppms simulation
+ convert from CRLF to LF

Change-Id: I46fab0c970ccc5e7e704a5dc0ab2cfd51213cd31
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/28233
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
2022-04-26 08:35:16 +02:00
d3379d5e95 support for OI mercury series
- temperature (incl. heater)
- pressure (incl. control via valve motor)
- LHe and LN2 levels

not yet included: magnet power supply

Change-Id: Id4ee8f9b7ebfa6284e519ba485217f9a19d70d59
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/28028
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2022-04-22 16:02:22 +02:00
d6ad5f058d improve poller error handling
- repeated errors on poller are only once logged (per poll
  function / read_* method)
- during exception handling, silent=True on a SECoP error indicates
  that the error is already logged
+ fix the name of HardwareError
+ add test for consistency of SECoPErrors
+ catch socket.timeout in AsynTcp

Change-Id: I9df6c775cc19553b22a4d6e39591092adf7ff9a1
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/28139
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>
2022-04-12 18:12:28 +02:00
a35134978a avoid deadlock in proxy
in secop.proxy the callers modules method announceUpdate is
called from an other thread while the accessLock is locked,
creating a deadlock. solve this by creating an other lock
'updateLock' for the update.

+ add status parameter even to non-Readable proxy modules,
  in order to indicate a failed connection
+ fix an error in secop_psi/softcal.py

Change-Id: Iae7c6d5a74001150a47aa9dc99209c15d972cd5e
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/28130
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>
2022-04-12 18:11:12 +02:00
7891c281e1 fix error in secop.logging
Implement LogfileHandler.getChild. This is needed to inherit
the configured level from the parent handler.

+ remove redundant assignmet of logfile_handler.max_days

Change-Id: I7277c28221bbb6108d75f2437634e9db9bf6761e
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/28140
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>
2022-04-12 18:10:59 +02:00
6460e51920 improved trinamic driver
- safe_current: current limit for unlimited move
- move_limit: max. angle to move with high current > safe_current
- direct axis parameter access is not exported by default
- support for home switch
- allow use without encoder
- automatic reset for motors in a configuration, where the motor
  current is deliberatly low for a limited torque
- improved error message on driving failures

Change-Id: I25f8516905a2c4c3cda09d091d5a43004ec6dc6f
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/28029
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>
2022-04-11 16:25:21 +02:00
b40b0e75b1 motor valve using trinamic motor
This valve needs 8 turns to open. As the encoder forgets
the number if turns on power cycle, a home switch is
mounte, which engages during the last turn when closing.
The final close position is determined by closing the valve
with a defined motor current/torque.

+ fix an issue in StateMachine.start: the first cycle
  must be called after the new state is assigned

Change-Id: I34cd05d10d97b043f9e3126310943b74ee727382
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/28030
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>
2022-04-11 16:25:05 +02:00
af983287e7 use a common poller thread for modules sharing io
When several poller threads are using the same io, the resposivity
of client requests is reduced, as every thread first finishes
its pending communication requests, before it is the turn of the
request thread. This is solved by using one common poller thread
for all modules sharing the same communicator.

+ fix an issue with overriding a property with a parameter, as
  this is the case for pollperiod (cfg was applied to property
  instead of overriding parameter)
+ separate setFastPoll arguments into flag and fast interval
+ fix missing announceUpdate call when read function fails
+ fix mechanism for triggering polls after an io connection
  reconnected again.

Change-Id: I1115a61fae3de80d18416e61f40b52a0eebb637c
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/28021
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2022-04-06 17:12:36 +02:00
8d23503bbd fix statemachine
- fix: calling state.start(<new state>) on restart must ensure
  that the function <new state> is called before state.start()
  returns.
- modify slighly behaviour of cleanup function

Change-Id: I483a3aefa6af4712b3cf13f62c86d4c06edd1d8d
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/28020
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>
2022-03-29 08:08:44 +02:00
bb097ac3ba reintroduced individual init of generalConfig.defaults
revert basically the former change
"init generalConfig.defaults only in secop-server"

The problem of import order when setting generalConfig.defaults
has to be solved by not overriding already existing keys when
setting the default.

Change-Id: I82121e346607dd74146279c4241e13ab63c14096
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/28011
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>
2022-03-25 07:35:26 +01:00
16a9550080 avoid race conditions in read_*/write_* methods
using one RLock per Module
+ init generalConfig for all tests

Change-Id: I88db6cacdb4aaac2ecd56644ccd6a3e5fd2d1cf2
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/28005
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2022-03-23 10:40:37 +01:00
9858973ba1 HasConvergence mixin
the HasConvergence mixin runs a state machine to determine
when the value has reached target from parameters 'tolerance',
'settling_time' or detects convergence failure depending on
the parameter 'timeout'.

Change-Id: Iccc3d43bcf5ab54ae02ce3a81423c2decc1b392d
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/27967
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2022-03-23 09:41:34 +01:00
e6d6179925 init generalConfig.defaults only in secop-server
generalConfig.defaults must not be set on import, as this
depends on import order

Change-Id: I00395b40b4281ddc044c196713f6512068011380
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/27985
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>
2022-03-22 07:56:38 +01:00
60c62a340d support write_ method on readonly param and more
- write method may be used internally on a readonly parameter
+ add IDLE, WARN, BUSY and ERROR to secop.core
+ secop.datatype.EnumType: allow 'self' as member name
+ secop.lib.statemachine: log Restart and Stop exceptions only on debug level
+ secop_psi.ccu4.CCU4: explicit conversion to float
+ secop.proxy: remove superfluos and erroneous make_secop_error

Change-Id: I2f13d31ceacd2bde65eab64f8eae4225556c18f5
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/27963
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>
2022-03-21 12:06:51 +01:00
3c0c60615a fix error in write wrapper and more
- write wrapper must return the result, not the argument
- modify test_modules.py for this
- mixins are not required to inherit from HasAttributes -> modify method check
- config for Attach may be mandatory (default: True)

Change-Id: I34f2965b12d69717e81d9296715467df6f3ac447
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/27934
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>
2022-03-11 15:16:27 +01:00
fda1939324 fix and improved Attached
- Attached checks now for proper base class
- fixes an error in Attached: attached saved in attachedModules
  dict instead on the Attached object (which sits on the class!)
+ fix: in testonly mode errors must be logged before returning
+ fix: use repr of exception in poll to check for repeated errors

Change-Id: I141fa107fed48e58b55ddf1e071987656c0f618f
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/27913
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2022-03-08 16:34:14 +01:00
8767be2aac improve k2601b driver
- activate current/voltage by setting their target
- deactive output by setting both active parameters to False
- split out power and resistivity to be separate modules

Change-Id: Ie2d7353bcd088da496f547da6fe83a192001fe8f
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/27910
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2022-03-08 11:25:52 +01:00
39a3e79eb3 move markdown to requirements-dev.txt
Change-Id: I6493483091bffdbff7c5ffec8c52b5b6f48e8664
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/27911
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>
2022-03-08 11:23:21 +01:00
c1d42f0f02 improve softcal
- be more tolerant parsing header of .340 file
- when curve not found, look also in secop_psi/calcurves
- better error message when curve not readable
- check that data points are monotonic
- auto create description if missing
- some more minor stuff

Change-Id: Iecc4dd3dda843b44391aa56272840472a61d4b2c
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/27909
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>
2022-03-07 16:18:21 +01:00
3fe44d32b1 reset connection on identification
required for issue 66.
The other stuff in issue 66 ('error_closed' message), has to be
implemented if and when frappy will support serial server connections

Change-Id: I63bcd59741c3c330a72b829ce8491766ffe6c3a8
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/27908
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>
2022-03-07 16:14:12 +01:00
f58ab263e7 various small fixes
- fix some earlyInit and initModules methods
- remove some comments
- change name of Done unique value to 'Done', this seems more
  useful for __repr__ and debug logging

Change-Id: I73f0e09bfef858ddca11bba0e92e941ebc151160
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/27907
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>
2022-03-07 16:13:13 +01:00
e0fe7e46d1 support for fast poll when busy
Module.setFastPoll may be called depending on status in order to
change the poll interval dependent whether the module is busy or
not. It is assured that the new interval is applied immediately.

Change-Id: I2bd8f68440dc4a93b39e5083a579fc1c123fe578
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/27896
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>
2022-03-04 17:21:03 +01:00
b423235c5d new poll mechanism
- remove secop.poller and basic poller
- regular polls for 'important' parameters done by method doPoll
- all other parameters are polled slower (slowInterval) and
  with lower priority (only one at a time when main poll is due)
- nopoll decorator for read_* to disable poll
- enablePoll attribute (default True) for disabling polling a module
- fast polls may be implemented by means of a statemachine
- configurable slow poll interval
+ allow a Parameter to override a Property (parameter
  Readable.pollinterval overrides Module.pollinterval)

Change-Id: Ib1b3453041a233678b7c4b4add22ac399670e447
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/27832
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>
2022-03-04 09:58:15 +01:00
aa82bc580d proper return value in handler read_* methods
wrapped read_* methods must always return a value

+ do not copy __name__ attribute of handler method to wrapped method

Change-Id: I54cd4b37cf7452621ee734be393aec4611fe809b
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/27870
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>
2022-03-02 11:36:33 +01:00
c2596a9629 implement a state machine
a quite simple, but powerful state machine

There is not need to subclass StateMachine, but use an instance
of it. The code typically lives on methods of an other class.

Features:
- store any variables (except already defined attributes) on the state
- actions handle the conditions to stay or initiate a transition
  by calling the state machines goto method
- a state machine might run endlessly or finish in a None action.
- it may be started or restarted
- a cleanup function for handling exceptions and for stop or restart
- support for time dependent features

Change-Id: I86b86ed1f25d04e305237edb99206912b068aedf
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/27593
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>
2022-02-23 18:20:23 +01:00
bf1761bbc4 common read/write handlers
introduce CommonReadHandler and CommonWriteHandler for
better handling of the case when several parameters are
read or written in one go.

- ppms: use common handlers
+ ppms: modify error handling when command result is not OK
+ store poll attribute on read_* methods

Change-Id: I9a9d0972e206956bcb5a83c204fe5f92c69716e3
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/27822
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>
2022-02-23 17:04:06 +01:00
99588fc815 fix handling commands
- commands have to import arguments and export the result properly

Change-Id: I4ff8879e4e9a93b0a3c57e015b7df8a6328a9bbc
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/27577
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>
2022-02-15 15:38:50 +01:00
bbc4663266 ppms: replace IOHandler by Read/WriteHandler
- add MultiWriteHandler
- the target and value type of secop_psi.ppms.Chamber are enums.
  make the code for them compatible.
+ fix a bug overriding exportname with export=True in parameter

Change-Id: Iec1daf19b3fdf2c017f967e45019867b77c6c59a
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/27583
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>
2022-02-15 15:38:27 +01:00
c1307cdd03 unify name and module on Attached property
- setting the attribute using the name of an attached module
- getting the attribute results in the module object

+ change names iodev to io, iodevClass to ioClass,
  sendRecv to communicate, HasIodev to HasIO

Change-Id: I200b63a5a7dc1453bf6ac998782b065645201900
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/27575
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2022-01-31 10:57:49 +01:00
b911bc1838 check for problematic value range
A common problematic practice is, to declare the value parameter
with the same FloatRange than the target. Because of measurement
errors, a value might be near, but outside the limit.
In order to avoid this, we force the programmer to declare a
bigger range for the value than for the target, or to
explicitly disable this check on a module property.
It is also fine to declare the value without limits.

This behavior may be disabled via command line option or in the
general config file. For simplicity, FloatRanges inside data
structures are not considered.

+ above command line option is also used to disable the error
  handling on a string to float conversion
+ log appropriate error message for string to float conversion

Change-Id: Ib78ea1fb7c821442bf5847030573c8c27822dea5
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/27574
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>
2022-01-31 09:12:39 +01:00
26a0f2e078 do not convert string to float
a read method should not reply on the automatic conversion
of the return value from string to a number.

- transitional solution with generalConfig.lazy_numer_validation
+ changing slighly generalInit mechanism: for above feature
  generalConfig.init is not required to be called (i.e. when
  used on the client side)

Change-Id: Ibecce1a45669273c105932acdc0908de55bfd1b9
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/27516
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>
2022-01-28 16:04:41 +01:00
4f7083bc98 ReadHandler and WriteHandler decorators
modules with a couple of parameters with similar read_* or
write_* methods may handle them by generic methods wrapped
with decorators ReadHandler / WriteHandler

The trinamic driver is included in this change for demonstrating
how it works.

In a further step, the special handling for the iohandler stuff can
be moved away from secop.server and secop.params, using this feature.

+ fix problem on startup of trinamic driver (needs MultiEvent.queue)
+ some other small fixes
+ apply recommended functools.wraps for wrapping

Change-Id: Ibfeff9209f53c47194628463466cee28366e17ac
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/27460
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>
2022-01-27 17:04:45 +01:00
0909f92e12 UniqueObject
create a class to be used for unique objects.
better for debugging and documentation than just using object()

+ remove unused unique objects

Change-Id: I32f65960ea2fbee4fccbeb49a4e11176b7185aa0
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/27455
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>
2022-01-17 11:38:15 +01:00
f3450375ce enhance logging
- bin/secop-server options -v and -q applied to console logger only
- level for logfile taken from general config
- option for automatic deletion of old logfiles
- added 'comlog' level (between debug and info)

This allows to run the servers by default with 'comlog' level on
the logfiles, which helps a lot for analyzing very rare communication
errors in retrospect.

to avoid spamming of the normal log files, comlog data is stored
separately, one file per communicator

+ redesign of remote logging (no more need of LoggerAdapter)

Change-Id: Ie156a202b1e7304e50bbe830901bc75872f6ffe2
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/27427
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2022-01-17 10:19:55 +01:00
eb2e8f5f74 fix doc (stringio - > io)
+ bug in secop.lib.classdoc

Change-Id: Ic1f6f2896466ce53dd176a338088b7ee6b8047af
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/27428
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>
2022-01-13 10:23:38 +01:00
2ef0da68e8 change name of read_hw_status method in sequencer mixin
change name to 'readHwStatus'
needed after commit "check for bad read* and write_* methods"

Change-Id: I27467aa2a3a3bb0db5f418c99f2d2065390a190a
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/27394
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>
2022-01-11 10:10:11 +01:00
9b38db7706 check for bad read_* and write_* methods
raise a ProgrammingError when a read_<param> or write_<param>
method is defined, but <param> is no parameter.

Change-Id: Iae4e617d078229182a90b202a6f81ebc49050118
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/27386
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>
2022-01-07 17:44:49 +01:00
8f7fb1e45b improve handling of module init methods
- complain when super call is omitted (this is a common programming
  error in Mixins)
- redesign waiting mechanism for startup

+ rename MultiEvent method 'setfunc' to 'get_trigger'

Change-Id: Ica27a75597321f2571a604a7a55448cffb1bec5e
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/27369
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>
2022-01-07 17:41:59 +01:00
f13e29aad2 introduce general config file
+ redesign general config
+ remove obsolete secop/paths.py

Change-Id: Ice08ec37c54b1a6e2e2e6e29fdaaf0bd2dd725dc
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/27362
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2022-01-05 09:05:00 +01:00
c5d228ffc4 add timeouts to MultiEvents
to be used for a follow up change for startup events

Change-Id: Id8816eb8f561dcd8d1473e25a9685e796fb14953
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/27364
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2021-12-22 15:12:56 +01:00
071ba38b60 remote logging (issue 46)
Change-Id: Id92e66280811b1f871157b5c2ceca65085d2c15b
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/27346
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>
2021-12-21 09:06:22 +01:00
b29b1e1b36 entangle.AnalogOutput: fix window mechanism
fix 2 problems:
- in case the window is smaller than the pollinterval, isAtTarget might be False
  for up to the timeout delay
- in case the history is shorter than the window, and the ramp is fast enough to miss
  any points during ramp, isAtTarget is True before the window time is reached.
  This happens because the history is reset on write_target

+ do not wait when target is not changed (by more than precision)

tested!

Change-Id: Ia4ff4378fe91fa93be50168b2883a20b49ebfb6a
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/27159
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>
2021-11-17 16:55:43 +01:00
c91d726f9d add more tests and fixes for command inheritance
- fix CommandType.__repr__
- secop/modules.py: command properties are allowed to be configured:
  - section 2: remove comment and rename
  - section 3: all accessible properties should be checked
- command description should be inherited also when taken from docstring
- move test for command inheritance to test_modules.py
- added tests to check for valid properties of commands

Change-Id: Ic7795e305048625558e415ece099e6824df6e2c4
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/27135
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>
2021-11-12 16:48:58 +01:00
1d75d192e5 automatic saving of persistent parameters
change persistent flag to be an enum off/on/auto

Change-Id: I3b1685ea76afb3b7f8c2e6ca63fbf81fa987750e
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/27100
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>
2021-11-12 10:48:10 +01:00
4bf3acab98 various small changes
- set default target unit to '$'
- shorten too verbose error message on client
- add shutdown method to server and dispatcher

Change-Id: Ib3a8b26bc31e988e45a3ff2efd734168d723d794
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/27095
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>
2021-11-12 10:47:52 +01:00
Georg Brandl
eebc9232cd debian: fix email addresses in changelog
Change-Id: I7279f2eb0fecbde5f7f02a983e1b58537b79566f
2021-11-12 09:18:24 +01:00
Jenkins system
c16f159599 [deb] Release v0.12.4 2021-11-11 16:21:19 +01:00
796be752b7 fix command inheritance
Command.ownProperties must be definead in __init__

+ add test for this

Change-Id: I283331be6439a49ec61d28f04869a5b44704236f
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/27104
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>
2021-11-11 14:20:10 +01:00
Jenkins system
b8e8d24b50 [deb] Release v0.12.3 2021-11-10 16:33:19 +01:00
45dd14a72c fix feature for removing commands
from a bug introduced in the 'fix parameter inheritance' change

Change-Id: I757c354130077d8838aac864b21b4f81caa9bccf
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/27096
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>
2021-11-10 16:21:58 +01:00
ad7cfe4ea0 automatically register subclasses of AsynConn
using __init_subclass__ method.

+ correct typo

Change-Id: I9a57c467efcd138651248f92fbf84195624e0b9a
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/27093
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>
2021-11-10 13:50:46 +01:00
47d09e9b08 improve simulation
- customizable simulation interval
- add stop command to SimDrivable

Change-Id: Id4eb0ec465ecc97a115397c295c4a052aceb762c
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/27092
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>
2021-11-10 13:50:30 +01:00
d76d79aebb omit updates of unchanged values within short time
Sometimes it happens, that the same value determined once is
assigned several times to a parameter within a very short period.
Sending multiple updates is not useful in this case.

Change-Id: Icea66934c831fd9b2eac7d0394a124d002469914
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/27091
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2021-11-10 12:34:51 +01:00
a64eb7f33b fix python 3.5 compatibility
- move workaround for PEP487 ty secop.lib.py35compat
- add missing context manager to TCPServer
- remove redundant code in secop/property.py

Change-Id: I0822010f196ad6cec5ec44e990013b79c5d4048b
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/27090
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>
2021-11-10 12:34:31 +01:00
3d0d779d81 fix property inheritance
+ remove obsolete filterDescriptor method
+ copying properties should support extensions (e.g. Attached)

Change-Id: I301947a4ae28fcad98250b277c6b0e7e0100eaf9
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/27084
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>
2021-11-09 18:21:03 +01:00
3b7cc33f64 fix parameter inheritance
Correct inheritance has to follow the MRO, not only consider
the direct base classes.

Patchset 3: changed only tests, indicating that we need to change the code

Following patchsets include a major change in params.py and
modules.py. The parameter properties for inheritance, corresponding
mainly to the constructor arguments have to be stored separately
from the property values including inherited stuff.

Change-Id: Ibcbccb6abcc22e7e2d91df8f70ef64226684d8cc
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/26805
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>
2021-11-09 15:06:36 +01:00
41489a4a24 show first instead of last traceback on multiple errors
on initialization, the error message are collected and
shown before starting the server together with the traceback
of the last error. This should be the traceback of the
first error instead.

Change-Id: I86d4b42f7d4f98f2ab3b692cd6548e62acffa11b
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/27011
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>
2021-11-09 14:42:14 +01:00
3140d454ae fix Parameter/Command copy method
in case the Parameter/Command is subclassed

Change-Id: Ib34fc78e72cd04e743e35ef7ccd40b2eae03b614
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/26450
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2021-07-27 08:06:20 +02:00
7bd166a8a1 persistent params / trinamic motor
for the trinamic motor we need persistent parameters

Change-Id: Id509b87f8368ea5ba1aca71951f79433b0b4b79f
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/26405
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2021-07-27 07:57:49 +02:00
f3978385b4 GUI fixes
- do not show command result dialog when result is None
- apply fmtstr, if available

+ fix io import in secop.core
+ change old style <basecls>.__init__(self, ...) calls to super().__init__(...)

Change-Id: I599d5d8e8ff430ea9454a0858d703290e87454fc
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/26397
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Jens Krueger <jens.krueger@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2021-07-16 14:50:00 +02:00
bc6a99e11b introduce BytesIO
rename secop.stringio to secop.io, which includes now
also BytesIO and the common base class IOBase

+ a small fix in error handling

Change-Id: I8e305e2c164f4ed131f4b36ef45edd8bd222336d
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/26393
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>
2021-07-15 15:54:51 +02:00
6b610f1e25 remove irrelevant comments
+ improve error message 'can not convert %r to float'
Change-Id: Idf534a4105086463fd238d7c91317424a809d7ba

Change-Id: I09260dda8deff1e6ee0af2fa38a42a09884a2061
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/26345
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2021-07-06 16:13:33 +02:00
9a60de9c1c various fixes
- nodestatechange callback must appear after the online attribute
  is changed
- IntRange: move range validation outside of try except
- fixes on some error names
- well defined error message 'no such class' in secop.lib.get_class
- try again 4 times when starting Tcp Server on EADDRINUSE
- fix error handling

Change-Id: I4eee9b79ea8173936b9f5193b87e006ac8fca827
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/26171
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>
2021-06-14 09:03:41 +02:00
Georg Brandl
026e657799 Makefile: fix docker image
Change-Id: I90a3fe36abbea0501c7e7e27fa33e90bfd4f116d
2021-05-29 14:46:25 +02:00
Jenkins system
35f08bf4ad [deb] Release v0.12.2 2021-05-18 10:29:17 +02:00
Enrico Faulhaber
76ae75a926 secop_mlz: small fixes
- wrong unit for 'ramp'
- disable Setposition for TemperatureController
- write_target should return the new target
- AnalogInput should not crash initialisation if reading the unit fails
- convert super(...) calls to py3 style super()
- use proper exception chaining
- NamedDigital*put: mapping may already be a dict.

Change-Id: I03ce5f29581dcb3b33466771e7a8b8dd4b1e2bdb
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/25960
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>
2021-05-18 10:27:54 +02:00
27ac70b1da allow to remove accessibles
removing an inherited command or parameter can now be indicated
with an attribute set to None

Change-Id: I7582434013856190b346e381d2e634509896ccb3
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/25963
Tested-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
2021-05-18 10:27:37 +02:00
a343b07f1d treat specifier of describe message
for debugging purposes, getting the description of a module
or even a parameter is usefull

therefore the following will work

describe <module>
describe <module>:<param>

Change-Id: Ie262ae12c23d1c151cdc01830ad4f8fd5ec3c5f1
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/25962
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>
2021-05-17 17:36:47 +02:00
09411f36f3 fix issue with new syntax in simulation
for creating extra parameters a subclass of SimBase is created,
in order to treat parameters and read_/write_ methods properly.

Change-Id: I9061b9afb0f8922b36b8f9448c45bb3aadb8f515
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/25961
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>
2021-05-17 17:36:28 +02:00
Jenkins system
b0f0a48e51 [deb] Release v0.12.1 2021-05-04 09:42:53 +02:00
Enrico Faulhaber
e4261ecfe1 remove secop-console from debian *.install file
Change-Id: I9ba8bd37b9460db83512a35bc2e98b63a4df9687
2021-05-04 09:41:12 +02:00
Jenkins system
598dd07888 [deb] Release v0.12.0 2021-05-04 08:49:58 +02:00
Bjoern Pedersen
f2b330a3f0 Correct checks enum
Change-Id: Ibe23825bfdfcac15262987383407e18ead4cf880
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/25840
Tested-by: Bjoern Pedersen <bjoern.pedersen@frm2.tum.de>
Reviewed-by: Bjoern Pedersen <bjoern.pedersen@frm2.tum.de>
2021-04-30 08:08:22 +02:00
Bjoern Pedersen
a85201ad7d Another Jenkisfile error
Change-Id: I313f1471aad166c794374c7d381c1b66a4395b4d
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/25839
Tested-by: Bjoern Pedersen <bjoern.pedersen@frm2.tum.de>
Reviewed-by: Bjoern Pedersen <bjoern.pedersen@frm2.tum.de>
2021-04-30 07:59:02 +02:00
Bjoern Pedersen
2cf6e167a8 No pull for images, they are recreated in the job
Change-Id: I4ac389873310a411ea33ed6c06af8ec8f752dfd6
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/25838
Tested-by: Bjoern Pedersen <bjoern.pedersen@frm2.tum.de>
Reviewed-by: Bjoern Pedersen <bjoern.pedersen@frm2.tum.de>
2021-04-30 07:54:43 +02:00
Bjoern Pedersen
ffc2c495fb Fixes to Jenkinsfile
Change-Id: Id75b49fd8c38ef90a0869ba6845a36f338a239b5
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/25837
Tested-by: Bjoern Pedersen <bjoern.pedersen@frm2.tum.de>
Reviewed-by: Bjoern Pedersen <bjoern.pedersen@frm2.tum.de>
2021-04-30 07:52:14 +02:00
Bjoern Pedersen
7ea4e3955a Jenkisfile: verification
Change-Id: I58829f1672c95bb76c765aa1ce86d808f9e50dfd
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/25836
Tested-by: Bjoern Pedersen <bjoern.pedersen@frm2.tum.de>
Reviewed-by: Bjoern Pedersen <bjoern.pedersen@frm2.tum.de>
2021-04-30 07:49:28 +02:00
cc1632e07d user friendly reporting of config errors
Config errors are collected first, and raised after processing
all modules. This is more user friendly.

+ remove redundant check for predefined accessibles in modules.py
+ fixed error handling for exporting parameters in params.py
+ fixed handling of bare attributes overwriting properties
+ fixed race condition in writeInitParams

Change-Id: I894bda291ab85ccec3d771c4903393c808af0a2a
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/25128
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>
2021-04-27 18:20:53 +02:00
l_samenv
1e17d0c6b9 fixed bugs from syntax migration
- a new wrapper for a read function is not only to be created when
  the a new read method is in the class dict, but also when
  it is inherited, but not yet wrapped
- a handler must not be ignored, when a write method is inherited
- a proxy class must not call checkProperties

+ remove trailing spaces in tutorial_helevel.rst

Change-Id: I16024c14232ea200db91a1bc07ec23326219ab68
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/25093
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2021-03-05 08:33:23 +01:00
l_samenv
e568c665a8 improve tutorial_helevel
- fix indent of query method
- add remark about the CCU4 cid command

Change-Id: Iaee821cf7739536cc823494f646a1d2a4bbbfa44
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/25092
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2021-03-03 16:03:26 +01:00
d0f895ed44 fix autoscan behaviour in ls370res
when in autoscan, and dwell < filter, the channel was never read

+ do not export pollinterval on both Main and ResChannel

Change-Id: I50df9e151b219ab28875ac78107dcdfdede42c51
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/25087
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2021-03-03 14:31:40 +01:00
69f5692951 move historywriter to secop_psi
as historywriter currently could be used at psi only
secop_psi is a better place for it

+ add comment about a general config file

Change-Id: I9b0e74d3da83ac485bd4bcc13475695c3140822c
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/25077
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>
2021-03-02 16:00:26 +01:00
980499ba41 fixed errors during migration
- reference.rst did still contain do_<something>
- trailing commas in secop_demo/cryo.py

Change-Id: I5bb8bd310576366c8cfe406f0ec770fa40bcab5b
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/25079
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>
2021-03-01 16:33:08 +01:00
6cde8177d5 added hook for optional history writer
- activated with envrionment variable FRAPPY_HISTORY
- using the (currently) private package 'frappyhistory'

Change-Id: I8f747b29d8311af677ed77268a4c38c8d71b08c2
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/25064
Tested-by: Markus Zolliker <markus.zolliker@psi.ch>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2021-02-26 13:26:50 +01:00
23779c8f8c lookup cfg files in a list of directories
environment variable SECOP_CONFDIR may be a ':' separated
list of directories to lookup for cfg files

Change-Id: I058be6a270d3a3f6cd8ca45fdd4ab68c80fa5c23
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/25063
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>
2021-02-26 13:22:19 +01:00
899a07aec8 remove obsolete code
- basic_validators is not needed any more since the implementation
  of datatypes.Stub
- client/baseclient.y is replaced by client/__init__.py both for
  the gui client and NICOS SECoP client
- lib/parsing.py used by baseclient only

Change-Id: I15b6ac880017000e155b8f6b7e2456e1bbf56dab
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/25058
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>
2021-02-26 13:21:48 +01:00
6a32ecf342 fix inheritance order
+ hide pollperiod on PPMS Modules

Change-Id: I77ad5502884360bf6babfd226de0675ee06a6196
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/25054
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>
2021-02-24 15:42:33 +01:00
1464a6bce5 try to follow PEP8
- fixed most important code after checking with flake8
- ignored code which has to be reworked or removed
+ mark unused code with 'TODO: remove ...'

Change-Id: Ic45e541049e391e2853d29cd64bb0963bd9a2125
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/25053
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
2021-02-24 15:00:06 +01:00
bb6f692c6b after running isort
Change-Id: I6d7dbb8dee9480fc9242529089a1b40f17f068e7
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/25052
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2021-02-24 10:50:37 +01:00
1a8ddbc696 removed old style syntax
- removed secop/metaclass.py
- moved code from ModuleMeta to modules.HasAccessibles.__init_subclass__
- reworked properties:
  assignment obj.property = value now always allowed
- reworked Parameters and Command to be true descriptors
- Command must now be solely used as decorator
- renamed 'usercommand' to 'Command'
- command methods no longer start with 'do_'
- reworked mechanism to determine accessible order:
  the attribute paramOrder, if given, determines order of accessibles
+ fixed some issues makeing the IDE more happy
+ simplified code for StatusType and added a test for it

Change-Id: I8045cf38ee6f4d4862428272df0b12a7c8abaca7
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/25049
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>
2021-02-24 08:44:13 +01:00
ed02131a37 enhance documentation
- flatten hierarchy (some links do not work when using folders)
- add a tutorial for programming a simple driver
- clean description using inspect.cleandoc
+ fix a bug with 'unit' pseudo property in a Parameter used as override

Change-Id: I31ddba5d516d1ee5e785e28fbd79fca44ed23f5e
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/25000
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2021-02-10 17:07:08 +01:00
a19425684c new syntax for parameter/commands/properties
New Syntax:

- define properties and parameters as class attributes directly
  instead of items in class attribute dicts
- define commands with decorator @usercommand(...)
- old syntax is still supported for now

still to do (with decreasing priority):
- turn parameters into descriptors (vs. creating getters/setters)
- migrate all existing code to new syntax
- get rid of or reduce code in metaclasses using __set_name__ and
  __init_subclass__ instead, including a fix for allowing py < 3.6

Change-Id: Id47e0f89c506f50c40fa518b01822c6e5bbf4e98
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/24991
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>
2021-02-05 12:30:13 +01:00
24cffad4df make arguments of Parameter and Override consistent
- allow (description and) datatype being positional args in Override
- disallow ctr and unit being a positional arg in Parameter
- disallow reorder being a positional arg in Override

Change-Id: Ic5711d091af11d5843943b0b2b31567127f8ed8c
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/24934
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>
2021-01-27 10:08:53 +01:00
05fec236da improve softcal
- bugfix: stop searching for file on the first match
- allow to ignore the sign on input by abs (bool) parameter

Change-Id: I0e5544d7645f124d4c4ac720174b0f5bde7e71a6
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/24928
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
2021-01-27 08:56:26 +01:00
b1a88440ef main module of LS370 is now drivable
The main value of main module is the selected channel, it is 0
when pausing during scanning, and the status is busy.

+ cosmetics to make IDE more happy

Change-Id: I11d8f08ea67d25fb00f7492080b4a55efc124bfb
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/24927
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>
2021-01-27 08:56:04 +01:00
c9721649a3 make order of accessibles work again
- when applying overrides with reorder=True, take ctr from Override,
  else copy from the cloned Accesible. This did not work properly
- reworked:
  - replaced CountedObj class by object_counter
  - accessibles created by a copy or by applying Overrides
    do not need fresh counted values
- adjusted tests

Change-Id: Id2fcf1ab1295aa1ea80ea81ae8cd02d36f86e969
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/24926
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>
2021-01-27 08:55:30 +01:00
d2c3370a40 fix initwrite behaviour
with handlers, a parameter from the cfg file which is not the
first of parameters with the same handler were not written.
fix: write_<param> method is called for all parameters in
<module>.writeDict even if there is no poll entry.

with this fix, when a parameter has the property initwrite=True,
the write_<param> method is called even when <param>
is not polled and even when <module>.pollerClass is None

Change-Id: I9b397deb5b20709fc4fa7c860c85b251a204c7f6
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/23995
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>
2020-09-29 07:52:59 +02:00
242 changed files with 12412 additions and 8029 deletions

View File

@ -1,2 +1,2 @@
SECoP playground for creating specification and testing one implementation.
Frappy framework for implementing SEC-nodes (see SECoP protocol on github).

View File

@ -38,27 +38,21 @@ confidence=
# multiple time.
disable=missing-docstring
,locally-disabled
,locally-enabled
,fixme
,no-member
,bad-whitespace
,wrong-import-position
,ungrouped-imports
,import-self
,bad-continuation
,protected-access
,unused-argument
,duplicate-code
,attribute-defined-outside-init
,access-member-before-definition
,no-self-use
,broad-except
,unneeded-not
,unidiomatic-typecheck
,undefined-loop-variable
,redefined-variable-type
,deprecated-lambda
,consider-using-f-string
[REPORTS]
# Set the output format. Available formats are text, parseable, colorized, msvs
@ -67,10 +61,6 @@ disable=missing-docstring
msg-template={path}:{line}: [{msg_id}({symbol}), {obj}] {msg}
# Put messages in a separate file for each module / package specified on the
# command line instead of printing them on stdout. Reports (if any) will be
# written in a file name "pylint_global.[txt|html]".
files-output=no
# Tells whether to display a full report or only the messages
reports=no
@ -93,14 +83,11 @@ dummy-variables-rgx=_|dummy
# List of additional names supposed to be defined in builtins. Remember that
# you should avoid to define new builtins when possible.
additional-builtins=
additional-builtins=Node,Mod,Param,Command,Group
[BASIC]
# List of builtins function names that should not be used, separated by a comma
#bad-functions=map,filter,apply,input
bad-functions=apply,input
# Regular expression which should only match correct module names
module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9_]+))$
@ -155,14 +142,8 @@ notes=FIXME,XXX,TODO
# Maximum number of characters on a single line.
max-line-length=132
# List of optional constructs for which whitespace checking is disabled. `dict-
# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}.
# `trailing-comma` allows a space between comma and closing bracket: (a, ).
# `empty-line` allows space-only lines.
no-space-check=trailing-comma,dict-separator
# Maximum number of lines in a module
max-module-lines=1200
max-module-lines=1000
# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
# tab).
@ -212,13 +193,13 @@ max-locals=50
max-returns=10
# Maximum number of branch for function / method body
max-branches=40
max-branches=50
# Maximum number of statements in function / method body
max-statements=150
# Maximum number of parents for a class (see R0901).
max-parents=10
max-parents=15
# Maximum number of attributes for a class (see R0902).
max-attributes=50

View File

@ -3,12 +3,18 @@
all: clean doc
# Make spawns a new shell for each command.
# Save each PID in temporary file
# sleep in order for "test" to have started reliably
demo:
@bin/secop-server -q demo &
@bin/secop-server -q test &
@bin/secop-server -q cryo &
@bin/secop-gui localhost:10767 localhost:10768 localhost:10769
@ps aux|grep [s]ecop-server|awk '{print $$2}'|xargs kill
@rm -f frappydemo.PID || true
@{ bin/frappy-server -q demo & echo $$! >> frappydemo.PID; }
@{ bin/frappy-server -q test & echo $$! >> frappydemo.PID; }
@{ bin/frappy-server -q cryo & echo $$! >> frappydemo.PID; }
@sleep 0.2
@bin/frappy-gui localhost:10767 localhost:10768 localhost:10769
@cat frappydemo.PID | xargs kill || true
@rm frappydemo.PID
build:
python3 setup.py build
@ -32,18 +38,18 @@ test-verbose:
python3 $(shell which pytest) -v test -s
test-coverage:
python3 $(shell which pytest) -v test --cov=secop
python3 $(shell which pytest) -v test --cov=frappy
doc:
$(MAKE) -C doc html
lint:
pylint -j 0 -f colorized -r n --rcfile=.pylintrc secop secop_* test
pylint -f colorized -r n --rcfile=.pylintrc frappy frappy_* test
isort:
@find test -name '*.py' -print0 | xargs -0 isort -e -m 2 -w 80 -ns __init__.py
@find secop -name '*.py' -print0 | xargs -0 isort -e -m 2 -w 80 -ns __init__.py
@find . -wholename './secop_*.py' -print0 | xargs -0 isort -e -m 2 -w 80 -ns __init__.py
@find frappy -name '*.py' -print0 | xargs -0 isort -e -m 2 -w 80 -ns __init__.py
@find . -wholename './frappy_*.py' -print0 | xargs -0 isort -e -m 2 -w 80 -ns __init__.py
release-patch:
MODE="patch" $(MAKE) release
@ -55,8 +61,8 @@ release-major:
MODE="major" $(MAKE) release
release:
ssh jenkinsng.admin.frm2 -p 29417 build -v -s -p GERRIT_PROJECT=$(shell git config --get remote.origin.url | rev | cut -d '/' -f -3 | rev) -p ARCH=all -p MODE=$(MODE) ReleasePipeline
ssh jenkins.admin.frm2.tum.de -p 29417 build -v -s -p GERRIT_PROJECT=$(shell git config --get remote.origin.url | rev | cut -d '/' -f -2 | rev) -p ARCH=all -p MODE=$(MODE) ReleasePipeline
build-pkg:
debocker build --image jenkinsng.admin.frm2:5000/mlzbase/buster
debocker build --image docker.ictrl.frm2.tum.de:5443/mlzbase/buster

View File

@ -29,8 +29,8 @@ from os import path
# Add import path for inplace usage
sys.path.insert(0, path.abspath(path.join(path.dirname(__file__), '..')))
from secop.gui.qt import QApplication
from secop.gui.cfg_editor.mainwindow import MainWindow
from frappy.gui.qt import QApplication
from frappy.gui.cfg_editor.mainwindow import MainWindow
def main(argv=None):

View File

@ -26,42 +26,49 @@
from __future__ import print_function
import sys
import argparse
from os import path
# Add import path for inplace usage
sys.path.insert(0, path.abspath(path.join(path.dirname(__file__), '..')))
import mlzlog
import logging
from mlzlog import ColoredConsoleHandler
from secop.gui.qt import QApplication
from secop.gui.mainwindow import MainWindow
from frappy.gui.qt import QApplication
from frappy.gui.mainwindow import MainWindow
def parseArgv(argv):
parser = argparse.ArgumentParser()
loggroup = parser.add_mutually_exclusive_group()
loggroup.add_argument('-d', '--debug',
help='Enable debug output',
action='store_true', default=False)
loggroup.add_argument('-q', '--quiet',
help='Supress everything but errors',
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'])
return parser.parse_args(argv)
def main(argv=None):
if argv is None:
argv = sys.argv
if '-h' in argv or '--help' in argv:
print("Usage: secop-gui [-d] [-h] [host:[port]]")
print()
print("Option GNU long option Meaning")
print("-h --help Show this message")
print("-d --debug Enable debug output")
print()
print("if not given, host defaults to 'localhost' and port to 10767")
sys.exit(0)
args = parseArgv(argv[1:])
if '-d' in argv or '--debug' in argv:
mlzlog.initLogging('gui', 'debug')
else:
mlzlog.initLogging('gui', 'info')
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)
app = QApplication(argv)
hosts = [host for host in argv[1:] if not host.startswith('-')]
if not hosts:
hosts = ['localhost:10767']
win = MainWindow(hosts)
win = MainWindow(args.node, logger)
win.show()
return app.exec_()

View File

@ -27,13 +27,12 @@ import sys
import argparse
from os import path
import mlzlog
# Add import path for inplace usage
sys.path.insert(0, path.abspath(path.join(path.dirname(__file__), '..')))
from secop.lib import getGeneralConfig
from secop.server import Server
from frappy.lib import generalConfig
from frappy.logging import logger
from frappy.server import Server
def parseArgv(argv):
@ -60,15 +59,26 @@ def parseArgv(argv):
parser.add_argument('-c',
'--cfgfiles',
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,"
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",
default=None)
parser.add_argument('-g',
'--gencfg',
action='store',
help="full path of general config file,\n"
"defaults to env. variable FRAPPY_CONFIG_FILE\n",
default=None)
parser.add_argument('-t',
'--test',
action='store_true',
help='Check cfg files only',
help='check cfg files only',
default=False)
parser.add_argument('-r',
'--relaxed',
action='store_true',
help='no checking of problematic behaviour',
default=False)
return parser.parse_args(argv)
@ -80,9 +90,12 @@ def main(argv=None):
args = parseArgv(argv[1:])
loglevel = 'debug' if args.verbose else ('error' if args.quiet else 'info')
mlzlog.initLogging('secop', loglevel, getGeneralConfig()['logdir'])
generalConfig.defaults = {k: args.relaxed for k in (
'lazy_number_validation', 'disable_value_range_check', 'legacy_hasiodev', 'tolerate_poll_property')}
generalConfig.init(args.gencfg)
logger.init(loglevel)
srv = Server(args.name, mlzlog.log, cfgfiles=args.cfgfiles, interface=args.port, testonly=args.test)
srv = Server(args.name, logger.log, cfgfiles=args.cfgfiles, interface=args.port, testonly=args.test)
if args.daemonize:
srv.start()

View File

@ -1,76 +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:
# Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
#
# *****************************************************************************
import sys
import argparse
from os import path
# Path magic to make python find our stuff.
# also remember our basepath (for etc, pid lookup, etc)
basepath = path.abspath(path.join(sys.path[0], '..'))
etc_path = path.join(basepath, 'etc')
pid_path = path.join(basepath, 'pid')
log_path = path.join(basepath, 'log')
# sys.path[0] = path.join(basepath, 'src')
sys.path[0] = basepath
# do not move above!
import mlzlog
from secop.client.console import ClientConsole
def parseArgv(argv):
parser = argparse.ArgumentParser(description="Connect to a SECoP server")
loggroup = parser.add_mutually_exclusive_group()
loggroup.add_argument("-v", "--verbose",
help="Output lots of diagnostic information",
action='store_true', default=False)
loggroup.add_argument("-q", "--quiet", help="suppress non-error messages",
action='store_true', default=False)
parser.add_argument("name",
type=str,
help="Name of the instance.\n"
" Uses etc/name.cfg for configuration\n",)
return parser.parse_args()
def main(argv=None):
if argv is None:
argv = sys.argv
args = parseArgv(argv[1:])
loglevel = 'debug' if args.verbose else ('error' if args.quiet else 'info')
mlzlog.initLogging('console', loglevel, log_path)
console = ClientConsole(args.name, basepath)
try:
console.run()
except KeyboardInterrupt:
console.close()
if __name__ == '__main__':
sys.exit(main(sys.argv))

View File

@ -42,7 +42,7 @@ import ast
# Add import path for inplace usage
sys.path.insert(0, path.abspath(path.join(path.dirname(__file__), '..')))
from secop.lib import get_class, formatException
from frappy.lib import get_class, formatException
class LineHandler(asyncore.dispatcher_with_send):
@ -136,7 +136,7 @@ for arg in sys.argv[1:]:
pass
opts[k] = v
verbose = opts.pop('verbose', False)
opts['cls'] = 'secop_psi.ls370sim.Ls370Sim'
opts['cls'] = 'frappy_psi.ls370sim.Ls370Sim'
opts['port'] = 4567
if len(args) > 2:
raise ValueError('do not know about: %s' % ' '.join(args[2:]))

View File

@ -7,11 +7,11 @@ bindto = 0.0.0.0
bindport = 5000
[module cap]
class = secop_psi.ah2700.Capacitance
class = frappy_psi.ah2700.Capacitance
description = capacitance
uri=ldmse3-ts:3015
#[module ahcom]
#class = secop_psi.ah2700.StringIO
#class = frappy_psi.ah2700.StringIO
#uri=ldmse3-ts:3015
#description = serial communicator to an AH2700

View File

@ -19,7 +19,7 @@ bindto=0.0.0.0
bindport=10767
[module enable]
class=secop_mlz.entangle.NamedDigitalOutput
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}]
@ -27,7 +27,7 @@ target.datatype=["enum", {'On':1,'Off':0}]
.visibility='advanced'
[module polarity]
class=secop_mlz.entangle.NamedDigitalOutput
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}]
@ -41,7 +41,7 @@ comtries=50
[module symmetry]
class=secop_mlz.entangle.NamedDigitalOutput
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}]
@ -51,35 +51,35 @@ target.datatype=["enum",{'symmetric':1,'short':0, 'asymmetric':-1}]
.visibility=advanced
[module T1]
class=secop_mlz.entangle.AnalogInput
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=secop_mlz.entangle.AnalogInput
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=secop_mlz.entangle.AnalogInput
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=secop_mlz.entangle.AnalogInput
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=secop_mlz.entangle.PowerSupply
class=frappy_mlz.entangle.PowerSupply
tangodevice=tango://localhost:10000/box/lambda/curr
.description=Device for the magnet power supply (current mode)
abslimits=(0,200)
@ -92,7 +92,7 @@ voltage=10
.visibility=advanced
[module mf]
class=secop_mlz.amagnet.GarfieldMagnet
class=frappy_mlz.amagnet.GarfieldMagnet
.description=magnetic field module, handling polarity switching and stuff
subdev_currentsource=currentsource
subdev_enable=enable

View File

@ -11,7 +11,7 @@ bindto=0.0.0.0
bindport=10767
[module automatik]
class=secop_mlz.entangle.NamedDigitalOutput
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
@ -19,13 +19,13 @@ description="controls the (simple) pressure regulation
selects between off, regulate on p1 or regulate on p2 sensor"
[module compressor]
class=secop_mlz.entangle.NamedDigitalOutput
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=secop_mlz.entangle.NamedDigitalOutput
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)
@ -35,7 +35,7 @@ description=control the gas inlet into the ccr (on/off)
note: if the pressure regulation is active, it enslave this device
[module vacuum]
class=secop_mlz.entangle.NamedDigitalOutput
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)
@ -44,19 +44,19 @@ description=control the vacuum inlet into the ccr (on/off)
note: if the pressure regulation is active, it enslave this device
[module p1]
class=secop_mlz.entangle.AnalogInput
class=frappy_mlz.entangle.AnalogInput
tangodevice=tango://localhost:10000/box/plc/_p1
value.unit='mbar'
description=pressure sensor 1 (linear scale)
[module p2]
class=secop_mlz.entangle.AnalogInput
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=secop_mlz.entangle.NamedDigitalInput
class=frappy_mlz.entangle.NamedDigitalInput
tangodevice=tango://localhost:10000/box/plc/_curve
value.default=0
description=calibration curve for pressure sensor 2
@ -71,25 +71,25 @@ mapping="{'0-10V':0, '0-1000mbar':1, '1-9V to 0-1 mbar':2,
# sensors
[module T_sample]
class=secop_mlz.entangle.Sensor
class=frappy_mlz.entangle.Sensor
tangodevice=tango://localhost:10000/box/sample/sensora
value.unit='K'
description=sample temperature
[module T_stick]
class=secop_mlz.entangle.Sensor
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=secop_mlz.entangle.Sensor
class=frappy_mlz.entangle.Sensor
tangodevice=tango://localhost:10000/box/coldhead/sensorc
value.unit='K'
description=temperature at coldhead
[module T_tube]
class=secop_mlz.entangle.Sensor
class=frappy_mlz.entangle.Sensor
tangodevice=tango://localhost:10000/box/tube/sensord
value.unit='K'
description=temperature at thermal coupling tube <-> stick
@ -98,7 +98,7 @@ description=temperature at thermal coupling tube <-> stick
# regulations
[module T_stick_regulation]
class=secop_mlz.entangle.TemperatureController
class=frappy_mlz.entangle.TemperatureController
tangodevice=tango://localhost:10000/box/stick/control2
heateroutput.default=0
description=regulation of stick temperature
@ -114,7 +114,7 @@ value.unit='K'
# OMG! a NamedDigitalOutput, but with float'ints' 0..3
[module T_stick_regulation_heaterrange]
class=secop_mlz.entangle.AnalogOutput
class=frappy_mlz.entangle.AnalogOutput
tangodevice=tango://localhost:10000/box/stick/range2
precision.default=1
abslimits=(0,3)
@ -122,7 +122,7 @@ description=heaterrange for stick regulation
[module T_tube_regulation]
class=secop_mlz.entangle.TemperatureController
class=frappy_mlz.entangle.TemperatureController
tangodevice=tango://localhost:10000/box/tube/control1
description=regulation of tube temperature
heateroutput.default=0
@ -138,13 +138,13 @@ value.unit='K'
# OMG! a NamedDigitalOutput, but with float'ints' 0..3
#[module T_tube_regulation_heaterrange]
#class=secop_mlz.entangle.AnalogOutput
#class=frappy_mlz.entangle.AnalogOutput
#tangodevice=tango://localhost:10000/box/tube/range1
#precision.default=1
#abslimits=(0,3)
[module T_tube_regulation_heaterrange]
class=secop_mlz.entangle.NamedDigitalOutput
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

View File

@ -1,50 +0,0 @@
[node cryo_7]
# set SEC-node properties
description = short description
.
This is a very long description providing all the glory details in all the glory details about the stuff we are describing
[interface tcp]
type=tcp
bindto=0.0.0.0
bindport=10769
[module cryo]
# some (non-defaut) module properties
.group=very important/stuff
.description=A simulated cc cryostat with heat-load, specific heat for the sample
and a temperature dependend heat-link between sample and regulation.
# class of module:
class=secop_demo.cryo.Cryostat
# some parameters
jitter=0.1
T_start=10.0
target=10.0
looptime=1
ramp=6
maxpower=20.0
heater=4.1
p=40
i=10
d=2
mode=pid
tolerance=0.1
window=30
timeout=900
# some (non-default) parameter properties
pollinterval.export=False
# some parameter grouping
p.group=pid
i.group=pid
d.group=pid
value.unit=K
# test custom properties
value.test=customized value

37
cfg/cryo_cfg.py Normal file
View File

@ -0,0 +1,37 @@
#####################################################################
# Python version of frappy config
#####################################################################
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',
'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.',
group='very important/stuff',
jitter=0.1,
T_start=10.0,
target=10.0,
looptime=1,
ramp=6,
maxpower=20.0,
heater=4.1,
mode='pid',
tolerance=0.1,
window=30,
timeout=900,
p = Param(40, unit='%/K'), # in case 'default' is the first arg, we can omit 'default='
i = 10,
d = 2,
pid = Group('p', 'i', 'd'),
pollinterval = Param(export=False),
value = Param(unit = 'K', test = 'customized value'),
)

View File

@ -1,43 +0,0 @@
[node Equipment_ID_for_demonstration]
description = virtual modules to play around with
[interface tcp]
bindto=0.0.0.0
bindport=10767
[module heatswitch]
class=secop_demo.modules.Switch
switch_on_time=5
switch_off_time=10
.description="Heatswitch for `mf` device"
[module mf]
class=secop_demo.modules.MagneticField
heatswitch = heatswitch
.description="simulates some cryomagnet with persistent/non-persistent switching"
[module ts]
class=secop_demo.modules.SampleTemp
sensor = 'Q1329V7R3'
ramp = 4
target = 10
value = 10
.description = "some temperature"
[module tc1]
class=secop_demo.modules.CoilTemp
sensor="X34598T7"
.description = "some temperature"
[module tc2]
class=secop_demo.modules.CoilTemp
sensor="X39284Q8'
.description = "some temperature"
[module label]
class=secop_demo.modules.Label
system=Cryomagnet MX15
subdev_mf=mf
subdev_ts=ts
.description = "some label indicating the state of the magnet `mf`."

45
cfg/demo_cfg.py Normal file
View File

@ -0,0 +1,45 @@
Node('demo.frappy.demo',
'Basic demo server for frappy',
'tcp://10767',
)
Mod('heatswitch',
'frappy_demo.modules.Switch',
'Heatswitch for `mf` device',
switch_on_time = 5,
switch_off_time = 10,
)
Mod('mf',
'frappy_demo.modules.MagneticField',
'simulates some cryomagnet with persistent/non-persistent switching',
heatswitch = 'heatswitch',
)
Mod('ts',
'frappy_demo.modules.SampleTemp',
'some temperature',
sensor = 'Q1329V7R3',
ramp = 4,
target = 10,
value = 10,
)
Mod('tc1',
'frappy_demo.modules.CoilTemp',
'some temperature',
sensor = 'X34598T7',
)
Mod('tc2',
'frappy_demo.modules.CoilTemp',
'some temperature',
sensor = 'X39284Q8',
)
Mod('label',
'frappy_demo.modules.Label',
'some label indicating the state of the magnet `,f`.',
subdev_mf = 'mf',
subdev_ts = 'ts',
)

View File

@ -7,23 +7,23 @@ bindto=0.0.0.0
bindport=10767
[module tc1]
class=secop_demo.modules.CoilTemp
class=frappy_demo.modules.CoilTemp
sensor="X34598T7"
[module tc2]
class=secop_demo.modules.CoilTemp
class=frappy_demo.modules.CoilTemp
sensor="X39284Q8'
[module sensor1]
class=secop_ess.epics.EpicsReadable
class=frappy_ess.epics.EpicsReadable
epics_version="v4"
.group="Lakeshore336"
value_pv="DEV:KRDG1"
[module loop1]
class=secop_ess.epics.EpicsTempCtrl
class=frappy_ess.epics.EpicsTempCtrl
epics_version="v4"
.group="Lakeshore336"
@ -33,14 +33,14 @@ heaterrange_pv="DEV:RANGE_S1"
[module sensor2]
class=secop_ess.epics.EpicsReadable
class=frappy_ess.epics.EpicsReadable
epics_version="v4"
.group="Lakeshore336"
value_pv="DEV:KRDG2"
[module loop2]
class=secop_ess.epics.EpicsTempCtrl
class=frappy_ess.epics.EpicsTempCtrl
epics_version="v4"
.group="Lakeshore336"

5
cfg/generalConfig.cfg Normal file
View File

@ -0,0 +1,5 @@
[FRAPPY]
# general config for running in git repo
logdir = ./log
piddir = ./pid
confdir = ./cfg

View File

@ -1,24 +1,28 @@
[node LscSIM.psi.ch]
[NODE]
id = LscSIM.psi.ch
description = Lsc Simulation at PSI
[interface tcp]
type = tcp
bindto = 0.0.0.0
bindport = 5000
[INTERFACE]
uri = tcp://5000
[module res]
class = secop_psi.ls370res.ResChannel
.channel = 3
.description = resistivity
.main = lsmain
.iodev = lscom
[lscom]
class = frappy_psi.ls370sim.Ls370Sim
description = simulated serial communicator to a LS 370
visibility = 3
[module lsmain]
class = secop_psi.ls370res.Main
.description = main control of Lsc controller
.iodev = lscom
[sw]
class = frappy_psi.ls370res.Switcher
description = channel switcher for Lsc controller
io = lscom
[module lscom]
class = secop_psi.ls370sim.Ls370Sim
.description = simulated serial communicator to a LS 370
.visibility = 3
[a]
class = frappy_psi.ls370res.ResChannel
channel = 1
description = resistivity
switcher = sw
[b]
class = frappy_psi.ls370res.ResChannel
channel = 3
description = resistivity
switcher = sw

View File

@ -7,12 +7,12 @@ bindto = 0.0.0.0
bindport = 5000
[module lsmain]
class = secop_psi.ls370res.Main
class = frappy_psi.ls370res.Main
description = main control of Lsc controller
uri = localhost:4567
[module res]
class = secop_psi.ls370res.ResChannel
class = frappy_psi.ls370res.ResChannel
vexc = '2mV'
channel = 3
description = resistivity

View File

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

View File

@ -7,13 +7,13 @@ bindto = 0.0.0.0
bindport = 5002
[module secnode]
class = secop.SecNode
class = frappy.SecNode
description = a SEC node
uri = tcp://localhost:5000
[module mf]
class = secop.Proxy
remote_class = secop_psi.ppms.Field
class = frappy.Proxy
remote_class = frappy_psi.ppms.Field
description = magnetic field
iodev = secnode
value.min = -0.1

View File

@ -10,7 +10,7 @@ bindport=10767
[module sim]
class=secop.simulation.SimDrivable
class=frappy.simulation.SimDrivable
.description=simulation stuff
.extra_params=param3,param4,jitter,ramp
param3.datatype={"type":"bool"}

View File

@ -19,14 +19,14 @@ bindto=0.0.0.0
bindport=10767
[module enable]
class=secop.simulation.SimWritable
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=secop.simulation.SimWritable
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
@ -38,7 +38,7 @@ target.datatype={"type":"enum", "members":{'+1':1,'0':0,'-1':-1}}
[module symmetry]
class=secop.simulation.SimWritable
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
@ -48,31 +48,31 @@ target.datatype={"type":"enum", "members":{'symmetric':1,'short':0, 'asymmetric'
value.default = 'symmetric'
[module T1]
class=secop.simulation.SimReadable
class=frappy.simulation.SimReadable
.description=Temperature1 of the coils system
value.unit='degC'
value.default = 23.45
[module T2]
class=secop.simulation.SimReadable
class=frappy.simulation.SimReadable
.description=Temperature2 of the coils system
value.unit='degC'
value.default = 23.45
[module T3]
class=secop.simulation.SimReadable
class=frappy.simulation.SimReadable
.description=Temperature3 of the coils system
value.unit='degC'
value.default = 23.45
[module T4]
class=secop.simulation.SimReadable
class=frappy.simulation.SimReadable
.description=Temperature4 of the coils system
value.unit='degC'
value.default = 23.45
[module currentsource]
class=secop.simulation.SimDrivable
class=frappy.simulation.SimDrivable
.description=Device for the magnet power supply (current mode)
abslimits=(0,200)
speed=1
@ -98,7 +98,7 @@ window.datatype = {"type":"double", "min":0, "max":120, "unit":"s"}
window.default = 10
[module mf]
class=secop_mlz.amagnet.GarfieldMagnet
class=frappy_mlz.amagnet.GarfieldMagnet
.description=magnetic field module, handling polarity switching and stuff
subdev_currentsource=currentsource
subdev_enable=enable

View File

@ -11,7 +11,7 @@ bindto=0.0.0.0
bindport=10767
[module T_cci3he1]
class=secop.simulation.SimDrivable
class=frappy.simulation.SimDrivable
.description=Main temperature control node of cci3he1.
.
Controls the regulation loop of the ls370.
@ -26,7 +26,7 @@ ramp.default=60
.meaning=["temperature_regulation",40]
[module T_cci3he1_A]
class=secop.simulation.SimReadable
class=frappy.simulation.SimReadable
.description=3He pot temperature sensor. Also used for the regulation.
.visibility=expert
value.default=300
@ -34,7 +34,7 @@ value.datatype={"type":"double","unit":"K"}
.meaning=["temperature",38]
[module T_cci3he1_B]
class=secop.simulation.SimReadable
class=frappy.simulation.SimReadable
.description=(optional) sample temperature sensor close to sample.
.visibility=user
value.default=300
@ -42,49 +42,49 @@ value.datatype={"type":"double","unit":"K"}
.meaning=["temperature",39]
[module cci3he1_p1]
class=secop.simulation.SimReadable
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=secop.simulation.SimReadable
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=secop.simulation.SimReadable
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=secop.simulation.SimReadable
class=frappy.simulation.SimReadable
.description=Pressure at compressor outlet.
.visibility=expert
value.default=999
value.datatype={"type":"double","unit":"mbar"}
[module cci3he1_p5]
class=secop.simulation.SimReadable
class=frappy.simulation.SimReadable
.description=Pressure in dump tank.
.visibility=expert
value.default=567
value.datatype={"type":"double","unit":"mbar"}
[module cci3he1_p6]
class=secop.simulation.SimReadable
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=secop.simulation.SimReadable
class=frappy.simulation.SimReadable
.description=Gas Flow (condensing line).
.visibility=expert
value.default=12.34

View File

@ -11,7 +11,7 @@ bindto=0.0.0.0
bindport=10767
[module T_ccidu1]
class=secop.simulation.SimDrivable
class=frappy.simulation.SimDrivable
.description=Main temperature control node of ccidu1.
.
Controls the regulation loop of the ls372.
@ -26,7 +26,7 @@ ramp.default=60
.meaning=["temperature_regulation",40]
[module T_ccidu1_A]
class=secop.simulation.SimReadable
class=frappy.simulation.SimReadable
.description=mixing chamber temperature sensor. Also used for the regulation.
.visibility=expert
value.default=300
@ -34,7 +34,7 @@ value.datatype={"type":"double", "unit":"K"}
.meaning=["temperature",38]
[module T_ccidu1_B]
class=secop.simulation.SimReadable
class=frappy.simulation.SimReadable
.description=(optional) sample temperature sensor close to sample.
.visibility=user
value.default=300
@ -42,49 +42,49 @@ value.datatype={"type":"double", "unit":"K"}
.meaning=["temperature",39]
[module ccidu1_pstill]
class=secop.simulation.SimReadable
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=secop.simulation.SimReadable
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=secop.simulation.SimReadable
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=secop.simulation.SimReadable
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=secop.simulation.SimReadable
class=frappy.simulation.SimReadable
.description=Pressure in dump tank.
.visibility=expert
value.default=999
value.datatype={"type":"double", "unit":"mbar"}
[module ccidu1_pvac]
class=secop.simulation.SimReadable
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=secop.simulation.SimReadable
class=frappy.simulation.SimReadable
.description=Gas Flow (condensing line).
.visibility=expert
value.default=999
@ -92,14 +92,14 @@ value.datatype={"type":"double", "unit":"mbar"}
# note: all valves and switches are missing: use VNC to control them
[module ccidu1_V6]
class=secop.simulation.SimDrivable
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=secop.simulation.SimWritable
class=frappy.simulation.SimWritable
.description=Dump Valve
.visibility=expert
value.default="OFF"

View File

@ -12,7 +12,7 @@ bindto=0.0.0.0
bindport=10767
[module T_ccr12]
class=secop.simulation.SimDrivable
class=frappy.simulation.SimDrivable
.description=Main temperature control node of CCR12.
.
Switches between regulation on stick and regulation on tube depending on temperature requested.
@ -30,7 +30,7 @@ target.default=300
.meaning=["temperature_regulation", 20]
[module T_ccr12_stick]
class=secop.simulation.SimDrivable
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"}
@ -42,7 +42,7 @@ target.default=300
.meaning=["temperature_regulation", 15]
[module T_ccr12_tube]
class=secop.simulation.SimDrivable
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"}
@ -54,28 +54,28 @@ target.default=300
.meaning=["temperature_regulation", 10]
[module T_ccr12_A]
class=secop.simulation.SimReadable
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=secop.simulation.SimReadable
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=secop.simulation.SimReadable
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=secop.simulation.SimReadable
class=frappy.simulation.SimReadable
.description=(regulation) temperature at coupling to stick.
value.datatype={"type":"double", "unit":"K"}
value.default=80
@ -84,7 +84,7 @@ value.default=80
[module ccr12_pressure_regulate]
class=secop.simulation.SimWritable
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}}
@ -93,7 +93,7 @@ target.datatype={"type":"enum", "members":{'off':0,'p1':1,'p2':2}}
target.default='off'
[module ccr12_compressor]
class=secop.simulation.SimDrivable
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.
@ -103,7 +103,7 @@ target.datatype={"type":"enum", "members":{'off':0,'on':1}}
target.default='on'
[module ccr12_gas_switch]
class=secop.simulation.SimWritable
class=frappy.simulation.SimWritable
.description=Switches the gas inlet on or off.
.
note: in reality this switches itself off after 15min.
@ -115,7 +115,7 @@ target.datatype={"type":"enum", "members":{'off':0,'on':1}}
target.default='off'
[module ccr12_vacuum_switch]
class=secop.simulation.SimWritable
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!
@ -126,19 +126,19 @@ target.datatype={"type":"enum", "members":{'off':0,'on':1}}
target.default='off'
[module ccr12_p1]
class=secop.simulation.SimReadable
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=secop.simulation.SimReadable
class=frappy.simulation.SimReadable
.description=Auxillary pressure Sensor.
value.datatype={"type":"double", "unit":"mbar"}
value.default=1e-6
[module ccr12_curve_p2]
class=secop.simulation.SimWritable
class=frappy.simulation.SimWritable
.description=Curve for Aux pressure Sensor p2
.visibility=expert
value.default='TTR100'
@ -146,7 +146,7 @@ value.datatype={"type":"enum", "members":{'0..10V':0,'default':1,'0..9V':2,'DI20
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=secop.simulation.SimWritable
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"}}
@ -155,7 +155,7 @@ target.datatype={"type":"limit","members":{"type":"double", "min":0,"max":1000,
target.default=[0,10]
[module ccr12_p2_limits]
class=secop.simulation.SimWritable
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"}}

View File

@ -12,7 +12,7 @@ bindto=0.0.0.0
bindport=10767
[module T_ccr12]
class=secop.simulation.SimDrivable
class=frappy.simulation.SimDrivable
.description=Main temperature control node of CCR12.
.
Switches between regulation on stick and regulation on tube depending on temperature requested.
@ -41,7 +41,7 @@ userlimits.readonly=False
.meaning=["temperature_regulation", 20]
[module T_ccr12_A]
class=secop.simulation.SimReadable
class=frappy.simulation.SimReadable
.description=(optional) Sample temperature sensor.
.visibility=expert
value.datatype={"type":"double", "min":0, "unit":"K"}
@ -49,7 +49,7 @@ value.default=300
.meaning=["temperature", 9]
[module T_ccr12_B]
class=secop.simulation.SimReadable
class=frappy.simulation.SimReadable
.description=(regulation) temperature sensor on stick.
.visibility=expert
value.datatype={"type":"double", "min":0, "unit":"K"}
@ -57,7 +57,7 @@ value.default=300
.meaning=["temperature", 10]
[module T_ccr12_C]
class=secop.simulation.SimReadable
class=frappy.simulation.SimReadable
.description=Temperature at the coldhead.
.visibility=expert
value.datatype={"type":"double", "min":0, "unit":"K"}
@ -65,7 +65,7 @@ value.default=70
.meaning=["temperature", 1]
[module T_ccr12_D]
class=secop.simulation.SimReadable
class=frappy.simulation.SimReadable
.description=(regulation) temperature at coupling to stick.
.visibility=expert
value.datatype={"type":"double", "min":0, "unit":"K"}
@ -75,7 +75,7 @@ value.default=80
[module ccr12_pressure_regulation]
class=secop.simulation.SimReadable
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
@ -91,7 +91,7 @@ value.datatype={"type":"double", "min":0, "max":1000, "unit":"mbar"}
value.default = 1e-5
[module ccr12_compressor]
class=secop.simulation.SimDrivable
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.
@ -101,7 +101,7 @@ value.default='off'
target.datatype={"type":"enum", "members":{'off':0,'on':1}}
[module ccr12_gas_switch]
class=secop.simulation.SimWritable
class=frappy.simulation.SimWritable
.description=Switches the gas inlet on or off.
.
note: in reality this switches itself off after 15min.
@ -113,7 +113,7 @@ target.datatype={"type":"enum", "members":{'off':0,'on':1}}
target.default='off'
[module ccr12_vacuum_switch]
class=secop.simulation.SimWritable
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!
@ -124,7 +124,7 @@ target.datatype={"type":"enum", "members":{'off':0,'on':1}}
target.default='off'
[module ccr12_p1]
class=secop.simulation.SimReadable
class=frappy.simulation.SimReadable
.description=Default pressure Sensor, linear scale 0..1000 mbar
.
Good candidate for a 'Sensor' Interface class!
@ -140,7 +140,7 @@ userlimits.description=current user set limits for the pressure regulation.
userlimits.readonly=False
[module ccr12_p2]
class=secop.simulation.SimReadable
class=frappy.simulation.SimReadable
.description=Auxillary pressure Sensor.
value.default=1e-6
value.unit=mbar

View File

@ -10,7 +10,7 @@ bindto=0.0.0.0
bindport=10767
[module T_htf02]
class=secop.simulation.SimDrivable
class=frappy.simulation.SimDrivable
.description=Main temperature control node of htf02.
.
Controls the regulation loop of the Eurotherm.
@ -26,7 +26,7 @@ ramp.readonly=False
.meaning=["temperature", 10]
[module htf02_p]
class=secop.simulation.SimReadable
class=frappy.simulation.SimReadable
.description=Pressure Sensor at sample space (ivc).
value.datatype={"type":"double", "min":0, "unit":"mbar"}
value.default=989

View File

@ -10,7 +10,7 @@ bindto=0.0.0.0
bindport=10767
[module T_stressihtf2]
class=secop.simulation.SimDrivable
class=frappy.simulation.SimDrivable
.description=Main temperature control node of Stressihtf2.
value.datatype={"type":"double", "min":0, "unit":"degC"}
value.default=20
@ -30,7 +30,7 @@ userlimits.readonly=False
.meaning=['temperature_regulation', 10]
[module T_stressihtf2_sample]
class=secop.simulation.SimReadable
class=frappy.simulation.SimReadable
.description=(optional) Sample temperature sensor.
.visibility=expert
value.default=300
@ -38,7 +38,7 @@ value.datatype={"type":"double", "min":0, "unit":"degC"}
.meaning=["temperature", 9]
[module stressihtf2_n2]
class=secop.simulation.SimWritable
class=frappy.simulation.SimWritable
.description=Switches the N2 gas inlet on or off.
.visibility=expert
value.default='off'
@ -47,7 +47,7 @@ target.datatype={"type":"enum", "members":{'off':0,'on':1}}
target.default='off'
[module stressihtf2_he]
class=secop.simulation.SimWritable
class=frappy.simulation.SimWritable
.description=Switches the He gas inlet on or off.
.visibility=expert
value.default='off'
@ -56,7 +56,7 @@ target.datatype={"type":"enum", "members":{'off':0,'on':1}}
target.default='off'
[module stressihtf2_lamps]
class=secop.simulation.SimWritable
class=frappy.simulation.SimWritable
.description=Switches the heating lamps on or off.
.visibility=expert
value.default='on'
@ -65,7 +65,7 @@ target.datatype={"type":"enum", "members":{'off':0,'on':1}}
target.default='on'
[module stressihtf2_water_ok]
class=secop.simulation.SimReadable
class=frappy.simulation.SimReadable
.description=Readout of the cooling water state.
.visibility=expert
value.default='ok'

View File

@ -10,7 +10,7 @@ bindto=0.0.0.0
bindport=10767
[module T]
class=secop.simulation.SimDrivable
class=frappy.simulation.SimDrivable
.description=Main temperature control node of Stressihtf2.
value.datatype={"type":"double", "min":0, "unit":"degC"}
value.default=20
@ -30,7 +30,7 @@ userlimits.readonly=False
.meaning=['temperature_regulation', 10]
[module T_sample]
class=secop.simulation.SimReadable
class=frappy.simulation.SimReadable
.description=(optional) Sample temperature sensor.
.visibility=expert
value.default=300
@ -38,7 +38,7 @@ value.datatype={"type":"double", "min":0, "unit":"degC"}
.meaning=["temperature", 9]
[module N2]
class=secop.simulation.SimWritable
class=frappy.simulation.SimWritable
.description=Switches the N2 gas inlet on or off.
.visibility=expert
value.default='off'
@ -47,7 +47,7 @@ target.datatype={"type":"enum", "members":{'off':0,'on':1}}
target.default='off'
[module He]
class=secop.simulation.SimWritable
class=frappy.simulation.SimWritable
.description=Switches the He gas inlet on or off.
.visibility=expert
value.default='off'
@ -56,7 +56,7 @@ target.datatype={"type":"enum", "members":{'off':0,'on':1}}
target.default='off'
[module lamps]
class=secop.simulation.SimWritable
class=frappy.simulation.SimWritable
.description=Switches the heating lamps on or off.
.visibility=expert
value.default='on'
@ -65,7 +65,7 @@ target.datatype={"type":"enum", "members":{'off':0,'on':1}}
target.default='on'
[module water_ok]
class=secop.simulation.SimReadable
class=frappy.simulation.SimReadable
.description=Readout of the cooling water state.
.visibility=expert
value.default='ok'

View File

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

View File

@ -11,7 +11,7 @@ bindto=0.0.0.0
bindport=10767
[module T]
class=secop_mlz.entangle.TemperatureController
class=frappy_mlz.entangle.TemperatureController
tangodevice=tango://localhost:10000/box/eurotherm/ctrl
.description=Main temperature control node of Stressihtf2.
value.unit='degC'
@ -41,42 +41,42 @@ pid.default=[1,0,0]
speed.default=0
[module T_sample_a]
class=secop_mlz.entangle.Sensor
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=secop_mlz.entangle.Sensor
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=secop_mlz.entangle.NamedDigitalOutput
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=secop_mlz.entangle.NamedDigitalOutput
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=secop_mlz.entangle.NamedDigitalOutput
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=secop_mlz.entangle.NamedDigitalInput
class=frappy_mlz.entangle.NamedDigitalInput
tangodevice=tango://localhost:10000/box/plc/_waterok
.description=Readout of the cooling water state.
.visibility=expert

View File

@ -1,46 +0,0 @@
[node test config]
description=description of the testing sec-node
.
Here should be the long description.
It can be very long.
.
a single . on a line gets stripped so you can make paragraphs.
.
These texts are supposed to be possibly very long.
[interface tcp]
type=tcp
bindto=0.0.0.0
bindport=10768
[module LN2]
class=secop_demo.test.LN2
.description="random value between 0..100%%"
value.unit = "%%"
[module heater]
class=secop_demo.test.Heater
maxheaterpower=10
.description="some heater"
[module T1]
class=secop_demo.test.Temp
sensor="X34598T7"
.description="some temperature"
[module T2]
class=secop_demo.modules.CoilTemp
sensor="X34598T8"
.description="some temperature"
[module T3]
class=secop_demo.modules.CoilTemp
sensor="X34598T9"
.description="some temperature"
[module Lower]
class=secop_demo.test.Lower
.description="something else"

46
cfg/test_cfg.py Normal file
View File

@ -0,0 +1,46 @@
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.
Very long!
The needed fields are Equipment id (1st argument), description (this)
and the main interface of the node (3rd arg)
''',
'tcp://10768',
)
Mod('LN2',
'frappy_demo.test.LN2',
'random value between 0..100%',
value = Param(default = 0, unit = '%'),
)
Mod('heater',
'frappy_demo.test.Heater',
'some heater',
maxheaterpower = 10,
)
Mod('T1',
'frappy_demo.test.Temp',
'some temperature',
sensor = 'X34598T7',
)
Mod('T2',
'frappy_demo.test.Temp',
'some temperature',
sensor = 'X34598T8',
)
Mod('T3',
'frappy_demo.test.Temp',
'some temperature',
sensor = 'X34598T9',
)
Mod('Lower',
'frappy_demo.test.Lower',
'something else',
)

View File

@ -1,4 +1,4 @@
FROM python:3-buster AS base
FROM python:3.9 AS base
ARG PYVER=python3
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && \
@ -11,7 +11,7 @@ RUN apt-get update && \
locales \
python3 \
python3-dev \
python3-pytango \
python3-tango \
python3-venv python3-setuptools \
virtualenv
@ -33,14 +33,15 @@ RUN virtualenv /home/jenkins/tools2 && \
rm -rf /home/jenkins/tools2src
RUN virtualenv -p /usr/bin/python3 --system-site-packages /home/jenkins/secopvenv && \
git clone https://forge.frm2.tum.de/review/sine2020/secop/playground /home/jenkins/playground && \
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/playground/requirements-dev.txt -r /home/jenkins/playground/requirements.txt pylint pytest && \
rm -rf /home/jenkins/playground
pip install -r /home/jenkins/frappy/requirements-dev.txt -r /home/jenkins/frappy/requirements.txt pylint pytest && \
rm -rf /home/jenkins/frappy
FROM base AS docs
ARG PYVER=python3
ENV DEBIAN_FRONTEND=noninteractive
USER root
@ -50,6 +51,8 @@ RUN apt-get update && \
texlive-latex-base \
texlive-latex-recommended \
texlive-fonts-recommended \
texlive-fonts-extra \
tex-gyre \
texlive-base \
texlive-binaries \
latexmk

60
ci/Jenkinsfile vendored
View File

@ -4,7 +4,7 @@ properties([
daysToKeepStr: '',
numToKeepStr: '50')),
parameters([
string(defaultValue: 'sine2020/secop/playground',
string(defaultValue: 'secop/frappy',
description: '', name: 'GERRIT_PROJECT'),
string(defaultValue: 'master',
description: '', name: 'GERRIT_BRANCH'),
@ -43,21 +43,21 @@ git diff HEAD~1... --name-only --diff-filter=ARCM -- \\*.py
pip install -r requirements-dev.txt
pip install -r requirements.txt
pip install isort pylint
python3 setup.py develop
pip install -e .
export PYTHONIOENCODING=utf8
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 | tee isort_results.txt
fi
"""
withCredentials([string(credentialsId: 'GERRITHTTP',
variable: 'GERRITHTTP')]) {
sh """\
#!/bin/bash
if [ -f pylint_results.txt ] ; then
#!/bin/bash
if [ -f pylint_results.txt ] ; then
/home/jenkins/tools2/bin/pylint2gerrit
mv pylint_results.txt pylint-${pyver}.txt
else
@ -67,19 +67,11 @@ fi
} // credentials
echo "pylint result: $res"
this.verifyresult.put('pylint'+pyver, 1)
if ( res != 0 ) {
currentBuild.result='FAILURE'
this.verifyresult.put('pylint'+ pyver, -1)
status = 'FAILURE'
}
gerritverificationpublisher([
verifyStatusValue: this.verifyresult['pylint'+pyver],
verifyStatusCategory: 'pylint ',
verifyStatusName: 'pylint-'+pyver,
verifyStatusReporter: 'jenkins',
verifyStatusRerun: '!recheck'])
archiveArtifacts([allowEmptyArchive: true,
artifacts: 'pylint-*.txt'])
recordIssues([enabledForFailure: true,
@ -90,21 +82,17 @@ fi
failedTotalAll: 1])
if (status == 'FAILURE') {
throw new Exception('Failure in pylint with ' + pyver)
}
}
} // run_pylint
def run_tests(pyver) {
stage('Test:' + pyver) {
writeFile file: 'setup.cfg', text: '''
writeFile file: 'setup.cfg', text: '''
[tool:pytest]
addopts = --junit-xml=pytest.xml --junit-prefix=''' + pyver
def status = "OK"
verifyresult.put(pyver, 0)
try {
timeout(5) {
sh '''\
@ -112,28 +100,17 @@ addopts = --junit-xml=pytest.xml --junit-prefix=''' + pyver
. /home/jenkins/secopvenv/bin/activate
pip install -r requirements-dev.txt
pip install -r requirements.txt
python3 setup.py develop
pip install -e .
make test
'''
verifyresult.put(pyver, 1)
}
} catch (all) {
currentBuild.result = 'FAILURE'
status = 'FAILURE'
verifyresult.put(pyver, -1)
}
gerritverificationpublisher([
verifyStatusValue: verifyresult[pyver],
verifyStatusCategory: 'test ',
verifyStatusName: 'pytest-'+pyver,
verifyStatusReporter: 'jenkins',
verifyStatusRerun: '!recheck'])
step([$class: 'JUnitResultArchiver', allowEmptyResults: true,
keepLongStdio: true, testResults: 'pytest.xml'])
if (status == 'FAILURE') {
throw new Exception('Failure in test with ' + pyver)
}
}
}
@ -143,7 +120,7 @@ def run_docs() {
. /home/jenkins/secopvenv/bin/activate
pip install -r requirements-dev.txt
pip install -r requirements.txt
python3 setup.py develop
pip install -e .
'''
}
@ -185,15 +162,7 @@ def run_docs() {
stage('store html doc for build') {
publishHTML([allowMissing: false, alwaysLinkToLastBuild: false, keepAll: true, reportDir: 'doc/_build/html', reportFiles: 'index.html', reportName: 'Built documentation', reportTitles: ''])
gerritverificationpublisher([
verifyStatusValue: 1,
verifyStatusCategory: 'test ',
verifyStatusName: 'doc',
verifyStatusReporter: 'jenkins',
verifyStatusRerun: '@recheck'
])
}
}
@ -225,16 +194,16 @@ node("dockerhost") {
sh '''#!/bin/bash
git worktree add tmpmaster origin/master
cd tmpmaster
docker build --target base --tag secop_base:latest ci
docker build --target docs --tag secop_docs:latest ci
docker build --target base --tag frappy_base:latest ci
docker build --target docs --tag frappy_docs:latest ci
cd ..
rm -rf tmpmaster
'''
}
stage('execute tests') {
def img = docker.image('secop_base:latest')
def docimg = docker.image('secop_docs:latest')
def img = docker.image('frappy_base:latest')
def docimg = docker.image('frappy_docs:latest')
parallel 'Test': {
img.inside {
@ -252,9 +221,10 @@ node("dockerhost") {
if (GERRIT_EVENT_TYPE == 'change-merged')
{
sh '''
rsync -rlv doc/_build/* /ictrlsrv/share/public/doc/secop
rsync -rlv doc/_build/* /ictrlsrv/share/public/doc/frappy
'''
}
}}
}}, failFast: false
}
setGerritReview()
}

View File

@ -10,10 +10,10 @@ The Dockerfile defines two images:
To create the images:
docker build --target <base|docs> --tag secop_<base|docs>:latest .
docker build --target <base|docs> --tag frappy_<base|docs>:latest .
To test images interactivly:
docker run -u jenkins -i -t secop<base|docs> /bin/bash
docker run -u jenkins -i -t frappy<base|docs> /bin/bash
The Jenkinsfile uses this Dockerfile (only approved checked-in versions from master)
to build the images (a rebuild will only happen if the Dockerfile is changed as docker

2
debian/README vendored
View File

@ -1,4 +1,4 @@
The Debian Package secop-core
The Debian Package frappy-core
-----------------------------
SECoP is currently under development.

324
debian/changelog vendored
View File

@ -1,3 +1,263 @@
frappy-core (0.15.0) focal; urgency=medium
[ Björn Pedersen ]
* Remove iohandler left-overs from docs
[ Georg Brandl ]
* Makefile: fix release target
[ Alexander Zaft ]
* Add requirements-gui.txt and add PyQT5
[ Christian Felder ]
* Fix typo in .description
[ Alexander Zaft ]
* fixed pylint warnings
* Rename from secop to frappy
* rename debian package files
[ Björn Pedersen ]
* CI build: upgrade base image
[ Alexander Zaft ]
* rename debian files
[ Björn Pedersen ]
* Fix doc warnings/errors
-- Björn Pedersen <jenkins@frm2.tum.de> Thu, 10 Nov 2022 14:46:01 +0100
secop-core (0.14.3) focal; urgency=medium
[ Enrico Faulhaber ]
* change repo to secop/frappy
[ Georg Brandl ]
* secop_mlz/amagnet: formatting fixup
[ Bjoern Pedersen ]
* Upgrade for ci
[ Enrico Faulhaber ]
* MLZ/entangle: fix AnalogOutput.read_status()
-- Enrico Faulhaber <jenkins@frm2.tum.de> Thu, 03 Nov 2022 13:51:52 +0100
secop-core (0.14.2) focal; 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
[ Markus Zolliker ]
* secop_psi.entangle.AnalogInput: fix main value
[ Georg Brandl ]
* gui: clarify needed input for "add sec node" dialog
* mlz: avoid error on import due to consistency check
* Makefile: fix Jenkins host
-- Markus Zolliker <jenkins@frm2.tum.de> Thu, 20 Oct 2022 14:04:07 +0200
secop-core (0.14.0) focal; urgency=medium
* add simple interactive python client
* fix undefined status in softcal
* improve HasConvergence mixin
* fix bug in persistent.py
* fix bug when restarting statemachine
* improve general config
* improvements on interactive client
* apply main unit also in structured types
* HasIO: automatic creation of io from uri fails
-- Markus Zolliker <jenkins@frm2.tum.de> Wed, 19 Oct 2022 11:31:50 +0200
secop-core (0.13.1) focal; urgency=medium
[ Markus Zolliker ]
* an enum with value 0 should be interpreted as False
* make startup faster in case of errors
[ Enrico Faulhaber ]
* secop_mlz: minor rework entangle client
-- Markus Zolliker <jenkins@jenkins02.admin.frm2.tum.de> Tue, 02 Aug 2022 15:31:52 +0200
secop-core (0.13.0) focal; urgency=medium
[ Georg Brandl ]
* debian: fix email addresses in changelog
[ Markus Zolliker ]
* various small changes
* automatic saving of persistent parameters
* add more tests and fixes for command inheritance
* entangle.AnalogOutput: fix window mechanism
* remote logging (issue 46)
* add timeouts to MultiEvents
* introduce general config file
* improve handling of module init methods
* check for bad read_* and write_* methods
* change name of read_hw_status method in sequencer mixin
* fix doc (stringio - > io)
* enhance logging
* UniqueObject
* ReadHandler and WriteHandler decorators
* do not convert string to float
* check for problematic value range
* unify name and module on Attached property
* ppms: replace IOHandler by Read/WriteHandler
* fix handling commands
* common read/write handlers
* implement a state machine
* proper return value in handler read_* methods
* new poll mechanism
* support for fast poll when busy
* various small fixes
* reset connection on identification
* improve softcal
* move markdown to requirements-dev.txt
* improve k2601b driver
* fix and improved Attached
* fix error in write wrapper and more
* support write_ method on readonly param and more
* init generalConfig.defaults only in secop-server
* HasConvergence mixin
* avoid race conditions in read_*/write_* methods
* reintroduced individual init of generalConfig.defaults
* fix statemachine
* use a common poller thread for modules sharing io
* motor valve using trinamic motor
* improved trinamic driver
* fix error in secop.logging
* avoid deadlock in proxy
* improve poller error handling
* support for OI mercury series
* add 'ts' to the ppms simulation
* allow a configfile path as single argument to secop-server
* fix keithley 2601b after tests
* channel switcher for Lakeshore 370 with scanner
* feature implementation
* allow to convert numpy arrays to ArrayOf
* remove IOHandler stuff
[ Enrico Faulhaber ]
* default unit to UTF8
-- Georg Brandl <jenkins@frm2.tum.de> Tue, 02 Aug 2022 09:47:06 +0200
secop-core (0.12.4) focal; 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
[ Georg Brandl ]
* Makefile: fix docker image
[ Markus Zolliker ]
* various fixes
* remove irrelevant comments
* introduce BytesIO
* GUI fixes
* persistent params / trinamic motor
* fix Parameter/Command copy method
* show first instead of last traceback on multiple errors
* fix parameter inheritance
* fix property inheritance
* fix python 3.5 compatibility
* omit updates of unchanged values within short time
* improve simulation
* automatically register subclasses of AsynConn
* fix feature for removing commands
-- Georg Brandl <jenkins@jenkins01.admin.frm2.tum.de> Wed, 10 Nov 2021 16:33:19 +0100
secop-core (0.12.2) focal; urgency=medium
[ Markus Zolliker ]
* fix issue with new syntax in simulation
* treat specifier of describe message
* allow to remove accessibles
[ Enrico Faulhaber ]
* secop_mlz: small fixes
-- Markus Zolliker <jenkins@jenkins01.admin.frm2.tum.de> Tue, 18 May 2021 10:29:17 +0200
secop-core (0.12.1) focal; 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
[ Markus Zolliker ]
* make datatypes immutable
* customizable general config
* support for multiple secop servers
* secop.asynconn without pyserial
* change cfg file format
* fix bug in secop.gui.valuewidgets
* fix deadlock when reconnecting client
* allow class instead of class name in proxy_class
* fix pylint command in Makefile
* change arguments of stringio-server
* router bug fix
* introduce update callbacks
* improve error handling on client connections
* ppms: improve status and temperature
* rework tcp server
* cosmetics on datatypes.TextType
* improve error handling in SecopClient
* improve HasIodev
* HasIodev bug fix
* fix handling of StructOf datatype
* more flexible end_of_line in stringio
* improvements on PPMS and LS370
* add readbytes method to AsynConn
* Param(..., initwrite=True) works only with poll=True
* fix initwrite behaviour
* make order of accessibles work again
* main module of LS370 is now drivable
* improve softcal
* make arguments of Parameter and Override consistent
* new syntax for parameter/commands/properties
* enhance documentation
* removed old style syntax
* after running isort
* try to follow PEP8
* fix inheritance order
* remove obsolete code
* lookup cfg files in a list of directories
* added hook for optional history writer
* fixed errors during migration
* move historywriter to secop_psi
* fix autoscan behaviour in ls370res
[ l_samenv ]
* improve tutorial_helevel
* fixed bugs from syntax migration
[ Markus Zolliker ]
* user friendly reporting of config errors
[ Bjoern Pedersen ]
* Jenkisfile: verification
* Fixes to Jenkinsfile
* No pull for images, they are recreated in the job
* Another Jenkisfile error
* Correct checks enum
-- Markus Zolliker <jenkins@jenkins02.admin.frm2.tum.de> Tue, 04 May 2021 08:49:57 +0200
secop-core (0.11.6) unstable; urgency=medium
* fix secop-generator
@ -133,7 +393,7 @@ secop-core (0.10.5) unstable; urgency=low
[ Jenkins ]
-- Jenkins <jenkins@debuild.taco.frm2> Tue, 29 Oct 2019 16:33:18 +0100
-- Jenkins <jenkins@debuild.taco.frm2.tum.de> Tue, 29 Oct 2019 16:33:18 +0100
secop-core (0.10.3) unstable; urgency=low
@ -142,7 +402,7 @@ secop-core (0.10.3) unstable; urgency=low
[ Jenkins ]
-- Jenkins <jenkins@debuild.taco.frm2> Fri, 11 Oct 2019 10:49:43 +0200
-- Jenkins <jenkins@debuild.taco.frm2.tum.de> Fri, 11 Oct 2019 10:49:43 +0200
secop-core (0.10.2) unstable; urgency=low
@ -153,7 +413,7 @@ secop-core (0.10.2) unstable; urgency=low
[ Jenkins ]
-- Jenkins <jenkins@debuild.taco.frm2> Fri, 11 Oct 2019 10:42:58 +0200
-- Jenkins <jenkins@debuild.taco.frm2.tum.de> Fri, 11 Oct 2019 10:42:58 +0200
secop-core (0.10.1) unstable; urgency=low
@ -162,7 +422,7 @@ secop-core (0.10.1) unstable; urgency=low
[ Jenkins ]
-- Jenkins <jenkins@debuild.taco.frm2> Thu, 26 Sep 2019 16:41:10 +0200
-- Jenkins <jenkins@debuild.taco.frm2.tum.de> Thu, 26 Sep 2019 16:41:10 +0200
secop-core (0.10.0) unstable; urgency=low
@ -171,7 +431,7 @@ secop-core (0.10.0) unstable; urgency=low
[ Jenkins ]
-- Jenkins <jenkins@debuild.taco.frm2> Thu, 26 Sep 2019 16:31:14 +0200
-- Jenkins <jenkins@debuild.taco.frm2.tum.de> Thu, 26 Sep 2019 16:31:14 +0200
secop-core (0.9.0) unstable; urgency=low
@ -198,7 +458,7 @@ secop-core (0.9.0) unstable; urgency=low
[ Jenkins ]
-- Jenkins <jenkins@debuild.taco.frm2> Thu, 26 Sep 2019 16:26:07 +0200
-- Jenkins <jenkins@debuild.taco.frm2.tum.de> Thu, 26 Sep 2019 16:26:07 +0200
secop-core (0.8.1) unstable; urgency=low
@ -207,7 +467,7 @@ secop-core (0.8.1) unstable; urgency=low
[ Jenkins ]
-- Jenkins <jenkins@debuild.taco.frm2> Wed, 25 Sep 2019 15:40:44 +0200
-- Jenkins <jenkins@debuild.taco.frm2.tum.de> Wed, 25 Sep 2019 15:40:44 +0200
secop-core (0.8.0) unstable; urgency=low
@ -275,7 +535,7 @@ secop-core (0.8.0) unstable; urgency=low
[ Jenkins ]
-- Jenkins <jenkins@debuild.taco.frm2> Wed, 25 Sep 2019 10:27:51 +0200
-- Jenkins <jenkins@debuild.taco.frm2.tum.de> Wed, 25 Sep 2019 10:27:51 +0200
secop-core (0.7.0) unstable; urgency=low
@ -311,7 +571,7 @@ secop-core (0.7.0) unstable; urgency=low
[ Jenkins ]
-- Jenkins <jenkins@debuild.taco.frm2> Thu, 28 Mar 2019 13:46:08 +0100
-- Jenkins <jenkins@debuild.taco.frm2.tum.de> Thu, 28 Mar 2019 13:46:08 +0100
secop-core (0.6.4) unstable; urgency=low
@ -376,7 +636,7 @@ secop-core (0.6.4) unstable; urgency=low
[ Jenkins ]
-- Jenkins <jenkins@debuild.taco.frm2> Thu, 20 Dec 2018 16:44:03 +0100
-- Jenkins <jenkins@debuild.taco.frm2.tum.de> Thu, 20 Dec 2018 16:44:03 +0100
secop-core (0.6.3) unstable; urgency=low
@ -390,7 +650,7 @@ secop-core (0.6.3) unstable; urgency=low
[ Jenkins ]
-- Jenkins <jenkins@debuild.taco.frm2> Fri, 27 Jul 2018 09:31:59 +0200
-- Jenkins <jenkins@debuild.taco.frm2.tum.de> Fri, 27 Jul 2018 09:31:59 +0200
secop-core (0.6.2) unstable; urgency=low
@ -429,7 +689,7 @@ secop-core (0.6.2) unstable; urgency=low
[ Jenkins ]
-- Jenkins <jenkins@debuild.taco.frm2> Wed, 18 Jul 2018 12:06:57 +0200
-- Jenkins <jenkins@debuild.taco.frm2.tum.de> Wed, 18 Jul 2018 12:06:57 +0200
secop-core (0.6.1) unstable; urgency=low
@ -438,7 +698,7 @@ secop-core (0.6.1) unstable; urgency=low
[ Jenkins ]
-- Jenkins <jenkins@debuild.taco.frm2> Thu, 19 Apr 2018 10:24:44 +0200
-- Jenkins <jenkins@debuild.taco.frm2.tum.de> Thu, 19 Apr 2018 10:24:44 +0200
secop-core (0.6.0) unstable; urgency=low
@ -458,7 +718,7 @@ secop-core (0.6.0) unstable; urgency=low
[ Jenkins ]
-- Jenkins <jenkins@debuild.taco.frm2> Tue, 17 Apr 2018 17:38:52 +0200
-- Jenkins <jenkins@debuild.taco.frm2.tum.de> Tue, 17 Apr 2018 17:38:52 +0200
secop-core (0.5.0) unstable; urgency=low
@ -470,7 +730,7 @@ secop-core (0.5.0) unstable; urgency=low
* fix amagnet
* add info about Meeting @PSI
* fix typo and include comment from Niklas
* playground: give sequencermixin a loopcounter (per step)
* give sequencermixin a loopcounter (per step)
[ Frank Wutzler ]
* describe SECoP motivation discussed in meeting 2017-11-27
@ -521,7 +781,7 @@ secop-core (0.5.0) unstable; urgency=low
[ Jenkins ]
-- Jenkins <jenkins@debuild.taco.frm2> Tue, 17 Apr 2018 12:45:58 +0200
-- Jenkins <jenkins@debuild.taco.frm2.tum.de> Tue, 17 Apr 2018 12:45:58 +0200
secop-core (0.4.4) unstable; urgency=low
@ -530,7 +790,7 @@ secop-core (0.4.4) unstable; urgency=low
[ Jenkins ]
-- Jenkins <jenkins@debuild.taco.frm2> Sun, 24 Sep 2017 22:25:01 +0200
-- Jenkins <jenkins@debuild.taco.frm2.tum.de> Sun, 24 Sep 2017 22:25:01 +0200
secop-core (0.4.3) unstable; urgency=low
@ -539,7 +799,7 @@ secop-core (0.4.3) unstable; urgency=low
[ Jenkins ]
-- Jenkins <jenkins@debuild.taco.frm2> Fri, 22 Sep 2017 17:29:46 +0200
-- Jenkins <jenkins@debuild.taco.frm2.tum.de> Fri, 22 Sep 2017 17:29:46 +0200
secop-core (0.4.2) unstable; urgency=low
@ -548,7 +808,7 @@ secop-core (0.4.2) unstable; urgency=low
[ Jenkins ]
-- Jenkins <jenkins@debuild.taco.frm2> Fri, 22 Sep 2017 16:37:59 +0200
-- Jenkins <jenkins@debuild.taco.frm2.tum.de> Fri, 22 Sep 2017 16:37:59 +0200
secop-core (0.4.1) unstable; urgency=low
@ -557,7 +817,7 @@ secop-core (0.4.1) unstable; urgency=low
[ Jenkins ]
-- Jenkins <jenkins@debuild.taco.frm2> Fri, 22 Sep 2017 13:25:28 +0200
-- Jenkins <jenkins@debuild.taco.frm2.tum.de> Fri, 22 Sep 2017 13:25:28 +0200
secop-core (0.4.0) unstable; urgency=low
@ -567,7 +827,7 @@ secop-core (0.4.0) unstable; urgency=low
[ Jenkins ]
-- Jenkins <jenkins@debuild.taco.frm2> Fri, 22 Sep 2017 10:33:04 +0200
-- Jenkins <jenkins@debuild.taco.frm2.tum.de> Fri, 22 Sep 2017 10:33:04 +0200
secop-core (0.3.0) unstable; urgency=low
@ -633,7 +893,7 @@ secop-core (0.3.0) unstable; urgency=low
[ Jenkins ]
-- Jenkins <jenkins@debuild.taco.frm2> Mon, 18 Sep 2017 14:18:36 +0200
-- Jenkins <jenkins@debuild.taco.frm2.tum.de> Mon, 18 Sep 2017 14:18:36 +0200
secop-core (0.2.0) unstable; urgency=low
@ -642,7 +902,7 @@ secop-core (0.2.0) unstable; urgency=low
[ Jenkins ]
-- Jenkins <jenkins@debuild.taco.frm2> Thu, 07 Sep 2017 14:55:41 +0200
-- Jenkins <jenkins@debuild.taco.frm2.tum.de> Thu, 07 Sep 2017 14:55:41 +0200
secop-core (0.1.1) unstable; urgency=low
@ -651,7 +911,7 @@ secop-core (0.1.1) unstable; urgency=low
[ Jenkins ]
-- Jenkins <jenkins@debuild.taco.frm2> Thu, 07 Sep 2017 11:02:19 +0200
-- Jenkins <jenkins@debuild.taco.frm2.tum.de> Thu, 07 Sep 2017 11:02:19 +0200
secop-core (0.1.0) unstable; urgency=low
@ -660,7 +920,7 @@ secop-core (0.1.0) unstable; urgency=low
[ Jenkins ]
-- Jenkins <jenkins@debuild.taco.frm2> Thu, 07 Sep 2017 10:50:24 +0200
-- Jenkins <jenkins@debuild.taco.frm2.tum.de> Thu, 07 Sep 2017 10:50:24 +0200
secop-core (0.0.8) unstable; urgency=low
@ -669,7 +929,7 @@ secop-core (0.0.8) unstable; urgency=low
[ Jenkins ]
-- Jenkins <jenkins@debuild.taco.frm2> Tue, 01 Aug 2017 14:13:11 +0200
-- Jenkins <jenkins@debuild.taco.frm2.tum.de> Tue, 01 Aug 2017 14:13:11 +0200
secop-core (0.0.7) unstable; urgency=low
@ -678,7 +938,7 @@ secop-core (0.0.7) unstable; urgency=low
[ Jenkins ]
-- Jenkins <jenkins@debuild.taco.frm2> Tue, 01 Aug 2017 13:52:15 +0200
-- Jenkins <jenkins@debuild.taco.frm2.tum.de> Tue, 01 Aug 2017 13:52:15 +0200
secop-core (0.0.6) unstable; urgency=low
@ -688,7 +948,7 @@ secop-core (0.0.6) unstable; urgency=low
[ Jenkins ]
-- Jenkins <jenkins@debuild.taco.frm2> Tue, 01 Aug 2017 13:39:07 +0200
-- Jenkins <jenkins@debuild.taco.frm2.tum.de> Tue, 01 Aug 2017 13:39:07 +0200
secop-core (0.0.5) unstable; urgency=low
@ -697,7 +957,7 @@ secop-core (0.0.5) unstable; urgency=low
[ Jenkins ]
-- Jenkins <jenkins@debuild.taco.frm2> Tue, 01 Aug 2017 13:11:43 +0200
-- Jenkins <jenkins@debuild.taco.frm2.tum.de> Tue, 01 Aug 2017 13:11:43 +0200
secop-core (0.0.4) unstable; urgency=low
@ -706,7 +966,7 @@ secop-core (0.0.4) unstable; urgency=low
[ Jenkins ]
-- Jenkins <jenkins@debuild.taco.frm2> Thu, 27 Jul 2017 11:39:42 +0200
-- Jenkins <jenkins@debuild.taco.frm2.tum.de> Thu, 27 Jul 2017 11:39:42 +0200
secop-core (0.0.3) unstable; urgency=low
@ -716,7 +976,7 @@ secop-core (0.0.3) unstable; urgency=low
[ Jenkins ]
-- Jenkins <jenkins@debuild.taco.frm2> Thu, 27 Jul 2017 11:27:28 +0200
-- Jenkins <jenkins@debuild.taco.frm2.tum.de> Thu, 27 Jul 2017 11:27:28 +0200
secop-core (0.0.2) unstable; urgency=medium
@ -794,4 +1054,4 @@ secop-core (0.0.2) unstable; urgency=medium
[ Jenkins ]
-- Jenkins <jenkins@debuild.taco.frm2> Wed, 19 Jul 2017 11:44:13 +0200
-- Jenkins <jenkins@debuild.taco.frm2.tum.de> Wed, 19 Jul 2017 11:44:13 +0200

48
debian/control vendored
View File

@ -1,4 +1,4 @@
Source: secop-core
Source: frappy-core
Section: contrib/misc
Priority: optional
Maintainer: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
@ -23,7 +23,7 @@ Build-Depends: debhelper (>= 11~),
Standards-Version: 4.1.4
X-Python3-Version: >= 3.6
Package: secop-core
Package: frappy-core
Architecture: all
Depends: python3 (>= 3.6),
${misc:Depends},
@ -35,60 +35,72 @@ Depends: python3 (>= 3.6),
python3-mlzlog,
markdown,
python3-daemon
Replaces: secop-core (<= 0.14.3)
Breaks: secop-core (<= 0.14.3)
Description: Frappy SECoP core system
contains the core server and client libraries and the server binary
as well as the systemd integration
#Package: secop-doc
#Package: frappy-doc
#Architecture: all
#Section: doc
#Depends: ${sphinxdoc:Depends},
# ${misc:Depends}
#Description: Frappy SECoP docu
# This is the documentation to all the secop-* packages
# This is the documentation to all the frappy-* packages
Package: secop-gui
Package: frappy-gui
Architecture: all
Depends: secop-core,
Depends: frappy-core,
${misc:Depends},
${python3:Depends},
python3-pyqt (>=4)
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: secop-demo
Package: frappy-demo
Architecture: all
Depends: secop-core,
Depends: frappy-core,
${misc:Depends},
${python3:Depends}
Recommends: secop-gui
Replaces: secop-demo (<= 0.14.3)
Breaks: secop-demo (<= 0.14.3)
Recommends: frappy-gui
Description: SECoP demo files
for demonstration purposes
Package: secop-ess
Package: frappy-ess
Architecture: all
Depends: secop-core,
Depends: frappy-core,
${misc:Depends},
${python3:Depends}
Recommends: secop-gui
Replaces: secop-ess (<= 0.14.3)
Breaks: secop-ess (<= 0.14.3)
Recommends: frappy-gui
Description: SECoP ess files
Modules specific for ESS
Package: secop-mlz
Package: frappy-mlz
Architecture: all
Depends: secop-core,
Depends: frappy-core,
${misc:Depends},
${python3:Depends},
python3-tango (>=9)
Recommends: secop-gui
Replaces: secop-mlz (<= 0.14.3)
Breaks: secop-mlz (<= 0.14.3)
Recommends: frappy-gui
Description: SECoP mlz files
Modules specific for MLZ
Package: secop-psi
Package: frappy-psi
Architecture: all
Depends: secop-core,
Depends: frappy-core,
${misc:Depends},
${python3:Depends}
Recommends: secop-gui
Replaces: secop-psi (<= 0.14.3)
Breaks: secop-psi (<= 0.14.3)
Recommends: frappy-gui
Description: SECoP psi files
Modules specific for PSI

6
debian/copyright vendored
View File

@ -1,15 +1,15 @@
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: frappy
Source: http://forge.frm2.tum.de/cgit/cgit.cgi/frm2/sine2020/secop/playground.git
Source: http://forge.frm2.tum.de/cgit/cgit.cgi/secop/frappy.git
Comment: FRAPPY is an implementation of the free SECoP protocol
see https://www.github.com/SampleEnvironment/SECoP
Files: *
Copyright: 2016-2019 by the FRAPPY-SECOP contributors (see AUTHORS)
Copyright: 2016-2022 by the FRAPPY-SECOP contributors (see AUTHORS)
License: GPL-2
Files: debian/*
Copyright: 2015-2019 Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Copyright: 2015-2022 Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
License: GPL-2
License: GPL-2

9
debian/frappy-core.install vendored Normal file
View File

@ -0,0 +1,9 @@
usr/bin/frappy-server
usr/lib/python3.*/dist-packages/frappy/*.py
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
lib/systemd
var/log/frappy

2
debian/frappy-demo.install vendored Normal file
View File

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

1
debian/frappy-ess.install vendored Normal file
View File

@ -0,0 +1 @@
usr/lib/python3.*/dist-packages/frappy_ess

3
debian/frappy-gui.install vendored Normal file
View File

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

1
debian/frappy-mlz.install vendored Normal file
View File

@ -0,0 +1 @@
usr/lib/python3.*/dist-packages/frappy_mlz

1
debian/frappy-psi.install vendored Normal file
View File

@ -0,0 +1 @@
usr/lib/python3.*/dist-packages/frappy_psi

4
debian/rules vendored
View File

@ -4,12 +4,12 @@
# Uncomment this to turn on verbose mode.
#export DH_VERBOSE=1
export PYBUILD_NAME=secop
export PYBUILD_NAME=frappy
export PYBUILD_TEST_PYTEST=1
override_dh_install:
rmdir debian/tmp
mv debian/python3-secop debian/tmp
mv debian/python3-frappy debian/tmp
dh_install -i -O--buildsystem=pybuild
dh_missing --fail-missing

View File

@ -1,10 +0,0 @@
usr/bin/secop-server
usr/bin/secop-console
usr/lib/python3.*/dist-packages/secop/*.py
usr/lib/python3.*/dist-packages/secop/lib
usr/lib/python3.*/dist-packages/secop/client
usr/lib/python3.*/dist-packages/secop/protocol
usr/lib/python3.*/dist-packages/secop_core-*
usr/lib/python3.*/dist-packages/secop/RELEASE-VERSION
lib/systemd
var/log/secop

View File

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

View File

@ -1 +0,0 @@
usr/lib/python3.*/dist-packages/secop_ess

View File

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

View File

@ -1 +0,0 @@
usr/lib/python3.*/dist-packages/secop_mlz

View File

@ -1 +0,0 @@
usr/lib/python3.*/dist-packages/secop_psi

View File

@ -2,3 +2,19 @@ div.wy-nav-content
{
max-width: 100% !important;
}
/* make some bullet lists more dense (this rule exists in theme.css, but not important)*/
.wy-plain-list-disc li p:last-child, .rst-content .section ul li p:last-child, .rst-content .toctree-wrapper ul li p:last-child, article ul li p:last-child {
margin-bottom: 0 !important;
}
/* overwrite custom font (to save bandwidth not using a custom font) */
body {
font-family: "proxima-nova", "Helvetica Neue", Arial, sans-serif;
}
h1, h2, .rst-content .toctree-wrapper p.caption, h3, h4, h5, h6, legend {
font-family: "ff-tisa-web-pro", "Georgia", Arial, sans-serif;
}

View File

@ -1,6 +0,0 @@
Client documentation
====================
.. toctree::
:maxdepth: 2

View File

@ -1,7 +1,7 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# SECoP documentation build configuration file, created by
# Frappy documentation build configuration file, created by
# sphinx-quickstart on Mon Sep 11 10:58:28 2017.
#
# This file is execfile()d with the current directory set to its
@ -27,7 +27,7 @@ from os import path
# Add import path for inplace usage
sys.path.insert(0, path.abspath(path.join(path.dirname(__file__), '..', '..')))
from secop.version import get_version
from frappy.version import get_version
# -- General configuration ------------------------------------------------
@ -57,9 +57,9 @@ source_suffix = ['.rst', '.md']
master_doc = 'index'
# General information about the project.
project = 'SECoP'
#copyright = '2017, Enrico Faulhaber, Markus Zolliker'
copyright = '2017, SECoP Committee'
project = 'Frappy'
copyright = '2017-2021, Enrico Faulhaber, Markus Zolliker,'
#copyright = '2017, SECoP Committee'
author = 'Enrico Faulhaber, Markus Zolliker'
# The version info for the project you're documenting, acts as replacement for
@ -76,7 +76,7 @@ version = release.split('-')[0]
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = None
language = "en"
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
@ -89,6 +89,10 @@ pygments_style = 'sphinx'
# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = True
autodoc_default_options = {
'member-order': 'bysource',
'show-inheritance': True,
}
default_role = 'any'
# -- Options for HTML output ----------------------------------------------
@ -106,11 +110,6 @@ html_theme = 'sphinx_rtd_theme'
html_last_updated_fmt = '%Y-%m-%d %H:%M'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#
# html_theme_options = {}
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
@ -136,7 +135,7 @@ html_sidebars = {
# -- Options for HTMLHelp output ------------------------------------------
# Output file base name for HTML help builder.
htmlhelp_basename = 'SECoPdoc'
htmlhelp_basename = 'Frappydoc'
# -- Options for LaTeX output ---------------------------------------------
@ -163,7 +162,7 @@ latex_elements = {
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
(master_doc, 'SECoP.tex', 'SECoP source documentation',
(master_doc, 'Frappy.tex', 'Frappy source documentation',
'Enrico Faulhaber, Markus Zolliker', 'manual'),
]
@ -173,7 +172,7 @@ latex_documents = [
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
(master_doc, 'secop', 'SECoP source documentation',
(master_doc, 'frappy', 'Frappy source documentation',
[author], 1)
]
@ -184,8 +183,8 @@ man_pages = [
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(master_doc, 'SECoP', 'SECoP source documentation',
author, 'SECoP', 'One line description of project.',
(master_doc, 'Frappy', 'Frappy source documentation',
author, 'Frappy', 'One line description of project.',
'Miscellaneous'),
]
@ -212,4 +211,9 @@ epub_exclude_files = ['search.html']
# Example configuration for intersphinx: refer to the Python standard library.
intersphinx_mapping = {'https://docs.python.org/': 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)

View File

@ -1,6 +0,0 @@
Demo cryostat
=============
.. automodule:: secop_demo.cryo
:members:

View File

@ -1,12 +0,0 @@
Demo
====
Specific sample environments
----------------------------
.. toctree::
:maxdepth: 3
cryo
test

View File

@ -1,6 +0,0 @@
Test devices
=============
.. automodule:: secop_demo.test
:members:

View File

@ -1,6 +0,0 @@
EPICS modules
=============
.. automodule:: secop_ess.epics
:members:

View File

@ -1,11 +0,0 @@
ESS
===
Frameworks
----------
.. toctree::
:maxdepth: 3
epics

View File

@ -1,9 +0,0 @@
Facility specific functionalities
=================================
.. toctree::
:maxdepth: 3
demo/index
mlz/index
ess/index

View File

@ -1,6 +0,0 @@
ANTARES magnet (amagnet)
========================
.. automodule:: secop_mlz.amagnet
:members:

View File

@ -1,6 +0,0 @@
Entangle
========
.. automodule:: secop_mlz.entangle
:members:

View File

@ -1,20 +0,0 @@
MLZ
===
Frameworks
----------
.. toctree::
:maxdepth: 3
entangle
Specific sample environments
----------------------------
.. toctree::
:maxdepth: 3
amagnet

View File

@ -1,6 +0,0 @@
Datatypes
=========
.. automodule:: secop.datatypes
:members:

View File

@ -1,6 +0,0 @@
Exception classes
=================
.. automodule:: secop.errors
:members:

View File

@ -1,9 +0,0 @@
Framework documentation
=======================
.. toctree::
:maxdepth: 2
datatypes
errors

View File

@ -0,0 +1,10 @@
Demo
====
.. automodule:: frappy_demo.cryo
:show-inheritance:
:members:
.. automodule:: frappy_demo.test
:show-inheritance:
:members:

View File

@ -0,0 +1,9 @@
ESS
---
EPICS
.....
.. automodule:: frappy_ess.epics
:show-inheritance:
:members:

19
doc/source/frappy_mlz.rst Normal file
View File

@ -0,0 +1,19 @@
MLZ
---
Amagnet (Garfield)
..................
.. automodule:: frappy_mlz.amagnet
:show-inheritance:
:members:
Entangle Framework
..................
.. automodule:: frappy_mlz.entangle
:show-inheritance:
:members:

27
doc/source/frappy_psi.rst Normal file
View File

@ -0,0 +1,27 @@
PSI (SINQ)
----------
CCU4 tutorial example
.....................
.. automodule:: frappy_psi.ccu4
:show-inheritance:
:members:
PPMS
....
.. automodule:: frappy_psi.ppms
:show-inheritance:
:members:
LakeShore 370
.............
Calibrated sensors and control loop not yet supported.
.. automodule:: frappy_psi.ls370res
:show-inheritance:
:members:

View File

@ -1,6 +0,0 @@
Graphical user interface documentation
======================================
.. toctree::
:maxdepth: 2

View File

@ -1,19 +1,16 @@
Welcome to FRAPPY documentation!
================================
Frappy Programming Guide
========================
.. toctree::
:maxdepth: 2
server/index
client/index
framework/index
gui/index
facility/index
Indices and tables
==================
introduction
tutorial
reference
frappy_psi
frappy_demo
frappy_mlz
frappy_ess
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`

View File

@ -0,0 +1,70 @@
Introduction
============
Frappy - a Python Framework for SECoP
-------------------------------------
*Frappy* is a Python framework for creating Sample Environment Control Nodes (SEC Node) with
a SECoP interface. A *SEC Node* is a service, running usually a computer or microcomputer,
which accesses the hardware over the interfaces given by the manufacturer of the used
electronic devices. It provides access to the data in an abstracted form over the SECoP interface.
`SECoP <https://github.com/SampleEnvironment/SECoP/tree/master/protocol>`_ is a protocol for
communicating with Sample Environment and other mobile devices, specified by a committee of
the `ISSE <https://sampleenvironment.org>`_.
The Frappy framework deals with all the details of the SECoP protocol, so the programmer
can concentrate on the details of accessing the hardware with support for different types
of interfaces (TCP or Serial, ASCII or binary). However, the programmer should be aware of
the basic principle of the SECoP protocol: the hardware abstraction.
Hardware Abstraction
--------------------
The idea of hardware abstraction is to hide the details of hardware access from the SECoP interface.
A SECoP module is a logical component of an abstract view of the sample environment.
It is one independent value of measurement like a temperature or pressure or a physical output like
a current or voltage. This corresponds roughly to an EPICS channel or a NICOS device. On the
hardware side we may have devices with several channels, like a typical temperature controller,
which will be represented individual SECoP modules.
On the other hand a SECoP channel might be linked with several hardware devices, for example if
you imagine a superconducting magnet controller built of separate electronic devices like a power
supply, switch heater and coil temperature monitor. The latter case does not mean that we have
to hide the details in the SECoP interface. For an expert it might be useful to give at least
read access to hardware specific data by providing them as separate SECoP modules. But the
magnet module should be usable without knowledge of all the inner details.
A SECoP module has:
* **properties**: static information describing the module, for example a human readable
*description* of the module or information about the intended *visibility*.
* **parameters**: changing information about the state of a module (for example the *status*
containing information about the state of the module) or modifiable information influencing
the measurement (for example a "ramp" rate).
* **commands**: actions, for example *stop*.
A SECoP module belongs to an interface class, mainly *Readable* or *Drivable*. A *Readable*
has at least the parameters *value* and *status*, a *Drivable* in addition *target*. *value* is
the main value of the module and is read only. *status* is a tuple (status code, status text),
and *target* is the target value. When the *target* parameter value of a *Drivable* changes,
the status code changes normally to a busy code. As soon as the target value is reached,
the status code changes back to an idle code, if no error occurs.
**Programmers Hint:** before starting to code, choose carefully the main SECoP modules you want
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`.
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.

89
doc/source/reference.rst Normal file
View File

@ -0,0 +1,89 @@
Reference
---------
Module Base Classes
...................
.. autodata:: frappy.modules.Done
.. autoclass:: frappy.modules.Module
:members: earlyInit, initModule, startModule
.. autoclass:: frappy.modules.Readable
:members: Status
.. autoclass:: frappy.modules.Writable
.. autoclass:: frappy.modules.Drivable
:members: Status, isBusy, isDriving, stop
Parameters, Commands and Properties
...................................
.. autoclass:: frappy.params.Parameter
.. autoclass:: frappy.params.Command
.. autoclass:: frappy.properties.Property
.. autoclass:: frappy.modules.Attached
:show-inheritance:
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
Communication
.............
.. autoclass:: frappy.modules.Communicator
:show-inheritance:
:members: communicate
.. autoclass:: frappy.io.StringIO
:show-inheritance:
:members: communicate, multicomm
.. autoclass:: frappy.io.BytesIO
:show-inheritance:
:members: communicate, multicomm
.. autoclass:: frappy.io.HasIO
:show-inheritance:
.. autoclass:: frappy.rwhandler.ReadHandler
:show-inheritance:
:members:
.. autoclass:: frappy.rwhandler.CommonReadHandler
:show-inheritance:
:members:
.. autoclass:: frappy.rwhandler.WriteHandler
:show-inheritance:
:members:
.. autoclass:: frappy.rwhandler.CommonWriteHandler
:show-inheritance:
:members:
Exception classes
.................
.. automodule:: frappy.errors
:members:
.. include:: server.rst

72
doc/source/server.rst Normal file
View File

@ -0,0 +1,72 @@
Configuration
.............
The configuration consists of a **NODE** section, an **INTERFACE** section and one
section per SECoP module.
The **NODE** section contains a description of the SEC node and a globally unique ID of
the SEC node. Example:
.. code::
[NODE]
description = a description of the SEC node
id = globally.valid.identifier
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:
.. 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
**HeLevel** used by the **helevel** module can be found in the PSI facility subdirectory
frappy_psi in the python module file ccu4.py:
.. code::
[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
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,
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.
Starting
........
The Frappy server can be started via the **bin/frappy-server** script.
.. parsed-literal::
usage: frappy-server [-h] [-v | -q] [-d] name
Manage a Frappy server
positional arguments:
name name of the instance. Uses etc/name.cfg for configuration
optional arguments:
-c, --cfgfiles config files to be used. Comma separated list.
defaults to <name> when omitted
-p, --port server port (default: take from cfg file)
-h, --help show this help message and exit
-v, --verbose output lots of diagnostic information
-q, --quiet suppress non-error messages
-d, --daemonize run as daemon
-t, --test check cfg files only

View File

@ -1,3 +0,0 @@
Configuration
=============

View File

@ -1,11 +0,0 @@
Server documentation
====================
.. toctree::
:maxdepth: 3
starting
configuration
modules
protocol/index

View File

@ -1,6 +0,0 @@
Module base classes
===================
.. automodule:: secop.modules
:members:

View File

@ -1,8 +0,0 @@
protocol stack
==============
.. toctree::
:maxdepth: 3
interface/index

View File

@ -1,9 +0,0 @@
Interfaces
==========
.. toctree::
:maxdepth: 3
tcp
zmq

View File

@ -1,6 +0,0 @@
TCP
===
.. automodule:: secop.protocol.interface.tcp
:members:

View File

@ -1,6 +0,0 @@
ZMQ
===
.. automodule:: secop.protocol.interface.zmq
:members:

View File

@ -1,21 +0,0 @@
Starting
========
The SECoP server can be started via the ``bin/secop-server`` script.
.. parsed-literal::
usage: secop-server [-h] [-v | -q] [-d] name
Manage a SECoP server
positional arguments:
name Name of the instance. Uses etc/name.cfg for configuration
optional arguments:
-h, --help show this help message and exit
-v, --verbose Output lots of diagnostic information
-q, --quiet suppress non-error messages
-d, --daemonize Run as daemon

7
doc/source/tutorial.rst Normal file
View File

@ -0,0 +1,7 @@
Tutorial
--------
.. toctree::
:maxdepth: 2
tutorial_helevel

View File

@ -0,0 +1,250 @@
HeLevel - a Simple Driver
=========================
Coding the Driver
-----------------
For this tutorial we choose as an example a cryostat. Let us start with the helium level
meter, as this is the simplest module.
As mentioned in the introduction, we have to code the access to the hardware (driver),
and the Frappy framework will deal with the SECoP interface. The code for the driver is
located in a subdirectory named after the facility or institute programming the driver
in our case *frappy_psi*. We create a file named from the electronic device CCU4 we use
here for the He level reading.
CCU4 luckily has a very simple and logical protocol:
* ``<name>=<value>\n`` sets the parameter named ``<name>`` to the value ``<value>``
* ``<name>\n`` reads the parameter named ``<name>``
* in both cases, the reply is ``<name>=<value>\n``
``frappy_psi/ccu4.py``:
.. code:: python
# the most common Frappy classes can be imported from frappy.core
from frappy.core import Readable, Parameter, FloatRange, BoolType, StringIO, HasIO
class CCU4IO(StringIO):
"""communication with CCU4"""
# for completeness: (not needed, as it is the default)
end_of_line = '\n'
# on connect, we send 'cid' and expect a reply starting with 'CCU4'
# 'cid' is a CCU4 command returning the current version prefixed with CCU4
identification = [('cid', r'CCU4.*')]
# inheriting HasIO allows us to use the communicate method for talking with the hardware
# 'Readable' as base class defines the value and status parameters
class HeLevel(HasIO, Readable):
"""He Level channel of CCU4"""
# define the communication class for automatic creation of the IO module
ioClass = CCU4IO
# define or alter the parameters
# as Readable.value exists already, we give only the modified property 'unit'
value = Parameter(unit='%')
def read_value(self):
# method for reading the main value
reply = self.communicate('h') # send 'h\n' and get the reply 'h=<value>\n'
name, txtvalue = reply.split('=')
assert name == 'h' # check that we got a reply to our command
return float(txtvalue)
The class :class:`frappy_psi.ccu4.CCU4IO`, an extension of (:class:`frappy.stringio.StringIO`)
serves as communication class.
:Note:
You might wonder why the parameter *value* is declared here as class attribute.
In Python, usually class attributes are used to set a default value which might
be overwritten in a method. But class attributes can do more, look for Python
descriptors or properties if you are interested in details.
In Frappy, the *Parameter* class is a descriptor, which does the magic needed for
the SECoP interface. Given ``lev`` as an instance of the class ``HeLevel`` above,
``lev.value`` will just return its internal cached value.
``lev.value = 85.3`` will try to convert to the data type of the parameter,
put it to the internal cache and send a messages to the SECoP clients telling
that ``lev.value`` has got a new value.
For getting a value from the hardware, you have to call ``lev.read_value()``.
Frappy has replaced your version of *read_value* with a wrapped one which
also takes care to announce the change to the clients.
Even when you did not code this method, Frappy adds it silently, so calling
``<module>.read_<parameter>`` will be possible for all parameters declared
in a module.
Above is already the code for a very simple working He Level meter driver. For a next step,
we want to improve it:
* We should inform the client about errors. That is what the *status* parameter is for.
* We want to be able to configure the He Level sensor.
* We want to be able to switch the Level Monitor to fast reading before we start to fill.
Let us start to code these additions. We do not need to declare the status parameter,
as it is inherited from *Readable*. But we declare the new parameters *empty_length*,
*full_length* and *sample_rate*, and we have to code the communication and convert
the status codes from the hardware to the standard SECoP status codes.
.. code:: python
...
# the first two arguments to Parameter are 'description' and 'datatype'
# it is highly recommended to define always the physical unit
empty_length = Parameter('warm length when empty', FloatRange(0, 2000, unit='mm'),
readonly=False)
full_length = Parameter('warm length when full', FloatRange(0, 2000, unit='mm'),
readonly=False)
sample_rate = Parameter('sample rate', EnumType(slow=0, fast=1), readonly=False)
...
Status = Readable.Status
# conversion of the code from the CCU4 parameter 'hsf'
STATUS_MAP = {
0: (Status.IDLE, 'sensor ok'),
1: (Status.ERROR, 'sensor warm'),
2: (Status.ERROR, 'no sensor'),
3: (Status.ERROR, 'timeout'),
4: (Status.ERROR, 'not yet read'),
5: (Status.DISABLED, 'disabled'),
}
def read_status(self):
name, txtvalue = self.communicate('hsf').split('=')
assert name == 'hsf'
return self.STATUS_MAP(int(txtvalue))
def read_empty_length(self):
name, txtvalue = self.communicate('hem').split('=')
assert name == 'hem'
return float(txtvalue)
def write_empty_length(self, value):
name, txtvalue = self.communicate('hem=%g' % value).split('=')
assert name == 'hem'
return float(txtvalue)
...
Here we start to realize, that we will repeat similar code for other parameters,
which means it might be worth to create a *query* method, and then the
*read_<param>* and *write_<param>* methods will become shorter:
.. code:: python
...
class HeLevel(Readable):
...
def query(self, cmd):
"""send a query and get the response
:param cmd: the name of the parameter to query or '<parameter>=<value'
for changing a parameter
:returns: the (new) value of the parameter
"""
name, txtvalue = self.communicate(cmd).split('=')
assert name == cmd.split('=')[0] # check that we got a reply to our command
return float(txtvalue)
def read_value(self):
return self.query('h')
def read_status(self):
return self.STATUS_MAP[int(self.query('hsf'))]
def read_empty_length(self):
return self.query('hem')
def write_empty_length(self, value):
return self.query('hem=%g' % value)
def read_full_length(self):
return self.query('hfu')
def write_full_length(self, value):
return self.query('hfu=%g' % value)
def read_sample_rate(self):
return self.query('hf')
def write_sample_rate(self, value):
return self.query('hf=%d' % value)
:Note:
It make sense to unify *empty_length* and *full_length* to one parameter *calibration*,
as a :class:`frappy.datatypes.StructOf` with members *empty_length* and *full_length*:
.. code:: python
calibration = Parameter(
'sensor calibration',
StructOf(empty_length=FloatRange(0, 2000, unit='mm'),
full_length=FloatRange(0, 2000, unit='mm')),
readonly=False)
For simplicity we stay with two float parameters for this tutorial.
The full documentation of the example can be found here: :class:`frappy_psi.ccu4.HeLevel`
Configuration
-------------
Before we continue coding, we may try out what we have coded and 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* in the *cfg* subdirectory:
``cfg/example_cryo.cfg``:
.. code:: ini
[NODE]
description = this is an example cryostat for the Frappy tutorial
id = example_cryo.psi.ch
[INTERFACE]
uri = tcp://5000
[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
A configuration file contains several sections with a header enclosed by rectangular brackets.
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 *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
the parameters *empty_length* and *full_length* from the client by defining:
.. code:: ini
empty_length.export = False
full_length.export = False
However, we do not put this here, as it is nice to try out changing parameters for a test!
*to be continued*

View File

@ -25,33 +25,33 @@
import os
import sys
import fnmatch
from os import path
from secop.lib import getGeneralConfig
from frappy.lib import generalConfig
def main():
normal_dir = sys.argv[1]
global_config = getGeneralConfig()
config_dir = global_config['confdir']
generalConfig.init()
config_dir = generalConfig['confdir']
secop_unit = '/lib/systemd/system/secop@.service'
wants_dir = normal_dir + '/secop.target.wants'
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.sort()
for srv in all_servers:
symlink = '%s/secop@%s.service' % (normal_dir, srv)
os.symlink(secop_unit, symlink)
symlink = '%s/frappy@%s.service' % (normal_dir, srv)
os.symlink(frappy_unit, symlink)
if not path.isdir(wants_dir):
os.mkdir(wants_dir)
os.symlink(symlink, '%s/%s' % (wants_dir, path.basename(symlink)))
# the stamp file signals successful run of the generator
open(normal_dir + '/secop.stamp', 'w').close()
open(normal_dir + '/frappy.stamp', 'w').close()
if __name__ == '__main__':

View File

@ -1,10 +1,10 @@
[Unit]
Description=SECoP SEC-node: %i
Description=FRAPPY SECoP SEC-node: %i
After=network-online.service
[Service]
Type=notify
ExecStart=/usr/bin/secop-server %I
ExecStart=/usr/bin/frappy-server %I
Restart=on-abnormal
RestartSec=30

View File

@ -3,12 +3,12 @@
block_cipher = None
a = Analysis(['bin\\secop-server'],
a = Analysis(['bin\\frappy-server'],
pathex=['.'],
binaries=[],
datas=[],
hiddenimports=['secop.protocol', 'secop.protocol.dispatcher', 'secop.protocol.interface', 'secop.protocol.interface.tcp',
'secop_psi.ppmssim', 'secop_psi.ppmswindows', 'secop_psi.ppms'],
hiddenimports=['frappy.protocol', 'frappy.protocol.dispatcher', 'frappy.protocol.interface', 'frappy.protocol.interface.tcp',
'frappy_psi.ppmssim', 'frappy_psi.ppmswindows', 'frappy_psi.ppms'],
hookspath=[],
runtime_hooks=[],
excludes=[],
@ -22,7 +22,7 @@ exe = EXE(pyz,
a.scripts,
[],
exclude_binaries=True,
name='secop-server',
name='frappy-server',
debug=False,
bootloader_ignore_signals=False,
strip=False,
@ -35,4 +35,4 @@ coll = COLLECT(exe,
strip=False,
upx=True,
upx_exclude=[],
name='secop-server')
name='frappy-server')

View File

@ -18,29 +18,33 @@
# Module authors:
# Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
# Markus Zolliker <markus.zolliker@psi.ch>
# Alexander Zaft <a.zaft@fz-juelich.de>
#
# *****************************************************************************
"""general SECoP client"""
import time
import queue
import re
import json
from threading import Event, RLock, current_thread
import queue
import time
from collections import defaultdict
from threading import Event, RLock, current_thread
from secop.lib import mkthread, formatExtendedTraceback, formatExtendedStack
from secop.lib.asynconn import AsynConn, ConnectionClosed
from secop.datatypes import get_datatype
from secop.protocol.interface import encode_msg_frame, decode_msg
from secop.protocol.messages import REQUEST2REPLY, ERRORPREFIX, EVENTREPLY, WRITEREQUEST, WRITEREPLY, \
READREQUEST, READREPLY, IDENTREQUEST, IDENTPREFIX, ENABLEEVENTSREQUEST, COMMANDREQUEST, \
DESCRIPTIONREQUEST, HEARTBEATREQUEST
import secop.errors
import secop.params
import frappy.errors
import frappy.params
from frappy.datatypes import get_datatype
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
# replies to be handled for cache
UPDATE_MESSAGES = {EVENTREPLY, READREPLY, WRITEREPLY, ERRORPREFIX + READREQUEST, ERRORPREFIX + EVENTREPLY}
VERSIONFMT= re.compile(r'^[^,]*?ISSE[^,]*,SECoP,')
class UNREGISTER:
"""a magic value, used a returned value in a callback
@ -160,7 +164,6 @@ class ProxyClient:
if not cblist:
self.callbacks[cbname].pop(key)
def callback(self, key, cbname, *args):
"""perform callbacks
@ -243,9 +246,16 @@ class SecopClient(ProxyClient):
self.secop_version = reply.decode('utf-8')
else:
raise self.error_map('HardwareError')('no answer to %s' % IDENTREQUEST)
if not self.secop_version.startswith(IDENTPREFIX):
if not VERSIONFMT.match(self.secop_version):
raise self.error_map('HardwareError')('bad answer to %s: %r' %
(IDENTREQUEST, self.secop_version))
# 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)
# now its safe to do secop stuff
self._running = True
self._rxthread = mkthread(self.__rxthread)
@ -317,7 +327,7 @@ class SecopClient(ProxyClient):
if module_param is not None:
if action.startswith(ERRORPREFIX):
timestamp = data[2].get('t', None)
readerror = secop.errors.make_secop_error(*data[0:2])
readerror = frappy.errors.make_secop_error(*data[0:2])
value = None
else:
timestamp = data[1].get('t', None)
@ -356,7 +366,7 @@ class SecopClient(ProxyClient):
except ConnectionClosed:
pass
except Exception as e:
self.log.error('rxthread ended with %s' % e)
self.log.error('rxthread ended with %r', e)
self._rxthread = None
self.disconnect(False)
if self._shutdown:
@ -393,7 +403,7 @@ class SecopClient(ProxyClient):
if time.time() > self.disconnect_time + self.reconnect_timeout:
if self.online: # was recently connected
self.disconnect_time = 0
self.log.warning('can not reconnect to %s (%r)' % (self.nodename, e))
self.log.warning('can not reconnect to %s (%r)', self.nodename, e)
self.log.info('continue trying to reconnect')
# self.log.warning(formatExtendedTraceback())
self._set_state(False)
@ -490,17 +500,15 @@ class SecopClient(ProxyClient):
def _unhandled_message(self, action, ident, data):
if not self.callback(None, 'unhandledMessage', action, ident, data):
self.log.warning('unhandled message: %s %s %r' % (action, ident, data))
self.log.warning('unhandled message: %s %s %r', action, ident, data)
def _set_state(self, online, state=None):
# treat reconnecting as online!
state = state or self.state
self.callback(None, 'nodeStateChange', online, state)
for mname in self.modules:
self.callback(mname, 'nodeStateChange', online, state)
# set online attribute after callbacks -> callback may check for old state
# remark: reconnecting is treated as online
self.online = online
self.state = state
self.state = state or self.state
self.callback(None, 'nodeStateChange', self.online, self.state)
for mname in self.modules:
self.callback(mname, 'nodeStateChange', self.online, self.state)
def queue_request(self, action, ident=None, data=None):
"""make a request"""
@ -520,7 +528,7 @@ class SecopClient(ProxyClient):
action, _, data = entry[2] # pylint: disable=unpacking-non-sequence
if action.startswith(ERRORPREFIX):
errcls = self.error_map(data[0])
raise errcls('on SEC-Node: ' + data[1])
raise errcls(data[1])
return entry[2] # reply
def request(self, action, ident=None, data=None):
@ -535,7 +543,7 @@ class SecopClient(ProxyClient):
"""forced read over connection"""
try:
self.request(READREQUEST, self.identifier[module, parameter])
except secop.errors.SECoPError:
except frappy.errors.SECoPError:
# error reply message is already stored as readerror in cache
pass
return self.cache.get((module, parameter), None)
@ -563,7 +571,7 @@ class SecopClient(ProxyClient):
argument = datatype.export_value(argument)
else:
if argument is not None:
raise secop.errors.BadValueError('command has no argument')
raise frappy.errors.BadValueError('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
@ -573,9 +581,9 @@ class SecopClient(ProxyClient):
# the following attributes may be/are intended to be overwritten by a subclass
ERROR_MAP = secop.errors.EXCEPTIONS
DEFAULT_EXCEPTION = secop.errors.SECoPError
PREDEFINED_NAMES = set(secop.params.PREDEFINED_ACCESSIBLES)
ERROR_MAP = frappy.errors.EXCEPTIONS
DEFAULT_EXCEPTION = frappy.errors.SECoPError
PREDEFINED_NAMES = set(frappy.params.PREDEFINED_ACCESSIBLES)
activate = True
def error_map(self, exc):

View File

@ -0,0 +1,295 @@
# -*- 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>
#
# *****************************************************************************
"""simple interactive python client"""
import sys
import time
import re
from queue import Queue
from frappy.client import SecopClient
from frappy.errors import SECoPError
from frappy.datatypes import get_datatype
USAGE = """
Usage:
from frappy.client.interactive import Client
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__']
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
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 PrettyFloat(float):
"""float with a nicer repr:
- numbers which are close to a fractional decimal number do not have
additional annoying digits
- always display a decimal point
"""
def __repr__(self):
result = '%.12g' % self
if '.' in result or 'e' in result:
return result
return result + '.'
class Module:
_log_pattern = re.compile('.*')
def __init__(self, name, secnode):
self._name = name
self._secnode = secnode
self._parameters = list(secnode.modules[name]['parameters'])
self._commands = list(secnode.modules[name]['commands'])
self._running = None
self._status = None
props = secnode.modules[name]['properties']
self._title = '# %s (%s)' % (props.get('implementation', ''), props.get('interface_classes', [''])[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)
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)
def _isBusy(self):
return 300 <= self.status[0] < 400
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 _watch_parameter(self, m, pname, *args, forced=False, mininterval=0):
"""show parameter update"""
pobj = getattr(type(self), pname)
if not args:
args = self._secnode.cache[self._name, pname]
value = args[0]
now = time.time()
if (value != pobj.prev and now >= pobj.prev_time + mininterval) or forced:
self._secnode.log.info('%s', self._one_line(pname))
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})
else:
enabled.update(arg)
enabled.update(kwds)
for pname, enable in enabled.items():
self._secnode.unregister_callback((self._name, pname), updateEvent=self._watch_parameter)
if enable:
self._secnode.register_callback((self._name, pname), updateEvent=self._watch_parameter)
def read(self, pname='value'):
value, _, error = self._secnode.readParameter(self._name, pname)
if error:
raise 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
try:
while self._running.get():
self._watch_parameter(self._name, 'value', mininterval=self._secnode.mininterval)
self._watch_parameter(self._name, 'status')
except KeyboardInterrupt:
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)
return self.value
def __repr__(self):
wid = max(len(k) for k in self._parameters)
return '%s\n%s\nCommands: %s' % (
self._title,
'\n'.join(self._one_line(k, wid) for k in self._parameters),
', '.join(k + '()' for k in self._commands))
def logging(self, level='comlog', pattern='.*'):
self._log_pattern = re.compile(pattern)
self._secnode.request('logging', self._name, level)
def handle_log_message_(self, data):
if self._log_pattern.match(data):
self._secnode.log.info('%s: %r', self._name, data)
class Param:
def __init__(self, name, datainfo):
self.name = name
self.prev = None
self.prev_time = 0
self.datatype = get_datatype(datainfo)
def __get__(self, obj, owner):
if obj is None:
return self
value, _, error = obj._secnode.cache[obj._name, self.name]
if error:
raise error
return value
def __set__(self, obj, value):
if self.name == 'target':
obj._running = Queue()
try:
obj._secnode.setParameter(obj._name, self.name, value)
except SECoPError as 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):
self.name = name
self.modname = modname
self.exec = secnode.execCommand
def call(self, *args, **kwds):
if kwds:
if args:
raise TypeError('mixed arguments forbidden')
result, _ = self.exec(self.modname, self.name, kwds)
else:
result, _ = self.exec(self.modname, self.name, args or None)
return result
def __get__(self, obj, owner=None):
if obj is None:
return self
return self.call
class Client(SecopClient):
activate = True
secnodes = {}
mininterval = 1
def __init__(self, uri, loglevel='info'):
# remove previous client:
prev = self.secnodes.pop(uri, None)
if prev:
prev.log.info('remove previous client to %s', uri)
for modname in prev.modules:
prevnode = getattr(getattr(main, modname, None), '_secnode', None)
if prevnode == prev:
prev.log.info('remove previous module %s', modname)
delattr(main, modname)
prev.disconnect()
self.secnodes[uri] = self
super().__init__(uri, Logger(loglevel))
self.connect()
for modname, moddesc in self.modules.items():
prev = getattr(main, modname, None)
if prev is None:
self.log.info('create module %s', modname)
else:
if getattr(prev, '_secnode', None) is None:
self.log.error('skip module %s overwriting a global variable' % modname)
continue
self.log.info('overwrite module %s', 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)
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(None, self.unhandledMessage)
self.log.info('%s', USAGE)
def unhandledMessage(self, action, ident, data):
"""handle logging messages"""
if action == 'log':
modname = ident.split(':')[0]
modobj = getattr(main, modname, None)
if modobj:
modobj.handle_log_message_(data)
return
self.log.info('module %s not found', modname)
self.log.info('unhandled: %s %s %r', action, ident, data)

184
frappy/config.py Normal file
View File

@ -0,0 +1,184 @@
# -*- 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:
# Alexander Zaft <a.zaft@fz-juelich.de>
#
# *****************************************************************************
import os
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,
**kwds
):
super().__init__(
equipment_id=equipment_id,
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__(
name=name,
cls=cls,
description=description
)
# Make parameters out of all keywords
groups = {}
for key, val in kwds.items():
if isinstance(val, Param):
self[key] = val
elif isinstance(val, Group):
groups[key] = val
else:
# shortcut to only set value
self[key] = Param(val)
for group, members in groups.items():
for member in members:
self[member]['group'] = group
class Collector:
def __init__(self, cls):
self.list = []
self.cls = cls
def add(self, *args, **kwds):
self.list.append(self.cls(*args, **kwds))
def append(self, mod):
self.list.append(mod)
class NodeCollector:
def __init__(self):
self.node = None
def add(self, *args, **kwds):
if self.node is None:
self.node = Node(*args, **kwds)
else:
raise ConfigError('Only one Node is allowed per file!')
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}
self.ambiguous = set()
def merge_modules(self, other):
""" merges only the modules from 'other' into 'self'"""
self.ambiguous |= self.module_names & other.module_names
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)
def process_file(config_text):
node = NodeCollector()
mods = Collector(Mod)
ns = {'Node': node.add, 'Mod': mods.add, 'Param': Param, 'Command': Param, 'Group': Group}
# pylint: disable=exec-used
exec(config_text, ns)
return Config(node, mods)
def to_config_path(cfgfile, log):
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
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):
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
def load_config(cfgfiles, log):
"""Load config files.
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
- log : frappy.logging.Mainlogger
Logger aquired from frappy.logging
Returns
- config: Config
merged configuration
"""
config = None
for cfgfile in cfgfiles.split(','):
filename = to_config_path(cfgfile, log)
log.debug('Parsing config file %s...', filename)
with open(filename, 'rb') as f:
config_text = f.read()
cfg = process_file(config_text)
if config:
config.merge_modules(cfg)
else:
config = cfg
if config.ambiguous:
log.warning('ambiguous sections in %s: %r',
cfgfiles, list(config.ambiguous))
return config

View File

@ -23,16 +23,23 @@
#
# *****************************************************************************
# allow to import the most important classes from 'secop'
# allow to import the most important classes from 'frappy'
# pylint: disable=unused-import
from secop.datatypes import FloatRange, IntRange, ScaledInteger, \
BoolType, EnumType, BLOBType, StringType, TupleOf, ArrayOf, StructOf
from secop.lib.enum import Enum
from secop.modules import Module, Readable, Writable, Drivable, Communicator, Attached
from secop.properties import Property
from secop.params import Parameter, Command, Override
from secop.metaclass import Done
from secop.iohandler import IOHandler, IOHandlerBase
from secop.stringio import StringIO, HasIodev
from secop.proxy import SecNode, Proxy, proxy_class
from frappy.datatypes import ArrayOf, BLOBType, BoolType, EnumType, \
FloatRange, IntRange, ScaledInteger, StringType, StructOf, TupleOf
from frappy.lib.enum import Enum
from frappy.modules import Attached, Communicator, \
Done, Drivable, Feature, Module, Readable, Writable, HasAccessibles
from frappy.params import Command, Parameter
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.rwhandler import ReadHandler, WriteHandler, CommonReadHandler, \
CommonWriteHandler, nopoll
ERROR = Drivable.Status.ERROR
WARN = Drivable.Status.WARN
BUSY = Drivable.Status.BUSY
IDLE = Drivable.Status.IDLE

File diff suppressed because it is too large Load Diff

View File

@ -17,23 +17,28 @@
#
# Module authors:
# Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
# Markus Zolliker <markus.zolliker@psi.ch>
#
# *****************************************************************************
"""Define (internal) SECoP Errors"""
import re
from ast import literal_eval
class SECoPError(RuntimeError):
silent = False # silent = True indicates that the error is already logged
def __init__(self, *args, **kwds):
RuntimeError.__init__(self)
super().__init__()
self.args = args
for k, v in list(kwds.items()):
setattr(self, k, v)
def __repr__(self):
args = ', '.join(map(repr, self.args))
kwds = ', '.join(['%s=%r' % i for i in list(self.__dict__.items())])
kwds = ', '.join(['%s=%r' % i for i in list(self.__dict__.items())
if i[0] != 'silent'])
res = []
if args:
res.append(args)
@ -103,14 +108,6 @@ class CommunicationFailedError(SECoPError):
pass
class SilentError(SECoPError):
pass
class CommunicationSilentError(SilentError, CommunicationFailedError):
name = 'CommunicationFailed'
class IsBusyError(SECoPError):
pass
@ -124,11 +121,30 @@ class DisabledError(SECoPError):
class HardwareError(SECoPError):
pass
name = 'HardwareError'
FRAPPY_ERROR = re.compile(r'(.*)\(.*\)$')
def make_secop_error(name, text):
errcls = EXCEPTIONS.get(name, InternalError)
"""create an instance of SECoPError from an error report
:param name: the error class from the SECoP error report
: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)
@ -144,7 +160,7 @@ EXCEPTIONS = dict(
NoSuchCommand=NoSuchCommandError,
CommandFailed=CommandFailedError,
CommandRunning=CommandRunningError,
Readonly=ReadOnlyError,
ReadOnly=ReadOnlyError,
BadValue=BadValueError,
CommunicationFailed=CommunicationFailedError,
HardwareError=HardwareError,
@ -152,7 +168,8 @@ EXCEPTIONS = dict(
IsError=IsErrorError,
Disabled=DisabledError,
SyntaxError=ProtocolError,
NotImplementedError=NotImplementedError,
NotImplemented=NotImplementedError,
ProtocolError=ProtocolError,
InternalError=InternalError,
# internal short versions (candidates for spec)
Protocol=ProtocolError,

245
frappy/features.py Normal file
View File

@ -0,0 +1,245 @@
# -*- 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>
# Markus Zolliker <markus.zolliker@psi.ch>
#
# *****************************************************************************
"""Define Mixin Features for real Modules implemented in the server"""
from frappy.datatypes import ArrayOf, BoolType, EnumType, \
FloatRange, StringType, StructOf, TupleOf
from frappy.core import Command, Done, Drivable, Feature, \
Parameter, Property, PersistentParam, Readable
from frappy.errors import BadValueError, ConfigError
from frappy.lib import clamp
# --- proposals, to be used at SINQ (not agreed as standard yet) ---
class HasOffset(Feature):
"""has an offset parameter
implementation to be done in the subclass
"""
offset = PersistentParam('offset (physical value + offset = HW value)',
FloatRange(unit='deg'), readonly=False, default=0)
def write_offset(self, value):
self.offset = value
if isinstance(self, HasLimits):
self.read_limits()
if isinstance(self, Readable):
self.read_value()
if isinstance(self, Drivable):
self.read_target()
self.saveParameters()
return Done
class HasLimits(Feature):
"""user limits
implementation to be done in the subclass
for a drivable, abslimits is roughly the same as the target datatype limits,
except for the offset
"""
abslimits = Property('abs limits (raw values)', default=(-9e99, 9e99), extname='abslimits', export=True,
datatype=TupleOf(FloatRange(unit='deg'), FloatRange(unit='deg')))
limits = PersistentParam('user limits', readonly=False, default=(-9e99, 9e99),
datatype=TupleOf(FloatRange(unit='deg'), FloatRange(unit='deg')))
_limits = None
def apply_offset(self, sign, *values):
if isinstance(self, HasOffset):
return tuple(v + sign * self.offset for v in values)
return values
def earlyInit(self):
super().earlyInit()
# make limits valid
_limits = self.apply_offset(1, *self.limits)
self._limits = tuple(clamp(self.abslimits[0], v, self.abslimits[1]) for v in _limits)
self.read_limits()
def checkProperties(self):
pname = 'target' if isinstance(self, Drivable) else 'value'
dt = self.parameters[pname].datatype
min_, max_ = self.abslimits
t_min, t_max = self.apply_offset(1, dt.min, dt.max)
if t_min > max_ or t_max < min_:
raise ConfigError('abslimits not within %s range' % pname)
self.abslimits = clamp(t_min, min_, t_max), clamp(t_min, max_, t_max)
super().checkProperties()
def read_limits(self):
return self.apply_offset(-1, *self._limits)
def write_limits(self, value):
min_, max_ = self.apply_offset(-1, *self.abslimits)
if not min_ <= value[0] <= value[1] <= max_:
if value[0] > value[1]:
raise BadValueError('invalid interval: %r' % value)
raise BadValueError('limits not within abs limits [%g, %g]' % (min_, max_))
self.limits = value
self.saveParameters()
return Done
def check_limits(self, value):
"""check if value is valid"""
min_, max_ = self.limits
if not min_ <= value <= max_:
raise BadValueError('limits violation: %g outside [%g, %g]' % (value, min_, max_))
# --- not used, not tested yet ---
class HAS_PID(Feature):
# note: implementors should either use p,i,d or pid, but ECS must be handle both cases
# note: if both p,i,d and pid are implemented, it MUST NOT matter which one gets a change, the final result should be the same
# note: if there are additional custom accessibles with the same name as an element of the struct, the above applies
# note: (i would still but them in the same group, though)
# note: if extra elements are implemented in the pid struct they MUST BE
# properly described in the description of the pid Parameter
# parameters
use_pid = Parameter('use the pid mode', datatype=EnumType(openloop=0, pid_control=1), )
# pylint: disable=invalid-name
p = Parameter('proportional part of the regulation', datatype=FloatRange(0), )
i = Parameter('(optional) integral part', datatype=FloatRange(0), optional=True)
d = Parameter('(optional) derivative part', datatype=FloatRange(0), optional=True)
base_output = Parameter('(optional) minimum output value', datatype=FloatRange(0), optional=True)
pid = Parameter('(optional) Struct of p,i,d, minimum output value',
datatype=StructOf(p=FloatRange(0),
i=FloatRange(0),
d=FloatRange(0),
base_output=FloatRange(0),
), optional=True,
) # note: struct may be extended with custom elements (names should be prefixed with '_')
output = Parameter('(optional) output of pid-control', datatype=FloatRange(0), optional=True, readonly=False)
class Has_PIDTable(HAS_PID):
# parameters
use_pidtable = Parameter('use the zoning mode', datatype=EnumType(fixed_pid=0, zone_mode=1))
pidtable = Parameter('Table of pid-values vs. target temperature', datatype=ArrayOf(TupleOf(FloatRange(0),
StructOf(p=FloatRange(0),
i=FloatRange(0),
d=FloatRange(0),
_heater_range=FloatRange(0),
_base_output=FloatRange(0),),),), optional=True) # struct may include 'heaterrange'
class HAS_Persistent(Feature):
#extra_Status {
# 'decoupled' : Status.IDLE+1, # to be discussed.
# 'coupling' : Status.BUSY+1, # to be discussed.
# 'coupled' : Status.BUSY+2, # to be discussed.
# 'decoupling' : Status.BUSY+3, # to be discussed.
#}
# parameters
persistent_mode = Parameter('Use persistent mode',
datatype=EnumType(off=0,on=1),
default=0, readonly=False)
is_persistent = Parameter('current state of persistence',
datatype=BoolType(), optional=True)
# stored_value = Parameter('current persistence value, often used as the modules value',
# datatype='main', unit='$', optional=True)
# driven_value = Parameter('driven value (outside value, syncs with stored_value if non-persistent)',
# datatype='main', unit='$' )
class HAS_Tolerance(Feature):
# detects IDLE status by checking if the value lies in a given window:
# tolerance is the maximum allowed deviation from target, value must lie in this interval
# for at least ´timewindow´ seconds.
# parameters
tolerance = Parameter('Half height of the Window',
datatype=FloatRange(0), default=1, unit='$')
timewindow = Parameter('Length of the timewindow to check',
datatype=FloatRange(0), default=30, unit='s',
optional=True)
class HAS_Timeout(Feature):
# parameters
timeout = Parameter('timeout for movement',
datatype=FloatRange(0), default=0, unit='s')
class HAS_Pause(Feature):
# just a proposal, can't agree on it....
@Command(argument=None, result=None)
def pause(self):
"""pauses movement"""
@Command(argument=None, result=None)
def go(self):
"""continues movement or start a new one if target was change since the last pause"""
class HAS_Ramp(Feature):
# parameters
ramp =Parameter('speed of movement', unit='$/min',
datatype=FloatRange(0))
use_ramp = Parameter('use the ramping of the setpoint, or jump',
datatype=EnumType(disable_ramp=0, use_ramp=1),
optional=True)
setpoint = Parameter('currently active setpoint',
datatype=FloatRange(0), unit='$',
readonly=True, )
class HAS_Speed(Feature):
# parameters
speed = Parameter('(maximum) speed of movement (of the main value)',
unit='$/s', datatype=FloatRange(0))
class HAS_Accel(HAS_Speed):
# parameters
accel = Parameter('acceleration of movement', unit='$/s^2',
datatype=FloatRange(0))
decel = Parameter('deceleration of movement', unit='$/s^2',
datatype=FloatRange(0), optional=True)
class HAS_MotorCurrents(Feature):
# parameters
movecurrent = Parameter('Current while moving',
datatype=FloatRange(0))
idlecurrent = Parameter('Current while idle',
datatype=FloatRange(0), optional=True)
class HAS_Curve(Feature):
# proposed, not yet agreed upon!
# parameters
curve = Parameter('Calibration curve', datatype=StringType(), default='<unset>')

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