Skip to content

Commit

Permalink
fix(plc4py): Fix up documentation and more Modbus testing
Browse files Browse the repository at this point in the history
  • Loading branch information
hutcheb committed Oct 30, 2024
1 parent 688f8a8 commit b8e23a7
Show file tree
Hide file tree
Showing 9 changed files with 179 additions and 149 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ class ${type.name}:
<@emitImport import="from plc4py.api.value.PlcValue import PlcValue" />
${helper.camelCaseToSnakeCase(arrayField.name)}: List[PlcValue] = []
for _ in range(item_count):
${helper.camelCaseToSnakeCase(arrayField.name)}.append(${helper.getPlcValueTypeForTypeReference(elementTypeReference)}(${helper.getLanguageTypeNameForTypeReference(elementTypeReference, false)}(<#if elementTypeReference.isSimpleTypeReference()>${helper.getReadBufferReadMethodCall(elementTypeReference.asSimpleTypeReference().orElseThrow(), "", arrayField)}${helper.getFieldOptions(typedField, parserArguments)}))<#else>${elementTypeReference.asComplexTypeReference().orElseThrow().name}IO.static_parse(read_buffer<#if elementTypeReference.params.isPresent()>, <#list elementTypeReference.params.orElseThrow() as parserArgument>(${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(elementTypeReference, parserArgument?index), true)}) (${helper.toParseExpression(arrayField, elementTypeReference, parserArgument,parserArguments)})<#sep>, </#sep></#list></#if>)</#if>))
${helper.camelCaseToSnakeCase(arrayField.name)}.append(<#if elementTypeReference.isSimpleTypeReference()>${helper.getReadBufferReadMethodCall(elementTypeReference.asSimpleTypeReference().orElseThrow(), "", arrayField)}${helper.getFieldOptions(typedField, parserArguments)}))<#else>${elementTypeReference.asComplexTypeReference().orElseThrow().name}IO.static_parse(read_buffer<#if elementTypeReference.params.isPresent()>, <#list elementTypeReference.params.orElseThrow() as parserArgument>(${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(elementTypeReference, parserArgument?index), true)}) (${helper.toParseExpression(arrayField, elementTypeReference, parserArgument,parserArguments)})<#sep>, </#sep></#list></#if>)</#if>

<#-- In all other cases do we have to work with a list, that is later converted to an array -->
<#else>
Expand Down
59 changes: 47 additions & 12 deletions plc4py/plc4py/drivers/modbus/ModbusDevice.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#
import asyncio
import logging
import math
from asyncio import Transport
from dataclasses import dataclass, field
from math import ceil
Expand Down Expand Up @@ -221,7 +222,7 @@ async def write(
)
elif isinstance(tag, ModbusTagHoldingRegister):
values = self._serialize_data_items(tag, values)
quantity = tag.quantity * (tag.data_type.data_type_size / 2)
quantity = math.ceil(tag.quantity * (tag.data_type.data_type_size / 2))
pdu = ModbusPDUWriteMultipleHoldingRegistersRequestBuilder(
tag.address, quantity, values
).build()
Expand Down Expand Up @@ -259,15 +260,49 @@ async def write(
return write_response

def _serialize_data_items(self, tag: ModbusTag, values: PlcValue) -> List[int]:
length = tag.quantity * tag.data_type.data_type_size
write_buffer = WriteBufferByteBased(length, self._configuration.byte_order)

DataItem.static_serialize(
write_buffer,
values,
tag.data_type,
tag.quantity,
True,
self._configuration.byte_order,
)
if (
isinstance(tag, ModbusTagCoil)
and (tag.data_type == ModbusDataType.BOOL)
and not isinstance(values, PlcList)
):
# Booleans are writen different depending on what registers they are being written to
length = tag.quantity
write_buffer = WriteBufferByteBased(length, self._configuration.byte_order)
write_buffer.write_unsigned_short(int(0x0000), 7, "int0x0000")
# Simple Field (value)
value: bool = values.get_bool()
write_buffer.write_bit((value), "value")
elif (
isinstance(tag, ModbusTagCoil)
and (tag.data_type == ModbusDataType.BOOL)
and isinstance(values, PlcList)
):
length = math.ceil(tag.quantity / 8)
write_buffer = WriteBufferByteBased(length, self._configuration.byte_order)
for i in range(length):
if i == length - 1:
sub_length = tag.quantity % 8
else:
sub_length = 8
sub_array = values.value[i * 8 : i * 8 + sub_length]
sub_array.reverse()
for j in range(8 - sub_length):
write_buffer.write_bit(False, "value")
for item in sub_array:
# Simple Field (value)
value: bool = item.get_bool()
write_buffer.write_bit(value, "value")
else:
length = tag.quantity * tag.data_type.data_type_size
if (length % 2) == 1:
length += 1
write_buffer = WriteBufferByteBased(length, self._configuration.byte_order)
DataItem.static_serialize(
write_buffer,
values,
tag.data_type,
tag.quantity,
True,
self._configuration.byte_order,
)
return list(write_buffer.get_bytes().tobytes())
53 changes: 14 additions & 39 deletions plc4py/plc4py/protocols/modbus/readwrite/DataItem.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
from plc4py.spi.values.PlcValues import PlcList
from plc4py.spi.values.PlcValues import PlcREAL
from plc4py.spi.values.PlcValues import PlcSINT
from plc4py.spi.values.PlcValues import PlcSTRING
from plc4py.spi.values.PlcValues import PlcUDINT
from plc4py.spi.values.PlcValues import PlcUINT
from plc4py.spi.values.PlcValues import PlcULINT
Expand Down Expand Up @@ -114,7 +113,7 @@ def static_parse(
item_count: int = int(number_of_values)
value: List[PlcValue] = []
for _ in range(item_count):
value.append(PlcBOOL(bool(read_buffer.read_bit(""))))
value.append(read_buffer.read_bit(""))

return PlcList(value)
if (
Expand Down Expand Up @@ -165,7 +164,7 @@ def static_parse(
item_count: int = int(number_of_values * int(8))
value: List[PlcValue] = []
for _ in range(item_count):
value.append(PlcBOOL(bool(read_buffer.read_bit(""))))
value.append(read_buffer.read_bit(""))

return PlcList(value)
if data_type == ModbusDataType.WORD: # WORD
Expand Down Expand Up @@ -234,9 +233,7 @@ def static_parse(
item_count: int = int(number_of_values)
value: List[PlcValue] = []
for _ in range(item_count):
value.append(
PlcSINT(int(read_buffer.read_signed_byte(8, logical_name="")))
)
value.append(read_buffer.read_signed_byte(8, logical_name=""))

return PlcList(value)
if data_type == ModbusDataType.INT and number_of_values == int(1): # INT
Expand All @@ -251,7 +248,7 @@ def static_parse(
item_count: int = int(number_of_values)
value: List[PlcValue] = []
for _ in range(item_count):
value.append(PlcINT(int(read_buffer.read_short(16, logical_name=""))))
value.append(read_buffer.read_short(16, logical_name=""))

return PlcList(value)
if data_type == ModbusDataType.DINT and number_of_values == int(1): # DINT
Expand All @@ -266,7 +263,7 @@ def static_parse(
item_count: int = int(number_of_values)
value: List[PlcValue] = []
for _ in range(item_count):
value.append(PlcDINT(int(read_buffer.read_int(32, logical_name=""))))
value.append(read_buffer.read_int(32, logical_name=""))

return PlcList(value)
if data_type == ModbusDataType.LINT and number_of_values == int(1): # LINT
Expand All @@ -281,7 +278,7 @@ def static_parse(
item_count: int = int(number_of_values)
value: List[PlcValue] = []
for _ in range(item_count):
value.append(PlcLINT(int(read_buffer.read_long(64, logical_name=""))))
value.append(read_buffer.read_long(64, logical_name=""))

return PlcList(value)
if (
Expand Down Expand Up @@ -332,9 +329,7 @@ def static_parse(
item_count: int = int(number_of_values)
value: List[PlcValue] = []
for _ in range(item_count):
value.append(
PlcUINT(int(read_buffer.read_unsigned_short(8, logical_name="")))
)
value.append(read_buffer.read_unsigned_short(8, logical_name=""))

return PlcList(value)
if data_type == ModbusDataType.UINT and number_of_values == int(1): # UINT
Expand All @@ -349,9 +344,7 @@ def static_parse(
item_count: int = int(number_of_values)
value: List[PlcValue] = []
for _ in range(item_count):
value.append(
PlcUDINT(int(read_buffer.read_unsigned_int(16, logical_name="")))
)
value.append(read_buffer.read_unsigned_int(16, logical_name=""))

return PlcList(value)
if data_type == ModbusDataType.UDINT and number_of_values == int(1): # UDINT
Expand All @@ -366,9 +359,7 @@ def static_parse(
item_count: int = int(number_of_values)
value: List[PlcValue] = []
for _ in range(item_count):
value.append(
PlcULINT(int(read_buffer.read_unsigned_long(32, logical_name="")))
)
value.append(read_buffer.read_unsigned_long(32, logical_name=""))

return PlcList(value)
if data_type == ModbusDataType.ULINT and number_of_values == int(1): # ULINT
Expand All @@ -383,9 +374,7 @@ def static_parse(
item_count: int = int(number_of_values)
value: List[PlcValue] = []
for _ in range(item_count):
value.append(
PlcLINT(int(read_buffer.read_unsigned_long(64, logical_name="")))
)
value.append(read_buffer.read_unsigned_long(64, logical_name=""))

return PlcList(value)
if data_type == ModbusDataType.REAL and number_of_values == int(1): # REAL
Expand All @@ -400,9 +389,7 @@ def static_parse(
item_count: int = int(number_of_values)
value: List[PlcValue] = []
for _ in range(item_count):
value.append(
PlcREAL(float(read_buffer.read_float(32, logical_name="")))
)
value.append(read_buffer.read_float(32, logical_name=""))

return PlcList(value)
if data_type == ModbusDataType.LREAL and number_of_values == int(1): # LREAL
Expand All @@ -417,9 +404,7 @@ def static_parse(
item_count: int = int(number_of_values)
value: List[PlcValue] = []
for _ in range(item_count):
value.append(
PlcLREAL(float(read_buffer.read_double(64, logical_name="")))
)
value.append(read_buffer.read_double(64, logical_name=""))

return PlcList(value)
if data_type == ModbusDataType.CHAR and number_of_values == int(1): # CHAR
Expand All @@ -435,11 +420,7 @@ def static_parse(
value: List[PlcValue] = []
for _ in range(item_count):
value.append(
PlcSTRING(
str(
read_buffer.read_str(8, logical_name="", encoding='"UTF-8"')
)
)
read_buffer.read_str(8, logical_name="", encoding='"UTF-8"')
)

return PlcList(value)
Expand All @@ -456,13 +437,7 @@ def static_parse(
value: List[PlcValue] = []
for _ in range(item_count):
value.append(
PlcSTRING(
str(
read_buffer.read_str(
16, logical_name="", encoding='"UTF-16"'
)
)
)
read_buffer.read_str(16, logical_name="", encoding='"UTF-16"')
)

return PlcList(value)
Expand Down
Loading

0 comments on commit b8e23a7

Please sign in to comment.