Skip to content
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
2 changes: 2 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ Versioning <https://semver.org/spec/v2.0.0.html>`_.
Unreleased_
-----------

- `Allow "status" and "severity" on In record init <../../pull/111>`_

4.1.0_ - 2022-08-05
-------------------

Expand Down
15 changes: 13 additions & 2 deletions docs/reference/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,19 @@ Test Facilities`_ documentation for more details of each function.

This is used to specify an initial value for each record.

.. _status and severity:

`status and severity`
~~~~~~~~~~~~~~~~~~~~~

Only available on IN records. These can be used with the alarm value enums
from `softioc.alarm` to set the initial alarm state of a record.

.. note::

By default the builder module sets ``PINI`` to ``YES``, which means the
record will process at initialization and the alarm status will be reset.

.. _on_update:

`on_update`
Expand Down Expand Up @@ -243,8 +256,6 @@ Test Facilities`_ documentation for more details of each function.
.. seealso::
`SetBlocking` for configuring a global default blocking value



For all of these functions any EPICS database field can be assigned a value by
passing it as a keyword argument for the corresponding field name (in upper
case) or by assigning to the corresponding field of the returned record object.
Expand Down
13 changes: 13 additions & 0 deletions softioc/builder.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import os
import numpy

from .softioc import dbLoadDatabase

from epicsdbbuilder import *
Expand All @@ -24,10 +25,17 @@ def _set_in_defaults(fields):
fields.setdefault('SCAN', 'I/O Intr')
fields.setdefault('PINI', 'YES')
fields.setdefault('DISP', 1)
_set_alarm(fields)

def _set_out_defaults(fields):
fields.setdefault('OMSL', 'supervisory')

def _set_alarm(fields):
if "status" in fields:
fields['STAT'] = _statStrings[fields.pop('status')]
if "severity" in fields:
fields['SEVR'] = _severityStrings[fields.pop('severity')]

Comment thread
AlexanderWells-diamond marked this conversation as resolved.
# For longout and ao we want DRV{L,H} to match {L,H}OPR by default
def _set_scalar_out_defaults(fields, DRVL, DRVH):
fields['DRVL'] = DRVL
Expand Down Expand Up @@ -76,6 +84,11 @@ def longOut(name, DRVL=None, DRVH=None, EGU=None, **fields):
# All the severity strings supported by <prefix>SV
_severityStrings = ['NO_ALARM', 'MINOR', 'MAJOR', 'INVALID']

_statStrings = [
'NO_ALARM', 'READ', 'WRITE', 'HIHI', 'HIGH', 'LOLO', 'LOW', 'STATE', 'COS',
'COMM', 'TIMEOUT', 'HWLIMIT', 'CALC', 'SCAN', 'LINK', 'SOFT', 'BAD_SUB',
'UDF', 'DISABLE', 'SIMM', 'READ_ACCESS', 'WRITE_ACCESS']

# Converts a list of (option [,severity]) values or tuples into field settings
# suitable for mbbi and mbbo records.
def _process_mbb_values(options, fields):
Expand Down
60 changes: 38 additions & 22 deletions tests/test_records.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,23 @@
)

from softioc import asyncio_dispatcher, builder, softioc
from softioc import alarm
from softioc.device import SetBlocking

# Test file for miscellaneous tests related to records

# Test parameters
DEVICE_NAME = "RECORD-TESTS"

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

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 @@ -60,32 +70,18 @@ def test_enum_length_restriction():
"seventeen",
)


def test_DISP_defaults_on():
@pytest.mark.parametrize("creation_func", in_records)
def test_DISP_defaults_on(creation_func):
"""Test that all IN record types have DISP=1 set by default"""
in_records = [
builder.aIn,
builder.boolIn,
builder.longIn,
builder.mbbIn,
builder.stringIn,
builder.WaveformIn,
]

record_counter = 0
kwargs = {}

for creation_func in in_records:
kwargs = {}
record_counter += 1
record_name = "DISP" + str(record_counter)
if creation_func == builder.WaveformIn:
kwargs = {"length": 1}

if creation_func == builder.WaveformIn:
kwargs = {"length": 1}
record = creation_func("RECORD", **kwargs)

record = creation_func(record_name, **kwargs)

# Note: DISP attribute won't exist if field not specified
assert record.DISP.Value() == 1
# Note: DISP attribute won't exist if field not specified
assert record.DISP.Value() == 1


def test_DISP_can_be_overridden():
Expand Down Expand Up @@ -183,6 +179,26 @@ def test_pini_always_on():
mbbi = builder.mbbIn("BBB", initial_value=5)
assert mbbi.PINI.Value() == "YES"

@pytest.mark.parametrize("creation_func", in_records)
def test_setting_alarm_in_records(creation_func):
"""Test that In records can have a custom alarm value set using the "status"
and "severity" keywords"""
kwargs = {}
if creation_func == builder.WaveformIn:
kwargs["length"] = 1

record = creation_func(
"NEW_RECORD",
severity=alarm.MINOR_ALARM,
status=alarm.LOLO_ALARM,
**kwargs
)

assert record.STAT.Value() == "LOLO"
assert record.SEVR.Value() == "MINOR"



def validate_fixture_names(params):
"""Provide nice names for the out_records fixture in TestValidate class"""
return params[0].__name__
Expand Down