Skip to content

Commit

Permalink
Also updated for WSTRING
Browse files Browse the repository at this point in the history
  • Loading branch information
RobertoRoos committed Sep 13, 2024
1 parent 88b44c6 commit 7b5b368
Show file tree
Hide file tree
Showing 3 changed files with 13 additions and 25 deletions.
5 changes: 1 addition & 4 deletions pyads/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,6 @@
MAX_ADS_SUB_COMMANDS: int = 500


class PLCTYPE_WSTRING:
"""Special dummy class for handling WSTRING."""


# plc data types:
PLCTYPE_BOOL = c_bool
PLCTYPE_BYTE = c_ubyte
Expand All @@ -45,6 +41,7 @@ class PLCTYPE_WSTRING:
PLCTYPE_REAL = c_float
PLCTYPE_SINT = c_int8
PLCTYPE_STRING = c_char
PLCTYPE_WSTRING = c_wchar
PLCTYPE_TOD = c_int32
PLCTYPE_UBYTE = c_ubyte
PLCTYPE_UDINT = c_uint32
Expand Down
27 changes: 10 additions & 17 deletions pyads/pyads_ex.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,11 @@ def type_is_wstring(plc_type: Type) -> bool:
if plc_type == PLCTYPE_WSTRING:
return True

# If char array
if type(plc_type).__name__ == "PyCArrayType":
if plc_type._type_ == PLCTYPE_WSTRING:
return True

return False


Expand All @@ -264,13 +269,7 @@ def get_value_from_ctype_data(read_data: Optional[Any], plc_type: Type) -> Any:
return read_data.value.decode("utf-8")

if type_is_wstring(plc_type):
for ix in range(1, len(read_data), 2):
if (read_data[ix - 1], read_data[ix]) == (0, 0):
null_idx = ix - 1
break
else:
raise ValueError("No null-terminator found in buffer")
return bytearray(read_data[:null_idx]).decode("utf-16-le")
return read_data.value # ctypes automatically decoded the string for us

if type(plc_type).__name__ == "PyCArrayType":
return list(read_data)
Expand Down Expand Up @@ -835,11 +834,9 @@ def adsSyncReadReqEx2(
index_group_c = ctypes.c_ulong(index_group)
index_offset_c = ctypes.c_ulong(index_offset)

if type_is_wstring(data_type):
data = (STRING_BUFFER * ctypes.c_uint8)()
else:
# Regular string types already contain size too, rely on this type:
data = data_type()
# Strings were handled specifically before, but their sizes are contained and we
# can proceed as normal:
data = data_type()

data_pointer = ctypes.pointer(data)
data_length = ctypes.c_ulong(ctypes.sizeof(data))
Expand All @@ -862,11 +859,7 @@ def adsSyncReadReqEx2(

# If we're reading a value of predetermined size (anything but wstring, regular
# strings also contain size), validate that the correct number of bytes were read
if (
check_length
and not type_is_wstring(data_type)
and bytes_read.value != data_length.value
):
if check_length and bytes_read.value != data_length.value:
raise RuntimeError(
"Insufficient data (expected {0} bytes, {1} were read).".format(
data_length.value, bytes_read.value
Expand Down
6 changes: 2 additions & 4 deletions pyads/symbol.py
Original file line number Diff line number Diff line change
Expand Up @@ -299,9 +299,7 @@ def get_type_from_str(type_str: str) -> Optional[Type[PLCDataType]]:
# If simple scalar
plc_name = "PLCTYPE_" + type_str

# if type is WSTRING just return the PLCTYPE constant
if plc_name.startswith("PLCTYPE_WSTRING"):
return constants.PLCTYPE_WSTRING
# WSTRING used to be captured specifically but is now handled as normal

if hasattr(constants, plc_name):
# Map e.g. 'LREAL' to 'PLCTYPE_LREAL' directly based on the name
Expand Down Expand Up @@ -345,7 +343,7 @@ def get_type_from_str(type_str: str) -> Optional[Type[PLCDataType]]:
scalar_type = AdsSymbol.get_type_from_str(scalar_type_str)

if scalar_type:
if scalar_type == constants.PLCTYPE_STRING:
if scalar_type in [constants.PLCTYPE_STRING, constants.PLCTYPE_WSTRING]:
# E.g. `STRING(80)` actually has a size of 81 including the string
# terminator, so add one to the size
size = size + 1
Expand Down

0 comments on commit 7b5b368

Please sign in to comment.