Metadata-Version: 2.4
Name: dg645-ioc
Version: 0.9.4
Summary: CAproto-based pure-Python EPICS IOC for the Stanford Research Systems DG645 delay generator.
Author-email: Matthias Rössle <matthias.roessle@helmholtz-berlin.de>, Florin Boariu <florin.pt@rootshell.ro>
Project-URL: Source, https://gitlab.com/kmc3-xpp/kronos-ioc
Project-URL: Issues, https://gitlab.com/kmc3-xpp/kronos-ioc/-/issues
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
Classifier: Operating System :: POSIX :: Linux
Classifier: Development Status :: 2 - Pre-Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: Science/Research
Classifier: Topic :: Scientific/Engineering
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: caproto
Requires-Dist: emmi>=0.5.0
Requires-Dist: pyvisa-py
Requires-Dist: pyvisa-sim
Requires-Dist: parse
Requires-Dist: opentelemetry-api
Requires-Dist: opentelemetry-exporter-otlp
Requires-Dist: pyyaml
Requires-Dist: schema
Provides-Extra: test
Requires-Dist: pytest; extra == "test"
Requires-Dist: pytest-cov; extra == "test"
Requires-Dist: pytest-asyncio; extra == "test"
Dynamic: license-file

EPICS-IOC for the Stanford DG645 Delay Generator
================================================

![release](https://gitlab.com/kmc3-xpp/kronos-ioc/-/badges/release.svg) 
![pipeline](https://gitlab.com/kmc3-xpp/kronos-ioc/badges/release/pipeline.svg)
![coverage](https://gitlab.com/kmc3-xpp/kronos-ioc/badges/release/coverage.svg)


Quickstart
----------

### In a System Shell

#### Obtaining

Download via PyPI: `pip install dg645-ioc` or via GitLab:

   ```
   git clone https://gitlab.com/kmc3-xpp/kronos-ioc
   ```

#### Running from the command line

Configure at least the IP address and the EPICS prefix and start via shell:

   ```
   $ export DG645_EPICS_PREFIX="BEAMLINE:DG645:"
   $ export DG645_HOST="10.0.0.17"
   $ dg645-ioc
   INFO:kronos.ioc:Stanford Research Systems,DG645,s/n001776,ver1.14.10E
   INFO:root:Starting IOC, PV list following
   [...]
   INFO:caproto.ctx:Server startup complete.
   ```

### In a Container

#### Obtaining a Container


You can download the automatically generated container:

   ```
   podman pull registry.gitlab.com/kmc3-xpp/kronos-ioc:latest
   ```

...or create your own, assuming  you've downloaded the sources into `./kronos-ioc`:

   ```
   $ podman build -t kronos-ioc -f kronos-ioc/Dockerfile -v $PWD/kronos-ioc:/kronos_src:z
   ```

#### Running in Podman / Docker

Start as a Podman container (Docker should work the same, just replace thed
`podman` command by `docker`):

   ```
   $ podman run -ti --rm \
       --env DG645_EPICS_PREFIX="BEAMLINE:DG645:" \
	   --env DG645_HOST=10.0.0.17\
	   --name dg645-ioc \
	   --net=host \
	   kronos-ioc:latest
   ```
   Note that we're using host networking in the example above to
   integrate into an existing EPICS network as mindlessly as possible.
   If you care (as you should) for security and access control,
   you might want to think about an more elaborate deployment,
   e.g. using Wireguard interfaces or CAgateway access control.
   
 - Assuming that you've installed the EPICS userland tools, access
   your PVs using `caget`, `caput` and `camonitor` as you're used to:
   ```
   $ caget BEAMLINE:DG645:ch4:dly_RBV
   BEAMLINE:DG645:ch4:dly_RBV        3.14
   ```

Configuration
-------------

 Here's a list of environment variables that might help:
 
- `KRONOS_VISA_HOST`: host name or IP of the DG645 controller
  
- `KRONOS_VISA_PORT`: this is better left blank (the default). In that
  case, the IOC will create a "`TCPIP::<host>::INSTR`" PyVISA device
  name. If the port is specified, it will create a
  "`TCPIP::<host>::<ip>::SOCKET`" device name instead.
  
- `KRONOS_VISA_DEV`: PyVISA device to connecto to, instead of the
  TCP/IP device. If set, overrides host/port.
	
- `KRONOS_VISA_RMAN`: PyVISA resource manager. Defaults to `"@py"`.
  If you've got this far, you know what this is good for ;-)
	
- `KRONOS_EPICS_PREFIX`: EPICS PV prefix to use. Include trailing column
  (`:`) if you need one. Defaults to `KMC3:XPP:DG645:`.
	
- `DG645_LOGGING`: one of `error`, `warn`, `info` or `debug`. Defaults
  to `info`.
	
- `DG645_LOG_STATUS`: if set to `yes`, the IOC will periodically
  (about once per second) log the
  current status of all variables it observes to the `info` logging
  acility. The default is not to do that.

- `KRONOS_EPICS_PROPAGATION_DELAY`: in busy networks, broken
  EPICS gateway setups, or broken EPICS clients, the order of variable
  propagation is apparently not guaranteed -- i.e. if variables A and B
  are set in this order, but in close succession, there is a sufficiently
  large chance for the values to actually arrive in the oder B, then A.
  This breaks `MSTA` / `RBV` dialogues.
  This value introduces a small delay (default is 0.3 seconds) between
  the updating of `RBV` PVs, and clearing of `MSTA` busy flags, hoping
  to mitigate this. Set this to the empty string (`""`) to disable.

- `KRONOS_OTELCOL_URL`: URL to connect to in order to push OpenTelemetry
  logs and metrics


EPICS Variables
---------------

The IOC exports the following variables. To all of these the
desginated prefix (`$DG645_EPICS_PREFIX`) needs to be prepended.

Main IOC control and flow variables:

- `update`: used to drive the main query loop. When read, returns
  an integer value which is being continuously increased on
  every device readout (all readback values are read out regularly,
  quasi-simultaneously, typically 1 up to 4 times per second).

The presets device module:

- `pres:load`: when a string is written to this, the corresponding
   preset is loaded. This is typically an instrument-specific feature.
   on the DG645, `0` is loading instrument defaults, and `1` to `9`
   are user-addressable slots.

- `pres:save`: when a string is written to this, current settings are
  saved to the corresponding slot.
	
	
The error device module (for error handling)

- `err:last_RBV`: string representation of the latest device error.
- `err:clear`: when 1 is written here, the errors are cleared
  (typically using a `*CLS` SCPI command)
	
	
Trigger device module variables:

- `trig:lvl`: set the trigger channel level.
- `trig:lvl_RBV`: readback value for trigger channel level
- `trig:src`: trigger source. Currently `"RISING"` and `"FALLING"`
  are supported for the corresponding edges of the external
  trigger pulse, and `"INTERNAL"` (on DG645) for an automated
  internal trigger
- `trig:src_RBV`: trigger source readback.
- `trig:intrate`: trigger rate for internal trigger (in Hz)
- `trig:intrate_RBV`: readback for the internal trigger frequency.


Channel specific variables: the DG645 has 4 channels, labeled
`1`, `2`, `3` and `4`, respectively. Other devices may have
different labels (when and if supported). For every channel,
the following set of variables is exported. `{label}` designates
the channel label, e.g. `ch{label}...` for channel 4 would be
`ch4...`:

- `ch{label}:dly`: start of the delay, in seconds, from the
  trigger pulse
- `ch{label}:dur`: pulse duration in seconds
- `ch{label}:div`: pulse divider (i.e. which N-th pulse to
  trigger for)
- `ch{label}:ampl`: pulse amplitude in V
- `ch{label}:offs`: pulse offset in V
- `ch{label}:pol`: pulse polarity, can be one of `"POS"` or `"NEG"`.
- `ch{label}:..._RBV`: each of the variables above publishes
  its readback value in the corresponding `_RBV` PV.
- `ch{label}:..._MSTA`: for each of the variables, a very limited
  EPICS motor record-like behavior is implemeted, by publish this
  variable (suffix `_MSTA`), which sets bit 2 (0x02) when the "motor"
  is moving, i.e. the newly set value isn't yet available in `_RBV`,
  and resets it to 0 once it's available.
  **Note**: The setting of values is, of course, instantaneous, but
  the `_RBV` values are updated in fixed cycles (of about ~1 second
  or so). This usually satisfies experimental orchestration systems
  like SPEC.


Caveats & Bugs
--------------

Might kick your dog, empty your fridge, and run off with your
girlfriend.

Otherwise enjoy! :-D
