Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add int64in/out record support #161

Merged
merged 5 commits into from
Jun 7, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
1 change: 1 addition & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Unreleased_

Added:

- `Add int64In/Out record support <../../pull/161>`_
- `Enable setting alarm status of Out records <../../pull/157>`_
- `Adding the non_interactive_ioc function <../../pull/156>`_

Expand Down
23 changes: 17 additions & 6 deletions docs/reference/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ and stderr streams, is sent directly to the terminal.
but note that only the following records types have direct support from this
module:

ai, ao, bi, bo, longin, longout, mbbi, mbbo, stringin, stringout, waveform
ai, ao, bi, bo, int64in, int64out, longin, longout, mbbi, mbbo, stringin, stringout, waveform

The following methods create records of the corresponding type. For all records
the `initial_value` parameter can be used to specify an initial value for the
Expand Down Expand Up @@ -285,6 +285,15 @@ All functions return a wrapped `ProcessDeviceSupportIn` or
Create ``bi`` and ``bo`` records with the specified names for false (zero)
and true (one).

.. function::
int64In(name, LOPR=None, HOPR=None, EGU=None, **fields)
int64Out(name, DRVL=None, DRVH=None, EGU=None, **fields)

Create ``int64In`` and ``int64Out`` records with specified limits and units.
The lower and upper display limits for the record can be specified. For
``int64Out`` records the ``LOPR`` and ``HOPR`` fields will be set by default
to the values of the ``DRVL`` and ``DRVH`` fields respectively.

.. function::
longIn(name, LOPR=None, HOPR=None, EGU=None, **fields)
longOut(name, DRVL=None, DRVH=None, EGU=None, **fields)
Expand Down Expand Up @@ -532,15 +541,17 @@ Create IN records (used for publishing data *from* the IOC, the naming of the
direction is confusing) using the following `softioc.builder` methods:

:func:`~softioc.builder.aIn`, :func:`~softioc.builder.boolIn`,
:func:`~softioc.builder.longIn`, :func:`~softioc.builder.stringIn`,
:func:`~softioc.builder.mbbIn`, :func:`~softioc.builder.WaveformIn`.
:func:`~softioc.builder.int64In` :func:`~softioc.builder.longIn`,
:func:`~softioc.builder.stringIn`, :func:`~softioc.builder.mbbIn`,
:func:`~softioc.builder.WaveformIn`.

Create OUT records for receiving control information into the IOC using the
following methods:

:func:`~softioc.builder.aOut`, :func:`~softioc.builder.boolOut`,
:func:`~softioc.builder.longOut`, :func:`~softioc.builder.stringOut`,
:func:`~softioc.builder.mbbOut`, :func:`~softioc.builder.WaveformOut`.
:func:`~softioc.builder.int64Out`, :func:`~softioc.builder.longOut`,
:func:`~softioc.builder.stringOut`, :func:`~softioc.builder.mbbOut`,
:func:`~softioc.builder.WaveformOut`.

For all records the `initial_value` keyword argument can be used to specify the
records value on startup.
Expand All @@ -554,7 +565,7 @@ class which provides the methods documented below.
.. class:: ProcessDeviceSupportIn

This class is used to implement Python device support for the record types
``ai``, ``bi``, ``longin``, ``mbbi`` and IN ``waveform`` records.
``ai``, ``bi``, ``int64in``, ``longin``, ``mbbi`` and IN ``waveform`` records.
AlexanderWells-diamond marked this conversation as resolved.
Show resolved Hide resolved

.. method:: set(value, severity=NO_ALARM, alarm=NO_ALARM, timestamp=None)

Expand Down
11 changes: 11 additions & 0 deletions softioc/builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,17 @@ def longOut(name, DRVL=None, DRVH=None, EGU=None, **fields):
_set_scalar_out_defaults(fields, DRVL, DRVH)
return PythonDevice.longout(name, EGU = EGU, **fields)

def int64In(name, LOPR=None, HOPR=None, EGU=None, **fields):
_set_in_defaults(fields)
fields.setdefault('MDEL', -1)
return PythonDevice.int64in(
name, LOPR = LOPR, HOPR = HOPR, EGU = EGU, **fields)

def int64Out(name, DRVL=None, DRVH=None, EGU=None, **fields):
_set_out_defaults(fields)
_set_scalar_out_defaults(fields, DRVL, DRVH)
return PythonDevice.int64out(name, EGU = EGU, **fields)


# Field name prefixes for mbbi/mbbo records.
_mbbPrefixes = [
Expand Down
2 changes: 2 additions & 0 deletions softioc/device.dbd
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
device(longin, INST_IO, devPython_longin, "Python")
device(longout, INST_IO, devPython_longout, "Python")
device(int64in, INST_IO, devPython_int64in, "Python")
device(int64out, INST_IO, devPython_int64out, "Python")
device(ai, INST_IO, devPython_ai, "Python")
device(ao, INST_IO, devPython_ao, "Python")
device(bi, INST_IO, devPython_bi, "Python")
Expand Down
2 changes: 2 additions & 0 deletions softioc/device.py
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,8 @@ def _Device_Out(*args, **kargs):

longin = _Device_In('longin', c_int32, fields.DBF_LONG, EPICS_OK)
longout = _Device_Out('longout', c_int32, fields.DBF_LONG, EPICS_OK)
int64in = _Device_In('int64in', c_int64, fields.DBF_INT64, EPICS_OK)
int64out = _Device_Out('int64out', c_int64, fields.DBF_INT64, EPICS_OK)
bi = _Device_In('bi', c_uint16, fields.DBF_CHAR, NO_CONVERT)
bo = _Device_Out('bo', c_uint16, fields.DBF_CHAR, NO_CONVERT)
mbbi = _Device_In('mbbi', c_uint16, fields.DBF_SHORT, NO_CONVERT)
Expand Down
4 changes: 3 additions & 1 deletion softioc/extension.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ static void set_dict_item_steal(

/* Alas, EPICS has changed the numerical assignments of the DBF_ enums between
* versions, so to avoid unpleasant surprises, we compute thes values here in C
* and pass them back to the Python layer. */
* and pass them back to the Python layer. Order matches dbFldTypes.h. */
static PyObject *get_DBF_values(PyObject *self, PyObject *args)
{
PyObject *dict = PyDict_New();
Expand All @@ -43,6 +43,8 @@ static PyObject *get_DBF_values(PyObject *self, PyObject *args)
ADD_ENUM(dict, DBF_USHORT);
ADD_ENUM(dict, DBF_LONG);
ADD_ENUM(dict, DBF_ULONG);
ADD_ENUM(dict, DBF_INT64);
ADD_ENUM(dict, DBF_UINT64);
ADD_ENUM(dict, DBF_FLOAT);
ADD_ENUM(dict, DBF_DOUBLE);
ADD_ENUM(dict, DBF_ENUM);
Expand Down
7 changes: 5 additions & 2 deletions softioc/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@

from __future__ import print_function

import sys
from ctypes import *
from .imports import get_field_offsets, get_DBF_values
import numpy


from epicscorelibs.ca.dbr import *
from epicscorelibs.ca.dbr import ca_timestamp, EPICS_epoch
Expand All @@ -32,6 +31,8 @@
DBF_SHORT: c_int16,
DBF_USHORT: c_uint16,
DBF_LONG: c_int32,
DBF_INT64: c_int64,
DBF_UINT64: c_uint64, # TODO: Check whether this has same issue as below note
AlexanderWells-diamond marked this conversation as resolved.
Show resolved Hide resolved
DBF_ULONG: c_int32, # Should be uint32, but causes trouble later.
DBF_FLOAT: c_float,
DBF_DOUBLE: c_double,
Expand All @@ -50,6 +51,8 @@
DBR_ENUM: DBF_ENUM,
DBR_CHAR: DBF_CHAR,
DBR_LONG: DBF_LONG,
# DBR_INT64: DBF_INT64, # TODO: the DBR_ definitions come from epicscorelibs.ca.dbr, but they don't define the 64 versions
# DBR_UINT64: DBF_UINT64,
DBR_DOUBLE: DBF_DOUBLE
}
AlexanderWells-diamond marked this conversation as resolved.
Show resolved Hide resolved

Expand Down
5 changes: 3 additions & 2 deletions softioc/pythonSoftIoc.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,9 @@ class PythonDevice(object):
@classmethod
def __init_class__(cls):
for name in [
'ai', 'bi', 'longin', 'mbbi', 'stringin',
'ao', 'bo', 'longout', 'mbbo', 'stringout', 'waveform']:
'ai', 'bi', 'longin', 'mbbi', 'stringin', 'int64in',
'ao', 'bo', 'longout', 'mbbo', 'stringout', 'int64out',
'waveform']:
builder = getattr(epicsdbbuilder.records, name)
record = getattr(device, name)
setattr(cls, name, cls.makeRecord(builder, record))
Expand Down
12 changes: 12 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,20 @@
from typing import Any
import pytest

from softioc import builder
from softioc.builder import ClearRecords

in_records = [
builder.aIn,
builder.boolIn,
builder.longIn,
builder.int64In,
builder.mbbIn,
builder.stringIn,
builder.WaveformIn,
builder.longStringIn,
]

requires_cothread = pytest.mark.skipif(
sys.platform.startswith("win"), reason="Cothread doesn't work on windows"
)
Expand Down
22 changes: 10 additions & 12 deletions tests/test_record_values.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import multiprocessing
from typing import List
import numpy
import pytest
Expand All @@ -12,7 +11,8 @@
log,
select_and_recv,
TIMEOUT,
get_multiprocessing_context
get_multiprocessing_context,
in_records,
)

from softioc import asyncio_dispatcher, builder, softioc
Expand Down Expand Up @@ -54,23 +54,15 @@ def record_func_names(fixture_value):
builder.WaveformOut,
builder.longStringIn,
builder.longStringOut,
builder.int64In,
builder.int64Out,
],
ids=record_func_names,
)
def record_func(request):
"""The list of record creation functions"""
return request.param

# A list of all In records, used to filter out various tests
in_records = [
builder.aIn,
builder.boolIn,
builder.longIn,
builder.mbbIn,
builder.stringIn,
builder.WaveformIn,
builder.longStringIn,
]

def record_values_names(fixture_value):
"""Provide a nice name for the tests in the record_values fixture"""
Expand All @@ -96,6 +88,8 @@ def record_values_names(fixture_value):
("aOut_nan", builder.aOut, nan, nan, float),
("longIn_int", builder.longIn, 5, 5, int),
("longOut_int", builder.longOut, 5, 5, int),
("int64In_int", builder.int64In, 65, 65, int),
("int64Out_int", builder.int64Out, 65, 65, int),
("boolIn_int", builder.boolIn, 1, 1, int),
("boolOut_int", builder.boolOut, 1, 1, int),
("boolIn_true", builder.boolIn, True, 1, int),
Expand Down Expand Up @@ -737,6 +731,8 @@ def test_value_post_init_caput(self):
("default_aIn", builder.aIn, None, 0.0, float),
("default_longOut", builder.longOut, None, 0, int),
("default_longIn", builder.longIn, None, 0, int),
("default_int64Out", builder.int64Out, None, 0, int),
("default_int64In", builder.int64In, None, 0, int),
("default_boolOut", builder.boolOut, None, 0, int),
("default_boolIn", builder.boolIn, None, 0, int),
("default_Action", builder.Action, None, 0, int),
Expand All @@ -761,6 +757,8 @@ class TestDefaultValue:
(builder.aIn, 0.0, float),
(builder.longOut, 0, int),
(builder.longIn, 0, int),
(builder.int64Out, 0, int),
(builder.int64In, 0, int),
(builder.boolOut, 0, int),
(builder.boolIn, 0, int),
(builder.Action, 0, int),
Expand Down
17 changes: 6 additions & 11 deletions tests/test_records.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
WAVEFORM_LENGTH,
TIMEOUT,
select_and_recv,
get_multiprocessing_context
get_multiprocessing_context,
in_records
)

from softioc import alarm, asyncio_dispatcher, builder, softioc
Expand All @@ -25,16 +26,6 @@
# Test parameters
DEVICE_NAME = "RECORD-TESTS"

in_records = [
builder.aIn,
builder.boolIn,
builder.longIn,
builder.mbbIn,
builder.stringIn,
builder.WaveformIn,
builder.longStringIn,
]

def test_records(tmp_path):
# Ensure we definitely unload all records that may be hanging over from
# previous tests, then create exactly one instance of expected records.
Expand Down Expand Up @@ -362,6 +353,7 @@ class TestValidate:
(builder.boolOut, 1, 0),
(builder.Action, 1, 0),
(builder.longOut, 7, 0),
(builder.int64Out, 54, 0),
(builder.stringOut, "HI", ""),
(builder.mbbOut, 2, 0),
(builder.WaveformOut, [10, 11, 12], []),
Expand Down Expand Up @@ -504,6 +496,7 @@ class TestOnUpdate:
builder.boolOut,
# builder.Action, This is just boolOut + always_update
builder.longOut,
builder.int64Out,
builder.stringOut,
builder.mbbOut,
builder.WaveformOut,
Expand Down Expand Up @@ -1224,13 +1217,15 @@ class TestAlarms:
records = [
(builder.aIn, "AI_AlarmPV"),
(builder.boolIn, "BI_AlarmPV"),
(builder.int64Out, "I64I_AlarmPV"),
(builder.longIn, "LI_AlarmPV"),
(builder.mbbIn, "MBBI_AlarmPV"),
(builder.stringIn, "SI_AlarmPV"),
(builder.WaveformIn, "WI_AlarmPV"),
(builder.longStringIn, "LSI_AlarmPV"),
(builder.aOut, "AO_AlarmPV"),
(builder.boolOut, "BO_AlarmPV"),
(builder.int64Out, "I64O_AlarmPV"),
(builder.longOut, "LO_AlarmPV"),
(builder.stringOut, "SO_AlarmPV"),
(builder.mbbOut, "MBBO_AlarmPV"),
Expand Down
Loading