Skip to content

Commit 67c11e2

Browse files
committed
Remove option of specifying scalar value for mbbi and mbbo records
At the same time, remove all reference to RVAL fields by instead using EPICS NO_CONVERT return codes as appropriate. This style of processing is the same as that done for epics_device.
1 parent 5b99b99 commit 67c11e2

File tree

3 files changed

+60
-51
lines changed

3 files changed

+60
-51
lines changed

docs/reference/api.rst

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -263,18 +263,25 @@ All functions return a wrapped `ProcessDeviceSupportIn` or
263263
Create ``stringin`` and ``stringout`` records.
264264

265265
.. function::
266-
mbbIn(name, *option_values, **fields)
267-
mbbOut(name, *option_values, **fields)
266+
mbbIn(name, *options, **fields)
267+
mbbOut(name, *options, **fields)
268268
269269
Create ``mbbi`` and ``mbbo`` records. Up to 16 options can be specified as
270-
a list of two or three field tuples. The first field of each tuple is the
271-
option name, the second field is the option value, and the third optional
272-
field is the option severity. For example::
270+
either an option name or a tuple of tw fields. The name or first field of
271+
the tuple names the option, and the second optional field is the option
272+
severity. For example::
273273

274274
status = mbbIn('STATUS',
275-
('OK', 0),
276-
('FAILING', 1, alarm.MINOR_ALARM),
277-
('FAILED', 2, alarm.MAJOR_ALARM))
275+
'OK',
276+
('FAILING', alarm.MINOR_ALARM),
277+
('FAILED', alarm.MAJOR_ALARM))
278+
279+
Numerical values are assigned to options sequentially from 0 to 15 and
280+
cannot be overridden.
281+
282+
.. warning::
283+
This is a strictly incompatible change from version 2, but is now
284+
compatible with version 2 of epics_device_.
278285

279286
.. function::
280287
Waveform(name, [value,] **fields)
@@ -518,3 +525,5 @@ Working with OUT records
518525
.. method:: get()
519526

520527
Returns the value associated with the record.
528+
529+
.. _epics_device: https://github.com/Araneidae/epics_device

softioc/builder.py

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -63,31 +63,30 @@ def longOut(name, DRVL=None, DRVH=None, EGU=None, **fields):
6363
'ZR', 'ON', 'TW', 'TH', 'FR', 'FV', 'SX', 'SV', # 0-7
6464
'EI', 'NI', 'TE', 'EL', 'TV', 'TT', 'FT', 'FF'] # 8-15
6565

66-
# Adds a list of (option, value [,severity]) tuples into field settings
66+
# Converts a list of (option [,severity]) values or tuples into field settings
6767
# suitable for mbbi and mbbo records.
68-
def _process_mbb_values(option_values, fields):
69-
def process_value(prefix, option, value, severity=None):
68+
def _process_mbb_values(options, fields):
69+
def process_value(prefix, value, option, severity=None):
7070
fields[prefix + 'ST'] = option
7171
fields[prefix + 'VL'] = value
7272
if severity:
7373
fields[prefix + 'SV'] = severity
74-
for default_value, (prefix, value) in \
75-
enumerate(zip(_mbbPrefixes, option_values)):
76-
if isinstance(value, str):
77-
# The value is a simple string naming the option. Assign a
78-
# default numerical value (and no severity setting).
79-
process_value(prefix, value, default_value)
74+
for prefix, (value, option) in zip(_mbbPrefixes, enumerate(options)):
75+
if isinstance(value, tuple):
76+
# The option is tuple consisting of the option name and an optional
77+
# alarm severity.
78+
process_value(prefix, value, *option)
8079
else:
81-
# The value is two- or three-tuple consisting of an option name, a
82-
# corresponding numerical value and an alarm severity.
83-
process_value(prefix, *value)
80+
# The option is a simple string naming the option. Assign the
81+
# default numerical value (and no severity setting).
82+
process_value(prefix, value, option)
8483

85-
def mbbIn(name, *option_values, **fields):
86-
_process_mbb_values(option_values, fields)
84+
def mbbIn(name, *options, **fields):
85+
_process_mbb_values(options, fields)
8786
return _in_record('mbbi', name, **fields)
8887

89-
def mbbOut(name, *option_values, **fields):
90-
_process_mbb_values(option_values, fields)
88+
def mbbOut(name, *options, **fields):
89+
_process_mbb_values(options, fields)
9190
return PythonDevice.mbbo(name, OMSL = 'supervisory', **fields)
9291

9392

softioc/device.py

Lines changed: 28 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@
1515
dispatcher = None
1616

1717

18+
# EPICS processing return codes
19+
EPICS_OK = 0
20+
EPICS_ERROR = 1
21+
NO_CONVERT = 2
22+
23+
1824
class ProcessDeviceSupportCore(DeviceSupportCore, RecordLookup):
1925
'''Implements canonical default processing for records with a _process
2026
method. Processing typically either copies a locally set value into the
@@ -25,11 +31,15 @@ class ProcessDeviceSupportCore(DeviceSupportCore, RecordLookup):
2531
# will have to override this to also add their special_linconv method.
2632
_dset_extra_ = ([('process', CFUNCTYPE(c_int, c_void_p))], [0])
2733

34+
# For some record types we want to return a different return code either
35+
# from record init or processing
36+
_epics_rc = EPICS_OK
37+
2838
# Default implementations of read and write, overwritten where necessary.
2939
def _read_value(self, record):
30-
return getattr(record, self._val_field_)
40+
return getattr(record, 'VAL')
3141
def _write_value(self, record, value):
32-
setattr(record, self._val_field_, value)
42+
setattr(record, 'VAL', value)
3343

3444

3545
class ProcessDeviceSupportIn(ProcessDeviceSupportCore):
@@ -59,7 +69,7 @@ def _process(self, record, _value=None):
5969
self.process_severity(record, severity, alarm)
6070
if timestamp is not None:
6171
record.TIME = timestamp
62-
return 0
72+
return self._epics_rc
6373

6474
def set(self, value,
6575
severity=alarm.NO_ALARM, alarm=alarm.UDF_ALARM, timestamp=None):
@@ -112,28 +122,28 @@ def init_record(self, record):
112122
record.TIME = time.time()
113123
record.UDF = 0
114124
recGblResetAlarms(record)
115-
return self.__super.init_record(record)
125+
return self._epics_rc
116126

117127
def _process(self, record):
118128
'''Processing suitable for output records. Performs immediate value
119129
validation and asynchronous update notification.'''
120130
value = self._read_value(record)
121131
if numpy.all(value == self._value) and not self.__always_update:
122132
# If the value isn't making a change then don't do anything.
123-
return 0
133+
return EPICS_OK
124134
if self.__enable_write and self.__validate and \
125135
not self.__validate(self, value):
126136
# Asynchronous validation rejects value. It's up to the
127137
# validation routine to do any logging. In this case restore the
128138
# last good value.
129139
if self._value is not None:
130140
self._write_value(record, self._value)
131-
return 1
141+
return EPICS_ERROR
132142

133143
self._value = value
134144
if self.__on_update and self.__enable_write:
135145
dispatcher(self.__on_update, value)
136-
return 0
146+
return EPICS_OK
137147

138148

139149
NumpyCharCodeToDbr = {
@@ -209,16 +219,14 @@ def get(self):
209219
return self._value
210220

211221

212-
def _Device(Base, record_type, rval=False, mlst=False, default=0):
222+
def _Device(Base, record_type, mlst=False, default=0, convert=True):
213223
'''Wrapper for generating simple records.'''
214-
val_field = 'RVAL' if rval else 'VAL'
215-
216224
class GenericDevice(Base):
217225
_record_type_ = record_type
218226
_device_name_ = 'devPython_' + record_type
219-
_val_field_ = val_field
220227
_default_ = default
221-
_fields_ = ['UDF', val_field]
228+
_fields_ = ['UDF', 'VAL']
229+
_epics_rc = EPICS_OK if convert else NO_CONVERT
222230
if mlst:
223231
_fields_.append('MLST')
224232

@@ -231,21 +239,19 @@ class GenericDevice(Base):
231239
def _Device_In(type, **kargs):
232240
return _Device(_In, type, **kargs)
233241

234-
def _Device_Out(type, rval=False, mlst=True):
235-
return _Device(_Out, type, rval=rval, mlst=mlst, default=None)
242+
def _Device_Out(type, convert=True, mlst=True):
243+
return _Device(_Out, type, convert=convert, mlst=mlst, default=None)
236244

237245
longin = _Device_In('longin')
238246
longout = _Device_Out('longout')
239-
bi = _Device_In('bi', rval=True)
240-
bo = _Device_Out('bo', rval=True)
247+
bi = _Device_In('bi', convert=False)
248+
bo = _Device_Out('bo', convert=False)
241249
stringin = _Device_In('stringin', mlst=False, default='')
242250
stringout = _Device_Out('stringout', mlst=False)
243-
mbbi = _Device_In('mbbi', rval=True)
244-
mbbo = _Device_Out('mbbo', rval=True)
251+
mbbi = _Device_In('mbbi', convert=False)
252+
mbbo = _Device_Out('mbbo', convert=False)
245253

246254

247-
NO_CONVERT = 2
248-
249255
dset_process_linconv = (
250256
[('process', CFUNCTYPE(c_int, c_void_p)),
251257
('special_linconv', CFUNCTYPE(c_int, c_void_p, c_int))],
@@ -257,10 +263,10 @@ def _Device_Out(type, rval=False, mlst=True):
257263
class ai(ProcessDeviceSupportIn):
258264
_record_type_ = 'ai'
259265
_device_name_ = 'devPython_ai'
260-
_val_field_ = 'VAL'
261266
_default_ = 0.0
262267
_fields_ = ['UDF', 'VAL']
263268
_dset_extra_ = dset_process_linconv
269+
_epics_rc = NO_CONVERT
264270

265271
def _process(self, record):
266272
_value = self._value
@@ -270,17 +276,12 @@ def _process(self, record):
270276
record.UDF = int(numpy.isnan(_value[0]))
271277
return NO_CONVERT
272278

273-
274279
class ao(ProcessDeviceSupportOut):
275280
_record_type_ = 'ao'
276281
_device_name_ = 'devPython_ao'
277-
_val_field_ = 'VAL'
278282
_fields_ = ['UDF', 'VAL', 'MLST']
279283
_dset_extra_ = dset_process_linconv
280-
281-
def init_record(self, record):
282-
self.__super.init_record(record)
283-
return NO_CONVERT
284+
_epics_rc = NO_CONVERT
284285

285286

286287

0 commit comments

Comments
 (0)