Skip to content

Commit aa8a8b3

Browse files
Allow arrays of strings to be used with Waveforms
Note the tests fail, largely due to now numpy defaults to a floating point dtype, which we cannot coerce into an array of strings. Also TODOs need completion...
1 parent 77ec950 commit aa8a8b3

4 files changed

Lines changed: 31 additions & 1 deletion

File tree

‎softioc/builder.py‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,8 @@ def Action(name, **fields):
132132
'uint32': 'ULONG',
133133
'float32': 'FLOAT',
134134
'float64': 'DOUBLE',
135+
'bytes32': 'STRING',
136+
'bytes320': 'STRING',
135137
}
136138

137139
# Coverts FTVL string to numpy type
@@ -144,6 +146,7 @@ def Action(name, **fields):
144146
'ULONG': 'uint32',
145147
'FLOAT': 'float32',
146148
'DOUBLE': 'float64',
149+
'STRING': 'S40',
147150
}
148151

149152

@@ -195,11 +198,15 @@ def _waveform(value, fields):
195198

196199
# Special case for [u]int64: if the initial value comes in as 64 bit
197200
# integers we cannot represent that, so recast it as [u]int32
201+
# Special case for array of strings to correctly identify each element
202+
# of the array as a string type.
198203
if datatype is None:
199204
if initial_value.dtype == numpy.int64:
200205
initial_value = numpy.require(initial_value, numpy.int32)
201206
elif initial_value.dtype == numpy.uint64:
202207
initial_value = numpy.require(initial_value, numpy.uint32)
208+
elif initial_value.dtype.char == "S":
209+
initial_value = numpy.require(initial_value, numpy.dtype("S40"))
203210
else:
204211
initial_value = numpy.array([], dtype = datatype)
205212
length = _get_length(fields)

‎softioc/device.py‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,7 @@ def _read_value(self, record):
391391
return result
392392

393393
def _write_value(self, record, value):
394+
value = _require_waveform(value, self._dtype)
394395
nord = len(value)
395396
memmove(
396397
record.BPTR, value.ctypes.data_as(c_void_p),
@@ -409,6 +410,10 @@ def _value_to_epics(self, value):
409410
# common class of bug, at the cost of duplicated code and data, here we
410411
# ensure a copy is taken of the value.
411412
assert len(value) <= self._nelm, 'Value too long for waveform'
413+
# TODO: line below triggers "DeprecationWarning: Applying '+' to a
414+
# non-numerical array is ill-defined. Returning a copy, but in the
415+
# future this will error."
416+
# Probably should change to numpy.copy?
412417
return +value
413418

414419
def _epics_to_value(self, value):

‎softioc/fields.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,5 +146,5 @@ def __set_time(self, address, new_time):
146146
address[0].secs -= EPICS_epoch
147147

148148

149-
149+
# TODO: DbfCodeToNumpy doesn't exist!
150150
__all__ = ['RecordFactory', 'DbfCodeToNumpy', 'ca_timestamp']

‎tests/test_record_values.py‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,24 @@ def record_values_names(fixture_value):
188188
),
189189
numpy.ndarray,
190190
),
191+
(
192+
"wIn_byte_string_array",
193+
builder.WaveformIn,
194+
[b"AB", b"CD", b"EF"],
195+
numpy.array(
196+
[b"AB", b"CD", b"EF"], dtype=numpy.dtype("|S40")
197+
),
198+
numpy.ndarray,
199+
),
200+
(
201+
"wOut_byte_string_array",
202+
builder.WaveformOut,
203+
[b"AB", b"CD", b"EF"],
204+
numpy.array(
205+
[b"AB", b"CD", b"EF"], dtype=numpy.dtype("|S40")
206+
),
207+
numpy.ndarray,
208+
),
191209
(
192210
"longStringIn_str",
193211
builder.longStringIn,

0 commit comments

Comments
 (0)