diff --git a/code-generation/language-python/src/main/java/org/apache/plc4x/language/python/PythonLanguageTemplateHelper.java b/code-generation/language-python/src/main/java/org/apache/plc4x/language/python/PythonLanguageTemplateHelper.java
index bd2370721bd..c842e5ebe95 100644
--- a/code-generation/language-python/src/main/java/org/apache/plc4x/language/python/PythonLanguageTemplateHelper.java
+++ b/code-generation/language-python/src/main/java/org/apache/plc4x/language/python/PythonLanguageTemplateHelper.java
@@ -579,7 +579,7 @@ public String getPlcValueTypeForTypeReference(TypeReference typeReference) {
case BYTE:
// Byte values are represented as signed integers in PLC4Py
emitRequiredImport("from plc4py.spi.values.PlcValues import PlcSINT");
- return "PlcSINT";
+ return "PlcBYTE";
case UINT:
IntegerTypeReference unsignedIntegerTypeReference = (IntegerTypeReference) simpleTypeReference;
if (unsignedIntegerTypeReference.getSizeInBits() <= 4) {
@@ -807,10 +807,10 @@ public String getReadBufferReadMethodCall(String logicalName, SimpleTypeReferenc
switch (simpleTypeReference.getBaseType()) {
case BIT:
String bitType = "bit";
- return "read_buffer.read_" + bitType + "(\"" + logicalName + "\")";
+ return "read_buffer.read_" + bitType + "(\"" + logicalName + "\"";
case BYTE:
String byteType = "byte";
- return "read_buffer.read_" + byteType + "(\"" + logicalName + "\")";
+ return "read_buffer.read_" + byteType + "(\"" + logicalName + "\"";
case UINT:
String unsignedIntegerType;
IntegerTypeReference unsignedIntegerTypeReference = (IntegerTypeReference) simpleTypeReference;
@@ -825,7 +825,7 @@ public String getReadBufferReadMethodCall(String logicalName, SimpleTypeReferenc
} else {
unsignedIntegerType = "unsigned_long";
}
- return "read_buffer.read_" + unsignedIntegerType + "(" + simpleTypeReference.getSizeInBits() + ", logical_name=\"" + logicalName + "\")";
+ return "read_buffer.read_" + unsignedIntegerType + "(" + simpleTypeReference.getSizeInBits() + ", logical_name=\"" + logicalName + "\"";
case INT:
String integerType;
if (simpleTypeReference.getSizeInBits() <= 8) {
@@ -839,10 +839,10 @@ public String getReadBufferReadMethodCall(String logicalName, SimpleTypeReferenc
} else {
integerType = "long";
}
- return "read_buffer.read_" + integerType + "(" + simpleTypeReference.getSizeInBits() + ", logical_name=\"" + logicalName + "\")";
+ return "read_buffer.read_" + integerType + "(" + simpleTypeReference.getSizeInBits() + ", logical_name=\"" + logicalName + "\"";
case FLOAT:
String floatType = (simpleTypeReference.getSizeInBits() <= 32) ? "float" : "double";
- return "read_buffer.read_" + floatType + "(" + simpleTypeReference.getSizeInBits() + ", logical_name=\"" + logicalName + "\")";
+ return "read_buffer.read_" + floatType + "(" + simpleTypeReference.getSizeInBits() + ", logical_name=\"" + logicalName + "\"";
case STRING:
case VSTRING:
String stringType = "str";
@@ -856,7 +856,7 @@ public String getReadBufferReadMethodCall(String logicalName, SimpleTypeReferenc
VstringTypeReference vstringTypeReference = (VstringTypeReference) simpleTypeReference;
length = toParseExpression(field, INT_TYPE_REFERENCE, vstringTypeReference.getLengthExpression(), null);
}
- return "read_buffer.read_" + stringType + "(" + simpleTypeReference.getSizeInBits() + ", logical_name=\"" + logicalName + "\", encoding=" + "\"\")";
+ return "read_buffer.read_" + stringType + "(" + simpleTypeReference.getSizeInBits() + ", logical_name=\"" + logicalName + "\"";
default:
return "";
@@ -895,7 +895,8 @@ public String getWriteBufferWriteMethodCall(String logicalName, SimpleTypeRefere
case BIT:
return "write_buffer.write_bit(" + fieldName + ", \"" + logicalName + "\"" + writerArgsString + ")";
case BYTE:
- return "write_buffer.write_byte(" + fieldName + ", \"" + logicalName + "\"" + writerArgsString + ")";
+ ByteTypeReference byteTypeReference = (ByteTypeReference) simpleTypeReference;
+ return "write_buffer.write_byte(" + fieldName + ", " + byteTypeReference.getSizeInBits() + ", \"" + logicalName + "\"" + writerArgsString + ")";
case UINT:
IntegerTypeReference unsignedIntegerTypeReference = (IntegerTypeReference) simpleTypeReference;
if (unsignedIntegerTypeReference.getSizeInBits() <= 8) {
@@ -945,7 +946,7 @@ public String getWriteBufferWriteMethodCall(String logicalName, SimpleTypeRefere
.orElseThrow(() -> new FreemarkerException("Encoding must be a quoted string value")).getValue();
String length = Integer.toString(simpleTypeReference.getSizeInBits());
return "write_buffer.write_str(" + fieldName + ", " + length + ", \"" +
- encoding + "\", \"" + logicalName + "\"" + writerArgsString + ")";
+ logicalName + "\", \"" + encoding + "\"" + writerArgsString + ")";
}
case VSTRING: {
VstringTypeReference vstringTypeReference = (VstringTypeReference) simpleTypeReference;
@@ -957,7 +958,7 @@ public String getWriteBufferWriteMethodCall(String logicalName, SimpleTypeRefere
String lengthExpression = toExpression(field, null, vstringTypeReference.getLengthExpression(), null, Collections.singletonList(new DefaultArgument("stringLength", new DefaultIntegerTypeReference(SimpleTypeReference.SimpleBaseType.INT, 32))), true, false);
String length = Integer.toString(simpleTypeReference.getSizeInBits());
return "write_buffer.write_str(" + fieldName + ", " + lengthExpression + ", \"" +
- encoding + "\", \"" + logicalName + "\"" + writerArgsString + ")";
+ logicalName + "\", \"" + encoding + "\"" + writerArgsString + ")";
}
case DATE:
case TIME:
@@ -1511,7 +1512,7 @@ else if ((variableLiteral.getChild().isPresent()) && ((ComplexTypeDefinition) th
} else if ((serializerArguments != null) && serializerArguments.stream()
.anyMatch(argument -> argument.getName().equals(variableLiteralName))) {
tracer = tracer.dive("serialization argument");
- return tracer + "self." + camelCaseToSnakeCase(variableLiteralName) +
+ return tracer + camelCaseToSnakeCase(variableLiteralName) +
variableLiteral.getChild()
.map(child -> "." + camelCaseToSnakeCase(toVariableExpression(field, typeReference, child, parserArguments, serializerArguments, serialize, suppressPointerAccess, true)))
.orElse("");
diff --git a/code-generation/language-python/src/main/resources/templates/python/complex-type-template.python.ftlh b/code-generation/language-python/src/main/resources/templates/python/complex-type-template.python.ftlh
index 626d950a536..10a98c6a29c 100644
--- a/code-generation/language-python/src/main/resources/templates/python/complex-type-template.python.ftlh
+++ b/code-generation/language-python/src/main/resources/templates/python/complex-type-template.python.ftlh
@@ -565,7 +565,7 @@ class ${type.name}<#if type.isDiscriminatedParentTypeDefinition()>#if>(<#if ty
<#if parserArgument.type.isEnumTypeReference()>
${helper.camelCaseToSnakeCase(parserArgument.name)} = ${helper.getLanguageTypeNameForTypeReference(parserArgument.type, false)}[${helper.camelCaseToSnakeCase(parserArgument.name)}]
<#elseif helper.getLanguageTypeNameForTypeReference(parserArgument.type, false) = "bool">
- <@emitImport import="from distutils.util import strtobool" />
+ <@emitImport import="from plc4py.utils.ConnectionStringHandling import strtobool" />
${helper.camelCaseToSnakeCase(parserArgument.name)} = bool(strtobool(${helper.camelCaseToSnakeCase(parserArgument.name)}))
<#else>
${helper.camelCaseToSnakeCase(parserArgument.name)} = ${helper.getLanguageTypeNameForTypeReference(parserArgument.type, false)}(${helper.camelCaseToSnakeCase(parserArgument.name)})
diff --git a/code-generation/language-python/src/main/resources/templates/python/data-io-template.python.ftlh b/code-generation/language-python/src/main/resources/templates/python/data-io-template.python.ftlh
index 029c4854085..1daeb76bcc6 100644
--- a/code-generation/language-python/src/main/resources/templates/python/data-io-template.python.ftlh
+++ b/code-generation/language-python/src/main/resources/templates/python/data-io-template.python.ftlh
@@ -89,6 +89,7 @@ class ${type.name}:
<#switch field.typeName>
<#case "array">
<#assign arrayField = field.asArrayField().orElseThrow()>
+ <#assign typedField = field.asTypedField().orElseThrow()>
<#assign elementTypeReference=arrayField.type.elementTypeReference>
# Array field (${helper.camelCaseToSnakeCase(arrayField.name)})
<#-- Only update curPos if the length expression uses it -->
@@ -103,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)})<#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(${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>))
<#-- In all other cases do we have to work with a list, that is later converted to an array -->
<#else>
@@ -118,7 +119,7 @@ class ${type.name}:
while read_buffer.get_pos() < ${helper.camelCaseToSnakeCase(arrayField.name)}_end_pos):
value.append(<@compress single_line=true>
<#if elementTypeReference.isSimpleTypeReference()>
- ${helper.getPlcValueTypeForTypeReference(elementTypeReference)}(${helper.getReadBufferReadMethodCall(elementTypeReference.asSimpleTypeReference().orElseThrow(), "", arrayField)})
+ ${helper.getPlcValueTypeForTypeReference(elementTypeReference)}(${helper.getReadBufferReadMethodCall(elementTypeReference.asSimpleTypeReference().orElseThrow(), "", arrayField)}${helper.getFieldOptions(typedField, parserArguments)}))
<#else>${elementTypeReference.asNonSimpleTypeReference().orElseThrow().name}IO.static_parse(readBuffer
<#if elementTypeReference.params.isPresent()>,
<#list elementTypeReference.params.orElseThrow() as parserArgument>
@@ -136,7 +137,7 @@ class ${type.name}:
# Terminated array
${arrayField.name}: ${helper.getNonPrimitiveLanguageTypeNameForField(arrayField)} = new LinkedList<>()
while not bool(${helper.camelCaseToSnakeCase(helper.toParseExpression(arrayField, helper.boolTypeReference, arrayField.loopExpression,parserArguments))})):
- ${helper.camelCaseToSnakeCase(arrayField.name)}.append(<#if elementTypeReference.isSimpleTypeReference()>${helper.getReadBufferReadMethodCall(elementTypeReference.asSimpleTypeReference().orElseThrow(), "", arrayField)}<#else>${elementTypeReference.asComplexTypeReference().orElseThrow().name}IO.static_parse(readBuffer<#if arrayField.params.isPresent()>, <#list arrayField.params.orElseThrow() as parserArgument>(${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(elementTypeReference, parserArgument?index), true)}) (${helper.toParseExpression(arrayField, 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(readBuffer<#if arrayField.params.isPresent()>, <#list arrayField.params.orElseThrow() as parserArgument>(${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(elementTypeReference, parserArgument?index), true)}) (${helper.toParseExpression(arrayField, parserArgument,parserArguments)})<#sep>, #sep>#list>#if>)#if>)
<#-- After parsing, update the current position, but only if it's needed -->
<#if arrayField.loopExpression.contains("curPos")>
@@ -151,9 +152,10 @@ class ${type.name}:
<#break>
<#case "const">
<#assign constField=field.asConstField().orElseThrow()>
+ <#assign typedField = field.asTypedField().orElseThrow()>
# Const Field (${helper.camelCaseToSnakeCase(constField.name)})
- ${helper.camelCaseToSnakeCase(constField.name)}: ${helper.getNonPrimitiveLanguageTypeNameForField(constField)} = ${helper.getReadBufferReadMethodCall(constField.type.asSimpleTypeReference().orElseThrow(), "", constField)}
+ ${helper.camelCaseToSnakeCase(constField.name)}: ${helper.getNonPrimitiveLanguageTypeNameForField(constField)} = ${helper.getReadBufferReadMethodCall(constField.type.asSimpleTypeReference().orElseThrow(), "", constField)}${helper.getFieldOptions(typedField, parserArguments)})
if ${helper.camelCaseToSnakeCase(constField.name)} != ${dataIoTypeDefinition.name}.${constField.name?upper_case}):
<@emitImport import="from plc4py.api.exceptions.exceptions import ParseException" />
raise ParseException("Expected constant value " + ${dataIoTypeDefinition.name}.${constField.name?upper_case} + " but got " + ${helper.camelCaseToSnakeCase(constField.name)})
@@ -164,9 +166,10 @@ class ${type.name}:
<#break>
<#case "enum">
<#assign enumField=field.asEnumField().orElseThrow()>
+ <#assign typedField = field.asTypedField().orElseThrow()>
# Enum field (${helper.camelCaseToSnakeCase(enumField.name)})
- ${helper.camelCaseToSnakeCase(enumField.name)}: ${helper.getNonPrimitiveLanguageTypeNameForField(enumField)} = ${helper.getNonPrimitiveLanguageTypeNameForField(enumField)}.enum_for_value(${helper.getReadBufferReadMethodCall(helper.getEnumBaseTypeReference(enumField.type.asSimpleTypeReference().orElseThrow()), "", enumField)})
+ ${helper.camelCaseToSnakeCase(enumField.name)}: ${helper.getNonPrimitiveLanguageTypeNameForField(enumField)} = ${helper.getNonPrimitiveLanguageTypeNameForField(enumField)}.enum_for_value(${helper.getReadBufferReadMethodCall(helper.getEnumBaseTypeReference(enumField.type.asSimpleTypeReference().orElseThrow()), "", enumField)}${helper.getFieldOptions(typedField, parserArguments)}))
<#if enumField.name == "value">
<#assign valueDefined=true>
#if>
@@ -182,22 +185,24 @@ class ${type.name}:
<#break>
<#case "reserved">
<#assign reservedField=field.asReservedField().orElseThrow()>
+ <#assign typedField = field.asTypedField().orElseThrow()>
# Reserved Field (Compartmentalized so the "reserved" variable can't leak)
- reserved: ${helper.getLanguageTypeNameForField(field)} = ${helper.getReadBufferReadMethodCall(reservedField.type.asSimpleTypeReference().orElseThrow(), "", reservedField)}
+ reserved: ${helper.getLanguageTypeNameForField(field)} = ${helper.getReadBufferReadMethodCall(reservedField.type.asSimpleTypeReference().orElseThrow(), "", reservedField)}${helper.getFieldOptions(typedField, parserArguments)})
if reserved != ${helper.getReservedValue(reservedField)}:
<@emitImport import="import logging" />
logging.warning("Expected constant value " + str(${reservedField.referenceValue}) + " but got " + str(reserved) + " for reserved field.")
<#break>
<#case "simple">
<#assign simpleField=field.asSimpleField().orElseThrow()>
+ <#assign typedField = field.asTypedField().orElseThrow()>
<#if helper.isEnumField(simpleField)>
# Enum field (${simpleField.name})
- ${helper.camelCaseToSnakeCase(simpleField.name)}: ${helper.getNonPrimitiveLanguageTypeNameForField(simpleField)} = ${helper.getNonPrimitiveLanguageTypeNameForField(simpleField)}(${helper.getReadBufferReadMethodCall(helper.getEnumBaseTypeReference(simpleField.type), "", simpleField)})
+ ${helper.camelCaseToSnakeCase(simpleField.name)}: ${helper.getNonPrimitiveLanguageTypeNameForField(simpleField)} = ${helper.getNonPrimitiveLanguageTypeNameForField(simpleField)}(${helper.getReadBufferReadMethodCall(helper.getEnumBaseTypeReference(simpleField.type), "", simpleField)}${helper.getFieldOptions(typedField, parserArguments)}))
<#else>
# Simple Field (${simpleField.name})
- ${helper.camelCaseToSnakeCase(simpleField.name)}: ${helper.getNonPrimitiveLanguageTypeNameForField(simpleField)} = <#if simpleField.type.isSimpleTypeReference()>${helper.getReadBufferReadMethodCall(simpleField.type.asSimpleTypeReference().orElseThrow(), "", simpleField)}<#else>${simpleField.type.asComplexTypeReference().orElseThrow().name}IO.staticParse(readBuffer<#if simpleField.params.isPresent()>, <#list field.params.orElseThrow() as parserArgument>${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(simpleField.type, parserArgument?index), true)}(${helper.toParseExpression(simpleField, simpleField.type, parserArgument,parserArguments)})<#sep>, #sep>#list>#if>)#if>
+ ${helper.camelCaseToSnakeCase(simpleField.name)}: ${helper.getNonPrimitiveLanguageTypeNameForField(simpleField)} = <#if simpleField.type.isSimpleTypeReference()>${helper.getReadBufferReadMethodCall(simpleField.type.asSimpleTypeReference().orElseThrow(), "", simpleField)}${helper.getFieldOptions(typedField, parserArguments)})<#else>${simpleField.type.asComplexTypeReference().orElseThrow().name}IO.staticParse(readBuffer<#if simpleField.params.isPresent()>, <#list field.params.orElseThrow() as parserArgument>${helper.getLanguageTypeNameForTypeReference(helper.getArgumentType(simpleField.type, parserArgument?index), true)}(${helper.toParseExpression(simpleField, simpleField.type, parserArgument,parserArguments)})<#sep>, #sep>#list>#if>${helper.getFieldOptions(typedField, parserArguments)})#if>
#if>
<#if case.name == "Struct" ||
((case.name == "DATE_AND_TIME") && ((simpleField.name == "year") || (simpleField.name == "month") || (simpleField.name == "day") || (simpleField.name == "hour") || (simpleField.name == "minutes") || (simpleField.name == "seconds"))) ||
@@ -289,7 +294,8 @@ class ${type.name}:
<#break>
<#case "DATE">
<#if helper.hasFieldsWithNames(case.fields, "year", "month", "day")>
- value: LocalDate = LocalDate(int(year), (month == 0) ? 1 : int(month), (day == 0) ? 1 : int(day))
+ <@emitImport import="import datetime" />
+ value: datetime = datetime.datetime(int(year), int(month), int(day))
#if>
<@emitImport import="from plc4py.spi.values.PlcValues import PlcDATE" />
return PlcDATE(value)
@@ -304,12 +310,10 @@ class ${type.name}:
return PlcTIME_OF_DAY(value)
<#break>
<#case "DATE_AND_TIME">
- <#if helper.hasFieldsWithNames(case.fields, "year", "month", "day", "hour", "minutes", "seconds", "nanos")>
- value: LocalDateTime = LocalDateTime(int(year), (month == 0) ? 1 : int(month), (day == 0) ? 1 : int(day), int(hour), int(minutes), int(seconds), int(nanos))
+ <#if helper.hasFieldsWithNames(case.fields, "year", "month", "day", "hour", "minutes", "seconds", "microseconds")>
+ value: datetime = datetime.datetime(int(year), int(month), int(day), int(hour), int(minutes), int(seconds), int(microseconds))
<#elseif helper.hasFieldsWithNames(case.fields, "year", "month", "day", "hour", "minutes", "seconds")>
- value: LocalDateTime = LocalDateTime(int(year), (month == 0) ? 1 : int(month), (day == 0) ? 1 : int(day), int(hour), int(minutes), int(seconds))
- <#elseif helper.hasFieldsWithNames(case.fields, "secondsSinceEpoch")>
- value: LocalDateTime = LocalDateTime.ofEpochSecond(secondsSinceEpoch, 0, ZoneOffset.UTC)
+ value: datetime = datetime.datetime(int(year), int(month), int(day), int(hour), int(minutes), int(seconds))
#if>
<@emitImport import="from plc4py.spi.values.PlcValues import PlcDATE_AND_TIME" />
return PlcDATE_AND_TIME(value)
@@ -368,7 +372,7 @@ class ${type.name}:
for val in values.getStruct().get("${arrayField.name}").get_list():
<#if elementTypeReference.isByteBased()>
value: ${helper.getLanguageTypeNameForField(arrayField)} = val.get_raw()
- write_buffer.write_byte_array("", value)
+ write_buffer.write_byte(value, 8, "")
<#else>
value: ${helper.getLanguageTypeNameForField(arrayField)} = val.get_${helper.camelCaseToSnakeCase(helper.getLanguageTypeNameForField(arrayField)?cap_first)}()
${helper.getWriteBufferWriteMethodCall(elementTypeReference.asSimpleTypeReference().orElseThrow(), "value", arrayField)}
@@ -378,7 +382,7 @@ class ${type.name}:
<#if elementTypeReference.isByteBased()>
<@emitImport import="from typing import List" />
value: ${helper.getLanguageTypeNameForField(arrayField)} = val.get_raw()
- write_buffer.write_byte_array("", value)
+ write_buffer.write_byte(value, 8, "")
<#else>
value: ${helper.getLanguageTypeNameForTypeReference(elementTypeReference)} = val.get_${helper.camelCaseToSnakeCase(helper.getLanguageTypeNameForTypeReference(elementTypeReference)?cap_first)}()
${helper.getWriteBufferWriteMethodCall(elementTypeReference.asSimpleTypeReference().orElseThrow(), "(" + arrayField.name + ")", arrayField)}
@@ -406,7 +410,9 @@ class ${type.name}:
<#case "manual">
<#assign manualField=field.asManualField().orElseThrow()>
# Manual Field (${manualField.name})
- ${helper.toSerializationExpression(manualField, manualField.type, manualField.serializeExpression, type.parserArguments.orElse(null))}
+ <@emitImport import="from plc4py.protocols.${protocolName} import StaticHelper" />
+ value: PlcValue = _value
+ StaticHelper.${helper.toSerializationExpression(manualField, manualField.type, manualField.serializeExpression, type.parserArguments.orElse(null))}
<#break>
<#case "reserved">
diff --git a/code-generation/language-python/src/test/resources/plc4py/pom.xml b/code-generation/language-python/src/test/resources/plc4py/pom.xml
index 059fea2df21..f9b131f540b 100644
--- a/code-generation/language-python/src/test/resources/plc4py/pom.xml
+++ b/code-generation/language-python/src/test/resources/plc4py/pom.xml
@@ -53,7 +53,7 @@
.
${project.basedir}/../../../../../plc4py/
- setup.*
+ pyproject.toml
true
@@ -219,35 +219,36 @@
- python-black
+ python-test-compile
process-sources
exec
- ${python.venv.bin}${python.exe.bin}
+ ${python.venv.bin}pip3
- -m
- black
- .
+ install
+ .[dev]
- python-test-compile
- test-compile
+ python-black
+ process-sources
exec
- ${python.venv.bin}pip3
+ ${python.venv.bin}${python.exe.bin}
- install
- .[dev]
+ -m
+ black
+ .
+
diff --git a/plc4py/plc4py/api/messages/PlcResponse.py b/plc4py/plc4py/api/messages/PlcResponse.py
index 807dba5d43d..f61457bd965 100644
--- a/plc4py/plc4py/api/messages/PlcResponse.py
+++ b/plc4py/plc4py/api/messages/PlcResponse.py
@@ -22,7 +22,7 @@
from plc4py.api.messages.PlcField import PlcTag
from plc4py.api.messages.PlcMessage import PlcMessage
from plc4py.api.value.PlcValue import PlcResponseCode, PlcValue
-from plc4py.spi.messages.utils.ResponseItem import ResponseItem
+from plc4py.spi.messages.utils.ResponseItem import ResponseItem, PlcBrowseItem
@dataclass
@@ -75,7 +75,7 @@ class PlcWriteResponse(PlcTagResponse):
@dataclass
class PlcQueryResponse(PlcResponse):
- tags: Dict[str, List[ResponseItem[PlcTag]]]
+ tags: Dict[str, List[PlcBrowseItem[PlcTag]]]
@property
def tag_names(self):
@@ -84,5 +84,6 @@ def tag_names(self):
@dataclass
class PlcBrowseResponse(PlcQueryResponse):
- def get_tags(self) -> Dict[str, List[ResponseItem[PlcTag]]]:
+
+ def get_tags(self) -> Dict[str, List[PlcBrowseItem[PlcTag]]]:
return self.tags
diff --git a/plc4py/plc4py/drivers/modbus/ModbusConnection.py b/plc4py/plc4py/drivers/modbus/ModbusConnection.py
index d12b437f6a3..dc915464010 100644
--- a/plc4py/plc4py/drivers/modbus/ModbusConnection.py
+++ b/plc4py/plc4py/drivers/modbus/ModbusConnection.py
@@ -104,7 +104,7 @@ async def create(url: str) -> "ModbusConnection":
host=config.host,
port=config.port,
),
- 10,
+ 15,
)
except asyncio.TimeoutError:
# If the creation times out, cancel the Future
diff --git a/plc4py/plc4py/drivers/modbus/ModbusDevice.py b/plc4py/plc4py/drivers/modbus/ModbusDevice.py
index b52993027ad..056d3798bd2 100644
--- a/plc4py/plc4py/drivers/modbus/ModbusDevice.py
+++ b/plc4py/plc4py/drivers/modbus/ModbusDevice.py
@@ -209,6 +209,7 @@ async def write(
message_future = loop.create_future()
values = request.values[request.tag_names[0]]
if isinstance(tag, ModbusTagCoil):
+ values = self._serialize_data_items(tag, values)
pdu = ModbusPDUWriteMultipleCoilsRequest(tag.address, tag.quantity, values)
elif isinstance(tag, ModbusTagDiscreteInput):
raise PlcRuntimeException(
diff --git a/plc4py/plc4py/drivers/umas/UmasConnection.py b/plc4py/plc4py/drivers/umas/UmasConnection.py
index 4257b3c3d24..ca71a6faf90 100644
--- a/plc4py/plc4py/drivers/umas/UmasConnection.py
+++ b/plc4py/plc4py/drivers/umas/UmasConnection.py
@@ -29,6 +29,8 @@
PlcReadRequest,
PlcRequest,
ReadRequestBuilder,
+ WriteRequestBuilder,
+ PlcWriteRequest,
)
from plc4py.api.messages.PlcResponse import (
PlcResponse,
@@ -46,12 +48,16 @@
from plc4py.spi.messages.PlcRequest import (
DefaultBrowseRequestBuilder,
DefaultReadRequestBuilder,
+ DefaultWriteRequestBuilder,
)
from plc4py.spi.transport.Plc4xBaseTransport import Plc4xBaseTransport
from plc4py.spi.transport.TCPTransport import TCPTransport
+from plc4py.spi.messages.PlcWriter import DefaultPlcWriter
-class UmasConnection(PlcConnection, DefaultPlcReader, DefaultPlcBrowser):
+class UmasConnection(
+ PlcConnection, DefaultPlcReader, DefaultPlcWriter, DefaultPlcBrowser
+):
"""
Umas TCP PLC connection implementation
"""
@@ -115,6 +121,12 @@ def read_request_builder(self) -> ReadRequestBuilder:
"""
return DefaultReadRequestBuilder(UmasTagBuilder)
+ def write_request_builder(self) -> WriteRequestBuilder:
+ """
+ :return: write request builder.
+ """
+ return DefaultWriteRequestBuilder(UmasTagBuilder)
+
def browse_request_builder(self) -> BrowseRequestBuilder:
"""
:return: browse request builder.
@@ -133,6 +145,9 @@ async def execute(self, request: PlcRequest) -> PlcResponse:
if isinstance(request, PlcReadRequest):
return await self._read(request)
+ if isinstance(request, PlcWriteRequest):
+ return await self._write(request)
+
if isinstance(request, PlcBrowseRequest):
return await self._browse(request)
diff --git a/plc4py/plc4py/drivers/umas/UmasDevice.py b/plc4py/plc4py/drivers/umas/UmasDevice.py
index 5eb104143e5..cb3ad770759 100644
--- a/plc4py/plc4py/drivers/umas/UmasDevice.py
+++ b/plc4py/plc4py/drivers/umas/UmasDevice.py
@@ -19,8 +19,11 @@
import asyncio
from asyncio import AbstractEventLoop, Transport
from dataclasses import dataclass, field
+from logging import raiseExceptions
from typing import Dict, List, Tuple, cast
+from plc4py.drivers.umas.UmasVariables import UmasCustomVariable, UmasArrayVariable
+from plc4py.api.exceptions.exceptions import PlcFieldParseException, PlcRuntimeException
from plc4py.api.messages.PlcRequest import (
PlcBrowseRequest,
PlcReadRequest,
@@ -33,8 +36,12 @@
)
from plc4py.api.value.PlcValue import PlcResponseCode, PlcValue
from plc4py.drivers.umas.UmasConfiguration import UmasConfiguration
-from plc4py.drivers.umas.UmasTag import UmasTag
-from plc4py.drivers.umas.UmasVariables import UmasVariable, UmasVariableBuilder
+from plc4py.drivers.umas.UmasTag import UmasTag, UmasTagBuilder
+from plc4py.drivers.umas.UmasVariables import (
+ UmasVariable,
+ UmasVariableBuilder,
+ UmasElementryVariable,
+)
from plc4py.protocols.umas.readwrite import (
UmasPDUReadUnlocatedVariableResponse,
)
@@ -98,8 +105,23 @@
VariableReadRequestReference,
)
from plc4py.spi.generation.ReadBuffer import ReadBufferByteBased
-from plc4py.spi.messages.utils.ResponseItem import ResponseItem
+from plc4py.spi.messages.utils.ResponseItem import (
+ ResponseItem,
+ PlcBrowseItem,
+ ArrayInfo,
+)
from plc4py.utils.GenericTypes import ByteOrder
+from plc4py.protocols.umas.readwrite.UmasPDUWriteVariableRequest import (
+ UmasPDUWriteVariableRequestBuilder,
+)
+from plc4py.protocols.umas.readwrite.UmasPDUWriteVariableResponse import (
+ UmasPDUWriteVariableResponse,
+)
+from plc4py.protocols.umas.readwrite.VariableWriteRequestReference import (
+ VariableWriteRequestReference,
+)
+from plc4py.spi.values.PlcValues import PlcNull
+from plc4py.protocols.umas.readwrite.UmasDataType import UmasDataType
@dataclass
@@ -171,7 +193,7 @@ def _generate_variable_tree(
return_dict = {}
for kea, tag in tags.items():
temp_variable = UmasVariableBuilder(
- kea, tag, data_types, data_type_children, base_offset=tag.base_offset
+ kea, tag, data_types, data_type_children, base_offset=0
).build()
if temp_variable is not None:
return_dict[kea] = temp_variable
@@ -403,9 +425,15 @@ async def _send_read_variable_request(
else:
quantity = 1
+ if request_tag.data_type == None:
+ data_type = UmasDataType(self.variables[request_tag.tag_name].data_type)
+ else:
+ data_type = UmasDataType[request_tag.data_type]
+
+ value = DataItem.static_parse(read_buffer, data_type, request_tag.quantity)
response_item = ResponseItem(
PlcResponseCode.OK,
- DataItem.static_parse(read_buffer, request_tag.data_type, quantity),
+ value,
)
values[key] = response_item
@@ -413,6 +441,78 @@ async def _send_read_variable_request(
response = PlcReadResponse(PlcResponseCode.OK, values)
return response
+ async def _send_write_variable_request(
+ self,
+ transport: Transport,
+ loop: AbstractEventLoop,
+ request,
+ sorted_tags,
+ ):
+ message_future = loop.create_future()
+
+ sorted_variable_list: List[VariableWriteRequestReference] = [
+ variable_reference[1] for variable_reference in sorted_tags
+ ]
+ request_pdu = UmasPDUWriteVariableRequestBuilder(
+ crc=self.project_crc,
+ variable_count=len(sorted_variable_list),
+ variables=sorted_variable_list,
+ ).build(0, 0)
+
+ protocol = transport.protocol
+ protocol.write_wait_for_response(
+ request_pdu,
+ transport,
+ message_future,
+ )
+
+ await message_future
+ variable_name_response: UmasPDUWriteVariableResponse = message_future.result()
+
+ values: Dict[str, ResponseItem[PlcValue]] = {}
+ for key, tag in sorted_tags:
+ if variable_name_response.umas_request_function_key != 254:
+ response_item = ResponseItem(
+ PlcResponseCode.OK,
+ PlcNull(None),
+ )
+ else:
+ response_item = ResponseItem(
+ PlcResponseCode.REMOTE_ERROR,
+ PlcNull(None),
+ )
+
+ values[key] = response_item
+
+ response = PlcReadResponse(PlcResponseCode.OK, values)
+ return response
+
+ def _get_internal_words(self, tag) -> UmasElementryVariable:
+ system_word_block = 0x002B
+ area = tag[1:3].upper()
+ if area == "SW":
+ area_offset = 80
+ word_number = (int(tag[3:]) * 2) + area_offset
+ data_type = UmasDataType.INT.value
+ base_offset = word_number // 0x100
+ offset = word_number % 0x100
+ return UmasElementryVariable(
+ tag, data_type, system_word_block, base_offset, offset
+ )
+
+ area = tag[1:2].upper()
+ if area == "S":
+ area_offset = 50
+ word_number = (int(tag[3:]) * 2) + area_offset
+ data_type = UmasDataType.BOOL.value
+ base_offset = word_number // 0x100
+ offset = word_number % 0x100
+ return UmasElementryVariable(
+ tag, data_type, system_word_block, base_offset, offset
+ )
+ else:
+ raise PlcFieldParseException("Unable to read non system addresses")
+
def _sort_tags_based_on_memory_address(self, request):
tag_list: List[List[Tuple[str, VariableReadRequestReference]]] = [[]]
current_list_index = 0
@@ -421,7 +521,10 @@ def _sort_tags_based_on_memory_address(self, request):
for kea, tag in request.tags.items():
umas_tag = cast(UmasTag, tag)
base_tag_name = umas_tag.tag_name.split(".")[0]
- variable = self.variables[base_tag_name]
+ if base_tag_name[:1] != "%":
+ variable = self.variables[base_tag_name]
+ else:
+ variable = self._get_internal_words(base_tag_name)
if byte_count + variable.get_byte_length() > self.max_frame_size:
current_list_index += 1
@@ -432,7 +535,7 @@ def _sort_tags_based_on_memory_address(self, request):
current_list.append(
(
kea,
- variable.get_variable_reference(umas_tag.tag_name),
+ variable.get_read_variable_reference(umas_tag.tag_name),
)
)
@@ -446,6 +549,44 @@ def _sort_tags_based_on_memory_address(self, request):
return sorted_tag_lists
+ def _sort_write_tags_based_on_memory_address(self, request):
+ tag_list: List[List[Tuple[str, VariableWriteRequestReference]]] = [[]]
+ current_list_index = 0
+ current_list = tag_list[current_list_index]
+ byte_count: int = 0
+ for kea, tag in request.tags.items():
+ umas_tag = cast(UmasTag, tag)
+ base_tag_name = umas_tag.tag_name.split(".")[0]
+ if base_tag_name[:1] != "%":
+ variable = self.variables[base_tag_name]
+ else:
+ variable = self._get_internal_words(base_tag_name)
+
+ if byte_count + variable.get_byte_length() > self.max_frame_size:
+ current_list_index += 1
+ tag_list.append([])
+ current_list = tag_list[current_list_index]
+ byte_count = 0
+ byte_count += variable.get_byte_length() + variable.data_type
+ current_list.append(
+ (
+ kea,
+ variable.get_write_variable_reference(
+ umas_tag.tag_name, request.values[kea]
+ ),
+ )
+ )
+
+ sorted_tag_lists: List[List[Tuple[str, VariableWriteRequestReference]]] = []
+ for request in tag_list:
+ sorted_tags = sorted(
+ request,
+ key=lambda x: (x[1].block * 100000) + x[1].base_offset + x[1].offset,
+ )
+ sorted_tag_lists.append(sorted_tags)
+
+ return sorted_tag_lists
+
async def read(
self, request: PlcReadRequest, transport: Transport
) -> PlcReadResponse:
@@ -470,7 +611,77 @@ async def write(
"""
Writes one field from the UMAS Device
"""
- pass
+ loop = asyncio.get_running_loop()
+ await self._update_plc_project_info(transport, loop)
+ sorted_tag_list = self._sort_write_tags_based_on_memory_address(request)
+ response = PlcWriteResponse(PlcResponseCode.OK, {})
+ for sorted_tags in sorted_tag_list:
+ response_chunk = await self._send_write_variable_request(
+ transport, loop, request, sorted_tags
+ )
+ response.code = response_chunk.response_code
+ response.tags = {**response.tags, **response_chunk.tags}
+ return response
+
+ def generate_browse_tree(self, tag) -> PlcBrowseItem[UmasTag]:
+ builder = UmasTagBuilder()
+ if isinstance(tag, UmasElementryVariable):
+ plc_tag = builder.create(
+ tag.variable_name
+ + ":"
+ + str(UmasDataType(tag.data_type).data_type_conversion)
+ )
+
+ return PlcBrowseItem[UmasTag](
+ plc_tag, tag.variable_name, True, True, False, False, False
+ )
+
+ elif isinstance(tag, UmasCustomVariable):
+ plc_tag = builder.create(tag.variable_name)
+ children: Dict[str, "PlcBrowseItem"] = {}
+ for tag_name, child in tag.children.items():
+ children[tag_name] = self.generate_browse_tree(child)
+ return PlcBrowseItem[UmasTag](
+ plc_tag,
+ tag.variable_name,
+ True,
+ True,
+ False,
+ False,
+ False,
+ [],
+ children,
+ )
+ elif isinstance(tag, UmasArrayVariable):
+ plc_tag = builder.create(
+ tag.variable_name
+ + ":"
+ + str(UmasDataType(tag.data_type).data_type_conversion)
+ + "["
+ + str(tag.end_index)
+ + "]"
+ )
+
+ return PlcBrowseItem[UmasTag](
+ plc_tag,
+ tag.variable_name,
+ True,
+ True,
+ False,
+ False,
+ True,
+ [
+ ArrayInfo(
+ tag.end_index - tag.start_index + 1,
+ tag.start_index,
+ tag.end_index,
+ )
+ ],
+ )
+ else:
+ raise PlcRuntimeException(
+ f"Variable of type {type(tag).__name__} is not supported"
+ )
async def browse(
self, request: PlcBrowseRequest, transport: Transport
@@ -481,9 +692,9 @@ async def browse(
loop = asyncio.get_running_loop()
await self._update_plc_project_info(transport, loop)
response_items = {}
+
for key, query in request.queries.items():
- response_items[key] = [
- ResponseItem[UmasTag](PlcResponseCode.OK, tag)
- for tag in self.variables.values()
- ]
+ response_items[key] = []
+ for tag in self.variables.values():
+ response_items[key].append(self.generate_browse_tree(tag))
return PlcBrowseResponse(PlcResponseCode.OK, response_items)
diff --git a/plc4py/plc4py/drivers/umas/UmasTag.py b/plc4py/plc4py/drivers/umas/UmasTag.py
index 480a41dc85a..69ab09202b0 100644
--- a/plc4py/plc4py/drivers/umas/UmasTag.py
+++ b/plc4py/plc4py/drivers/umas/UmasTag.py
@@ -27,7 +27,7 @@
class UmasTag(PlcTag):
_ADDRESS_PATTERN: str = (
- "^(?P[%a-zA-Z_.0-9]+\\[?[0-9]*]?):?(?P[A-Z]*):?(?P[0-9]*)"
+ "^(?P[%a-zA-Z_.0-9]+):?(?P[A-Z_]*)(\[(?P[0-9]*)\])?"
)
_ADDRESS_COMPILED: Pattern[AnyStr] = re.compile(_ADDRESS_PATTERN)
@@ -36,7 +36,7 @@ class UmasTag(PlcTag):
def __init__(self, tag_name: str, quantity: int, data_type: UmasDataType):
self.tag_name: str = tag_name
self.quantity: int = quantity
- self.data_type: UmasDataType = data_type
+ self.data_type: str = data_type
@classmethod
def matches(cls, address_string: str):
@@ -60,11 +60,11 @@ def create(cls, address_string):
else 1
)
data_type = (
- UmasDataType[matcher.group("dataType")]
+ matcher.group("dataType")
if "dataType" in matcher.groupdict()
and matcher.group("dataType") is not None
and len(matcher.group("dataType")) is not 0
- else cls._DEFAULT_DATA_TYPE
+ else None
)
return cls(tag_name, quantity, data_type)
diff --git a/plc4py/plc4py/drivers/umas/UmasVariables.py b/plc4py/plc4py/drivers/umas/UmasVariables.py
index 421173bee33..8a22194eaf7 100644
--- a/plc4py/plc4py/drivers/umas/UmasVariables.py
+++ b/plc4py/plc4py/drivers/umas/UmasVariables.py
@@ -20,6 +20,7 @@
from dataclasses import dataclass
from typing import AnyStr, Dict, List, Pattern, Union
+from plc4py.api.value.PlcValue import PlcValue
from plc4py.api.exceptions.exceptions import PlcDataTypeNotFoundException
from plc4py.protocols.umas.readwrite.UmasDataType import UmasDataType
from plc4py.protocols.umas.readwrite.UmasDatatypeReference import (
@@ -32,6 +33,12 @@
from plc4py.protocols.umas.readwrite.VariableReadRequestReference import (
VariableReadRequestReference,
)
+from plc4py.protocols.umas.readwrite.VariableWriteRequestReference import (
+ VariableWriteRequestReference,
+)
+from plc4py.protocols.umas.readwrite.DataItem import DataItem
+from plc4py.spi.generation.WriteBuffer import WriteBufferByteBased
+from plc4py.utils.GenericTypes import ByteOrder
@dataclass
@@ -42,7 +49,14 @@ class UmasVariable:
base_offset: int
offset: int
- def get_variable_reference(self, address: str) -> VariableReadRequestReference:
+ def get_read_variable_reference(self, address: str) -> VariableReadRequestReference:
+ raise NotImplementedError(
+ f"UmasVariable subclass not implemented for variable {self.variable_name}"
+ )
+
+ def get_write_variable_reference(
+ self, address: str, value: PlcValue
+ ) -> VariableWriteRequestReference:
raise NotImplementedError(
f"UmasVariable subclass not implemented for variable {self.variable_name}"
)
@@ -55,14 +69,16 @@ def get_byte_length(self) -> int:
@dataclass
class UmasElementryVariable(UmasVariable):
- def get_variable_reference(self, address: str) -> VariableReadRequestReference:
+ def get_read_variable_reference(self, address: str) -> VariableReadRequestReference:
+ base_offset = self.base_offset + (self.offset // 0x100)
+ offset = self.offset % 0x100
if self.data_type == UmasDataType.STRING.value:
return VariableReadRequestReference(
is_array=1,
data_size_index=UmasDataType(self.data_type).request_size,
block=self.block_no,
- base_offset=self.base_offset,
- offset=self.offset,
+ base_offset=base_offset,
+ offset=offset,
array_length=16,
)
else:
@@ -70,9 +86,43 @@ def get_variable_reference(self, address: str) -> VariableReadRequestReference:
is_array=0,
data_size_index=UmasDataType(self.data_type).request_size,
block=self.block_no,
- base_offset=self.base_offset,
- offset=self.offset,
+ base_offset=base_offset,
+ offset=offset,
+ array_length=None,
+ )
+
+ def get_write_variable_reference(
+ self, address: str, value: PlcValue
+ ) -> VariableWriteRequestReference:
+ write_buffer = WriteBufferByteBased(
+ UmasDataType(self.data_type).data_type_size, ByteOrder.LITTLE_ENDIAN
+ )
+ DataItem.static_serialize(
+ write_buffer,
+ value,
+ UmasDataType(self.data_type),
+ 1,
+ ByteOrder.LITTLE_ENDIAN,
+ )
+ if self.data_type == UmasDataType.STRING.value:
+ return VariableWriteRequestReference(
+ is_array=1,
+ data_size_index=1,
+ block=self.block_no,
+ base_offset=self.offset,
+ offset=self.base_offset,
+ array_length=len(value.value),
+ record_data=bytearray(write_buffer.bb),
+ )
+ else:
+ return VariableWriteRequestReference(
+ is_array=0,
+ data_size_index=UmasDataType(self.data_type).request_size,
+ block=self.block_no,
+ base_offset=self.offset,
+ offset=self.base_offset,
array_length=None,
+ record_data=bytearray(write_buffer.bb),
)
def get_byte_length(self) -> int:
@@ -83,17 +133,30 @@ def get_byte_length(self) -> int:
class UmasCustomVariable(UmasVariable):
children: Dict[str, UmasVariable]
- def get_variable_reference(self, address: str) -> VariableReadRequestReference:
+ def get_read_variable_reference(self, address: str) -> VariableReadRequestReference:
split_tag_address: List[str] = address.split(".")
child_index = None
if len(split_tag_address) > 1:
child_index = split_tag_address[1]
- return self.children[child_index].get_variable_reference(
+ return self.children[child_index].get_read_variable_reference(
".".join(split_tag_address[1:])
)
else:
raise NotImplementedError("Unable to read structures of UDT's")
+ def get_write_variable_reference(
+ self, address: str, value: PlcValue
+ ) -> VariableWriteRequestReference:
+ split_tag_address: List[str] = address.split(".")
+ child_index = None
+ if len(split_tag_address) > 1:
+ child_index = split_tag_address[1]
+ return self.children[child_index].get_write_variable_reference(
+ ".".join(split_tag_address[1:]), value
+ )
+ else:
+ raise NotImplementedError("Unable to write structures of UDT's")
+
def get_byte_length(self) -> int:
byte_count = 0
for key, child in self.children.items():
@@ -106,7 +169,7 @@ class UmasArrayVariable(UmasVariable):
start_index: int
end_index: int
- def get_variable_reference(self, address: str) -> VariableReadRequestReference:
+ def get_read_variable_reference(self, address: str) -> VariableReadRequestReference:
split_tag_address: List[str] = address.split(".")
address_index = None
if len(split_tag_address) > 1:
@@ -132,6 +195,60 @@ def get_variable_reference(self, address: str) -> VariableReadRequestReference:
array_length=self.end_index - self.start_index + 1,
)
+ def get_write_variable_reference(
+ self, address: str, value: PlcValue
+ ) -> VariableWriteRequestReference:
+ split_tag_address: List[str] = address.split(".")
+ address_index = None
+ if len(split_tag_address) > 1:
+ address_index = int(split_tag_address[1])
+ data_type_enum = UmasDataType(self.data_type)
+
+ if address_index:
+ write_buffer = WriteBufferByteBased(
+ UmasDataType(self.data_type).data_type_size * address_index,
+ ByteOrder.LITTLE_ENDIAN,
+ )
+ DataItem.static_serialize(
+ write_buffer,
+ value,
+ UmasDataType(self.data_type),
+ address_index,
+ ByteOrder.LITTLE_ENDIAN,
+ )
+ return VariableWriteRequestReference(
+ is_array=0,
+ data_size_index=data_type_enum.request_size,
+ block=self.block_no,
+ base_offset=self.base_offset,
+ offset=self.offset
+ + (address_index - self.start_index) * data_type_enum.data_type_size,
+ array_length=address_index,
+ record_data=bytearray(write_buffer.bb),
+ )
+ else:
+ write_buffer = WriteBufferByteBased(
+ UmasDataType(self.data_type).data_type_size
+ * (self.end_index - self.start_index + 1),
+ ByteOrder.LITTLE_ENDIAN,
+ )
+ DataItem.static_serialize(
+ write_buffer,
+ value,
+ UmasDataType(self.data_type),
+ self.end_index - self.start_index + 1,
+ ByteOrder.LITTLE_ENDIAN,
+ )
+ return VariableWriteRequestReference(
+ is_array=1,
+ data_size_index=data_type_enum.request_size,
+ block=self.block_no,
+ base_offset=self.base_offset,
+ offset=self.offset,
+ array_length=self.end_index - self.start_index + 1,
+ record_data=bytearray(write_buffer.bb),
+ )
+
def get_byte_length(self) -> int:
return 9
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/DataItem.py b/plc4py/plc4py/protocols/modbus/readwrite/DataItem.py
index 2eec7384365..50fbafeefa1 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/DataItem.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/DataItem.py
@@ -425,7 +425,7 @@ def static_parse(
if data_type == ModbusDataType.CHAR and number_of_values == int(1): # CHAR
# Simple Field (value)
- value: str = read_buffer.read_str(8, logical_name="", encoding="")
+ value: str = read_buffer.read_str(8, logical_name="", encoding='"UTF-8"')
return PlcCHAR(value)
if data_type == ModbusDataType.CHAR: # List
@@ -436,7 +436,9 @@ def static_parse(
for _ in range(item_count):
value.append(
PlcSTRING(
- str(read_buffer.read_str(8, logical_name="", encoding=""))
+ str(
+ read_buffer.read_str(8, logical_name="", encoding='"UTF-8"')
+ )
)
)
@@ -444,7 +446,7 @@ def static_parse(
if data_type == ModbusDataType.WCHAR and number_of_values == int(1): # WCHAR
# Simple Field (value)
- value: str = read_buffer.read_str(16, logical_name="", encoding="")
+ value: str = read_buffer.read_str(16, logical_name="", encoding='"UTF-16"')
return PlcWCHAR(value)
if data_type == ModbusDataType.WCHAR: # List
@@ -455,7 +457,11 @@ def static_parse(
for _ in range(item_count):
value.append(
PlcSTRING(
- str(read_buffer.read_str(16, logical_name="", encoding=""))
+ str(
+ read_buffer.read_str(
+ 16, logical_name="", encoding='"UTF-16"'
+ )
+ )
)
)
@@ -691,24 +697,24 @@ def static_serialize(
elif data_type == ModbusDataType.CHAR and number_of_values == int(1): # CHAR
# Simple Field (value)
value: str = _value.get_str()
- write_buffer.write_str((value), 8, "UTF-8", "value")
+ write_buffer.write_str((value), 8, "value", "UTF-8")
elif data_type == ModbusDataType.CHAR: # List
values: PlcList = cast(PlcList, _value)
for val in values.get_list():
value: str = val.get_str()
- write_buffer.write_str((value), 8, "UTF-8", "value")
+ write_buffer.write_str((value), 8, "value", "UTF-8")
elif data_type == ModbusDataType.WCHAR and number_of_values == int(1): # WCHAR
# Simple Field (value)
value: str = _value.get_str()
- write_buffer.write_str((value), 16, "UTF-16", "value")
+ write_buffer.write_str((value), 16, "value", "UTF-16")
elif data_type == ModbusDataType.WCHAR: # List
values: PlcList = cast(PlcList, _value)
for val in values.get_list():
value: str = val.get_str()
- write_buffer.write_str((value), 16, "UTF-16", "value")
+ write_buffer.write_str((value), 16, "value", "UTF-16")
@staticmethod
def get_length_in_bytes(
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusADU.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusADU.py
index 7cac135246f..ec7864cbc79 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusADU.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusADU.py
@@ -21,7 +21,6 @@
from abc import ABC
from abc import abstractmethod
-from distutils.util import strtobool
from plc4py.api.exceptions.exceptions import ParseException
from plc4py.api.exceptions.exceptions import PlcRuntimeException
from plc4py.api.exceptions.exceptions import SerializationException
@@ -29,6 +28,7 @@
from plc4py.protocols.modbus.readwrite.DriverType import DriverType
from plc4py.spi.generation.ReadBuffer import ReadBuffer
from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
import math
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusAsciiADU.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusAsciiADU.py
index e18f5e9facd..8f78079ba2b 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusAsciiADU.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusAsciiADU.py
@@ -19,7 +19,6 @@
from dataclasses import dataclass
-from distutils.util import strtobool
from plc4py.api.exceptions.exceptions import PlcRuntimeException
from plc4py.api.exceptions.exceptions import SerializationException
from plc4py.api.messages.PlcMessage import PlcMessage
@@ -29,6 +28,7 @@
from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
from plc4py.spi.generation.ReadBuffer import ReadBuffer
from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
from plc4py.utils.GenericTypes import ByteOrder
from typing import ClassVar
import math
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDU.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDU.py
index d2fbad670b4..e03ec11f67e 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDU.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDU.py
@@ -21,13 +21,13 @@
from abc import ABC
from abc import abstractmethod
-from distutils.util import strtobool
from plc4py.api.exceptions.exceptions import ParseException
from plc4py.api.exceptions.exceptions import PlcRuntimeException
from plc4py.api.exceptions.exceptions import SerializationException
from plc4py.api.messages.PlcMessage import PlcMessage
from plc4py.spi.generation.ReadBuffer import ReadBuffer
from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
import math
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUDiagnosticRequest.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUDiagnosticRequest.py
index 9d8dc6ecbd6..92bab7e1f9e 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUDiagnosticRequest.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUDiagnosticRequest.py
@@ -19,13 +19,13 @@
from dataclasses import dataclass
-from distutils.util import strtobool
from plc4py.api.exceptions.exceptions import PlcRuntimeException
from plc4py.api.exceptions.exceptions import SerializationException
from plc4py.api.messages.PlcMessage import PlcMessage
from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
from plc4py.spi.generation.ReadBuffer import ReadBuffer
from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
from typing import ClassVar
import math
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUDiagnosticResponse.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUDiagnosticResponse.py
index 5644e5cbd7e..dc618192201 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUDiagnosticResponse.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUDiagnosticResponse.py
@@ -19,13 +19,13 @@
from dataclasses import dataclass
-from distutils.util import strtobool
from plc4py.api.exceptions.exceptions import PlcRuntimeException
from plc4py.api.exceptions.exceptions import SerializationException
from plc4py.api.messages.PlcMessage import PlcMessage
from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
from plc4py.spi.generation.ReadBuffer import ReadBuffer
from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
from typing import ClassVar
import math
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUError.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUError.py
index 0d0625be68b..f7a542b19b1 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUError.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUError.py
@@ -19,7 +19,6 @@
from dataclasses import dataclass
-from distutils.util import strtobool
from plc4py.api.exceptions.exceptions import PlcRuntimeException
from plc4py.api.exceptions.exceptions import SerializationException
from plc4py.api.messages.PlcMessage import PlcMessage
@@ -27,6 +26,7 @@
from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
from plc4py.spi.generation.ReadBuffer import ReadBuffer
from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
from typing import ClassVar
import math
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUGetComEventCounterRequest.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUGetComEventCounterRequest.py
index eed5c85f3ac..1a8967bbba2 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUGetComEventCounterRequest.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUGetComEventCounterRequest.py
@@ -19,13 +19,13 @@
from dataclasses import dataclass
-from distutils.util import strtobool
from plc4py.api.exceptions.exceptions import PlcRuntimeException
from plc4py.api.exceptions.exceptions import SerializationException
from plc4py.api.messages.PlcMessage import PlcMessage
from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
from plc4py.spi.generation.ReadBuffer import ReadBuffer
from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
from typing import ClassVar
import math
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUGetComEventCounterResponse.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUGetComEventCounterResponse.py
index ddb93a5e45d..0a857bb2478 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUGetComEventCounterResponse.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUGetComEventCounterResponse.py
@@ -19,13 +19,13 @@
from dataclasses import dataclass
-from distutils.util import strtobool
from plc4py.api.exceptions.exceptions import PlcRuntimeException
from plc4py.api.exceptions.exceptions import SerializationException
from plc4py.api.messages.PlcMessage import PlcMessage
from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
from plc4py.spi.generation.ReadBuffer import ReadBuffer
from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
from typing import ClassVar
import math
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUGetComEventLogRequest.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUGetComEventLogRequest.py
index 61327aae3c1..68ca6e23df8 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUGetComEventLogRequest.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUGetComEventLogRequest.py
@@ -19,13 +19,13 @@
from dataclasses import dataclass
-from distutils.util import strtobool
from plc4py.api.exceptions.exceptions import PlcRuntimeException
from plc4py.api.exceptions.exceptions import SerializationException
from plc4py.api.messages.PlcMessage import PlcMessage
from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
from plc4py.spi.generation.ReadBuffer import ReadBuffer
from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
from typing import ClassVar
import math
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUGetComEventLogResponse.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUGetComEventLogResponse.py
index 2717794df7d..f0fbcceb40e 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUGetComEventLogResponse.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUGetComEventLogResponse.py
@@ -19,13 +19,13 @@
from dataclasses import dataclass
-from distutils.util import strtobool
from plc4py.api.exceptions.exceptions import PlcRuntimeException
from plc4py.api.exceptions.exceptions import SerializationException
from plc4py.api.messages.PlcMessage import PlcMessage
from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
from plc4py.spi.generation.ReadBuffer import ReadBuffer
from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
from typing import Any
from typing import ClassVar
from typing import List
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUMaskWriteHoldingRegisterRequest.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUMaskWriteHoldingRegisterRequest.py
index 7f594f9608f..bf9ec7bfba2 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUMaskWriteHoldingRegisterRequest.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUMaskWriteHoldingRegisterRequest.py
@@ -19,13 +19,13 @@
from dataclasses import dataclass
-from distutils.util import strtobool
from plc4py.api.exceptions.exceptions import PlcRuntimeException
from plc4py.api.exceptions.exceptions import SerializationException
from plc4py.api.messages.PlcMessage import PlcMessage
from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
from plc4py.spi.generation.ReadBuffer import ReadBuffer
from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
from typing import ClassVar
import math
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUMaskWriteHoldingRegisterResponse.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUMaskWriteHoldingRegisterResponse.py
index 8bddc99dcab..9b14ca9e609 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUMaskWriteHoldingRegisterResponse.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUMaskWriteHoldingRegisterResponse.py
@@ -19,13 +19,13 @@
from dataclasses import dataclass
-from distutils.util import strtobool
from plc4py.api.exceptions.exceptions import PlcRuntimeException
from plc4py.api.exceptions.exceptions import SerializationException
from plc4py.api.messages.PlcMessage import PlcMessage
from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
from plc4py.spi.generation.ReadBuffer import ReadBuffer
from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
from typing import ClassVar
import math
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadCoilsRequest.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadCoilsRequest.py
index 9f95e4d164b..72b5180d94c 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadCoilsRequest.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadCoilsRequest.py
@@ -19,13 +19,13 @@
from dataclasses import dataclass
-from distutils.util import strtobool
from plc4py.api.exceptions.exceptions import PlcRuntimeException
from plc4py.api.exceptions.exceptions import SerializationException
from plc4py.api.messages.PlcMessage import PlcMessage
from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
from plc4py.spi.generation.ReadBuffer import ReadBuffer
from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
from typing import ClassVar
import math
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadCoilsResponse.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadCoilsResponse.py
index c3ddcba5a1a..2c0133cc06b 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadCoilsResponse.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadCoilsResponse.py
@@ -19,13 +19,13 @@
from dataclasses import dataclass
-from distutils.util import strtobool
from plc4py.api.exceptions.exceptions import PlcRuntimeException
from plc4py.api.exceptions.exceptions import SerializationException
from plc4py.api.messages.PlcMessage import PlcMessage
from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
from plc4py.spi.generation.ReadBuffer import ReadBuffer
from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
from typing import Any
from typing import ClassVar
from typing import List
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadDeviceIdentificationRequest.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadDeviceIdentificationRequest.py
index 21418393f26..00a81f26414 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadDeviceIdentificationRequest.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadDeviceIdentificationRequest.py
@@ -19,7 +19,6 @@
from dataclasses import dataclass
-from distutils.util import strtobool
from plc4py.api.exceptions.exceptions import PlcRuntimeException
from plc4py.api.exceptions.exceptions import SerializationException
from plc4py.api.messages.PlcMessage import PlcMessage
@@ -29,6 +28,7 @@
from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
from plc4py.spi.generation.ReadBuffer import ReadBuffer
from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
from typing import ClassVar
import math
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadDeviceIdentificationResponse.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadDeviceIdentificationResponse.py
index 77fa52e63f3..558ffd12f06 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadDeviceIdentificationResponse.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadDeviceIdentificationResponse.py
@@ -19,7 +19,6 @@
from dataclasses import dataclass
-from distutils.util import strtobool
from plc4py.api.exceptions.exceptions import PlcRuntimeException
from plc4py.api.exceptions.exceptions import SerializationException
from plc4py.api.messages.PlcMessage import PlcMessage
@@ -38,6 +37,7 @@
from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
from plc4py.spi.generation.ReadBuffer import ReadBuffer
from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
from typing import Any
from typing import ClassVar
from typing import List
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadDiscreteInputsRequest.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadDiscreteInputsRequest.py
index a93d3ca31af..11f544328af 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadDiscreteInputsRequest.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadDiscreteInputsRequest.py
@@ -19,13 +19,13 @@
from dataclasses import dataclass
-from distutils.util import strtobool
from plc4py.api.exceptions.exceptions import PlcRuntimeException
from plc4py.api.exceptions.exceptions import SerializationException
from plc4py.api.messages.PlcMessage import PlcMessage
from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
from plc4py.spi.generation.ReadBuffer import ReadBuffer
from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
from typing import ClassVar
import math
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadDiscreteInputsResponse.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadDiscreteInputsResponse.py
index 8f86ea5ad47..54c20fd0ed1 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadDiscreteInputsResponse.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadDiscreteInputsResponse.py
@@ -19,13 +19,13 @@
from dataclasses import dataclass
-from distutils.util import strtobool
from plc4py.api.exceptions.exceptions import PlcRuntimeException
from plc4py.api.exceptions.exceptions import SerializationException
from plc4py.api.messages.PlcMessage import PlcMessage
from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
from plc4py.spi.generation.ReadBuffer import ReadBuffer
from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
from typing import Any
from typing import ClassVar
from typing import List
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadExceptionStatusRequest.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadExceptionStatusRequest.py
index 38b316eb947..da9b7c0736c 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadExceptionStatusRequest.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadExceptionStatusRequest.py
@@ -19,13 +19,13 @@
from dataclasses import dataclass
-from distutils.util import strtobool
from plc4py.api.exceptions.exceptions import PlcRuntimeException
from plc4py.api.exceptions.exceptions import SerializationException
from plc4py.api.messages.PlcMessage import PlcMessage
from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
from plc4py.spi.generation.ReadBuffer import ReadBuffer
from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
from typing import ClassVar
import math
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadExceptionStatusResponse.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadExceptionStatusResponse.py
index b5641feeab6..6c845db1828 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadExceptionStatusResponse.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadExceptionStatusResponse.py
@@ -19,13 +19,13 @@
from dataclasses import dataclass
-from distutils.util import strtobool
from plc4py.api.exceptions.exceptions import PlcRuntimeException
from plc4py.api.exceptions.exceptions import SerializationException
from plc4py.api.messages.PlcMessage import PlcMessage
from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
from plc4py.spi.generation.ReadBuffer import ReadBuffer
from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
from typing import ClassVar
import math
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadFifoQueueRequest.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadFifoQueueRequest.py
index 41a8615efa2..62617f9f60f 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadFifoQueueRequest.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadFifoQueueRequest.py
@@ -19,13 +19,13 @@
from dataclasses import dataclass
-from distutils.util import strtobool
from plc4py.api.exceptions.exceptions import PlcRuntimeException
from plc4py.api.exceptions.exceptions import SerializationException
from plc4py.api.messages.PlcMessage import PlcMessage
from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
from plc4py.spi.generation.ReadBuffer import ReadBuffer
from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
from typing import ClassVar
import math
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadFifoQueueResponse.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadFifoQueueResponse.py
index 085c7744616..2b74fd2d174 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadFifoQueueResponse.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadFifoQueueResponse.py
@@ -19,13 +19,13 @@
from dataclasses import dataclass
-from distutils.util import strtobool
from plc4py.api.exceptions.exceptions import PlcRuntimeException
from plc4py.api.exceptions.exceptions import SerializationException
from plc4py.api.messages.PlcMessage import PlcMessage
from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
from plc4py.spi.generation.ReadBuffer import ReadBuffer
from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
from typing import Any
from typing import ClassVar
from typing import List
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadFileRecordRequest.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadFileRecordRequest.py
index a0b948f08f1..04b340d5e7d 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadFileRecordRequest.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadFileRecordRequest.py
@@ -19,7 +19,6 @@
from dataclasses import dataclass
-from distutils.util import strtobool
from plc4py.api.exceptions.exceptions import PlcRuntimeException
from plc4py.api.exceptions.exceptions import SerializationException
from plc4py.api.messages.PlcMessage import PlcMessage
@@ -30,6 +29,7 @@
from plc4py.spi.generation.ReadBuffer import ReadBuffer
from plc4py.spi.generation.WriteBuffer import WriteBuffer
from plc4py.spi.values.Common import get_size_of_array
+from plc4py.utils.ConnectionStringHandling import strtobool
from typing import Any
from typing import ClassVar
from typing import List
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadFileRecordResponse.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadFileRecordResponse.py
index 90173fa6bed..89e58c226e6 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadFileRecordResponse.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadFileRecordResponse.py
@@ -19,7 +19,6 @@
from dataclasses import dataclass
-from distutils.util import strtobool
from plc4py.api.exceptions.exceptions import PlcRuntimeException
from plc4py.api.exceptions.exceptions import SerializationException
from plc4py.api.messages.PlcMessage import PlcMessage
@@ -30,6 +29,7 @@
from plc4py.spi.generation.ReadBuffer import ReadBuffer
from plc4py.spi.generation.WriteBuffer import WriteBuffer
from plc4py.spi.values.Common import get_size_of_array
+from plc4py.utils.ConnectionStringHandling import strtobool
from typing import Any
from typing import ClassVar
from typing import List
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadHoldingRegistersRequest.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadHoldingRegistersRequest.py
index fae809b11f6..6a784d06514 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadHoldingRegistersRequest.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadHoldingRegistersRequest.py
@@ -19,13 +19,13 @@
from dataclasses import dataclass
-from distutils.util import strtobool
from plc4py.api.exceptions.exceptions import PlcRuntimeException
from plc4py.api.exceptions.exceptions import SerializationException
from plc4py.api.messages.PlcMessage import PlcMessage
from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
from plc4py.spi.generation.ReadBuffer import ReadBuffer
from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
from typing import ClassVar
import math
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadHoldingRegistersResponse.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadHoldingRegistersResponse.py
index 2bc94d6ea89..35b9dc7760a 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadHoldingRegistersResponse.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadHoldingRegistersResponse.py
@@ -19,13 +19,13 @@
from dataclasses import dataclass
-from distutils.util import strtobool
from plc4py.api.exceptions.exceptions import PlcRuntimeException
from plc4py.api.exceptions.exceptions import SerializationException
from plc4py.api.messages.PlcMessage import PlcMessage
from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
from plc4py.spi.generation.ReadBuffer import ReadBuffer
from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
from typing import Any
from typing import ClassVar
from typing import List
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadInputRegistersRequest.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadInputRegistersRequest.py
index e37e5aef01a..14f8d978c76 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadInputRegistersRequest.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadInputRegistersRequest.py
@@ -19,13 +19,13 @@
from dataclasses import dataclass
-from distutils.util import strtobool
from plc4py.api.exceptions.exceptions import PlcRuntimeException
from plc4py.api.exceptions.exceptions import SerializationException
from plc4py.api.messages.PlcMessage import PlcMessage
from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
from plc4py.spi.generation.ReadBuffer import ReadBuffer
from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
from typing import ClassVar
import math
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadInputRegistersResponse.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadInputRegistersResponse.py
index 68782da420b..1fbefc6fd36 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadInputRegistersResponse.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadInputRegistersResponse.py
@@ -19,13 +19,13 @@
from dataclasses import dataclass
-from distutils.util import strtobool
from plc4py.api.exceptions.exceptions import PlcRuntimeException
from plc4py.api.exceptions.exceptions import SerializationException
from plc4py.api.messages.PlcMessage import PlcMessage
from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
from plc4py.spi.generation.ReadBuffer import ReadBuffer
from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
from typing import Any
from typing import ClassVar
from typing import List
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadWriteMultipleHoldingRegistersRequest.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadWriteMultipleHoldingRegistersRequest.py
index c7889578520..8a669dbb3bf 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadWriteMultipleHoldingRegistersRequest.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadWriteMultipleHoldingRegistersRequest.py
@@ -19,13 +19,13 @@
from dataclasses import dataclass
-from distutils.util import strtobool
from plc4py.api.exceptions.exceptions import PlcRuntimeException
from plc4py.api.exceptions.exceptions import SerializationException
from plc4py.api.messages.PlcMessage import PlcMessage
from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
from plc4py.spi.generation.ReadBuffer import ReadBuffer
from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
from typing import Any
from typing import ClassVar
from typing import List
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadWriteMultipleHoldingRegistersResponse.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadWriteMultipleHoldingRegistersResponse.py
index 7c493df65b9..a23dcdafec5 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadWriteMultipleHoldingRegistersResponse.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReadWriteMultipleHoldingRegistersResponse.py
@@ -19,13 +19,13 @@
from dataclasses import dataclass
-from distutils.util import strtobool
from plc4py.api.exceptions.exceptions import PlcRuntimeException
from plc4py.api.exceptions.exceptions import SerializationException
from plc4py.api.messages.PlcMessage import PlcMessage
from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
from plc4py.spi.generation.ReadBuffer import ReadBuffer
from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
from typing import Any
from typing import ClassVar
from typing import List
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReportServerIdRequest.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReportServerIdRequest.py
index eec8b492611..213f265abd0 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReportServerIdRequest.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReportServerIdRequest.py
@@ -19,13 +19,13 @@
from dataclasses import dataclass
-from distutils.util import strtobool
from plc4py.api.exceptions.exceptions import PlcRuntimeException
from plc4py.api.exceptions.exceptions import SerializationException
from plc4py.api.messages.PlcMessage import PlcMessage
from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
from plc4py.spi.generation.ReadBuffer import ReadBuffer
from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
from typing import ClassVar
import math
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReportServerIdResponse.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReportServerIdResponse.py
index 60a26aa2ecf..43725092e7f 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReportServerIdResponse.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUReportServerIdResponse.py
@@ -19,13 +19,13 @@
from dataclasses import dataclass
-from distutils.util import strtobool
from plc4py.api.exceptions.exceptions import PlcRuntimeException
from plc4py.api.exceptions.exceptions import SerializationException
from plc4py.api.messages.PlcMessage import PlcMessage
from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
from plc4py.spi.generation.ReadBuffer import ReadBuffer
from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
from typing import Any
from typing import ClassVar
from typing import List
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteFileRecordRequest.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteFileRecordRequest.py
index ee142fb92b9..53e8fa097c7 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteFileRecordRequest.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteFileRecordRequest.py
@@ -19,7 +19,6 @@
from dataclasses import dataclass
-from distutils.util import strtobool
from plc4py.api.exceptions.exceptions import PlcRuntimeException
from plc4py.api.exceptions.exceptions import SerializationException
from plc4py.api.messages.PlcMessage import PlcMessage
@@ -30,6 +29,7 @@
from plc4py.spi.generation.ReadBuffer import ReadBuffer
from plc4py.spi.generation.WriteBuffer import WriteBuffer
from plc4py.spi.values.Common import get_size_of_array
+from plc4py.utils.ConnectionStringHandling import strtobool
from typing import Any
from typing import ClassVar
from typing import List
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteFileRecordResponse.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteFileRecordResponse.py
index f1905c6395f..7a1cc065651 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteFileRecordResponse.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteFileRecordResponse.py
@@ -19,7 +19,6 @@
from dataclasses import dataclass
-from distutils.util import strtobool
from plc4py.api.exceptions.exceptions import PlcRuntimeException
from plc4py.api.exceptions.exceptions import SerializationException
from plc4py.api.messages.PlcMessage import PlcMessage
@@ -30,6 +29,7 @@
from plc4py.spi.generation.ReadBuffer import ReadBuffer
from plc4py.spi.generation.WriteBuffer import WriteBuffer
from plc4py.spi.values.Common import get_size_of_array
+from plc4py.utils.ConnectionStringHandling import strtobool
from typing import Any
from typing import ClassVar
from typing import List
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteMultipleCoilsRequest.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteMultipleCoilsRequest.py
index bd95b6f942f..3f82c855f32 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteMultipleCoilsRequest.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteMultipleCoilsRequest.py
@@ -19,13 +19,13 @@
from dataclasses import dataclass
-from distutils.util import strtobool
from plc4py.api.exceptions.exceptions import PlcRuntimeException
from plc4py.api.exceptions.exceptions import SerializationException
from plc4py.api.messages.PlcMessage import PlcMessage
from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
from plc4py.spi.generation.ReadBuffer import ReadBuffer
from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
from typing import Any
from typing import ClassVar
from typing import List
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteMultipleCoilsResponse.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteMultipleCoilsResponse.py
index d8b8b42150a..fb4ec735d01 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteMultipleCoilsResponse.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteMultipleCoilsResponse.py
@@ -19,13 +19,13 @@
from dataclasses import dataclass
-from distutils.util import strtobool
from plc4py.api.exceptions.exceptions import PlcRuntimeException
from plc4py.api.exceptions.exceptions import SerializationException
from plc4py.api.messages.PlcMessage import PlcMessage
from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
from plc4py.spi.generation.ReadBuffer import ReadBuffer
from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
from typing import ClassVar
import math
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteMultipleHoldingRegistersRequest.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteMultipleHoldingRegistersRequest.py
index fdaec56e0dd..380debfe54d 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteMultipleHoldingRegistersRequest.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteMultipleHoldingRegistersRequest.py
@@ -19,13 +19,13 @@
from dataclasses import dataclass
-from distutils.util import strtobool
from plc4py.api.exceptions.exceptions import PlcRuntimeException
from plc4py.api.exceptions.exceptions import SerializationException
from plc4py.api.messages.PlcMessage import PlcMessage
from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
from plc4py.spi.generation.ReadBuffer import ReadBuffer
from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
from typing import Any
from typing import ClassVar
from typing import List
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteMultipleHoldingRegistersResponse.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteMultipleHoldingRegistersResponse.py
index 4c014d685aa..6898b495f6d 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteMultipleHoldingRegistersResponse.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteMultipleHoldingRegistersResponse.py
@@ -19,13 +19,13 @@
from dataclasses import dataclass
-from distutils.util import strtobool
from plc4py.api.exceptions.exceptions import PlcRuntimeException
from plc4py.api.exceptions.exceptions import SerializationException
from plc4py.api.messages.PlcMessage import PlcMessage
from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
from plc4py.spi.generation.ReadBuffer import ReadBuffer
from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
from typing import ClassVar
import math
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteSingleCoilRequest.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteSingleCoilRequest.py
index 044baa61dfc..ddcba2e4346 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteSingleCoilRequest.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteSingleCoilRequest.py
@@ -19,13 +19,13 @@
from dataclasses import dataclass
-from distutils.util import strtobool
from plc4py.api.exceptions.exceptions import PlcRuntimeException
from plc4py.api.exceptions.exceptions import SerializationException
from plc4py.api.messages.PlcMessage import PlcMessage
from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
from plc4py.spi.generation.ReadBuffer import ReadBuffer
from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
from typing import ClassVar
import math
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteSingleCoilResponse.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteSingleCoilResponse.py
index 670e698d030..2f1d45a1a99 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteSingleCoilResponse.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteSingleCoilResponse.py
@@ -19,13 +19,13 @@
from dataclasses import dataclass
-from distutils.util import strtobool
from plc4py.api.exceptions.exceptions import PlcRuntimeException
from plc4py.api.exceptions.exceptions import SerializationException
from plc4py.api.messages.PlcMessage import PlcMessage
from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
from plc4py.spi.generation.ReadBuffer import ReadBuffer
from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
from typing import ClassVar
import math
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteSingleRegisterRequest.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteSingleRegisterRequest.py
index 1303b8c5574..99482c8896d 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteSingleRegisterRequest.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteSingleRegisterRequest.py
@@ -19,13 +19,13 @@
from dataclasses import dataclass
-from distutils.util import strtobool
from plc4py.api.exceptions.exceptions import PlcRuntimeException
from plc4py.api.exceptions.exceptions import SerializationException
from plc4py.api.messages.PlcMessage import PlcMessage
from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
from plc4py.spi.generation.ReadBuffer import ReadBuffer
from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
from typing import ClassVar
import math
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteSingleRegisterResponse.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteSingleRegisterResponse.py
index f363b238b45..9e43b12b809 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteSingleRegisterResponse.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusPDUWriteSingleRegisterResponse.py
@@ -19,13 +19,13 @@
from dataclasses import dataclass
-from distutils.util import strtobool
from plc4py.api.exceptions.exceptions import PlcRuntimeException
from plc4py.api.exceptions.exceptions import SerializationException
from plc4py.api.messages.PlcMessage import PlcMessage
from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
from plc4py.spi.generation.ReadBuffer import ReadBuffer
from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
from typing import ClassVar
import math
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusRtuADU.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusRtuADU.py
index 30cd9f37fc8..48b881c666b 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusRtuADU.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusRtuADU.py
@@ -19,7 +19,6 @@
from dataclasses import dataclass
-from distutils.util import strtobool
from plc4py.api.exceptions.exceptions import PlcRuntimeException
from plc4py.api.exceptions.exceptions import SerializationException
from plc4py.api.messages.PlcMessage import PlcMessage
@@ -29,6 +28,7 @@
from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
from plc4py.spi.generation.ReadBuffer import ReadBuffer
from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
from plc4py.utils.GenericTypes import ByteOrder
from typing import ClassVar
import math
diff --git a/plc4py/plc4py/protocols/modbus/readwrite/ModbusTcpADU.py b/plc4py/plc4py/protocols/modbus/readwrite/ModbusTcpADU.py
index b0dac480c58..e89c73d4878 100644
--- a/plc4py/plc4py/protocols/modbus/readwrite/ModbusTcpADU.py
+++ b/plc4py/plc4py/protocols/modbus/readwrite/ModbusTcpADU.py
@@ -19,7 +19,6 @@
from dataclasses import dataclass
-from distutils.util import strtobool
from plc4py.api.exceptions.exceptions import PlcRuntimeException
from plc4py.api.exceptions.exceptions import SerializationException
from plc4py.api.messages.PlcMessage import PlcMessage
@@ -28,6 +27,7 @@
from plc4py.protocols.modbus.readwrite.ModbusPDU import ModbusPDU
from plc4py.spi.generation.ReadBuffer import ReadBuffer
from plc4py.spi.generation.WriteBuffer import WriteBuffer
+from plc4py.utils.ConnectionStringHandling import strtobool
from plc4py.utils.GenericTypes import ByteOrder
from typing import ClassVar
import math
diff --git a/plc4py/plc4py/protocols/simulated/readwrite/DataItem.py b/plc4py/plc4py/protocols/simulated/readwrite/DataItem.py
index f5a2dc2bbf1..7ff9685f549 100644
--- a/plc4py/plc4py/protocols/simulated/readwrite/DataItem.py
+++ b/plc4py/plc4py/protocols/simulated/readwrite/DataItem.py
@@ -298,7 +298,7 @@ def static_parse(read_buffer: ReadBuffer, data_type: str, number_of_values: int)
if data_type == "CHAR" and number_of_values == int(1): # CHAR
# Simple Field (value)
- value: str = read_buffer.read_str(8, logical_name="", encoding="")
+ value: str = read_buffer.read_str(8, logical_name="", encoding='"UTF-8"')
return PlcCHAR(value)
if data_type == "CHAR": # List
@@ -309,7 +309,9 @@ def static_parse(read_buffer: ReadBuffer, data_type: str, number_of_values: int)
for _ in range(item_count):
value.append(
PlcSTRING(
- str(read_buffer.read_str(8, logical_name="", encoding=""))
+ str(
+ read_buffer.read_str(8, logical_name="", encoding='"UTF-8"')
+ )
)
)
@@ -317,7 +319,7 @@ def static_parse(read_buffer: ReadBuffer, data_type: str, number_of_values: int)
if data_type == "WCHAR" and number_of_values == int(1): # WCHAR
# Simple Field (value)
- value: str = read_buffer.read_str(16, logical_name="", encoding="")
+ value: str = read_buffer.read_str(16, logical_name="", encoding='"UTF-16"')
return PlcWCHAR(value)
if data_type == "WCHAR": # List
@@ -328,7 +330,11 @@ def static_parse(read_buffer: ReadBuffer, data_type: str, number_of_values: int)
for _ in range(item_count):
value.append(
PlcSTRING(
- str(read_buffer.read_str(16, logical_name="", encoding=""))
+ str(
+ read_buffer.read_str(
+ 16, logical_name="", encoding='"UTF-16"'
+ )
+ )
)
)
@@ -336,13 +342,13 @@ def static_parse(read_buffer: ReadBuffer, data_type: str, number_of_values: int)
if data_type == "STRING": # STRING
# Simple Field (value)
- value: str = read_buffer.read_str(255, logical_name="", encoding="")
+ value: str = read_buffer.read_str(255, logical_name="", encoding='"UTF-8"')
return PlcSTRING(value)
if data_type == "WSTRING": # STRING
# Simple Field (value)
- value: str = read_buffer.read_str(255, logical_name="", encoding="")
+ value: str = read_buffer.read_str(255, logical_name="", encoding='"UTF-16"')
return PlcSTRING(value)
return None
@@ -523,34 +529,34 @@ def static_serialize(
elif data_type == "CHAR" and number_of_values == int(1): # CHAR
# Simple Field (value)
value: str = _value.get_str()
- write_buffer.write_str((value), 8, "UTF-8", "value")
+ write_buffer.write_str((value), 8, "value", "UTF-8")
elif data_type == "CHAR": # List
values: PlcList = cast(PlcList, _value)
for val in values.get_list():
value: str = val.get_str()
- write_buffer.write_str((value), 8, "UTF-8", "value")
+ write_buffer.write_str((value), 8, "value", "UTF-8")
elif data_type == "WCHAR" and number_of_values == int(1): # WCHAR
# Simple Field (value)
value: str = _value.get_str()
- write_buffer.write_str((value), 16, "UTF-16", "value")
+ write_buffer.write_str((value), 16, "value", "UTF-16")
elif data_type == "WCHAR": # List
values: PlcList = cast(PlcList, _value)
for val in values.get_list():
value: str = val.get_str()
- write_buffer.write_str((value), 16, "UTF-16", "value")
+ write_buffer.write_str((value), 16, "value", "UTF-16")
elif data_type == "STRING": # STRING
# Simple Field (value)
value: str = _value.get_str()
- write_buffer.write_str((value), 255, "UTF-8", "value")
+ write_buffer.write_str((value), 255, "value", "UTF-8")
elif data_type == "WSTRING": # STRING
# Simple Field (value)
value: str = _value.get_str()
- write_buffer.write_str((value), 255, "UTF-16", "value")
+ write_buffer.write_str((value), 255, "value", "UTF-16")
@staticmethod
def get_length_in_bytes(
diff --git a/plc4py/plc4py/protocols/umas/StaticHelper.py b/plc4py/plc4py/protocols/umas/StaticHelper.py
index b6f7e153929..686acf1adf3 100644
--- a/plc4py/plc4py/protocols/umas/StaticHelper.py
+++ b/plc4py/plc4py/protocols/umas/StaticHelper.py
@@ -137,4 +137,9 @@ def parse_terminated_string_bytes(read_buffer: ReadBuffer, string_length) -> str
def serialize_terminated_string(write_buffer, value, string_length):
- pass
+ terminated_char_position = len(value.value)
+ for i in range(len(value.value)):
+ if value.value[i] == "":
+ terminated_char_position = i
+ break
+ write_buffer.write_str(value.value, (terminated_char_position + 1) * 8)
diff --git a/plc4py/plc4py/protocols/umas/readwrite/DataItem.py b/plc4py/plc4py/protocols/umas/readwrite/DataItem.py
index 800ec4d68db..0fa4e4827be 100644
--- a/plc4py/plc4py/protocols/umas/readwrite/DataItem.py
+++ b/plc4py/plc4py/protocols/umas/readwrite/DataItem.py
@@ -24,12 +24,17 @@
from plc4py.spi.generation.WriteBuffer import WriteBuffer
from plc4py.spi.values.PlcValues import PlcBOOL
from plc4py.spi.values.PlcValues import PlcBYTE
+from plc4py.spi.values.PlcValues import PlcDATE
+from plc4py.spi.values.PlcValues import PlcDATE_AND_TIME
from plc4py.spi.values.PlcValues import PlcDINT
from plc4py.spi.values.PlcValues import PlcDWORD
from plc4py.spi.values.PlcValues import PlcINT
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 PlcTIME
+from plc4py.spi.values.PlcValues import PlcTIME_OF_DAY
from plc4py.spi.values.PlcValues import PlcUDINT
from plc4py.spi.values.PlcValues import PlcUINT
from plc4py.spi.values.PlcValues import PlcULINT
@@ -37,6 +42,7 @@
from plc4py.utils.GenericTypes import ByteOrder
from typing import List
from typing import cast
+import datetime
import logging
import math
@@ -63,28 +69,36 @@ def static_parse(
value: bool = read_buffer.read_bit("")
return PlcBOOL(value)
- if data_type == UmasDataType.BOOL: # List
- # Array field (value)
- # Count array
- item_count: int = int(number_of_values)
- value: List[PlcValue] = []
- for _ in range(item_count):
- value.append(PlcBOOL(bool(read_buffer.read_bit(""))))
+ if data_type == UmasDataType.EBOOL and number_of_values == int(1): # BOOL
- return PlcList(value)
+ # Reserved Field (Compartmentalized so the "reserved" variable can't leak)
+ reserved: int = read_buffer.read_unsigned_short(7, logical_name="")
+ if reserved != int(0x0000):
+ logging.warning(
+ "Expected constant value "
+ + str(0x0000)
+ + " but got "
+ + str(reserved)
+ + " for reserved field."
+ )
+
+ # Simple Field (value)
+ value: bool = read_buffer.read_bit("")
+
+ return PlcBOOL(value)
if data_type == UmasDataType.BYTE and number_of_values == int(1): # BYTE
# Simple Field (value)
- value: int = read_buffer.read_unsigned_short(8, logical_name="")
+ value: int = read_buffer.read_byte("")
return PlcBYTE(value)
if data_type == UmasDataType.BYTE: # List
# Array field (value)
# Count array
- item_count: int = int(number_of_values * int(8))
+ 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(PlcBYTE(int(read_buffer.read_byte(""))))
return PlcList(value)
if data_type == UmasDataType.WORD: # WORD
@@ -200,6 +214,100 @@ def static_parse(
)
return PlcList(value)
+ if data_type == UmasDataType.TIME and number_of_values == int(1): # TIME
+
+ # Simple Field (value)
+ value: int = read_buffer.read_unsigned_long(32, logical_name="")
+
+ return PlcTIME(value)
+ if data_type == UmasDataType.TIME: # List
+ # Array field (value)
+ # Count array
+ 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="")))
+ )
+
+ return PlcList(value)
+ if data_type == UmasDataType.DATE and number_of_values == int(1): # DATE
+
+ # Simple Field (day)
+ day: int = read_buffer.read_unsigned_short(
+ 8, logical_name="", encoding="BCD"
+ )
+
+ # Simple Field (month)
+ month: int = read_buffer.read_unsigned_short(
+ 8, logical_name="", encoding="BCD"
+ )
+
+ # Simple Field (year)
+ year: int = read_buffer.read_unsigned_int(
+ 16, logical_name="", encoding="BCD"
+ )
+
+ value: datetime = datetime.datetime(int(year), int(month), int(day))
+ return PlcDATE(value)
+ if data_type == UmasDataType.TOD and number_of_values == int(1): # TIME_OF_DAY
+
+ # Simple Field (value)
+ value: int = read_buffer.read_unsigned_long(32, logical_name="")
+
+ return PlcTIME_OF_DAY(value)
+ if data_type == UmasDataType.TOD: # List
+ # Array field (value)
+ # Count array
+ 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="")))
+ )
+
+ return PlcList(value)
+ if data_type == UmasDataType.DATE_AND_TIME and number_of_values == int(
+ 1
+ ): # DATE_AND_TIME
+
+ # Simple Field (unused)
+ unused: int = read_buffer.read_unsigned_short(8, logical_name="")
+
+ # Simple Field (seconds)
+ seconds: int = read_buffer.read_unsigned_short(
+ 8, logical_name="", encoding="BCD"
+ )
+
+ # Simple Field (minutes)
+ minutes: int = read_buffer.read_unsigned_short(
+ 8, logical_name="", encoding="BCD"
+ )
+
+ # Simple Field (hour)
+ hour: int = read_buffer.read_unsigned_short(
+ 8, logical_name="", encoding="BCD"
+ )
+
+ # Simple Field (day)
+ day: int = read_buffer.read_unsigned_short(
+ 8, logical_name="", encoding="BCD"
+ )
+
+ # Simple Field (month)
+ month: int = read_buffer.read_unsigned_short(
+ 8, logical_name="", encoding="BCD"
+ )
+
+ # Simple Field (year)
+ year: int = read_buffer.read_unsigned_int(
+ 16, logical_name="", encoding="BCD"
+ )
+
+ value: datetime = datetime.datetime(
+ int(year), int(month), int(day), int(hour), int(minutes), int(seconds)
+ )
+ return PlcDATE_AND_TIME(value)
return None
@staticmethod
@@ -217,11 +325,12 @@ def static_serialize(
value: bool = _value.get_bool()
write_buffer.write_bit((value), "value")
- elif data_type == UmasDataType.BOOL: # List
- values: PlcList = cast(PlcList, _value)
- for val in values.get_list():
- value: bool = val.get_bool()
- write_buffer.write_bit((value), "value")
+ elif data_type == UmasDataType.EBOOL and number_of_values == int(1): # BOOL
+ # Reserved Field
+ write_buffer.write_byte(int(0x0000), 7, "int0x0000")
+ # Simple Field (value)
+ value: bool = _value.get_bool()
+ write_buffer.write_bit((value), "value")
elif data_type == UmasDataType.BYTE and number_of_values == int(1): # BYTE
# Simple Field (value)
@@ -231,8 +340,8 @@ def static_serialize(
elif data_type == UmasDataType.BYTE: # List
values: PlcList = cast(PlcList, _value)
for val in values.get_list():
- value: bool = val.get_bool()
- write_buffer.write_bit((value), "value")
+ value: List[int] = val.get_raw()
+ write_buffer.write_byte(value, 8, "")
elif data_type == UmasDataType.WORD: # WORD
# Simple Field (value)
@@ -301,13 +410,84 @@ def static_serialize(
elif data_type == UmasDataType.STRING and number_of_values == int(1): # STRING
# Manual Field (value)
- serialize_terminated_string(write_buffer, self.value, self.number_of_values)
+ value: PlcValue = _value
+ StaticHelper.serialize_terminated_string(
+ write_buffer, value, number_of_values
+ )
elif data_type == UmasDataType.STRING: # List
values: PlcList = cast(PlcList, _value)
for val in values.get_list():
value: float = val.get_float()
write_buffer.write_float((value), 32, "value")
+ elif data_type == UmasDataType.TIME and number_of_values == int(1): # TIME
+ # Simple Field (value)
+ value: int = _value.get_int()
+ write_buffer.write_unsigned_int((value), 32, "value")
+
+ elif data_type == UmasDataType.TIME: # List
+ values: PlcList = cast(PlcList, _value)
+ for val in values.get_list():
+ value: int = val.get_int()
+ write_buffer.write_unsigned_int((value), 32, "value")
+
+ elif data_type == UmasDataType.DATE and number_of_values == int(1): # DATE
+ # Simple Field (day)
+ day: int = 0
+ write_buffer.write_byte((day), 8, "day")
+
+ # Simple Field (month)
+ month: int = 0
+ write_buffer.write_byte((month), 8, "month")
+
+ # Simple Field (year)
+ year: int = 0
+ write_buffer.write_unsigned_short((year), 16, "year")
+
+ elif data_type == UmasDataType.TOD and number_of_values == int(
+ 1
+ ): # TIME_OF_DAY
+ # Simple Field (value)
+ value: int = _value.get_int()
+ write_buffer.write_unsigned_int((value), 32, "value")
+
+ elif data_type == UmasDataType.TOD: # List
+ values: PlcList = cast(PlcList, _value)
+ for val in values.get_list():
+ value: int = val.get_int()
+ write_buffer.write_unsigned_int((value), 32, "value")
+
+ elif data_type == UmasDataType.DATE_AND_TIME and number_of_values == int(
+ 1
+ ): # DATE_AND_TIME
+ # Simple Field (unused)
+ unused: int = 0
+ write_buffer.write_byte((unused), 8, "unused")
+
+ # Simple Field (seconds)
+ seconds: int = 0
+ write_buffer.write_byte((seconds), 8, "seconds")
+
+ # Simple Field (minutes)
+ minutes: int = 0
+ write_buffer.write_byte((minutes), 8, "minutes")
+
+ # Simple Field (hour)
+ hour: int = 0
+ write_buffer.write_byte((hour), 8, "hour")
+
+ # Simple Field (day)
+ day: int = 0
+ write_buffer.write_byte((day), 8, "day")
+
+ # Simple Field (month)
+ month: int = 0
+ write_buffer.write_byte((month), 8, "month")
+
+ # Simple Field (year)
+ year: int = 0
+ write_buffer.write_unsigned_short((year), 16, "year")
+
@staticmethod
def get_length_in_bytes(
_value: PlcValue, data_type: UmasDataType, number_of_values: int
@@ -329,15 +509,17 @@ def get_length_in_bits(
size_in_bits += 7
# Simple Field (value)
size_in_bits += 1
- elif data_type == UmasDataType.BOOL: # List
- values: PlcList = cast(PlcList, _value)
- size_in_bits += len(values.get_list()) * 1
+ elif data_type == UmasDataType.EBOOL and number_of_values == int(1): # BOOL
+ # Reserved Field
+ size_in_bits += 7
+ # Simple Field (value)
+ size_in_bits += 1
elif data_type == UmasDataType.BYTE and number_of_values == int(1): # BYTE
# Simple Field (value)
size_in_bits += 8
elif data_type == UmasDataType.BYTE: # List
values: PlcList = cast(PlcList, _value)
- size_in_bits += len(values.get_list()) * 1
+ size_in_bits += len(values.get_list()) * 8
elif data_type == UmasDataType.WORD: # WORD
# Simple Field (value)
size_in_bits += 16
@@ -376,9 +558,47 @@ def get_length_in_bits(
size_in_bits += len(values.get_list()) * 32
elif data_type == UmasDataType.STRING and number_of_values == int(1): # STRING
# Manual Field (value)
- size_in_bits += self.number_of_values * int(8)
+ size_in_bits += number_of_values * int(8)
elif data_type == UmasDataType.STRING: # List
values: PlcList = cast(PlcList, _value)
size_in_bits += len(values.get_list()) * 32
+ elif data_type == UmasDataType.TIME and number_of_values == int(1): # TIME
+ # Simple Field (value)
+ size_in_bits += 32
+ elif data_type == UmasDataType.TIME: # List
+ values: PlcList = cast(PlcList, _value)
+ size_in_bits += len(values.get_list()) * 32
+ elif data_type == UmasDataType.DATE and number_of_values == int(1): # DATE
+ # Simple Field (day)
+ size_in_bits += 8
+ # Simple Field (month)
+ size_in_bits += 8
+ # Simple Field (year)
+ size_in_bits += 16
+ elif data_type == UmasDataType.TOD and number_of_values == int(
+ 1
+ ): # TIME_OF_DAY
+ # Simple Field (value)
+ size_in_bits += 32
+ elif data_type == UmasDataType.TOD: # List
+ values: PlcList = cast(PlcList, _value)
+ size_in_bits += len(values.get_list()) * 32
+ elif data_type == UmasDataType.DATE_AND_TIME and number_of_values == int(
+ 1
+ ): # DATE_AND_TIME
+ # Simple Field (unused)
+ size_in_bits += 8
+ # Simple Field (seconds)
+ size_in_bits += 8
+ # Simple Field (minutes)
+ size_in_bits += 8
+ # Simple Field (hour)
+ size_in_bits += 8
+ # Simple Field (day)
+ size_in_bits += 8
+ # Simple Field (month)
+ size_in_bits += 8
+ # Simple Field (year)
+ size_in_bits += 16
return size_in_bits
diff --git a/plc4py/plc4py/protocols/umas/readwrite/UmasDataType.py b/plc4py/plc4py/protocols/umas/readwrite/UmasDataType.py
index 69fcc90f31c..81366a22521 100644
--- a/plc4py/plc4py/protocols/umas/readwrite/UmasDataType.py
+++ b/plc4py/plc4py/protocols/umas/readwrite/UmasDataType.py
@@ -22,29 +22,29 @@
class UmasDataType(AutoNumberEnum):
- _init_ = "value, request_size, data_type_size"
- BOOL = (1, int(1), int(1))
- UNKNOWN2 = (2, int(1), int(1))
- UNKNOWN3 = (3, int(1), int(1))
- INT = (4, int(2), int(2))
- UINT = (5, int(2), int(2))
- DINT = (6, int(3), int(4))
- UDINT = (7, int(3), int(4))
- REAL = (8, int(3), int(4))
- STRING = (9, int(17), int(1))
- TIME = (10, int(3), int(4))
- UNKNOWN11 = (11, int(1), int(1))
- UNKNOWN12 = (12, int(1), int(1))
- UNKNOWN13 = (13, int(1), int(1))
- DATE = (14, int(3), int(4))
- TOD = (15, int(3), int(4))
- DT = (16, int(3), int(4))
- UNKNOWN17 = (17, int(1), int(1))
- UNKNOWN18 = (18, int(1), int(1))
- UNKNOWN19 = (19, int(1), int(1))
- UNKNOWN20 = (20, int(1), int(1))
- BYTE = (21, int(1), int(1))
- WORD = (22, int(2), int(2))
- DWORD = (23, int(3), int(4))
- UNKNOWN24 = (24, int(1), int(1))
- EBOOL = (25, int(1), int(1))
+ _init_ = "value, data_type_conversion, request_size, data_type_size"
+ BOOL = (1, str("BOOL"), int(1), int(1))
+ UNKNOWN2 = (2, str("BOOL"), int(1), int(1))
+ UNKNOWN3 = (3, str("BOOL"), int(1), int(1))
+ INT = (4, str("INT"), int(2), int(2))
+ UINT = (5, str("UINT"), int(2), int(2))
+ DINT = (6, str("DINT"), int(3), int(4))
+ UDINT = (7, str("UDINT"), int(3), int(4))
+ REAL = (8, str("REAL"), int(3), int(4))
+ STRING = (9, str("STRING"), int(17), int(1))
+ TIME = (10, str("TIME"), int(3), int(4))
+ UNKNOWN11 = (11, str("BYTE"), int(1), int(1))
+ UNKNOWN12 = (12, str("BYTE"), int(1), int(1))
+ UNKNOWN13 = (13, str("BYTE"), int(1), int(1))
+ DATE = (14, str("DATE"), int(3), int(4))
+ TOD = (15, str("TIME_OF_DAY"), int(3), int(4))
+ DATE_AND_TIME = (16, str("DATE_AND_TIME"), int(4), int(8))
+ UNKNOWN17 = (17, str("BYTE"), int(1), int(1))
+ UNKNOWN18 = (18, str("BYTE"), int(1), int(1))
+ UNKNOWN19 = (19, str("BYTE"), int(1), int(1))
+ UNKNOWN20 = (20, str("BYTE"), int(1), int(1))
+ BYTE = (21, str("BYTE"), int(1), int(1))
+ WORD = (22, str("WORD"), int(2), int(2))
+ DWORD = (23, str("DWORD"), int(3), int(4))
+ UNKNOWN24 = (24, str("BYTE"), int(1), int(1))
+ EBOOL = (25, str("BOOL"), int(1), int(1))
diff --git a/plc4py/plc4py/protocols/umas/readwrite/UmasPDUReadUnlocatedVariableNames.py b/plc4py/plc4py/protocols/umas/readwrite/UmasPDUReadUnlocatedVariableNames.py
deleted file mode 100644
index 3ab7e8882f9..00000000000
--- a/plc4py/plc4py/protocols/umas/readwrite/UmasPDUReadUnlocatedVariableNames.py
+++ /dev/null
@@ -1,153 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# https://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-import math
-from dataclasses import dataclass
-from typing import Any, ClassVar, List
-
-from plc4py.api.exceptions.exceptions import (
- PlcRuntimeException,
- SerializationException,
-)
-from plc4py.api.messages.PlcMessage import PlcMessage
-from plc4py.protocols.umas.readwrite.UmasPDUItem import UmasPDUItem
-from plc4py.protocols.umas.readwrite.UmasUnlocatedVariableReference import (
- UmasUnlocatedVariableReference,
-)
-from plc4py.spi.generation.ReadBuffer import ReadBuffer
-from plc4py.spi.generation.WriteBuffer import WriteBuffer
-from plc4py.utils.GenericTypes import ByteOrder
-
-
-@dataclass
-class UmasPDUReadUnlocatedVariableNames(UmasPDUItem):
- range: int
- no_of_records: int
- records: List[UmasUnlocatedVariableReference]
- # Accessors for discriminator values.
- umas_function_key: ClassVar[int] = 0xFE
- umas_request_function_key: ClassVar[int] = 0x26
-
- def serialize_umas_pdu_item_child(self, write_buffer: WriteBuffer):
- write_buffer.push_context("UmasPDUReadUnlocatedVariableNames")
-
- # Simple Field (range)
- write_buffer.write_unsigned_int(self.range, logical_name="range")
-
- # Simple Field (noOfRecords)
- write_buffer.write_unsigned_int(self.no_of_records, logical_name="noOfRecords")
-
- # Array Field (records)
- write_buffer.write_complex_array(self.records, logical_name="records")
-
- write_buffer.pop_context("UmasPDUReadUnlocatedVariableNames")
-
- def length_in_bytes(self) -> int:
- return int(math.ceil(float(self.length_in_bits() / 8.0)))
-
- def length_in_bits(self) -> int:
- length_in_bits: int = super().length_in_bits()
- _value: UmasPDUReadUnlocatedVariableNames = self
-
- # Simple field (range)
- length_in_bits += 32
-
- # Simple field (noOfRecords)
- length_in_bits += 32
-
- # Array field
- if self.records is not None:
- for element in self.records:
- length_in_bits += element.length_in_bits()
-
- return length_in_bits
-
- @staticmethod
- def static_parse_builder(read_buffer: ReadBuffer, umas_request_function_key: int):
- read_buffer.push_context("UmasPDUReadUnlocatedVariableNames")
-
- range: int = read_buffer.read_unsigned_int(
- logical_name="range",
- bit_length=32,
- byte_order=ByteOrder.LITTLE_ENDIAN,
- umas_request_function_key=umas_request_function_key,
- )
-
- no_of_records: int = read_buffer.read_unsigned_int(
- logical_name="noOfRecords",
- bit_length=32,
- byte_order=ByteOrder.LITTLE_ENDIAN,
- umas_request_function_key=umas_request_function_key,
- )
-
- records: List[Any] = read_buffer.read_array_field(
- logical_name="records",
- read_function=UmasUnlocatedVariableReference.static_parse,
- count=no_of_records,
- byte_order=ByteOrder.LITTLE_ENDIAN,
- umas_request_function_key=umas_request_function_key,
- )
-
- read_buffer.pop_context("UmasPDUReadUnlocatedVariableNames")
- # Create the instance
- return UmasPDUReadUnlocatedVariableNamesBuilder(range, no_of_records, records)
-
- def equals(self, o: object) -> bool:
- if self == o:
- return True
-
- if not isinstance(o, UmasPDUReadUnlocatedVariableNames):
- return False
-
- that: UmasPDUReadUnlocatedVariableNames = UmasPDUReadUnlocatedVariableNames(o)
- return (
- (self.range == that.range)
- and (self.no_of_records == that.no_of_records)
- and (self.records == that.records)
- and super().equals(that)
- and True
- )
-
- def hash_code(self) -> int:
- return hash(self)
-
- def __str__(self) -> str:
- pass
- # write_buffer_box_based: WriteBufferBoxBased = WriteBufferBoxBased(True, True)
- # try:
- # write_buffer_box_based.writeSerializable(self)
- # except SerializationException as e:
- # raise PlcRuntimeException(e)
-
- # return "\n" + str(write_buffer_box_based.get_box()) + "\n"
-
-
-@dataclass
-class UmasPDUReadUnlocatedVariableNamesBuilder:
- range: int
- no_of_records: int
- records: List[UmasUnlocatedVariableReference]
-
- def build(self, pairing_key) -> UmasPDUReadUnlocatedVariableNames:
- umas_pdu_read_unlocated_variable_names: UmasPDUReadUnlocatedVariableNames = (
- UmasPDUReadUnlocatedVariableNames(
- pairing_key, self.range, self.no_of_records, self.records
- )
- )
- return umas_pdu_read_unlocated_variable_names
diff --git a/plc4py/plc4py/protocols/umas/readwrite/UmasUnlocatedVariableReference.py b/plc4py/plc4py/protocols/umas/readwrite/UmasUnlocatedVariableReference.py
index 9a7874957f2..00f1f9bdbad 100644
--- a/plc4py/plc4py/protocols/umas/readwrite/UmasUnlocatedVariableReference.py
+++ b/plc4py/plc4py/protocols/umas/readwrite/UmasUnlocatedVariableReference.py
@@ -31,10 +31,8 @@
@dataclass
class UmasUnlocatedVariableReference:
data_type: int
- unknown1: int
block: int
offset: int
- base_offset: int
unknown4: int
string_length: int
value: str
@@ -43,13 +41,8 @@ def serialize(self, write_buffer: WriteBuffer):
write_buffer.push_context("UmasUnlocatedVariableReference")
# Simple Field (dataType)
- write_buffer.write_unsigned_byte(
- self.data_type, bit_length=8, logical_name="dataType"
- )
-
- # Simple Field (unknown1)
- write_buffer.write_unsigned_byte(
- self.unknown1, bit_length=8, logical_name="unknown1"
+ write_buffer.write_unsigned_short(
+ self.data_type, bit_length=16, logical_name="dataType"
)
# Simple Field (block)
@@ -58,13 +51,8 @@ def serialize(self, write_buffer: WriteBuffer):
)
# Simple Field (offset)
- write_buffer.write_unsigned_byte(
- self.offset, bit_length=8, logical_name="offset"
- )
-
- # Simple Field (baseOffset)
- write_buffer.write_unsigned_byte(
- self.base_offset, bit_length=8, logical_name="baseOffset"
+ write_buffer.write_unsigned_short(
+ self.offset, bit_length=16, logical_name="offset"
)
# Simple Field (unknown4)
@@ -94,19 +82,13 @@ def length_in_bits(self) -> int:
_value: UmasUnlocatedVariableReference = self
# Simple field (dataType)
- length_in_bits += 8
-
- # Simple field (unknown1)
- length_in_bits += 8
+ length_in_bits += 16
# Simple field (block)
length_in_bits += 16
# Simple field (offset)
- length_in_bits += 8
-
- # Simple field (baseOffset)
- length_in_bits += 8
+ length_in_bits += 16
# Simple field (unknown4)
length_in_bits += 16
@@ -127,24 +109,16 @@ def static_parse(read_buffer: ReadBuffer, **kwargs):
def static_parse_context(read_buffer: ReadBuffer):
read_buffer.push_context("UmasUnlocatedVariableReference")
- data_type: int = read_buffer.read_unsigned_byte(
- logical_name="data_type", bit_length=8
- )
-
- unknown1: int = read_buffer.read_unsigned_byte(
- logical_name="unknown1", bit_length=8
+ data_type: int = read_buffer.read_unsigned_short(
+ logical_name="data_type", bit_length=16
)
block: int = read_buffer.read_unsigned_short(
logical_name="block", bit_length=16
)
- offset: int = read_buffer.read_unsigned_byte(
- logical_name="offset", bit_length=8
- )
-
- base_offset: int = read_buffer.read_unsigned_byte(
- logical_name="base_offset", bit_length=8
+ offset: int = read_buffer.read_unsigned_short(
+ logical_name="offset", bit_length=16
)
unknown4: int = read_buffer.read_unsigned_short(
@@ -166,14 +140,7 @@ def static_parse_context(read_buffer: ReadBuffer):
# Create the instance
_umas_unlocated_variable_reference: UmasUnlocatedVariableReference = (
UmasUnlocatedVariableReference(
- data_type,
- unknown1,
- block,
- offset,
- base_offset,
- unknown4,
- string_length,
- value,
+ data_type, block, offset, unknown4, string_length, value
)
)
return _umas_unlocated_variable_reference
@@ -188,10 +155,8 @@ def equals(self, o: object) -> bool:
that: UmasUnlocatedVariableReference = UmasUnlocatedVariableReference(o)
return (
(self.data_type == that.data_type)
- and (self.unknown1 == that.unknown1)
and (self.block == that.block)
and (self.offset == that.offset)
- and (self.base_offset == that.base_offset)
and (self.unknown4 == that.unknown4)
and (self.string_length == that.string_length)
and (self.value == that.value)
diff --git a/plc4py/plc4py/protocols/umas/readwrite/UmasVariableBlock.py b/plc4py/plc4py/protocols/umas/readwrite/UmasVariableBlock.py
deleted file mode 100644
index 5a314a823d9..00000000000
--- a/plc4py/plc4py/protocols/umas/readwrite/UmasVariableBlock.py
+++ /dev/null
@@ -1,149 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# https://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-import math
-from abc import ABC, abstractmethod
-from dataclasses import dataclass
-
-from plc4py.api.exceptions.exceptions import (
- ParseException,
- PlcRuntimeException,
- SerializationException,
-)
-from plc4py.api.messages.PlcMessage import PlcMessage
-from plc4py.spi.generation.ReadBuffer import ReadBuffer
-from plc4py.spi.generation.WriteBuffer import WriteBuffer
-
-
-@dataclass
-class UmasVariableBlock(ABC, PlcMessage):
- # Abstract accessors for discriminator values.
- @property
- def record_format(self) -> int:
- pass
-
- @abstractmethod
- def serialize_umas_variable_block_child(self, write_buffer: WriteBuffer) -> None:
- pass
-
- def serialize(self, write_buffer: WriteBuffer):
- write_buffer.push_context("UmasVariableBlock")
-
- # Switch field (Serialize the sub-type)
- self.serialize_umas_variable_block_child(write_buffer)
-
- write_buffer.pop_context("UmasVariableBlock")
-
- def length_in_bytes(self) -> int:
- return int(math.ceil(float(self.length_in_bits() / 8.0)))
-
- def length_in_bits(self) -> int:
- length_in_bits: int = 0
- _value: UmasVariableBlock = self
-
- # Length of subtype elements will be added by sub-type...
-
- return length_in_bits
-
- @staticmethod
- def static_parse(read_buffer: ReadBuffer, **kwargs):
- if kwargs is None:
- raise PlcRuntimeException(
- "Wrong number of arguments, expected 1, but got None"
- )
-
- record_format: int = 0
- if isinstance(kwargs.get("record_format"), int):
- record_format = int(kwargs.get("record_format"))
- elif isinstance(kwargs.get("record_format"), str):
- record_format = int(str(kwargs.get("record_format")))
- else:
- raise PlcRuntimeException(
- "Argument 0 expected to be of type int or a string which is parseable but was "
- + kwargs.get("record_format").getClass().getName()
- )
-
- return UmasVariableBlock.static_parse_context(read_buffer, record_format)
-
- @staticmethod
- def static_parse_context(read_buffer: ReadBuffer, record_format: int):
- read_buffer.push_context("UmasVariableBlock")
-
- # Switch Field (Depending on the discriminator values, passes the instantiation to a sub-type)
- builder: UmasVariableBlockBuilder = None
- from plc4py.protocols.umas.readwrite.UmasPDUReadUnlocatedVariableNamesResponse import (
- UmasPDUReadUnlocatedVariableNamesResponse,
- )
-
- if record_format == int(0xDD02):
- builder = UmasPDUReadUnlocatedVariableNamesResponse.static_parse_builder(
- read_buffer, record_format
- )
- from plc4py.protocols.umas.readwrite.UmasPDUReadDatatypeNamesResponse import (
- UmasPDUReadDatatypeNamesResponse,
- )
-
- if record_format == int(0xDD03):
- builder = UmasPDUReadDatatypeNamesResponse.static_parse_builder(
- read_buffer, record_format
- )
- if builder is None:
- raise ParseException(
- "Unsupported case for discriminated type"
- + " parameters ["
- + "recordFormat="
- + str(record_format)
- + "]"
- )
-
- read_buffer.pop_context("UmasVariableBlock")
- # Create the instance
- _umas_variable_block: UmasVariableBlock = builder.build()
- return _umas_variable_block
-
- def equals(self, o: object) -> bool:
- if self == o:
- return True
-
- if not isinstance(o, UmasVariableBlock):
- return False
-
- that: UmasVariableBlock = UmasVariableBlock(o)
- return True
-
- def hash_code(self) -> int:
- return hash(self)
-
- def __str__(self) -> str:
- pass
- # write_buffer_box_based: WriteBufferBoxBased = WriteBufferBoxBased(True, True)
- # try:
- # write_buffer_box_based.writeSerializable(self)
- # except SerializationException as e:
- # raise PlcRuntimeException(e)
-
- # return "\n" + str(write_buffer_box_based.get_box()) + "\n"
-
-
-@dataclass
-class UmasVariableBlockBuilder:
- def build(
- self,
- ) -> UmasVariableBlock:
- pass
diff --git a/plc4py/plc4py/protocols/umas/readwrite/VariableRequestReference.py b/plc4py/plc4py/protocols/umas/readwrite/VariableRequestReference.py
deleted file mode 100644
index 7c43a744b87..00000000000
--- a/plc4py/plc4py/protocols/umas/readwrite/VariableRequestReference.py
+++ /dev/null
@@ -1,185 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# https://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-import math
-from dataclasses import dataclass
-
-from plc4py.api.exceptions.exceptions import (
- PlcRuntimeException,
- SerializationException,
-)
-from plc4py.api.messages.PlcMessage import PlcMessage
-from plc4py.spi.generation.ReadBuffer import ReadBuffer
-from plc4py.spi.generation.WriteBuffer import WriteBuffer
-
-
-@dataclass
-class VariableRequestReference:
- is_array: int
- data_size_index: int
- block: int
- base_offset: int
- offset: int
- array_length: int
- UNKNOWN1: int = 0x01
-
- def serialize(self, write_buffer: WriteBuffer):
- write_buffer.push_context("VariableRequestReference")
-
- # Simple Field (isArray)
- write_buffer.write_unsigned_byte(
- self.is_array, bit_length=4, logical_name="isArray"
- )
-
- # Simple Field (dataSizeIndex)
- write_buffer.write_unsigned_byte(
- self.data_size_index, bit_length=4, logical_name="dataSizeIndex"
- )
-
- # Simple Field (block)
- write_buffer.write_unsigned_short(
- self.block, bit_length=16, logical_name="block"
- )
-
- # Const Field (unknown1)
- write_buffer.write_unsigned_byte(self.UNKNOWN1, logical_name="unknown1")
-
- # Simple Field (baseOffset)
- write_buffer.write_unsigned_short(
- self.base_offset, bit_length=16, logical_name="baseOffset"
- )
-
- # Simple Field (offset)
- write_buffer.write_unsigned_byte(
- self.offset, bit_length=8, logical_name="offset"
- )
-
- # Optional Field (arrayLength) (Can be skipped, if the value is null)
- write_buffer.write_unsigned_short(self.array_length, logical_name="arrayLength")
-
- write_buffer.pop_context("VariableRequestReference")
-
- def length_in_bytes(self) -> int:
- return int(math.ceil(float(self.length_in_bits() / 8.0)))
-
- def length_in_bits(self) -> int:
- length_in_bits: int = 0
- _value: VariableRequestReference = self
-
- # Simple field (isArray)
- length_in_bits += 4
-
- # Simple field (dataSizeIndex)
- length_in_bits += 4
-
- # Simple field (block)
- length_in_bits += 16
-
- # Const Field (unknown1)
- length_in_bits += 8
-
- # Simple field (baseOffset)
- length_in_bits += 16
-
- # Simple field (offset)
- length_in_bits += 8
-
- # Optional Field (arrayLength)
- length_in_bits += 16
-
- return length_in_bits
-
- @staticmethod
- def static_parse(read_buffer: ReadBuffer, **kwargs):
- return VariableRequestReference.static_parse_context(read_buffer)
-
- @staticmethod
- def static_parse_context(read_buffer: ReadBuffer):
- read_buffer.push_context("VariableRequestReference")
-
- is_array: int = read_buffer.read_unsigned_byte(
- logical_name="isArray", bit_length=4
- )
-
- data_size_index: int = read_buffer.read_unsigned_byte(
- logical_name="dataSizeIndex", bit_length=4
- )
-
- block: int = read_buffer.read_unsigned_short(
- logical_name="block", bit_length=16
- )
-
- UNKNOWN1: int = read_buffer.read_unsigned_byte(logical_name="unknown1")
-
- base_offset: int = read_buffer.read_unsigned_short(
- logical_name="baseOffset", bit_length=16
- )
-
- offset: int = read_buffer.read_unsigned_byte(
- logical_name="offset", bit_length=8
- )
-
- array_length: int = None
- if self.is_array:
- array_length = read_buffer.read_unsigned_short(logical_name="arrayLength")
-
- read_buffer.pop_context("VariableRequestReference")
- # Create the instance
- _variable_request_reference: VariableRequestReference = (
- VariableRequestReference(
- is_array,
- data_size_index,
- block,
- base_offset,
- offset,
- array_length,
- )
- )
- return _variable_request_reference
-
- def equals(self, o: object) -> bool:
- if self == o:
- return True
-
- if not isinstance(o, VariableRequestReference):
- return False
-
- that: VariableRequestReference = VariableRequestReference(o)
- return (
- (self.is_array == that.is_array)
- and (self.data_size_index == that.data_size_index)
- and (self.block == that.block)
- and (self.base_offset == that.base_offset)
- and (self.offset == that.offset)
- and (self.array_length == that.array_length)
- and True
- )
-
- def hash_code(self) -> int:
- return hash(self)
-
- def __str__(self) -> str:
- pass
- # write_buffer_box_based: WriteBufferBoxBased = WriteBufferBoxBased(True, True)
- # try:
- # write_buffer_box_based.writeSerializable(self)
- # except SerializationException as e:
- # raise PlcRuntimeException(e)
-
- # return "\n" + str(write_buffer_box_based.get_box()) + "\n"
diff --git a/plc4py/plc4py/protocols/umas/readwrite/VariableWriteRequestReference.py b/plc4py/plc4py/protocols/umas/readwrite/VariableWriteRequestReference.py
index 055270c687b..30e34892d8d 100644
--- a/plc4py/plc4py/protocols/umas/readwrite/VariableWriteRequestReference.py
+++ b/plc4py/plc4py/protocols/umas/readwrite/VariableWriteRequestReference.py
@@ -38,7 +38,6 @@ class VariableWriteRequestReference:
offset: int
array_length: int
record_data: List[int]
- UNKNOWN1: int = 0x01
def serialize(self, write_buffer: WriteBuffer):
write_buffer.push_context("VariableWriteRequestReference")
@@ -58,17 +57,14 @@ def serialize(self, write_buffer: WriteBuffer):
self.block, bit_length=16, logical_name="block"
)
- # Const Field (unknown1)
- write_buffer.write_unsigned_byte(self.UNKNOWN1, logical_name="unknown1")
-
# Simple Field (baseOffset)
write_buffer.write_unsigned_short(
self.base_offset, bit_length=16, logical_name="baseOffset"
)
# Simple Field (offset)
- write_buffer.write_unsigned_byte(
- self.offset, bit_length=8, logical_name="offset"
+ write_buffer.write_unsigned_short(
+ self.offset, bit_length=16, logical_name="offset"
)
# Optional Field (arrayLength) (Can be skipped, if the value is null)
@@ -98,14 +94,11 @@ def length_in_bits(self) -> int:
# Simple field (block)
length_in_bits += 16
- # Const Field (unknown1)
- length_in_bits += 8
-
# Simple field (baseOffset)
length_in_bits += 16
# Simple field (offset)
- length_in_bits += 8
+ length_in_bits += 16
# Optional Field (arrayLength)
if self.is_array:
@@ -137,14 +130,12 @@ def static_parse_context(read_buffer: ReadBuffer):
logical_name="block", bit_length=16
)
- UNKNOWN1: int = read_buffer.read_unsigned_byte(logical_name="unknown1")
-
base_offset: int = read_buffer.read_unsigned_short(
logical_name="base_offset", bit_length=16
)
- offset: int = read_buffer.read_unsigned_byte(
- logical_name="offset", bit_length=8
+ offset: int = read_buffer.read_unsigned_short(
+ logical_name="offset", bit_length=16
)
array_length: int = None
diff --git a/plc4py/plc4py/spi/generation/ReadBuffer.py b/plc4py/plc4py/spi/generation/ReadBuffer.py
index f250582b979..2a985cd7bad 100644
--- a/plc4py/plc4py/spi/generation/ReadBuffer.py
+++ b/plc4py/plc4py/spi/generation/ReadBuffer.py
@@ -24,7 +24,7 @@
from bitarray import bitarray
from bitarray.util import ba2base, ba2int, zeros
-from plc4py.api.exceptions.exceptions import SerializationException
+from plc4py.api.exceptions.exceptions import SerializationException, ParseException
from plc4py.api.messages.PlcMessage import PlcMessage
from plc4py.utils.GenericTypes import ByteOrder, ByteOrderAware
@@ -220,6 +220,7 @@ def read_unsigned_short(
self, bit_length: int = 16, logical_name: str = "", **kwargs
) -> int:
byte_order = kwargs.get("byte_order", self.byte_order)
+ encoding = kwargs.get("encoding", "")
if bit_length <= 0:
raise SerializationException("unsigned short must contain at least 1 bit")
elif bit_length > 16:
@@ -227,19 +228,41 @@ def read_unsigned_short(
else:
if byte_order == ByteOrder.LITTLE_ENDIAN:
endian_string = "<"
+ padded = bitarray(
+ self.bb[self.position : self.position + bit_length]
+ ) + (16 - bit_length) * bitarray("0")
else:
endian_string = ">"
- padded = (16 - bit_length) * bitarray("0") + bitarray(
- self.bb[self.position : self.position + bit_length]
- )
- result: int = struct.unpack(endian_string + "H", padded)[0]
- self.position += bit_length
- return result
+ padded = (16 - bit_length) * bitarray("0") + bitarray(
+ self.bb[self.position : self.position + bit_length]
+ )
+
+ if encoding == "BCD":
+ if bit_length % 4 != 0:
+ raise ParseException(
+ "'BCD' encoded fields must have a length that is a multiple of 4 bits long"
+ )
+ result: int = 0
+ for i in range(0, bit_length, 4):
+ digit: int = ba2int(padded[i : i + 4])
+ if digit > 9:
+ raise ParseException(
+ "'BCD' encoded value is not a correctly encoded BCD value"
+ )
+ multiplier = 10 ** ((int(bit_length - i) / 4) - 1)
+ result += multiplier * digit
+ self.position += bit_length
+ return result
+ else:
+ result: int = struct.unpack(endian_string + "H", padded)[0]
+ self.position += bit_length
+ return result
def read_unsigned_int(
self, bit_length: int = 32, logical_name: str = "", **kwargs
) -> int:
byte_order = kwargs.get("byte_order", self.byte_order)
+ encoding = kwargs.get("encoding", "")
if bit_length <= 0:
raise SerializationException("unsigned int must contain at least 1 bit")
elif bit_length > 32:
@@ -247,14 +270,36 @@ def read_unsigned_int(
else:
if byte_order == ByteOrder.LITTLE_ENDIAN:
endian_string = "<"
+ padded = bitarray(
+ self.bb[self.position : self.position + bit_length]
+ ) + (32 - bit_length) * bitarray("0")
else:
endian_string = ">"
- padded = (32 - bit_length) * bitarray("0") + bitarray(
- self.bb[self.position : self.position + bit_length]
- )
- result: int = struct.unpack(endian_string + "I", padded)[0]
- self.position += bit_length
- return result
+ padded = (32 - bit_length) * bitarray("0") + bitarray(
+ self.bb[self.position : self.position + bit_length]
+ )
+ if encoding == "BCD":
+ if bit_length % 4 != 0:
+ raise ParseException(
+ "'BCD' encoded fields must have a length that is a multiple of 4 bits long"
+ )
+ if byte_order == ByteOrder.LITTLE_ENDIAN:
+ padded = padded[8:16] + padded[:8] + padded[24:32] + padded[16:24]
+ result: int = 0
+ for i in range(0, bit_length, 4):
+ digit: int = ba2int(padded[i : i + 4])
+ if digit > 9:
+ raise ParseException(
+ "'BCD' encoded value is not a correctly encoded BCD value"
+ )
+ multiplier = 10 ** ((int(bit_length - i) / 4) - 1)
+ result += multiplier * digit
+ self.position += bit_length
+ return result
+ else:
+ result: int = struct.unpack(endian_string + "I", padded)[0]
+ self.position += bit_length
+ return result
def read_unsigned_long(
self, bit_length: int = 64, logical_name: str = "", **kwargs
@@ -267,11 +312,14 @@ def read_unsigned_long(
else:
if byte_order == ByteOrder.LITTLE_ENDIAN:
endian_string = "<"
+ padded = bitarray(
+ self.bb[self.position : self.position + bit_length]
+ ) + (64 - bit_length) * bitarray("0")
else:
endian_string = ">"
- padded = (64 - bit_length) * bitarray("0") + bitarray(
- self.bb[self.position : self.position + bit_length]
- )
+ padded = (64 - bit_length) * bitarray("0") + bitarray(
+ self.bb[self.position : self.position + bit_length]
+ )
result: int = struct.unpack(endian_string + "Q", padded)[0]
self.position += bit_length
return result
@@ -301,11 +349,14 @@ def read_short(self, bit_length: int = 16, logical_name: str = "", **kwargs) ->
else:
if byte_order == ByteOrder.LITTLE_ENDIAN:
endian_string = "<"
+ padded = bitarray(
+ self.bb[self.position : self.position + bit_length]
+ ) + (16 - bit_length) * bitarray("0")
else:
endian_string = ">"
- padded = (16 - bit_length) * bitarray("0") + bitarray(
- self.bb[self.position : self.position + bit_length]
- )
+ padded = (16 - bit_length) * bitarray("0") + bitarray(
+ self.bb[self.position : self.position + bit_length]
+ )
result: int = struct.unpack(endian_string + "h", padded)[0]
self.position += bit_length
return result
@@ -319,11 +370,14 @@ def read_int(self, bit_length: int = 32, logical_name: str = "", **kwargs) -> in
else:
if byte_order == ByteOrder.LITTLE_ENDIAN:
endian_string = "<"
+ padded = bitarray(
+ self.bb[self.position : self.position + bit_length]
+ ) + (32 - bit_length) * bitarray("0")
else:
endian_string = ">"
- padded = (32 - bit_length) * bitarray("0") + bitarray(
- self.bb[self.position : self.position + bit_length]
- )
+ padded = (32 - bit_length) * bitarray("0") + bitarray(
+ self.bb[self.position : self.position + bit_length]
+ )
if (
byte_order == ByteOrder.BIG_ENDIAN_BYTE_SWAP
or byte_order == ByteOrder.LITTLE_ENDIAN_BYTE_SWAP
@@ -342,11 +396,14 @@ def read_long(self, bit_length: int = 64, logical_name: str = "", **kwargs) -> i
else:
if byte_order == ByteOrder.LITTLE_ENDIAN:
endian_string = "<"
+ padded = bitarray(
+ self.bb[self.position : self.position + bit_length]
+ ) + (64 - bit_length) * bitarray("0")
else:
endian_string = ">"
- padded = (64 - bit_length) * bitarray("0") + bitarray(
- self.bb[self.position : self.position + bit_length]
- )
+ padded = (64 - bit_length) * bitarray("0") + bitarray(
+ self.bb[self.position : self.position + bit_length]
+ )
if (
byte_order == ByteOrder.BIG_ENDIAN_BYTE_SWAP
or byte_order == ByteOrder.LITTLE_ENDIAN_BYTE_SWAP
diff --git a/plc4py/plc4py/spi/generation/WriteBuffer.py b/plc4py/plc4py/spi/generation/WriteBuffer.py
index b6519f5ee40..2a5e0ec145b 100644
--- a/plc4py/plc4py/spi/generation/WriteBuffer.py
+++ b/plc4py/plc4py/spi/generation/WriteBuffer.py
@@ -195,8 +195,10 @@ def write_bit(self, value: bool, logical_name: str = "", **kwargs) -> None:
self.bb[self.position] = value
self.position += 1
- def write_byte(self, value: int, logical_name: str = "", **kwargs) -> None:
- self.write_unsigned_byte(value, 8, logical_name, **kwargs)
+ def write_byte(
+ self, value: int, bit_length: int = 8, logical_name: str = "", **kwargs
+ ) -> None:
+ self.write_unsigned_byte(value, bit_length, logical_name, **kwargs)
def write_byte_array(
self, value: List[int], logical_name: str = "", **kwargs
@@ -346,6 +348,20 @@ def write_double(
raise SerializationException("Double can only contain max 64 bits")
self._handle_numeric_encoding(value, bit_length, numeric_format="d", **kwargs)
+ def write_str(
+ self,
+ value: str,
+ bit_length: int = -1,
+ logical_name: str = "",
+ encoding: str = "UTF-8",
+ **kwargs,
+ ) -> None:
+ bit_order = kwargs.get("bit_order", ByteOrder.BIG_ENDIAN)
+ src = bitarray(endian=ByteOrder.get_short_name(bit_order))
+ src.frombytes(value.encode(encoding))
+ self.bb[self.position : self.position + bit_length] = src[:bit_length]
+ self.position += bit_length
+
def write_complex_array(
self, value: List[PlcMessage], logical_name: str = "", **kwargs
) -> None:
@@ -376,10 +392,12 @@ def _handle_numeric_encoding(self, value, bit_length: int, **kwargs):
endianness = "<"
if not isinstance(value, int):
pass
+
result: bytes = struct.pack(
endianness + numeric_format,
value,
)
+
src.frombytes(result)
if (
byte_order == ByteOrder.BIG_ENDIAN_BYTE_SWAP
diff --git a/plc4py/plc4py/spi/messages/PlcWriter.py b/plc4py/plc4py/spi/messages/PlcWriter.py
index f3d943c5fd7..fc9c36b56db 100644
--- a/plc4py/plc4py/spi/messages/PlcWriter.py
+++ b/plc4py/plc4py/spi/messages/PlcWriter.py
@@ -86,7 +86,7 @@ async def _write(self, request: PlcWriteRequest) -> PlcWriteResponse:
# Send the write request to the device and wait for a response
logging.debug("Sending write request to Device")
response = await asyncio.wait_for(
- self._device.write(request, self._transport), 5
+ self._device.write(request, self._transport), 15
)
# Return the response
return response
diff --git a/plc4py/plc4py/spi/messages/utils/ResponseItem.py b/plc4py/plc4py/spi/messages/utils/ResponseItem.py
index f62912773cf..ddf225d206e 100644
--- a/plc4py/plc4py/spi/messages/utils/ResponseItem.py
+++ b/plc4py/plc4py/spi/messages/utils/ResponseItem.py
@@ -17,9 +17,11 @@
# under the License.
#
from abc import ABC
-from dataclasses import dataclass
-from typing import Generic, TypeVar, Union
+from dataclasses import dataclass, field
+from typing import Generic, TypeVar, Union, Dict, List
+
+from plc4py.api.messages.PlcField import PlcTag
from plc4py.api.messages.PlcResponse import PlcResponseCode
from plc4py.api.value.PlcValue import PlcValue
@@ -30,3 +32,27 @@
class ResponseItem(Generic[T], ABC):
response_code: PlcResponseCode
value: T
+
+
+@dataclass
+class ArrayInfo:
+ size: int
+ lower_bound: int
+ upper_bound: int
+
+
+R = TypeVar("R", bound=Union[PlcTag, None])
+
+
+@dataclass
+class PlcBrowseItem(Generic[R], ABC):
+ tag: R
+ name: str
+ readable: bool
+ writeable: bool
+ subscribable: bool
+ publishable: bool
+ array: bool
+ array_info: List[ArrayInfo] = field(default_factory=lambda: [])
+ children: Dict[str, "PlcBrowseItem"] = field(default_factory=lambda: {})
+ options: Dict[str, PlcValue] = field(default_factory=lambda: {})
diff --git a/plc4py/plc4py/spi/values/PlcValues.py b/plc4py/plc4py/spi/values/PlcValues.py
index 437c6a795f2..ed207cfb74d 100644
--- a/plc4py/plc4py/spi/values/PlcValues.py
+++ b/plc4py/plc4py/spi/values/PlcValues.py
@@ -17,9 +17,10 @@
# under the License.
#
from dataclasses import dataclass
+from datetime import datetime
from typing import Any, Dict, List
-from ...api.value.PlcValue import PlcValue
+from plc4py.api.value.PlcValue import PlcValue
class PlcINT(PlcValue[int]):
@@ -34,11 +35,11 @@ class PlcCHAR(PlcValue[str]):
pass
-class PlcDATE(PlcValue[int]):
+class PlcDATE(PlcValue[datetime]):
pass
-class PlcDATE_AND_TIME(PlcValue[int]):
+class PlcDATE_AND_TIME(PlcValue[datetime]):
pass
diff --git a/plc4py/plc4py/utils/ConnectionStringHandling.py b/plc4py/plc4py/utils/ConnectionStringHandling.py
index c4954de32db..4968c5b7eaf 100644
--- a/plc4py/plc4py/utils/ConnectionStringHandling.py
+++ b/plc4py/plc4py/utils/ConnectionStringHandling.py
@@ -30,3 +30,11 @@ def get_protocol_code(url: str) -> str:
"""
parsed = urlparse(url)
return parsed.scheme
+
+
+def strtobool(value: str) -> bool:
+ """Credit goes to https://danielms.site/zet/2023/pythons-distutil-strtobool-replacement/"""
+ value = value.lower()
+ if value in ("y", "yes", "on", "1", "true", "t"):
+ return True
+ return False
diff --git a/plc4py/pom.xml b/plc4py/pom.xml
index a2133680572..4952326df9e 100644
--- a/plc4py/pom.xml
+++ b/plc4py/pom.xml
@@ -215,6 +215,22 @@
+
+ python-test-compile
+ process-sources
+
+ exec
+
+
+ ${skipTests}
+ ${python.venv.bin}pip3
+
+ install
+ .[dev]
+
+
+
+
python-black
process-sources
@@ -232,17 +248,19 @@
- python-test-compile
+ python-dependency-check
test-compile
exec
- ${skipTests}
- ${python.venv.bin}pip3
+ ${python.venv.bin}${python.exe.bin}
- install
- .[dev]
+ -m
+ deptry
+ -ddg
+ dev
+ .
diff --git a/plc4py/pyproject.toml b/plc4py/pyproject.toml
new file mode 100644
index 00000000000..b58db1f1a81
--- /dev/null
+++ b/plc4py/pyproject.toml
@@ -0,0 +1,89 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+[build-system]
+requires = ["setuptools>=61.0", "wheel"]
+build-backend = "setuptools.build_meta"
+
+[tool.setuptools.packages.find]
+where = ["."] # list of folders that contain the packages (["."] by default)
+include = ["plc4py*"] # package names should match these glob patterns (["*"] by default)
+#exclude = ["my_package.tests*"] # exclude packages matching these glob patterns (empty by default)
+namespaces = false # to disable scanning PEP 420 namespaces (true by default)
+
+[project]
+name = "plc4py"
+description = "Plc4Py The Python Industrial IOT Adapter"
+version = "0.13"
+readme = "README.md"
+dependencies = [
+ "aenum",
+ "bitarray",
+ "typing_extensions",
+ "pluggy",
+ "xsdata",
+]
+classifiers = [
+ "Development Status :: 3 - Alpha",
+ "License :: OSI Approved :: Apache Software License",
+ "Programming Language :: Python :: 3.8",
+ "Topic :: Scientific/Engineering :: Interface Engine/Protocol Translator",
+]
+keywords=["modbus", "plc4x"]
+authors=[
+ {name='"Apache PLC4X <>"', email="dev@plc4x.apache.org"}
+]
+
+[project.urls]
+HomePage="https://plc4x.apache.org"
+Repository="https://github.com/apache/plc4x"
+
+[project.optional-dependencies]
+dev = [
+ "pytest-asyncio>=0.18.3",
+ "pip-tools",
+ "black",
+ "pip",
+ "deptry",
+ "requires",
+ "pre-commit>=2.6.0",
+ "pytest-mock>=3.8.1",
+ "mock>=4.0.2",
+ "mypy>=0.942",
+ "flake8>=4.0.1",
+ "pytest-asyncio",
+ "xsdata",
+]
+
+[project.entry-points."plc4py.drivers"]
+mock = "plc4py.drivers.mock.MockConnection:MockDriverLoader"
+modbus = "plc4py.drivers.modbus.ModbusConnection:ModbusDriverLoader"
+umas = "plc4py.drivers.umas.UmasConnection:UmasDriverLoader"
+
+[project.entry-points."plc4py.transports"]
+tcp = "plc4py.spi.transport.TCPTransport:TCPTransportLoader"
+mock = "plc4py.spi.transport.MockTransport:MockTransportLoader"
+
+[tool.pytest.ini_options]
+minversion = "6.0"
+addopts = "-ra -q"
+testpaths = [
+ "tests",
+]
+asyncio_mode = "auto"
+log_cli = "true"
diff --git a/plc4py/pytest.ini b/plc4py/pytest.ini
deleted file mode 100644
index 537563cdb10..00000000000
--- a/plc4py/pytest.ini
+++ /dev/null
@@ -1,21 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# https://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-[pytest]
-log_cli = true
\ No newline at end of file
diff --git a/plc4py/requirements.txt b/plc4py/requirements.txt
deleted file mode 100644
index 0b4e610f0af..00000000000
--- a/plc4py/requirements.txt
+++ /dev/null
@@ -1,54 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# https://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-aenum==3.1.15
-annotated-types==0.7.0
-bitarray==3.0.0
-black==24.10.0
-build==1.2.2.post1
-cfgv==3.4.0
-click==8.1.7
-coverage==7.6.4
-distlib==0.3.9
-filelock==3.16.1
-flake8==7.1.1
-funkify==0.4.5
-identify==2.6.1
-iniconfig==2.0.0
-mccabe==0.7.0
-mock==5.1.0
-mypy==1.13.0
-mypy-extensions==1.0.0
-nodeenv==1.9.1
-packaging==24.1
-pathspec==0.12.1
-pip-tools==7.4.1
-platformdirs==4.3.6
-pluggy==1.5.0
-pre-commit==4.0.1
-pycodestyle==2.12.1
-pyflakes==3.2.0
-pyproject_hooks==1.2.0
-pytest==8.3.3
-pytest-asyncio==0.24.0
-pytest-mock==3.14.0
-PyYAML==6.0.2
-requires==0.10.5
-typing_extensions==4.12.2
-virtualenv==20.27.0
-xtyping==0.8.2
diff --git a/plc4py/setup.cfg b/plc4py/setup.cfg
deleted file mode 100644
index 812fb33cb26..00000000000
--- a/plc4py/setup.cfg
+++ /dev/null
@@ -1,22 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# https://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-[tool:pytest]
-testpaths = tests
-asyncio_mode=auto
\ No newline at end of file
diff --git a/plc4py/setup.py b/plc4py/setup.py
deleted file mode 100644
index 9505736f533..00000000000
--- a/plc4py/setup.py
+++ /dev/null
@@ -1,74 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# https://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-from setuptools import setup, find_packages
-
-setup(
- name="plc4py",
- version="0.13",
- description="Plc4py The Python Industrial IOT Adapter",
- classifiers=[
- "Development Status :: 3 - Alpha",
- "License :: OSI Approved :: Apache Software License",
- "Programming Language :: Python :: 3.8",
- "Topic :: Scientific/Engineering :: Interface Engine/Protocol Translator",
- ],
- keywords="modbus plc4x",
- url="https://plc4x.apache.org",
- author='"Apache PLC4X <>"',
- author_email="dev@plc4x.apache.org",
- license="Apache 2.0",
- packages=find_packages(include=["plc4py", "plc4py.*"]),
- setup_requires=[
- "wheel",
- ],
- install_requires=[
- "pytest-asyncio>=0.18.3",
- "pip-tools",
- "black",
- "pip",
- "aenum",
- "bitarray",
- "typing_extensions",
- "pluggy",
- ],
- extras_require={
- "dev": [
- "requires",
- "pre-commit>=2.6.0",
- "pytest-mock>=3.8.1",
- "mock>=4.0.2",
- "mypy>=0.942",
- "flake8>=4.0.1",
- "pytest-asyncio",
- "xsdata",
- ]
- },
- entry_points={
- "plc4py.drivers": [
- "mock = plc4py.drivers.mock.MockConnection:MockDriverLoader",
- "modbus = plc4py.drivers.modbus.ModbusConnection:ModbusDriverLoader",
- "umas = plc4py.drivers.umas.UmasConnection:UmasDriverLoader",
- ],
- "plc4py.transports": [
- "tcp = plc4py.spi.transport.TCPTransport:TCPTransportLoader",
- "mock = plc4py.spi.transport.MockTransport:MockTransportLoader",
- ],
- },
-)
diff --git a/plc4py/tests/unit/plc4py/drivers/modbus/test_modbus_connection.py b/plc4py/tests/unit/plc4py/drivers/modbus/test_modbus_connection.py
index f3d2ea13ad8..b957876e7f0 100644
--- a/plc4py/tests/unit/plc4py/drivers/modbus/test_modbus_connection.py
+++ b/plc4py/tests/unit/plc4py/drivers/modbus/test_modbus_connection.py
@@ -17,382 +17,170 @@
# under the License.
#
import time
+from typing import AsyncGenerator
from unittest import TestCase
import pytest
+import pytest_asyncio
+from plc4py.api.PlcConnection import PlcConnection
from plc4py.PlcDriverManager import PlcDriverManager
from plc4py.api.value.PlcValue import PlcResponseCode
import logging
-from plc4py.spi.values.PlcValues import PlcINT, PlcREAL, PlcList
+from plc4py.spi.values.PlcValues import PlcINT, PlcREAL, PlcList, PlcBOOL, PlcCHAR
logger = logging.getLogger("testing")
-TEST_SERVER_IP = "192.168.190.174"
-@pytest.mark.asyncio
-@pytest.mark.xfail
-async def manual_test_plc_driver_modbus_connect():
- """
- Test the connection to a Modbus PLC using PlcDriverManager.
- """
- # Initialize the PlcDriverManager
+@pytest_asyncio.fixture
+async def connection() -> AsyncGenerator[PlcConnection, None]:
driver_manager = PlcDriverManager()
-
- # Establish a connection to the Modbus PLC
- async with driver_manager.connection(f"modbus://{TEST_SERVER_IP}") as connection:
- # Check if the connection is successful
- assert connection.is_connected()
-
- # Ensure the connection is closed after exiting the context manager
- assert not connection.is_connected()
+ async with driver_manager.connection("modbus://127.0.0.1:502") as connection:
+ yield connection
@pytest.mark.asyncio
@pytest.mark.xfail
-async def test_plc_driver_modbus_read_coil():
- """
- Test reading data from a Modbus PLC.
- """
- log = logging.getLogger(__name__)
+async def test_plc_driver_modbus_connect(connection):
+ assert connection.is_connected
- # Initialize the PlcDriverManager
- driver_manager = PlcDriverManager()
- # Establish a connection to the Modbus PLC
- async with driver_manager.connection(
- f"modbus://{TEST_SERVER_IP}:502"
- ) as connection:
- with connection.read_request_builder() as builder:
- builder.add_item("Random Tag", "0x00001")
- request = builder.build()
- response = await connection.execute(request)
- value = response.tags["Random Tag"].value
- assert value == True
+async def write_read(connection, tag_name, tag_value):
+ tag_alias = "Some Random Alias"
+ with connection.write_request_builder() as builder:
+ builder.add_item(tag_alias, tag_name, tag_value)
+ write_request = builder.build()
+ with connection.read_request_builder() as builder:
+ builder.add_item(tag_alias, tag_name)
+ read_request = builder.build()
+ future = connection.execute(write_request)
+ response = await future
+ assert response.response_code == PlcResponseCode.OK
+ future = connection.execute(read_request)
+ response = await future
+ assert response.response_code == PlcResponseCode.OK
-@pytest.mark.asyncio
-@pytest.mark.xfail
-async def test_plc_driver_modbus_read_coil_non_bool():
- """
- Test reading data from a Modbus PLC.
- """
- log = logging.getLogger(__name__)
-
- # Initialize the PlcDriverManager
- driver_manager = PlcDriverManager()
-
- # Establish a connection to the Modbus PLC
- async with driver_manager.connection(
- f"modbus://{TEST_SERVER_IP}:502"
- ) as connection:
- with connection.read_request_builder() as builder:
- builder.add_item("Random Tag", "0x00001:REAL")
- request = builder.build()
- TestCase.assertRaises(
- await connection.execute(request), NotImplementedError
- )
+ value = response.tags[tag_alias].value
+ response_code = response.tags[tag_alias].response_code
+ assert value == tag_value
+ assert response_code == PlcResponseCode.OK
@pytest.mark.asyncio
@pytest.mark.xfail
-async def test_plc_driver_modbus_read_coil_array():
- """
- Test reading data from a Modbus PLC.
- """
- log = logging.getLogger(__name__)
-
- # Initialize the PlcDriverManager
- driver_manager = PlcDriverManager()
-
- # Establish a connection to the Modbus PLC
- async with driver_manager.connection(
- f"modbus://{TEST_SERVER_IP}:502"
- ) as connection:
- with connection.read_request_builder() as builder:
- builder.add_item("Random Tag", "0x00001[2]")
- request = builder.build()
- response = await connection.execute(request)
- value = response.tags["Random Tag"].value
- assert value == [True, False]
+async def test_plc_driver_modbus_read_boolean(connection):
+ tag_name = "0x00001"
+ await write_read(connection, tag_name, PlcBOOL(True))
@pytest.mark.asyncio
@pytest.mark.xfail
-async def test_plc_driver_modbus_read_contacts():
- """
- Test reading data from a Modbus PLC.
- """
- log = logging.getLogger(__name__)
-
- # Initialize the PlcDriverManager
- driver_manager = PlcDriverManager()
-
- # Establish a connection to the Modbus PLC
- async with driver_manager.connection(
- f"modbus://{TEST_SERVER_IP}:502"
- ) as connection:
- with connection.read_request_builder() as builder:
- builder.add_item("Random Tag", "1x00001")
- request = builder.build()
- response = await connection.execute(request)
- value = response.tags["Random Tag"].value
- assert value == True
+async def test_plc_driver_modbus_read_int(connection):
+ tag_name = "4x00001"
+ await write_read(connection, tag_name, PlcINT(83))
@pytest.mark.asyncio
@pytest.mark.xfail
-async def test_plc_driver_modbus_read_contact_array():
- """
- Test reading data from a Modbus PLC.
- """
- log = logging.getLogger(__name__)
-
- # Initialize the PlcDriverManager
- driver_manager = PlcDriverManager()
-
- # Establish a connection to the Modbus PLC
- async with driver_manager.connection(
- f"modbus://{TEST_SERVER_IP}:502"
- ) as connection:
- with connection.read_request_builder() as builder:
- builder.add_item("Random Tag", "1x00001[2]")
- request = builder.build()
- response = await connection.execute(request)
- value = response.tags["Random Tag"].value
- assert value == [True, False]
+async def test_plc_driver_modbus_read_real(connection):
+ tag_name = "4x00001"
+ await write_read(connection, tag_name, PlcINT(83))
@pytest.mark.asyncio
@pytest.mark.xfail
-async def test_plc_driver_modbus_read_input_register():
- """
- Test reading data from a Modbus PLC.
- """
- log = logging.getLogger(__name__)
-
- # Initialize the PlcDriverManager
- driver_manager = PlcDriverManager()
-
- # Establish a connection to the Modbus PLC
- async with driver_manager.connection(
- f"modbus://{TEST_SERVER_IP}:502"
- ) as connection:
- with connection.read_request_builder() as builder:
- builder.add_item("Random Tag", "3x00001")
- request = builder.build()
- response = await connection.execute(request)
- value = response.tags["Random Tag"].value
- assert value == 333
+async def test_plc_driver_modbus_read_bool_array(connection):
+ tag_name = "0x00001[2]"
+ await write_read(connection, tag_name, PlcList([PlcBOOL(True), PlcBOOL(False)]))
@pytest.mark.asyncio
@pytest.mark.xfail
-async def test_plc_driver_modbus_read_input_register_array():
- """
- Test reading data from a Modbus PLC.
- """
- log = logging.getLogger(__name__)
-
- # Initialize the PlcDriverManager
- driver_manager = PlcDriverManager()
-
- # Establish a connection to the Modbus PLC
- async with driver_manager.connection(
- f"modbus://{TEST_SERVER_IP}:502"
- ) as connection:
- with connection.read_request_builder() as builder:
- builder.add_item("Random Tag", "3x00001[2]")
- request = builder.build()
- response = await connection.execute(request)
- value = response.tags["Random Tag"].value
- assert value == [333, 0]
+async def test_plc_driver_modbus_read_contacts(connection):
+ tag_name = "1x00001"
+ await write_read(connection, tag_name, PlcBOOL(True))
@pytest.mark.asyncio
@pytest.mark.xfail
-async def test_plc_driver_modbus_read_holding():
- """
- Test reading data from a Modbus PLC.
- """
- log = logging.getLogger(__name__)
-
- # Initialize the PlcDriverManager
- driver_manager = PlcDriverManager()
-
- # Establish a connection to the Modbus PLC
- async with driver_manager.connection(
- f"modbus://{TEST_SERVER_IP}:502"
- ) as connection:
- with connection.read_request_builder() as builder:
- builder.add_item("Random Tag", "4x00001")
- request = builder.build()
- response = await connection.execute(request)
- value = response.tags["Random Tag"].value
- assert value == 874
+async def test_plc_driver_modbus_read_bool_array_discrete_input(connection):
+ tag_name = "1x00001[2]"
+ await write_read(connection, tag_name, PlcList([PlcBOOL(True), PlcBOOL(False)]))
@pytest.mark.asyncio
@pytest.mark.xfail
-async def test_plc_driver_modbus_read_holding():
- """
- Test reading data from a Modbus PLC.
- """
- log = logging.getLogger(__name__)
-
- # Initialize the PlcDriverManager
- driver_manager = PlcDriverManager()
-
- # Establish a connection to the Modbus PLC
- async with driver_manager.connection(
- f"modbus://{TEST_SERVER_IP}:502"
- ) as connection:
- with connection.read_request_builder() as builder:
- builder.add_item("Random Tag", "4x00001[2]")
- request = builder.build()
- response = await connection.execute(request)
- value = response.tags["Random Tag"].value
- assert value == [874, 0]
+async def test_plc_driver_modbus_read_input_register(connection):
+ tag_name = "3x00001"
+ await write_read(connection, tag_name, PlcINT(333))
@pytest.mark.asyncio
@pytest.mark.xfail
-async def test_plc_driver_modbus_read_holding_real():
- """
- Test reading data from a Modbus PLC.
- """
- log = logging.getLogger(__name__)
-
- # Initialize the PlcDriverManager
- driver_manager = PlcDriverManager()
-
- # Establish a connection to the Modbus PLC
- async with driver_manager.connection(
- f"modbus://{TEST_SERVER_IP}:502?byte_order=BIG_ENDIAN_BYTE_SWAP"
- ) as connection:
- with connection.read_request_builder() as builder:
- builder.add_item("Random Tag", "4x00011:REAL[2]")
- request = builder.build()
- response = await connection.execute(request)
- value = response.tags["Random Tag"].value
- assert value == [PlcREAL(value=874), PlcREAL(value=0.0)]
+async def test_plc_driver_modbus_read_input_register_array(connection):
+ tag_name = "3x00001[2]"
+ await write_read(connection, tag_name, PlcList([PlcINT(333), PlcINT(0)]))
@pytest.mark.asyncio
@pytest.mark.xfail
-async def test_plc_driver_modbus_read_holding_string_even():
- """
- Test reading data from a Modbus PLC.
- """
- log = logging.getLogger(__name__)
-
- # Initialize the PlcDriverManager
- driver_manager = PlcDriverManager()
-
- # Establish a connection to the Modbus PLC
- async with driver_manager.connection(
- f"modbus://{TEST_SERVER_IP}:502"
- ) as connection:
- with connection.read_request_builder() as builder:
- builder.add_item("Random Tag", "4x00041:CHAR[6]")
- request = builder.build()
- response = await connection.execute(request)
- value = response.tags["Random Tag"].value
- assert value == [b"F", b"A", b"F", b"B", b"C", b"B"]
+async def test_plc_driver_modbus_read_holding_register(connection):
+ tag_name = "4x00001"
+ await write_read(connection, tag_name, PlcINT(334))
@pytest.mark.asyncio
@pytest.mark.xfail
-async def test_plc_driver_modbus_read_holding_string_odd():
- """
- Test reading data from a Modbus PLC.
- """
- log = logging.getLogger(__name__)
-
- # Initialize the PlcDriverManager
- driver_manager = PlcDriverManager()
-
- # Establish a connection to the Modbus PLC
- async with driver_manager.connection(
- f"modbus://{TEST_SERVER_IP}:502"
- ) as connection:
- with connection.read_request_builder() as builder:
- builder.add_item("Random Tag", "4x00041:CHAR[5]")
- request = builder.build()
- response = await connection.execute(request)
- value = response.tags["Random Tag"].value
- assert value == [b"F", b"A", b"F", b"B", b"C"]
+async def test_plc_driver_modbus_read_holdiong_register_array(connection):
+ tag_name = "4x00001[2]"
+ await write_read(connection, tag_name, PlcList([PlcINT(334), PlcINT(0)]))
@pytest.mark.asyncio
@pytest.mark.xfail
-async def test_plc_driver_modbus_write_holding_int():
- """
- Test reading data from a Modbus PLC.
- """
- log = logging.getLogger(__name__)
-
- # Initialize the PlcDriverManager
- driver_manager = PlcDriverManager()
-
- # Establish a connection to the Modbus PLC
- async with driver_manager.connection(
- f"modbus://{TEST_SERVER_IP}:502"
- ) as connection:
- with connection.write_request_builder() as builder:
- builder.add_item("Random Tag", "4x00001", PlcINT(874))
- request = builder.build()
- response = await connection.execute(request)
- value = response.tags["Random Tag"]
- assert value.response_code == PlcResponseCode.OK
+async def test_plc_driver_modbus_read_holding_register_real(connection):
+ tag_name = "4x00011:REAL[2]"
+ await write_read(
+ connection, tag_name, PlcList([PlcREAL(value=874), PlcREAL(value=0.0)])
+ )
@pytest.mark.asyncio
@pytest.mark.xfail
-async def test_plc_driver_modbus_write_holding_int_array():
- """
- Test reading data from a Modbus PLC.
- """
- log = logging.getLogger(__name__)
-
- # Initialize the PlcDriverManager
- driver_manager = PlcDriverManager()
-
- # Establish a connection to the Modbus PLC
- async with driver_manager.connection(
- f"modbus://{TEST_SERVER_IP}:502"
- ) as connection:
- with connection.write_request_builder() as builder:
- builder.add_item(
- "Random Tag",
- "4x00001[5]",
- PlcList([PlcINT(874), PlcINT(0), PlcINT(3), PlcINT(4), PlcINT(5)]),
- )
- request = builder.build()
- response = await connection.execute(request)
- value = response.tags["Random Tag"]
- assert value.response_code == PlcResponseCode.OK
+async def test_plc_driver_modbus_read_holding_string_even(connection):
+ tag_name = "4x00041:CHAR[6]"
+ await write_read(
+ connection,
+ tag_name,
+ PlcList(
+ [
+ PlcCHAR(value=b"F"),
+ PlcCHAR(value=b"A"),
+ PlcCHAR(value=b"F"),
+ PlcCHAR(value=b"B"),
+ PlcCHAR(value=b"C"),
+ PlcCHAR(value=b"B"),
+ ]
+ ),
+ )
@pytest.mark.asyncio
@pytest.mark.xfail
-async def test_plc_driver_modbus_write_holding_real():
- """
- Test reading data from a Modbus PLC.
- """
- log = logging.getLogger(__name__)
-
- # Initialize the PlcDriverManager
- driver_manager = PlcDriverManager()
-
- # Establish a connection to the Modbus PLC
- async with driver_manager.connection(
- f"modbus://{TEST_SERVER_IP}:502?byte_order=BIG_ENDIAN_BYTE_SWAP"
- ) as connection:
- with connection.write_request_builder() as builder:
- builder.add_item("Random Tag", "4x00011:REAL", PlcREAL(874))
- request = builder.build()
- response = await connection.execute(request)
- value = response.tags["Random Tag"]
- assert value.response_code == PlcResponseCode.OK
+async def test_plc_driver_modbus_read_holding_string_odd(connection):
+ tag_name = "4x00041:CHAR[5]"
+ await write_read(
+ connection,
+ tag_name,
+ PlcList(
+ [
+ PlcCHAR(value=b"F"),
+ PlcCHAR(value=b"A"),
+ PlcCHAR(value=b"F"),
+ PlcCHAR(value=b"B"),
+ PlcCHAR(value=b"C"),
+ ]
+ ),
+ )
diff --git a/plc4py/tests/unit/plc4py/drivers/umas/test_umas_connection.py b/plc4py/tests/unit/plc4py/drivers/umas/test_umas_connection.py
index 82a18f1f1fe..e03d4cdb9f6 100644
--- a/plc4py/tests/unit/plc4py/drivers/umas/test_umas_connection.py
+++ b/plc4py/tests/unit/plc4py/drivers/umas/test_umas_connection.py
@@ -17,50 +17,229 @@
# under the License.
#
import asyncio
+import datetime
import logging
import time
+from typing import AsyncGenerator
import pytest
+import pytest_asyncio
+from plc4py.api.PlcConnection import PlcConnection
+from plc4py.api.value.PlcValue import PlcResponseCode
from plc4py.PlcDriverManager import PlcDriverManager
+from plc4py.spi.values.PlcValues import (
+ PlcBOOL,
+ PlcINT,
+ PlcREAL,
+ PlcDINT,
+ PlcSTRING,
+ PlcTIME,
+ PlcBYTE,
+ PlcDATE,
+ PlcDATE_AND_TIME,
+ PlcList,
+)
+
+
+@pytest_asyncio.fixture
+async def connection() -> AsyncGenerator[PlcConnection, None]:
+ driver_manager = PlcDriverManager()
+ async with driver_manager.connection("umas://127.0.0.1:502") as connection:
+ yield connection
@pytest.mark.asyncio
@pytest.mark.xfail
-async def manual_test_plc_driver_umas_connect():
- driver_manager = PlcDriverManager()
- async with driver_manager.connection("umas://127.0.0.1:5555") as connection:
- assert connection.is_connected()
- assert not connection.is_connected()
+async def test_plc_driver_umas_connect(connection):
+ assert connection.is_connected
+
+
+async def write_read(connection, tag_name, tag_value):
+ tag_alias = "Some Random Alias"
+ with connection.write_request_builder() as builder:
+ builder.add_item(tag_alias, tag_name, tag_value)
+ write_request = builder.build()
+ with connection.read_request_builder() as builder:
+ builder.add_item(tag_alias, tag_name)
+ read_request = builder.build()
+ future = connection.execute(write_request)
+ response = await future
+ assert response.response_code == PlcResponseCode.OK
+
+ future = connection.execute(read_request)
+ response = await future
+ assert response.response_code == PlcResponseCode.OK
+
+ value = response.tags[tag_alias].value
+ response_code = response.tags[tag_alias].response_code
+ assert value == tag_value
+ assert response_code == PlcResponseCode.OK
@pytest.mark.asyncio
@pytest.mark.xfail
-async def test_plc_driver_umas_read():
- log = logging.getLogger(__name__)
+async def test_plc_driver_umas_read_boolean(connection):
+ tag_name = "TESTING"
+ await write_read(connection, tag_name, PlcBOOL(True))
- driver_manager = PlcDriverManager()
- async with driver_manager.connection("umas://192.168.190.174:502") as connection:
- with connection.read_request_builder() as builder:
- builder.add_item(f"Random Tag {1}", "blurbe:REAL")
- request = builder.build()
- future = connection.execute(request)
- response = await future
- value = response.tags["Random Tag 1"].value
- assert value == 0.0
+@pytest.mark.asyncio
+@pytest.mark.xfail
+async def test_plc_driver_umas_read_boolean_with_data_type(connection):
+ tag_name = "TESTING:BOOL"
+ await write_read(connection, tag_name, PlcBOOL(True))
@pytest.mark.asyncio
@pytest.mark.xfail
-async def test_plc_driver_umas_browse():
- driver_manager = PlcDriverManager()
- async with driver_manager.connection("umas://192.168.190.174:502") as connection:
- with connection.browse_request_builder() as builder:
- builder.add_query("All Tags", "*")
- request = builder.build()
-
- future = connection.execute(request)
- await future
- response = future.result()
- pass
+async def test_plc_driver_umas_read_int(connection):
+ tag_name = "TESTING_INT"
+ await write_read(connection, tag_name, PlcINT(99))
+
+
+@pytest.mark.asyncio
+@pytest.mark.xfail
+async def test_plc_driver_umas_read_int_with_data_type(connection):
+ tag_name = "TESTING_INT:INT"
+ await write_read(connection, tag_name, PlcINT(99))
+
+
+@pytest.mark.asyncio
+@pytest.mark.xfail
+async def test_plc_driver_umas_read_dint(connection):
+ tag_name = "TESTING_DINT"
+ await write_read(connection, tag_name, PlcDINT(763539))
+
+
+@pytest.mark.asyncio
+@pytest.mark.xfail
+async def test_plc_driver_umas_read_dint_with_data_type(connection):
+ tag_name = "TESTING_DINT:DINT"
+ await write_read(connection, tag_name, PlcDINT(763539))
+
+
+@pytest.mark.asyncio
+@pytest.mark.xfail
+async def test_plc_driver_umas_read_ebool(connection):
+ tag_name = "TESTING_EBOOL"
+ await write_read(connection, tag_name, PlcBOOL(True))
+
+
+@pytest.mark.asyncio
+@pytest.mark.xfail
+async def test_plc_driver_umas_read_ebool_with_data_type(connection):
+ tag_name = "TESTING_EBOOL:BOOL"
+ await write_read(connection, tag_name, PlcBOOL(True))
+
+
+@pytest.mark.asyncio
+@pytest.mark.xfail
+async def test_plc_driver_umas_read_string(connection):
+ tag_name = "TESTING_STRING"
+ await write_read(connection, tag_name, PlcSTRING("Hello pyToddy!"))
+
+
+@pytest.mark.asyncio
+@pytest.mark.xfail
+async def test_plc_driver_umas_read_string_with_data_type(connection):
+ tag_name = "TESTING_STRING:STRING"
+ await write_read(connection, tag_name, PlcSTRING("Hello pyToddy!"))
+
+
+@pytest.mark.asyncio
+@pytest.mark.xfail
+async def test_plc_driver_umas_read_time(connection):
+ tag_name = "TESTING_TIME"
+ await write_read(connection, tag_name, PlcTIME(200000))
+
+
+@pytest.mark.asyncio
+@pytest.mark.xfail
+async def test_plc_driver_umas_read_time_with_data_type(connection):
+ tag_name = "TESTING_TIME:TIME"
+ await write_read(connection, tag_name, PlcTIME(200000))
+
+
+@pytest.mark.asyncio
+@pytest.mark.xfail
+async def test_plc_driver_umas_read_byte(connection):
+ tag_name = "TESTING_BYTE"
+ await write_read(connection, tag_name, PlcBYTE(253))
+
+
+@pytest.mark.asyncio
+@pytest.mark.xfail
+async def test_plc_driver_umas_read_byte_with_data_type(connection):
+ tag_name = "TESTING_BYTE:BYTE"
+ await write_read(connection, tag_name, PlcBYTE(253))
+
+
+@pytest.mark.asyncio
+@pytest.mark.xfail
+async def test_plc_driver_umas_read_date(connection):
+ tag_name = "TESTING_DATE"
+ await write_read(connection, tag_name, PlcDATE(datetime.datetime(2024, 10, 25)))
+
+
+@pytest.mark.asyncio
+@pytest.mark.xfail
+async def test_plc_driver_umas_read_time_with_data_type(connection):
+ tag_name = "TESTING_DATE:DATE"
+ await write_read(connection, tag_name, PlcDATE(datetime.datetime(2025, 11, 22)))
+
+
+@pytest.mark.asyncio
+@pytest.mark.xfail
+async def test_plc_driver_umas_read_dt(connection):
+ tag_name = "TESTING_DT"
+ await write_read(
+ connection, tag_name, PlcDATE_AND_TIME(datetime.datetime(2000, 1, 10, 0, 40))
+ )
+
+
+@pytest.mark.asyncio
+@pytest.mark.xfail
+async def test_plc_driver_umas_read_dt_with_data_type(connection):
+ tag_alias = "Random Tag"
+ tag_name = "TESTING_DT:DATE_AND_TIME"
+ await write_read(
+ connection, tag_name, PlcDATE_AND_TIME(datetime.datetime(2002, 10, 31, 3, 38))
+ )
+
+
+@pytest.mark.asyncio
+@pytest.mark.xfail
+async def test_plc_driver_umas_read_array(connection):
+ tag_name = "TESTING_BYTE_ARRAY:BYTE[10]"
+ await write_read(
+ connection,
+ tag_name,
+ PlcList(
+ [
+ PlcBYTE(1),
+ PlcBYTE(2),
+ PlcBYTE(3),
+ PlcBYTE(4),
+ PlcBYTE(5),
+ PlcBYTE(6),
+ PlcBYTE(7),
+ PlcBYTE(8),
+ PlcBYTE(9),
+ PlcBYTE(10),
+ ]
+ ),
+ )
+
+
+@pytest.mark.asyncio
+@pytest.mark.xfail
+async def test_plc_driver_umas_browse(connection):
+ with connection.browse_request_builder() as builder:
+ builder.add_query("All Tags", "*")
+ request = builder.build()
+
+ future = connection.execute(request)
+ response = await future
+
+ pass
diff --git a/protocols/umas/src/main/resources/protocols/umas/umas.mspec b/protocols/umas/src/main/resources/protocols/umas/umas.mspec
index 1b5a32b0c12..cf65be4c060 100644
--- a/protocols/umas/src/main/resources/protocols/umas/umas.mspec
+++ b/protocols/umas/src/main/resources/protocols/umas/umas.mspec
@@ -196,19 +196,16 @@
[simple uint 4 isArray]
[simple uint 4 dataSizeIndex]
[simple uint 16 block]
- [const uint 8 unknown1 0x01]
[simple uint 16 baseOffset]
- [simple uint 8 offset]
+ [simple uint 16 offset]
[optional uint 16 arrayLength 'isArray']
- [array byte recordData length 'isArray == 1 ? dataSizeIndex * arrayLength : dataSizeIndex']
+ [array byte recordData length 'isArray == 1 ? dataSizeIndex * arrayLength : dataSizeIndex']
]
[type UmasUnlocatedVariableReference
- [simple uint 8 dataType]
- [simple uint 8 unknown1]
+ [simple uint 16 dataType]
[simple uint 16 block]
- [simple uint 8 offset]
- [simple uint 8 baseOffset]
+ [simple uint 16 offset]
[simple uint 16 unknown4]
[simple uint 16 stringLength]
[manual vstring value 'STATIC_CALL("parseTerminatedString", readBuffer, stringLength)' 'STATIC_CALL("serializeTerminatedString", writeBuffer, value, stringLength)' '(stringLength * 8)']
@@ -238,24 +235,22 @@
[simple uint 32 memoryLength]
]
-
[dataIo DataItem(UmasDataType dataType, uint 16 numberOfValues)
[typeSwitch dataType,numberOfValues
['BOOL','1' BOOL
+ [reserved uint 7 '0x0000' ]
+ [simple bit value ]
+ ]
+ ['EBOOL','1' BOOL
// TODO: Possibly change the order of the bit and the reserved part.
[reserved uint 7 '0x0000' ]
[simple bit value ]
]
- ['BOOL' List
- // TODO: Handle adding some reserved bits at the end to fill up the last word.
- [array bit value count 'numberOfValues' ]
- ]
['BYTE','1' BYTE
- [simple uint 8 value]
+ [simple byte value]
]
['BYTE' List
- // TODO: If the number of values is odd, add a reserved byte
- [array bit value count 'numberOfValues * 8' ]
+ [array byte value count 'numberOfValues' ]
]
['WORD' WORD
[simple uint 16 value]
@@ -294,40 +289,66 @@
[array float 32 value count 'numberOfValues']
]
['STRING','1' STRING
- [manual vstring value 'STATIC_CALL("parseTerminatedStringBytes", readBuffer, numberOfValues)' 'STATIC_CALL("serializeTerminatedString", writeBuffer, value, numberOfValues)' '(numberOfValues * 8)']
+ [manual vstring value 'STATIC_CALL("parseTerminatedStringBytes", readBuffer, numberOfValues)' 'STATIC_CALL("serializeTerminatedString", writeBuffer, _value, numberOfValues)' '(numberOfValues * 8)']
]
['STRING' List
[array float 32 value count 'numberOfValues']
]
+ ['TIME','1' TIME
+ [simple uint 32 value]
+ ]
+ ['TIME' List
+ [array uint 32 value count 'numberOfValues']
+ ]
+ ['DATE','1' DATE
+ [simple uint 8 day encoding='BCD']
+ [simple uint 8 month encoding='BCD']
+ [simple uint 16 year encoding='BCD']
+ ]
+ ['TOD','1' TIME_OF_DAY
+ [simple uint 32 value]
+ ]
+ ['TOD' List
+ [array uint 32 value count 'numberOfValues']
+ ]
+ ['DATE_AND_TIME','1' DATE_AND_TIME
+ [simple uint 8 unused]
+ [simple uint 8 seconds encoding='BCD']
+ [simple uint 8 minutes encoding='BCD']
+ [simple uint 8 hour encoding='BCD']
+ [simple uint 8 day encoding='BCD']
+ [simple uint 8 month encoding='BCD']
+ [simple uint 16 year encoding='BCD']
+ ]
]
]
-[enum uint 8 UmasDataType(uint 8 dataTypeSize, uint 8 requestSize)
- ['1' BOOL ['1','1']]
- ['2' UNKNOWN2 ['1','1']]
- ['3' UNKNOWN3 ['1','1']]
- ['4' INT ['2', '2']]
- ['5' UINT ['2','2']]
- ['6' DINT ['4','3']]
- ['7' UDINT ['4','3']]
- ['8' REAL ['4','3']]
- ['9' STRING ['1','17']]
- ['10' TIME ['4','3']]
- ['11' UNKNOWN11 ['1','1']]
- ['12' UNKNOWN12 ['1','1']]
- ['13' UNKNOWN13 ['1','1']]
- ['14' DATE ['4','3']]
- ['15' TOD ['4','3']]
- ['16' DT ['4','3']]
- ['17' UNKNOWN17 ['1','1']]
- ['18' UNKNOWN18 ['1','1']]
- ['19' UNKNOWN19 ['1','1']]
- ['20' UNKNOWN20 ['1','1']]
- ['21' BYTE ['1','1']]
- ['22' WORD ['2','2']]
- ['23' DWORD ['4','3']]
- ['24' UNKNOWN24 ['1','1']]
- ['25' EBOOL ['1','1']]
+[enum uint 8 UmasDataType(uint 8 dataTypeSize, uint 8 requestSize, vstring data_type_conversion )
+ ['1' BOOL ['1','1','"BOOL"']]
+ ['2' UNKNOWN2 ['1','1','"BOOL"']]
+ ['3' UNKNOWN3 ['1','1','"BOOL"']]
+ ['4' INT ['2', '2','"INT"']]
+ ['5' UINT ['2','2','"UINT"']]
+ ['6' DINT ['4','3','"DINT"']]
+ ['7' UDINT ['4','3','"UDINT"']]
+ ['8' REAL ['4','3','"REAL"']]
+ ['9' STRING ['1','17','"STRING"']]
+ ['10' TIME ['4','3','"TIME"']]
+ ['11' UNKNOWN11 ['1','1','"BYTE"']]
+ ['12' UNKNOWN12 ['1','1','"BYTE"']]
+ ['13' UNKNOWN13 ['1','1','"BYTE"']]
+ ['14' DATE ['4','3','"DATE"']]
+ ['15' TOD ['4','3','"TIME_OF_DAY"']]
+ ['16' DATE_AND_TIME ['8','4','"DATE_AND_TIME"']]
+ ['17' UNKNOWN17 ['1','1','"BYTE"']]
+ ['18' UNKNOWN18 ['1','1','"BYTE"']]
+ ['19' UNKNOWN19 ['1','1','"BYTE"']]
+ ['20' UNKNOWN20 ['1','1','"BYTE"']]
+ ['21' BYTE ['1','1','"BYTE"']]
+ ['22' WORD ['2','2','"WORD"']]
+ ['23' DWORD ['4','3','"DWORD"']]
+ ['24' UNKNOWN24 ['1','1','"BYTE"']]
+ ['25' EBOOL ['1','1','"BOOL"']]
]
[enum uint 8 ModbusErrorCode
diff --git a/src/site/asciidoc/users/protocols/index.adoc b/src/site/asciidoc/users/protocols/index.adoc
index 5ad3536941c..4bb5e16e541 100644
--- a/src/site/asciidoc/users/protocols/index.adoc
+++ b/src/site/asciidoc/users/protocols/index.adoc
@@ -153,6 +153,13 @@
|icon:check[role="green"]
|icon:times[role="red"]
+|UMAS
+|icon:times[role="red"]
+|icon:times[role="red"]
+|icon:times[role="red"]
+|icon:times[role="red"]
+|icon:check[role="green"]
+
|===
Legend:
@@ -379,6 +386,17 @@ The following table contains a list of operations and the protocols that support
|icon:question[role="red"]
|icon:question[role="red"]
+|UMAS
+|icon:question[role="red"]
+|icon:question[role="red"]
+|icon:check[role="green"]
+|icon:check[role="green"]
+|icon:check[role="green"]
+|icon:question[role="red"]
+|icon:question[role="red"]
+|icon:question[role="red"]
+|icon:question[role="red"]
+
|===
Legend:
diff --git a/src/site/asciidoc/users/protocols/umas.adoc b/src/site/asciidoc/users/protocols/umas.adoc
new file mode 100644
index 00000000000..3b188c97ee2
--- /dev/null
+++ b/src/site/asciidoc/users/protocols/umas.adoc
@@ -0,0 +1,118 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+:imagesdir: ../../images/users/protocols
+:icons: font
+
+== UMAS (Schneider Electric PLCs)
+
+(Supported by Plc4Py Only)
+
+=== Connection String Options
+
+[cols="2,2a,2a,2a,4a"]
+|===
+|Name |Type |Default Value |Required |Description
+|Name 4+|UMAS
+|Code 4+|`umas`
+|Default Transport 4+|`tcp`
+|Supported Transports 4+|
+ - `tcp`
+5+|Config options:
+|`request-timeout` |INT |5000| |Default timeout for all types of requests.
+|`unit-identifier` |INT |1| |Unit-identifier or slave-id that identifies the target PLC. Defaults to 1.
++++
+
+|===
+=== Supported Operations
+
+[cols="2,2a,5a"]
+|===
+|Name |Value |Description
+
+3+|Supported Operations
+
+|
+2+| `read`
+
+|
+2+| `write`
+
+|
+2+| `browse`
+|===
+
+=== Individual Resource Address Format
+
+==== Connection String
+
+UMAS has the following connection string format:-
+----
+umas:{transport}://{ip-address}:{port}?{options}
+----
+An example connection string would look like:-
+----
+umas:tcp://127.0.0.1:502
+----
+Note the transport, port and option fields are optional.
+
+
+==== General Format
+
+In general all UMAS addresses have this format:
+
+----
+{tag-name}.{child-name}.{child-name}:{data-type}[{array-size}]
+----
+
+Depending on the type of tag the child-name parameters are optional.
+e.g. A tag with a BOOL data type could be 'TESTING_BOOL_1' whereas
+if it is a UDT the tag name is followed by the child 'TESTING_UDT_1.START' which in itself could be a BOOL.
+
+If the array-size part is omitted, the size-default of `1` is assumed.
+
+If the data-type part is omitted, it defaults to the data type of the tag read from the PLC.
+
+==== Memory Areas
+
+Apart from tags defined in the PLC the driver is also able to access the %S and %SW
+system memory areas.
+
+The specific address details of the data in these areas are outlined in the devices
+manual.
+
+An example of the address format of these areas is %SW1 or %S20.
+
+==== Data Types
+
+The following data types are supported
+
+- BOOL (boolean)
+- SINT (int 8)
+- USINT (uint 8)
+- BYTE (uint 8)
+- INT (int 16)
+- UINT (uint 16)
+- WORD (uint 16)
+- DINT (int 32)
+- UDINT (uint 32)
+- DWORD (uint 32)
+- REAL (float)
+- STRING (char)
+- TIME
+- DATE
+- TOD (Time of Day)
+- DATE_AND_TIME
diff --git a/src/site/site.xml b/src/site/site.xml
index 0e4d6cd09af..8f37821fd30 100644
--- a/src/site/site.xml
+++ b/src/site/site.xml
@@ -87,6 +87,7 @@
+
-