Skip to content

Commit f198e73

Browse files
Beginning to rewrite create-an-ioc.
Extracted out the example file for ease of code sharing. Need to extract "creating a publishable ioc" into a how-to guide shortly.
1 parent 6d18b9a commit f198e73

File tree

3 files changed

+86
-128
lines changed

3 files changed

+86
-128
lines changed

README.rst

Lines changed: 1 addition & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -17,33 +17,7 @@ Documentation https://dls-controls.github.io/pythonIoc
1717

1818
A simple example of the use of this library is the following:
1919

20-
.. code:: python
21-
22-
# Import the basic framework components.
23-
from softioc import softioc, builder
24-
import cothread
25-
26-
# Set the record prefix
27-
builder.SetDeviceName("MY-DEVICE-PREFIX")
28-
29-
# Create some records
30-
ai = builder.aIn('AI', initial_value=5)
31-
ao = builder.aOut('AO', initial_value=12.45, on_update=lambda v: ai.set(v))
32-
33-
# Boilerplate get the IOC started
34-
builder.LoadDatabase()
35-
softioc.iocInit()
36-
37-
# Start processes required to be run after iocInit
38-
def update():
39-
while True:
40-
ai.set(ai.get() + 1)
41-
cothread.Sleep(1)
42-
43-
cothread.Spawn(update)
44-
45-
# Finally leave the IOC running with an interactive shell.
46-
softioc.interactive_ioc(globals())
20+
.. literalinclude:: examples/example_cothread_ioc.py
4721

4822

4923
.. |code_ci| image:: https://github.com/dls-controls/pythonIoc/workflows/Code%20CI/badge.svg?branch=master
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Import the basic framework components.
2+
from softioc import softioc, builder
3+
import cothread
4+
5+
# Set the record prefix
6+
builder.SetDeviceName("MY-DEVICE-PREFIX")
7+
8+
# Create some records
9+
ai = builder.aIn('AI', initial_value=5)
10+
ao = builder.aOut('AO', initial_value=12.45, on_update=lambda v: ai.set(v))
11+
12+
# Boilerplate get the IOC started
13+
builder.LoadDatabase()
14+
softioc.iocInit()
15+
16+
# Start processes required to be run after iocInit
17+
def update():
18+
while True:
19+
ai.set(ai.get() + 1)
20+
cothread.Sleep(1)
21+
22+
23+
cothread.Spawn(update)
24+
25+
# Finally leave the IOC running with an interactive shell.
26+
softioc.interactive_ioc(globals())

docs/tutorials/creating-an-ioc.rst

Lines changed: 59 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -1,126 +1,79 @@
11
Creating an IOC
22
===============
33

4-
THIS NEEDS UPDATING
5-
6-
Using ``pythonSoftIoc``
7-
-----------------------
8-
9-
Probably the best way to use ``pythonSoftIoc`` is to start by copying fragments
10-
of a simple example such as ``CS-DI-IOC-02``. This consists of the following
11-
elements:
12-
13-
1. A startup shell script ``start-ioc`` which launches the soft IOC using a
14-
production build of ``pythonSoftIoc``. This script typically looks like
15-
this::
16-
17-
#!/bin/sh
18-
19-
PYIOC=/path/to/pythonSoftIoc/pythonIoc
20-
21-
cd "$(dirname "$0")"
22-
exec $PYIOC start_ioc.py "$@"
23-
24-
2. The startup Python script. This establishes the essential component
25-
versions (apart from the ``pythonSoftIoc`` version), performs the appropriate
26-
initialisation and starts the IOC running. The following template is a
27-
useful starting point::
28-
29-
from pkg_resources import require
30-
require('cothread==2.12')
31-
require('epicsdbbuilder==1.0')
32-
33-
# Import the basic framework components.
34-
from softioc import softioc, builder
35-
import cothread
36-
37-
# Import any modules required to run the IOC
38-
import ...
39-
40-
# Boilerplate get the IOC started
41-
builder.LoadDatabase()
42-
softioc.iocInit()
43-
44-
# Start processes required to be run after iocInit
45-
...
46-
47-
# Finally leave the IOC running with an interactive shell.
48-
softioc.interactive_ioc(globals())
4+
Introduction
5+
------------
496

50-
Note that the use of ``require`` is specific to DLS, and you may have a
51-
different way of managing your installations.
7+
Once the module has been installed (see :doc:`installation`) we can create a
8+
simple EPICS Input/Output Controller (IOC).
529

53-
.. _numpy: http://www.numpy.org/
54-
.. _cothread: https://github.com/dls-controls/cothread
55-
.. _epicsdbbuilder: https://github.com/Araneidae/epicsdbbuilder
10+
An EPICS IOC created with the help of ``pythonIoc`` and :mod:`softioc` is
11+
referred to as a "Python soft IOC". The code below illustrates a simple IOC
12+
with two Process Variables (PVs):
5613

14+
.. literalinclude:: ../examples/example_cothread_ioc.py
5715

16+
This example script illustrates the following points.
5817

59-
Introduction
60-
------------
18+
.. literalinclude:: ../examples/example_cothread_ioc.py
19+
:start-after: # Import
20+
:end-before: # Set
6121

62-
The Python Soft IOC consists of two components: a command ``pythonIoc`` and an
63-
associated library :mod:`softioc`. The ``pythonIoc`` command consists of a bare
64-
EPICS IOC linked together with the DLS Python interpreter and configured so that
65-
startup arguments are interpreted by the Python interpreter -- this means that
66-
when ``pythonIoc`` is run it behaves the same as running ``dls-python``.
22+
The :mod:`softioc` library is part of ``pythonIoc``. The two submodules
23+
:mod:`softioc.softioc` and :mod:`softioc.builder` provide the basic
24+
functionality for Python soft IOCs and are the ones that are normally used.
6725

68-
Scripts run from within ``pythonIoc`` differ from standard Python scripts in one
69-
detail: they have the ability to create and publish PVs through the
70-
:mod:`softioc` library. Typically both :mod:`cothread` and
71-
:mod:`epicsdbbuilder` will be recruited to help: :mod:`cothread` is used for
72-
dispatching OUT record processing callback methods, :mod:`epicsdbbuilder` is
73-
used for constructing records during IOC initialisation.
7426

75-
An EPICS IOC created with the help of ``pythonIoc`` and :mod:`softioc` is
76-
referred to as a "Python soft IOC". The code below illustrates a simple IOC
77-
with one PV::
27+
.. literalinclude:: ../examples/example_cothread_ioc.py
28+
:start-after: # Create
29+
:end-before: # Boilerplate
7830

79-
# DLS requires
80-
from pkg_resources import require
81-
require('cothread==2.12')
82-
require('epicsdbbuilder==1.0')
31+
PVs are normally created dynamically using :mod:`softioc.builder`. All PV
32+
creation must be done before initialising the IOC. We define `on_update` for
33+
``ao`` such that whenever we set ``ao``, ``ai`` will be set to the same value.
8334

84-
# Import basic softioc framework
85-
from softioc import softioc, builder
35+
.. literalinclude:: ../examples/example_cothread_ioc.py
36+
:start-after: # Boilerplate
37+
:end-before: # Start
8638

87-
# Create PVs
88-
builder.SetDeviceName('TS-TEST-TEST-01')
89-
builder.stringIn('TEST', initial_value = 'This is a test')
39+
Once PVs have been created then the associated EPICS database can be created
40+
and loaded into the IOC and then the IOC can be started.
9041

91-
# Run the IOC. This is boilerplate, and must always be done in this order,
92-
# and must always be done after creating all PVs.
93-
builder.LoadDatabase()
94-
softioc.iocInit()
42+
.. literalinclude:: ../examples/example_cothread_ioc.py
43+
:start-after: # Start
44+
:end-before: # Finally
9545

96-
softioc.interactive_ioc(globals())
46+
We define a long-running operation that will increment the value of ``ai`` once per
47+
second. This is run as a background process by `cothread`.
9748

98-
This example script illustrates the following points.
49+
.. literalinclude:: ../examples/example_cothread_ioc.py
50+
:start-after: # Finally
9951

100-
- The use of ``pkg_resources.require`` is standard across all use of the
101-
``dls-python`` Python interpreter at Diamond, and in this example we are using
102-
both :mod:`cothread` and :mod:`epicsdbbuilder`. Of course, in an officially
103-
published IOC specific versions must be specified, in this example I'm using
104-
the most recent versions at the time of writing.
52+
Finally the application must refrain from exiting until the IOC is no longer
53+
needed. The :func:`~softioc.softioc.interactive_ioc` runs a Python
54+
interpreter shell with a number of useful EPICS functions in scope, and
55+
passing ``globals()`` through can allow interactive interaction with the
56+
internals of the IOC while it's running. The alternative is to call something
57+
like :func:`cothread.WaitForQuit` or some other :mod:`cothread` blocking
58+
action.
10559

106-
- The :mod:`softioc` library is part of ``pythonIoc`` and is automatically added
107-
to the path. The two submodules :mod:`softioc.softioc` and
108-
:mod:`softioc.builder` provide the basic functionality for Python soft IOCs
109-
and are the ones that are normally used.
60+
In this interpreter there is immediate access to methods defined in the
61+
:mod:`softioc.softioc` module. For example the :func:`~softioc.softioc.dbgf` function
62+
can be run to observe the increasing value of ``ai``::
11063

111-
- PVs are normally created dynamically using :mod:`softioc.builder`. All PV
112-
creation must be done before initialising the IOC.
64+
>>> dbgf("MY-DEVICE-PREFIX:AI")
65+
DBF_DOUBLE: 36
66+
>>> dbgf("MY-DEVICE-PREFIX:AI")
67+
DBF_DOUBLE: 37
11368

114-
- Once PVs have been created then the associated EPICS database can be created
115-
and loaded into the IOC and then the IOC can be started.
69+
And the :func:`~softioc.softioc.dbpf` method allows data to be set and to observe
70+
the functionality of the lambda passed to `on_update` . We set the value on ``ao``
71+
and read the value on ``ai`` (exact values may vary based on time between commands)::
11672

117-
- Finally the application must refrain from exiting until the IOC is no longer
118-
needed. The :func:`~softioc.softioc.interactive_ioc` runs a Python
119-
interpreter shell with a number of useful EPICS functions in scope, and
120-
passing ``globals()`` through can allow interactive interaction with the
121-
internals of the IOC while it's running. The alternative is to call something
122-
like :func:`cothread.WaitForQuit` or some other :mod:`cothread` blocking
123-
action.
73+
>>> dbpf("MY-DEVICE-PREFIX:AO","999")
74+
DBF_DOUBLE: 999
75+
>>> dbgf("MY-DEVICE-PREFIX:AI")
76+
DBF_DOUBLE: 1024
12477

12578

12679
Creating a Publishable IOC
@@ -247,3 +200,8 @@ done (:class:`cothread.Spawn` is recommended for initiating persistent backgroun
247200
activity) the top level script must pause, as as soon as it exits the IOC will
248201
exit. Calling :func:`~softioc.softioc.interactive_ioc` is recommended for this
249202
as the last statement in the top level script.
203+
204+
205+
.. _numpy: http://www.numpy.org/
206+
.. _cothread: https://github.com/dls-controls/cothread
207+
.. _epicsdbbuilder: https://github.com/Araneidae/epicsdbbuilder

0 commit comments

Comments
 (0)