Skip to content

Commit 4edf6bd

Browse files
Allow "status" and "severity" on In record init
Add new tests and refactor existing ones Add docs
1 parent 3f0ec72 commit 4edf6bd

File tree

4 files changed

+66
-24
lines changed

4 files changed

+66
-24
lines changed

CHANGELOG.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ Versioning <https://semver.org/spec/v2.0.0.html>`_.
1010
Unreleased_
1111
-----------
1212

13+
- `Allow "status" and "severity" on In record init <../../pull/111>`_
14+
1315
4.1.0_ - 2022-08-05
1416
-------------------
1517

docs/reference/api.rst

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,19 @@ Test Facilities`_ documentation for more details of each function.
165165

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

168+
.. _status and severity:
169+
170+
`status and severity`
171+
~~~~~~~~~~~~~~~~~~~~~
172+
173+
Only available on IN records. These can be used with the alarm value enums
174+
from `softioc.alarm` to set the initial alarm state of a record.
175+
176+
.. note::
177+
178+
By default the builder module sets ``PINI`` to ``YES``, which means the
179+
record will process at initialization and the alarm status will be reset.
180+
168181
.. _on_update:
169182

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

246-
247-
248259
For all of these functions any EPICS database field can be assigned a value by
249260
passing it as a keyword argument for the corresponding field name (in upper
250261
case) or by assigning to the corresponding field of the returned record object.

softioc/builder.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import os
22
import numpy
3+
34
from .softioc import dbLoadDatabase
45

56
from epicsdbbuilder import *
@@ -24,10 +25,17 @@ def _set_in_defaults(fields):
2425
fields.setdefault('SCAN', 'I/O Intr')
2526
fields.setdefault('PINI', 'YES')
2627
fields.setdefault('DISP', 1)
28+
_set_alarm(fields)
2729

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

33+
def _set_alarm(fields):
34+
if "status" in fields:
35+
fields['STAT'] = _statStrings[fields.pop('status')]
36+
if "severity" in fields:
37+
fields['SEVR'] = _severityStrings[fields.pop('severity')]
38+
3139
# For longout and ao we want DRV{L,H} to match {L,H}OPR by default
3240
def _set_scalar_out_defaults(fields, DRVL, DRVH):
3341
fields['DRVL'] = DRVL
@@ -76,6 +84,11 @@ def longOut(name, DRVL=None, DRVH=None, EGU=None, **fields):
7684
# All the severity strings supported by <prefix>SV
7785
_severityStrings = ['NO_ALARM', 'MINOR', 'MAJOR', 'INVALID']
7886

87+
_statStrings = [
88+
'NO_ALARM', 'READ', 'WRITE', 'HIHI', 'HIGH', 'LOLO', 'LOW', 'STATE', 'COS',
89+
'COMM', 'TIMEOUT', 'HWLIMIT', 'CALC', 'SCAN', 'LINK', 'SOFT', 'BAD_SUB',
90+
'UDF', 'DISABLE', 'SIMM', 'READ_ACCESS', 'WRITE_ACCESS']
91+
7992
# Converts a list of (option [,severity]) values or tuples into field settings
8093
# suitable for mbbi and mbbo records.
8194
def _process_mbb_values(options, fields):

tests/test_records.py

Lines changed: 38 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,23 @@
1717
)
1818

1919
from softioc import asyncio_dispatcher, builder, softioc
20+
from softioc import alarm
2021
from softioc.device import SetBlocking
2122

2223
# Test file for miscellaneous tests related to records
2324

2425
# Test parameters
2526
DEVICE_NAME = "RECORD-TESTS"
2627

28+
in_records = [
29+
builder.aIn,
30+
builder.boolIn,
31+
builder.longIn,
32+
builder.mbbIn,
33+
builder.stringIn,
34+
builder.WaveformIn,
35+
]
36+
2737
def test_records(tmp_path):
2838
# Ensure we definitely unload all records that may be hanging over from
2939
# previous tests, then create exactly one instance of expected records.
@@ -60,32 +70,18 @@ def test_enum_length_restriction():
6070
"seventeen",
6171
)
6272

63-
64-
def test_DISP_defaults_on():
73+
@pytest.mark.parametrize("creation_func", in_records)
74+
def test_DISP_defaults_on(creation_func):
6575
"""Test that all IN record types have DISP=1 set by default"""
66-
in_records = [
67-
builder.aIn,
68-
builder.boolIn,
69-
builder.longIn,
70-
builder.mbbIn,
71-
builder.stringIn,
72-
builder.WaveformIn,
73-
]
74-
75-
record_counter = 0
76+
kwargs = {}
7677

77-
for creation_func in in_records:
78-
kwargs = {}
79-
record_counter += 1
80-
record_name = "DISP" + str(record_counter)
78+
if creation_func == builder.WaveformIn:
79+
kwargs = {"length": 1}
8180

82-
if creation_func == builder.WaveformIn:
83-
kwargs = {"length": 1}
81+
record = creation_func("RECORD", **kwargs)
8482

85-
record = creation_func(record_name, **kwargs)
86-
87-
# Note: DISP attribute won't exist if field not specified
88-
assert record.DISP.Value() == 1
83+
# Note: DISP attribute won't exist if field not specified
84+
assert record.DISP.Value() == 1
8985

9086

9187
def test_DISP_can_be_overridden():
@@ -183,6 +179,26 @@ def test_pini_always_on():
183179
mbbi = builder.mbbIn("BBB", initial_value=5)
184180
assert mbbi.PINI.Value() == "YES"
185181

182+
@pytest.mark.parametrize("creation_func", in_records)
183+
def test_setting_alarm_in_records(creation_func):
184+
"""Test that In records can have a custom alarm value set using the "status"
185+
and "severity" keywords"""
186+
kwargs = {}
187+
if creation_func == builder.WaveformIn:
188+
kwargs["length"] = 1
189+
190+
record = creation_func(
191+
"NEW_RECORD",
192+
severity=alarm.MINOR_ALARM,
193+
status=alarm.LOLO_ALARM,
194+
**kwargs
195+
)
196+
197+
assert record.STAT.Value() == "LOLO"
198+
assert record.SEVR.Value() == "MINOR"
199+
200+
201+
186202
def validate_fixture_names(params):
187203
"""Provide nice names for the out_records fixture in TestValidate class"""
188204
return params[0].__name__

0 commit comments

Comments
 (0)