Skip to content

Commit b5c3e1b

Browse files
Finish publish ioc and use asyncio pages.
Add a docstring to AsyncioDispatcher.__init__ to suppress the docstring from threading.Thread, which is misleading.
1 parent 7a32999 commit b5c3e1b

File tree

5 files changed

+57
-56
lines changed

5 files changed

+57
-56
lines changed

docs/conf.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@
9696
intersphinx_mapping = dict(
9797
python=('https://docs.python.org/3/', None),
9898
cothread=("https://cothread.readthedocs.org/en/stable/", None),
99+
aioca=("https://dls-controls.github.io/aioca/master/", None),
99100
epicsdbbuilder=(
100101
"https://dls-controls.github.io/epicsdbbuilder/master/", None)
101102
)

docs/examples/example_asyncio_ioc.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
# Import the basic framework components.
22
from softioc import softioc, builder, asyncio_dispatcher
3-
from aioca import caget, caput
43
import asyncio
54

65
# Create an asyncio dispatcher, the event loop is now running
Lines changed: 24 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,65 +1,35 @@
11
Create a Publishable IOC
2-
--------------------------
2+
========================
33

4-
As the example script above shows, a single Python script can be an IOC.
5-
However, to fit into the DLS framework for publishing IOCs in ``/dls_sw/prod`` a
6-
bit more structure is needed. I recommend at least four files as shown:
4+
As seen in :doc:`../tutorials/creating-an-ioc`, a single Python script can be an IOC.
5+
It is also possible (and the most common situation) to have an entire Python module
6+
comprising an IOC. This guide explains both, as well as how to publish an IOC within
7+
the DLS environment.
78

8-
``Makefile``
9-
This file is necessary in order to run ``dls-release.py``, and needs to have
10-
both ``install`` and ``clean`` targets, but doesn't need to actually do
11-
anything. Thus the following content for this file is enough::
12-
13-
install:
14-
clean:
15-
16-
``start-ioc``
17-
An executable file for starting the IOC needs to be created. I recommend
18-
that this consist of the following boilerplate::
19-
20-
#!/bin/sh
21-
22-
PYIOC_VER=2-6
23-
EPICS_VER=3.14.12.3
24-
25-
PYIOC=/dls_sw/prod/R$EPICS_VER/support/pythonSoftIoc/$PYIOC_VER/pythonIoc
9+
Single File IOC
10+
----------------
11+
An IOC that is entirely contained within a single Python source file can be used as an
12+
IOC inside DLS simply by adding this shebang line::
2613

27-
exec $PYIOC ioc_entry.py "$@"
14+
#!/dls_sw/prod/python3/RHEL7-x86_64/pythonIoc/prefix/bin/pythonIoc
2815

29-
Here I have given the startup script for the IOC the name ``ioc_entry.py``.
30-
This name should be replaced by any appropriate name.
3116

32-
``ioc_entry.py``
33-
I recommend that the top level Python script used to launch the IOC contain
34-
only ``pkg_resources.require`` statements, simple code to start the body
35-
of the IOC, and it should end with standard code to start the IOC. The
36-
following structure can be followed (here I've assumed that the rest of the
37-
IOC is in a single file called ``ioc_body.py``::
17+
IOC entry point for a module
18+
------------------------------
19+
If your IOC is more complicated than one file, it is recommended to write a python
20+
module (including docs/tests/etc.). The Panda Blocks Client will be an example of
21+
this.
3822

39-
from pkg_resources import require
4023

41-
require('cothread==2.12')
42-
require('epicsdbbuilder==1.0')
43-
# Any other requires needed by this IOC
24+
Make an IOC publishable at DLS
25+
------------------------------
26+
To make the IOC publishable, a makefile is required:
4427

45-
from softioc import softioc
46-
47-
# Do whatever makes sense to create all the PVs and get ready to go
48-
import ioc_body
49-
ioc_body.initialise()
50-
51-
# Start the IOC -- this is boilerplate
52-
builder.LoadDatabase()
53-
softioc.iocInit()
54-
55-
# If activities need to be started after iocInit, now's the time
56-
ioc_body.start()
57-
58-
softioc.interactive_ioc(globals())
28+
``Makefile``
29+
This file is necessary in order to run ``dls-release.py``, and needs to have
30+
both ``install`` and ``clean`` targets, but doesn't need to actually do
31+
anything. Thus the following content for this file is enough::
5932

60-
Note that *all* requires *must* occur in this initial startup file.
33+
install:
34+
clean:
6135

62-
The rest of the IOC
63-
Of course, a Python script can be structured into any number of Python
64-
modules. In the example above I have illustrated just one such module
65-
called ``ioc_body.py`` with two entry points.
Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,32 @@
11
Use `asyncio` in an IOC
22
=======================
33

4-
Write about the differences creating an IOC using `AsyncioDispatcher`
4+
There are two libraries available for asynchronous operations in PythonIOC:
5+
:mod:`cothread` and :mod:`asyncio`. This guide shows how to use the latter in
6+
an IOC.
7+
8+
.. note::
9+
This page only explains the differences between using :mod:`cothread` and :mod:`asyncio`.
10+
For more thorough explanation of the IOC itself see :doc:`../tutorials/creating-an-ioc`
11+
12+
.. literalinclude:: ../examples/example_asyncio_ioc.py
13+
14+
15+
The ``dispatcher`` is created and passed to :func:`~softioc.softioc.iocInit`. This is what
16+
allows the use of :mod:`asyncio` functions in this IOC.
17+
18+
The ``async update`` function will increment the value of ``ai`` once per second,
19+
sleeping that coroutine between updates.
20+
Note that we run this coroutine in the ``loop`` of the ``dispatcher``, and not in the
21+
main event loop.
22+
23+
This IOC will, like the one in :doc:`../tutorials/creating-an-ioc`, leave an interactive
24+
shell open. The values of the PVs can be queried using the methods defined in the
25+
:mod:`softioc.softioc` module.
26+
27+
28+
Asynchronous Channel Access
29+
---------------------------
30+
31+
PVs can be retrieved in an asynchronous manner by using the :py:mod:`aioca` module.
32+
It provides ``await``-able implementations of ``caget``, ``caput``, etc.

softioc/asyncio_dispatcher.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ class AsyncioDispatcher(threading.Thread):
99
created.
1010
"""
1111
def __init__(self):
12+
"""Create the AsyncioDispatcher."""
13+
# Docstring specified to suppress threading.Thread's docstring, which
14+
# would otherwise be inherited by this method and be misleading.
1215
super().__init__()
1316
#: `asyncio` event loop that the callbacks will run under.
1417
self.loop = asyncio.new_event_loop()

0 commit comments

Comments
 (0)