Skip to content

Commit ed1b193

Browse files
committed
Add special support for long string records
1 parent 8ecdd88 commit ed1b193

File tree

6 files changed

+77
-18
lines changed

6 files changed

+77
-18
lines changed

softioc/builder.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,34 @@ def WaveformOut(name, *value, **fields):
182182
return PythonDevice.waveform_out(name, **fields)
183183

184184

185+
def _long_string(value, fields):
186+
if 'initial_value' in fields:
187+
assert not value, 'Can\'t specify initial value twice!'
188+
value = (fields.pop('initial_value'),)
189+
190+
if value:
191+
# If a value is specified it should be the *only* non keyword
192+
# argument.
193+
value, = value
194+
fields['initial_value'] = value
195+
length = len(value)
196+
else:
197+
# No value specified, so require length and datatype to be specified.
198+
length = fields.pop('length')
199+
200+
fields['NELM'] = length
201+
fields['FTVL'] = 'UCHAR'
202+
203+
204+
def longStringIn(name, *value, **fields):
205+
_long_string(value, fields)
206+
return _in_record('long_stringin', name, **fields)
207+
208+
def longStringOut(name, *value, **fields):
209+
_long_string(value, fields)
210+
return PythonDevice.long_stringout(name, **fields)
211+
212+
185213

186214
# ----------------------------------------------------------------------------
187215
# Support routines for builder
@@ -227,6 +255,7 @@ def UnsetDevice():
227255
'stringIn', 'stringOut',
228256
'mbbIn', 'mbbOut',
229257
'Waveform', 'WaveformOut',
258+
'longStringIn', 'longStringOut',
230259
'Action',
231260
# Other builder support functions
232261
'LoadDatabase',

softioc/device.dbd

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,7 @@ device(waveform, INST_IO, devPython_waveform, "Python")
1010
device(mbbi, INST_IO, devPython_mbbi, "Python")
1111
device(mbbo, INST_IO, devPython_mbbo, "Python")
1212

13-
# Waveforms as "out" devices need special treatment.
13+
# A variety of specialised versions of waveform need special treatment.
1414
device(waveform, INST_IO, devPython_waveform_out, "PythonWfOut")
15+
device(waveform, INST_IO, devPython_long_stringin, "PythonLongStringIn")
16+
device(waveform, INST_IO, devPython_long_stringout, "PythonLongStringOut")

softioc/device.py

Lines changed: 37 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -247,12 +247,11 @@ class EpicsString:
247247
_dbf_type_ = fields.DBF_STRING
248248

249249
def _value_to_epics(self, value):
250-
if isinstance(value, str):
251-
value = value.encode()
252250
# It's a little odd: we can't simply construct a value from the byte
253-
# string, but we can update the array in an existing value
251+
# string, but we can update the array in an existing value.
252+
# Value being written must be a string.
254253
result = self._ctype_()
255-
result.value = value
254+
result.value = value.encode()
256255
return result
257256

258257
def _epics_to_value(self, epics):
@@ -345,17 +344,6 @@ def _compare_values(self, value, other):
345344
return numpy.all(value == other)
346345

347346
def _value_to_epics(self, value):
348-
'''Handles strings and bytearrays as values for Waveforms. Returns the
349-
string converted to a numpy array.'''
350-
if isinstance(value, str):
351-
value = value.encode(errors = 'replace')
352-
if isinstance(value, bytes):
353-
# Convert a string into an array of characters. This will produce
354-
# the correct behaviour when treating a character array as a string.
355-
# Note that the trailing null is needed to work around problems with
356-
# some clients. Note this also exists in builder.py's _waveform().
357-
value = numpy.frombuffer(value + b'\0', dtype = numpy.uint8)
358-
359347
# Ensure we always convert incoming value into numpy array, regardless
360348
# of whether the record has been initialised or not
361349
value = numpy.require(value, dtype = self.dtype)
@@ -390,5 +378,39 @@ class waveform_out(WaveformBase, ProcessDeviceSupportOut):
390378
_device_name_ = 'devPython_waveform_out'
391379

392380

381+
# Convert string into numpy array of char
382+
def encode_string(value, length = None):
383+
value = value.encode(errors = 'replace')
384+
# Convert a string into an array of characters. This will produce
385+
# the correct behaviour when treating a character array as a string.
386+
# Note that the trailing null is needed to work around problems with
387+
# some clients.
388+
value = numpy.frombuffer(value + b'\0', dtype = numpy.uint8)
389+
390+
# Truncate value to fit
391+
if length:
392+
value = value[:length]
393+
return value
394+
395+
396+
class LongStringBase(WaveformBase):
397+
dtype = numpy.dtype('uint8')
398+
399+
def _value_to_epics(self, value):
400+
return encode_string(value, getattr(self, '_nelm', None))
401+
402+
def _epics_to_value(self, value):
403+
return value.decode(errors = 'replace')
404+
405+
406+
class long_stringin(LongStringBase, ProcessDeviceSupportIn):
407+
_record_type_ = 'waveform'
408+
_device_name_ = 'devPython_long_stringin'
409+
410+
class long_stringout(LongStringBase, ProcessDeviceSupportOut):
411+
_record_type_ = 'waveform'
412+
_device_name_ = 'devPython_long_stringout'
413+
414+
393415
# Ensure the .dbd file is loaded.
394416
dbLoadDatabase('device.dbd', os.path.dirname(__file__), None)

softioc/pythonSoftIoc.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,12 @@ def __init_class__(cls):
9292
cls.waveform_out = cls.makeRecord(
9393
epicsdbbuilder.records.waveform, device.waveform_out,
9494
'PythonWfOut')
95+
cls.long_stringin = cls.makeRecord(
96+
epicsdbbuilder.records.waveform, device.long_stringin,
97+
'PythonLongStringIn')
98+
cls.long_stringout = cls.makeRecord(
99+
epicsdbbuilder.records.waveform, device.long_stringout,
100+
'PythonLongStringOut')
95101

96102
class makeRecord:
97103
def __init__(self, builder, record, dtyp = 'Python'):

tests/expected_records.db

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ record(longout, "TS-DI-TEST-01:LONGOUT")
5353
record(waveform, "TS-DI-TEST-01:LONGSTRING")
5454
{
5555
field(DISP, "1")
56-
field(DTYP, "Python")
56+
field(DTYP, "PythonLongStringIn")
5757
field(FTVL, "UCHAR")
5858
field(INP, "@TS-DI-TEST-01:LONGSTRING")
5959
field(NELM, "256")

tests/sim_records.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ def update_sin_wf(value):
5757
t_waveform_out = WaveformOut('WAVEFORM_OUT', wf, on_update = on_update)
5858
t_waveform_in2 = Waveform('WAVEFORM2', length = 10)
5959

60-
t_longstring_in = Waveform('LONGSTRING', length = 256, datatype = numpy.uint8)
60+
t_longstring_in = longStringIn('LONGSTRING', length = 256)
6161

6262

6363
def Update():

0 commit comments

Comments
 (0)