Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/code.yml
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ jobs:
run: cibuildwheel --output-dir dist
env:
CIBW_BUILD: ${{ matrix.python }}*64
CIBW_TEST_REQUIRES: pytest-cov ${{ matrix.test_requires }}
CIBW_TEST_REQUIRES: pytest-cov p4p ${{ matrix.test_requires }}
CIBW_TEST_COMMAND: pytest --cov=softioc {project}/tests --cov-report xml:${{ matrix.cov_file }}
# Disable auditwheel as it isn't compatible with setuptools_dso approach
# https://github.com/mdavidsaver/setuptools_dso/issues/17
Expand Down
4 changes: 3 additions & 1 deletion CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ and this project adheres to `Semantic Versioning <https://semver.org/spec/v2.0.0
Unreleased_
-----------

Nothing yet
Added:

- PVA support to the IOC #17


3.0_ - 2021-07-05
Expand Down
1 change: 1 addition & 0 deletions Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pytest-flake8 = "*"
sphinx-rtd-theme = "*"
setuptools-dso = "*"
pytest-asyncio = "*"
p4p = "*"

[packages]
# All other package requirements from setup.py
Expand Down
192 changes: 151 additions & 41 deletions Pipfile.lock

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
from softioc import softioc
from cothread.catools import caget, caput, camonitor

print(caget("MY-DEVICE-PREFIX:AI"))
print(caget("MY-DEVICE-PREFIX:AO"))
print(caput("MY-DEVICE-PREFIX:AO", "999"))
caput("MY-DEVICE-PREFIX:AO", "999")
print(caget("MY-DEVICE-PREFIX:AO"))

softioc.interactive_ioc(globals())
7 changes: 7 additions & 0 deletions docs/examples/example_read_from_ioc_pva.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from p4p.client.cothread import Context

ctx = Context("pva")
print(ctx.get("MY-DEVICE-PREFIX:AI"))
print(ctx.get("MY-DEVICE-PREFIX:AO"))
ctx.put("MY-DEVICE-PREFIX:AO", "999")
print(ctx.get("MY-DEVICE-PREFIX:AO"))
55 changes: 39 additions & 16 deletions docs/how-to/read-data-from-ioc.rst
Original file line number Diff line number Diff line change
@@ -1,31 +1,54 @@
Read data from an IOC
======================

This guide explains how to read data from an IOC in a separate Python program.
This guide explains how to read data from an IOC in a separate Python program.

.. note::
Please ensure your firewall allows both TCP and UDP traffic on ports 5064 and 5065.
To start, run the `cothread` IOC from `../tutorials/creating-an-ioc` or the
`asyncio` IOC from `use-asyncio-in-an-ioc` and leave it running at the
interactive shell.

Using Channel Access
--------------------

.. note::
Please ensure your firewall allows both TCP and UDP traffic on ports 5064 and 5065.
These are used by EPICS for channel access to the PVs.

We will read data from the IOC using this script:

To start, run the `cothread` IOC from `../tutorials/creating-an-ioc` or the
`asyncio` IOC from `use-asyncio-in-an-ioc` and leave it running at the
interactive shell.
.. literalinclude:: ../examples/example_read_from_ioc_ca.py

We will read data from that IOC using this script:
You can run this as::

.. literalinclude:: ../examples/example_read_from_ioc.py
python -i example_read_from_ioc_ca.py

From the interactive command line you can now use the ``caget`` and ``caput`` functions to operate on
the PVs exposed in the IOC. Another interesting command to try is::

camonitor("MY-DEVICE-PREFIX:AI", print)

You should observe the value of ``AI`` being printed out, once per second, every time the PV value
updates.

Using PVAccess
--------------

.. note::
You may see warnings regarding the missing "caRepeater" program. This is an EPICS tool
that is used to track when PVs start and stop. It is not required for this simple example,
and so the warning can be ignored.
Please ensure your firewall allows both TCP and UDP traffic on ports 5075 and 5076.
These are used by EPICS for PVAccess to the PVs.

From the interactive command line you can now use the ``caget`` and ``caput`` functions to operate on
the PVs exposed in the IOC. Another interesting command to try is::
We will read data from the IOC using this script:

camonitor("MY-DEVICE-PREFIX:AI", lambda val: print(val))
.. literalinclude:: ../examples/example_read_from_ioc_pva.py

You can run this as::

You should observe the value of ``AI`` being printed out, once per second, every time the PV value
updates.
python -i example_read_from_ioc_pva.py

From the interactive command line you can now use the ``ctx.get`` and ``ctx.put`` functions to operate on
the PVs exposed in the IOC. Another interesting command to try is::

ctx.monitor("MY-DEVICE-PREFIX:AI", print)

You should observe the value and timestamp of ``AI`` being printed out, once per second, every time the PV value
updates.
4 changes: 3 additions & 1 deletion docs/tutorials/creating-an-ioc.rst
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,11 @@ functionality for Python soft IOCs and are the ones that are normally used.

`cothread` is one of the two possible libraries the IOC can use for
asynchronous operations.
(see `../how-to/use-asyncio-in-an-ioc` for the alternative)

.. note::

`cothread` doesn't work on Windows or on a Mac M1. You can use `asyncio`
instead by following `../how-to/use-asyncio-in-an-ioc`

.. literalinclude:: ../examples/example_cothread_ioc.py
:start-after: # Create
Expand Down
4 changes: 2 additions & 2 deletions docs/tutorials/installation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ You can now use ``pip`` to install the library::

python3 -m pip install softioc

Optionally on Linux or MacOS you can install cothread, which is used in the
first tutorial::
Optionally on Linux or MacOS (not M1) you can install cothread, which is used in
the first tutorial::

python3 -m pip install cothread

Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[build-system]
requires = ["setuptools", "wheel", "setuptools_dso", "epicscorelibs>=7.0.4.99.1"]
requires = ["setuptools", "wheel", "setuptools_dso", "epicscorelibs>=7.0.6.99.1.0a1"]
build-backend = "setuptools.build_meta:__legacy__"
11 changes: 10 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,16 @@ def _add_file(f):
epicscorelibs.path.include_path,
devIocStats_src, devIocStats_os, devIocStats_default
],
dsos = ['epicscorelibs.lib.dbCore', 'epicscorelibs.lib.Com'],
dsos = [
'epicscorelibs.lib.qsrv',
'epicscorelibs.lib.pvAccessIOC',
'epicscorelibs.lib.pvAccess',
'epicscorelibs.lib.pvData',
'epicscorelibs.lib.dbRecStd',
'epicscorelibs.lib.dbCore',
'epicscorelibs.lib.ca',
'epicscorelibs.lib.Com',
],
define_macros = get_config_var('CPPFLAGS'),
extra_compile_args = get_config_var('CFLAGS') + ["-std=c99"],
extra_link_args = get_config_var('LDFLAGS'),
Expand Down
3 changes: 2 additions & 1 deletion softioc/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@

# Need to do this before calling anything in device.py
iocshRegisterCommon()
dbLoadDatabase("base.dbd", os.path.join(path.base_path, "dbd"), None)
for dbd in ('base.dbd', 'PVAServerRegister.dbd', 'qsrv.dbd'):
dbLoadDatabase(dbd, os.path.join(path.base_path, "dbd"), None)
dbLoadDatabase("devIocStats.dbd", os.path.dirname(__file__), None)

if registerRecordDeviceDriver(pdbbase):
Expand Down
2 changes: 0 additions & 2 deletions softioc/imports.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
'''External DLL imports used for implementing Python EPICS device support.
'''

import os
import os.path
import sys
from ctypes import *

Expand Down
2 changes: 1 addition & 1 deletion softioc/softioc.py
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ def call_f(*args):
ExportTest('eltc', (c_int,), (), '''\
eltc(noYes)

TThis determines if error messages are displayed on the IOC console. 0 means no
This determines if error messages are displayed on the IOC console. 0 means no
and any other value means yes.''',
lib=imports.Com)

Expand Down
4 changes: 4 additions & 0 deletions tests/test_asyncio.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ async def test_asyncio_ioc(asyncio_ioc):
assert await caget(PV_PREFIX + ":AI") == 12.34
await asyncio.sleep(0.8)
assert await caget(PV_PREFIX + ":AI") == 3.56
# Check pvaccess works
from p4p.client.asyncio import Context
with Context("pva") as ctx:
assert await ctx.get(PV_PREFIX + ":AI") == 3.56
# Wait for a bit longer for the print output to flush
await asyncio.sleep(2)
# Stop
Expand Down
4 changes: 4 additions & 0 deletions tests/test_cothread.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ def test_cothread_ioc(cothread_ioc):
assert caget(PV_PREFIX + ":STRINGOUT") == "watevah"
caput(PV_PREFIX + ":STRINGOUT", "something", wait=True)
assert caget(PV_PREFIX + ":STRINGOUT") == "something"
# Check pvaccess works
from p4p.client.cothread import Context
with Context("pva") as ctx:
assert ctx.get(PV_PREFIX + ":STRINGOUT") == "something"
# Stop
cothread_ioc.send_signal(signal.SIGINT)
# Disconnect
Expand Down