You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by jf...@apache.org on 2020/10/21 13:42:20 UTC
[plc4x] 02/08: Cherry Picked commit to add Simotion Syntax to S7
Driver. Migrated everything to "native" decoding without mspec.
This is an automated email from the ASF dual-hosted git repository.
jfeinauer pushed a commit to branch rel/0.6
in repository https://gitbox.apache.org/repos/asf/plc4x.git
commit 09585ba5ebe5b5f9f953ac8ef2e2cdffd209bd09
Author: Julian Feinauer <j....@pragmaticminds.de>
AuthorDate: Tue Jul 28 20:53:13 2020 +0200
Cherry Picked commit to add Simotion Syntax to S7 Driver.
Migrated everything to "native" decoding without mspec.
---
plc4j/drivers/s7/pom.xml | 1 -
.../org/apache/plc4x/java/s7/model/S7Field.java | 29 ++-
.../s7/src/main/resources/protocols/s7/s7.mspec | 233 ++++++++++++++++-----
3 files changed, 212 insertions(+), 51 deletions(-)
diff --git a/plc4j/drivers/s7/pom.xml b/plc4j/drivers/s7/pom.xml
index 7a87d0c..02f12ca 100644
--- a/plc4j/drivers/s7/pom.xml
+++ b/plc4j/drivers/s7/pom.xml
@@ -116,7 +116,6 @@
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.12</version>
- <scope>test</scope>
</dependency>
<dependency>
<groupId>org.osgi</groupId>
diff --git a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/model/S7Field.java b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/model/S7Field.java
index 8f7f63c..d539bdf 100644
--- a/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/model/S7Field.java
+++ b/plc4j/protocols/s7/src/main/java/org/apache/plc4x/java/s7/model/S7Field.java
@@ -47,6 +47,9 @@ public class S7Field implements PlcField {
private static final Pattern DATA_BLOCK_SHORT_PATTERN =
Pattern.compile("^%DB(?<blockNumber>\\d{1,5}):(?<byteOffset>\\d{1,7})(.(?<bitOffset>[0-7]))?:(?<dataType>[a-zA-Z_]+)(\\[(?<numElements>\\d+)])?");
+ private static final Pattern SIMOTION_ADDRESS_PATTERN =
+ Pattern.compile("[0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2}");
+
private static final String DATA_TYPE = "dataType";
private static final String TRANSFER_SIZE_CODE = "transferSizeCode";
private static final String BLOCK_NUMBER = "blockNumber";
@@ -98,7 +101,8 @@ public class S7Field implements PlcField {
public static boolean matches(String fieldString) {
return DATA_BLOCK_ADDRESS_PATTERN.matcher(fieldString).matches() ||
ADDRESS_PATTERN.matcher(fieldString).matches() ||
- DATA_BLOCK_SHORT_PATTERN.matcher(fieldString).matches();
+ DATA_BLOCK_SHORT_PATTERN.matcher(fieldString).matches() ||
+ SIMOTION_ADDRESS_PATTERN.matcher(fieldString).matches();
}
/**
@@ -215,6 +219,29 @@ public class S7Field implements PlcField {
}
numElements = calcNumberOfElementsForIndividualTypes(numElements, dataType);
return new S7Field(dataType, memoryArea, blockNumber, byteOffset, bitOffset, numElements);
+ } else if (SIMOTION_ADDRESS_PATTERN.matcher(fieldString).matches()) {
+ matcher = SIMOTION_ADDRESS_PATTERN.matcher(fieldString);
+
+ boolean matches = matcher.matches();
+ assert matches;
+
+ try {
+ byte[] addressData = Hex.decodeHex(fieldString.replaceAll("[-]", ""));
+ ReadBuffer rb = new ReadBuffer(addressData);
+ // Read out values according to definition in mspec
+ final TransportSize transportSize = TransportSize.valueOf(rb.readByte(8));
+ final short numberOfElements = rb.readShort(16);
+ final short dbNumber = rb.readShort(16);
+ final MemoryArea memoryArea = MemoryArea.valueOf(rb.readByte(8));
+ assert 0x00 == rb.readByte(5);
+ final short byteAddress = rb.readShort(16);
+ final byte bitAddress = rb.readByte(3);
+
+ return new S7Field(transportSize, memoryArea, dbNumber, byteAddress, bitAddress,
+ numberOfElements);
+ } catch (ParseException | DecoderException e) {
+ throw new PlcInvalidFieldException("Unable to parse address: " + fieldString);
+ }
}
throw new PlcInvalidFieldException("Unable to parse address: " + fieldString);
}
diff --git a/protocols/s7/src/main/resources/protocols/s7/s7.mspec b/protocols/s7/src/main/resources/protocols/s7/s7.mspec
index 31b588c..e428620 100644
--- a/protocols/s7/src/main/resources/protocols/s7/s7.mspec
+++ b/protocols/s7/src/main/resources/protocols/s7/s7.mspec
@@ -99,20 +99,24 @@
[discriminator uint 8 'messageType']
[reserved uint 16 '0x0000']
[simple uint 16 'tpduReference']
- [implicit uint 16 'parameterLength' 'parameter.lengthInBytes']
- [implicit uint 16 'payloadLength' 'payload.lengthInBytes']
+ [implicit uint 16 'parameterLength' 'parameter != null ? parameter.lengthInBytes : 0']
+ [implicit uint 16 'payloadLength' 'payload != null ? payload.lengthInBytes : 0']
[typeSwitch 'messageType'
['0x01' S7MessageRequest
]
- ['0x03' S7MessageResponse
+ ['0x02' S7MessageResponse
+ [simple uint 8 'errorClass']
+ [simple uint 8 'errorCode']
+ ]
+ ['0x03' S7MessageResponseData
[simple uint 8 'errorClass']
[simple uint 8 'errorCode']
]
['0x07' S7MessageUserData
]
]
- [simple S7Parameter 'parameter' ['messageType']]
- [simple S7Payload 'payload' ['messageType', 'parameter']]
+ [optional S7Parameter 'parameter' 'parameterLength > 0' ['messageType']]
+ [optional S7Payload 'payload' 'payloadLength > 0' ['messageType', 'parameter']]
]
////////////////////////////////////////////////////////////////
@@ -208,14 +212,12 @@
// Payloads
[discriminatedType 'S7Payload' [uint 8 'messageType', S7Parameter 'parameter']
- [typeSwitch 'parameter.discriminatorValues[0]', 'messageType'
- ['0xF0' S7PayloadSetupCommunication]
- ['0x04','0x01' S7PayloadReadVarRequest]
+ [typeSwitch 'parameter.parameterType', 'messageType'
['0x04','0x03' S7PayloadReadVarResponse
- [array S7VarPayloadDataItem 'items' count 'CAST(parameter, S7ParameterReadVarResponse).numItems']
+ [array S7VarPayloadDataItem 'items' count 'CAST(parameter, S7ParameterReadVarResponse).numItems' ['lastItem']]
]
['0x05','0x01' S7PayloadWriteVarRequest
- [array S7VarPayloadDataItem 'items' count 'COUNT(CAST(parameter, S7ParameterWriteVarRequest).items)']
+ [array S7VarPayloadDataItem 'items' count 'COUNT(CAST(parameter, S7ParameterWriteVarRequest).items)' ['lastItem']]
]
['0x05','0x03' S7PayloadWriteVarResponse
[array S7VarPayloadStatusItem 'items' count 'CAST(parameter, S7ParameterWriteVarResponse).numItems']
@@ -227,24 +229,24 @@
]
// This is actually not quite correct as depending pon the transportSize the length is either defined in bits or bytes.
-[type 'S7VarPayloadDataItem'
- [simple uint 8 'returnCode']
- [enum DataTransportSize 'transportSize']
- [simple uint 16 'dataLength']
- [array uint 8 'data' count 'dataLength / 8']
- [padding uint 8 'pad' '0x00' '(dataLength / 8) % 2 == 1']
+[type 'S7VarPayloadDataItem' [bit 'lastItem']
+ [enum DataTransportErrorCode 'returnCode']
+ [enum DataTransportSize 'transportSize']
+ [implicit uint 16 'dataLength' 'COUNT(data) * ((transportSize == DataTransportSize.BIT) ? 1 : (transportSize.sizeInBits ? 8 : 1))']
+ [array int 8 'data' count 'transportSize.sizeInBits ? CEIL(dataLength / 8.0) : dataLength']
+ [padding uint 8 'pad' '0x00' '!lastItem && ((COUNT(data) % 2) == 1)']
]
[type 'S7VarPayloadStatusItem'
- [simple uint 8 'returnCode']
+ [enum DataTransportErrorCode 'returnCode']
]
[discriminatedType 'S7PayloadUserDataItem' [uint 4 'cpuFunctionType']
- [simple uint 8 'returnCode']
- [enum DataTransportSize 'transportSize']
- [implicit uint 16 'dataLength' 'lengthInBytes - 4']
- [simple SzlId 'szlId']
- [simple uint 16 'szlIndex']
+ [enum DataTransportErrorCode 'returnCode']
+ [enum DataTransportSize 'transportSize']
+ [implicit uint 16 'dataLength' 'lengthInBytes - 4']
+ [simple SzlId 'szlId']
+ [simple uint 16 'szlIndex']
[typeSwitch 'cpuFunctionType'
['0x04' S7PayloadUserDataItemCpuFunctionReadSzlRequest
]
@@ -256,8 +258,115 @@
]
]
+[dataIo 'DataItem' [uint 8 'dataProtocolId']
+ [typeSwitch 'dataProtocolId'
+ // -----------------------------------------
+ // Bit
+ // -----------------------------------------
+ ['01' Boolean
+ [reserved uint 7 '0x00']
+ [simple bit 'value']
+ ]
+
+ // -----------------------------------------
+ // Bit-strings
+ // -----------------------------------------
+ // 1 byte
+ ['11' List
+ [array bit 'value' count '8']
+ ]
+ // 2 byte (16 bit)
+ ['12' List
+ [array bit 'value' count '16']
+ ]
+ // 4 byte (32 bit)
+ ['13' List
+ [array bit 'value' count '32']
+ ]
+ // 8 byte (64 bit)
+ ['14' List
+ [array bit 'value' count '64']
+ ]
+
+ // -----------------------------------------
+ // Integers
+ // -----------------------------------------
+ // 8 bit:
+ ['21' Integer
+ [simple int 8 'value']
+ ]
+ ['22' Integer
+ [simple uint 8 'value']
+ ]
+ // 16 bit:
+ ['23' Integer
+ [simple int 16 'value']
+ ]
+ ['24' Integer
+ [simple uint 16 'value']
+ ]
+ // 32 bit:
+ ['25' Integer
+ [simple int 32 'value']
+ ]
+ ['26' Long
+ [simple uint 32 'value']
+ ]
+ // 64 bit:
+ ['27' Long
+ [simple int 64 'value']
+ ]
+ ['28' BigInteger
+ [simple uint 64 'value']
+ ]
+
+ // -----------------------------------------
+ // Floating point values
+ // -----------------------------------------
+ ['31' Float
+ [simple float 8.23 'value']
+ ]
+ ['32' Double
+ [simple float 11.52 'value']
+ ]
+
+ // -----------------------------------------
+ // Characters & Strings
+ // -----------------------------------------
+ ['41' String
+ ]
+ ['42' String
+ ]
+ ['43' String
+ [manual string 'UTF-8' 'value' 'STATIC_CALL("org.apache.plc4x.java.s7.utils.StaticHelper.parseS7String", io, _type.encoding)' 'STATIC_CALL("org.apache.plc4x.java.s7.utils.StaticHelper.serializeS7String", io, _value, _type.encoding)' '_value.length + 2']
+ ]
+ ['44' String
+ [manual string 'UTF-16' 'value''STATIC_CALL("org.apache.plc4x.java.s7.utils.StaticHelper.parseS7String", io, _type.encoding)' 'STATIC_CALL("org.apache.plc4x.java.s7.utils.StaticHelper.serializeS7String", io, _value, _type.encoding)' '(_value.length * 2) + 2']
+ ]
-[enum int 8 'COTPTpduSize' [uint 8 'sizeInBytes']
+ // -----------------------------------------
+ // TIA Date-Formats
+ // -----------------------------------------
+ ['51' Time
+ [manual time 'value' 'STATIC_CALL("org.apache.plc4x.java.s7.utils.StaticHelper.parseTiaTime", io)' 'STATIC_CALL("org.apache.plc4x.java.s7.utils.StaticHelper.serializeTiaTime", io, _value)' '4']
+ ]
+ // TODO: Check if this is really 8 bytes
+ ['52' Time
+ [manual time 'value' 'STATIC_CALL("org.apache.plc4x.java.s7.utils.StaticHelper.parseTiaLTime", io)' 'STATIC_CALL("org.apache.plc4x.java.s7.utils.StaticHelper.serializeTiaLTime", io, _value)' '8']
+ ]
+ ['53' Date
+ [manual date 'value' 'STATIC_CALL("org.apache.plc4x.java.s7.utils.StaticHelper.parseTiaDate", io)' 'STATIC_CALL("org.apache.plc4x.java.s7.utils.StaticHelper.serializeTiaDate", io, _value)' '2']
+ ]
+ ['54' Time
+ [manual time 'value' 'STATIC_CALL("org.apache.plc4x.java.s7.utils.StaticHelper.parseTiaTimeOfDay", io)' 'STATIC_CALL("org.apache.plc4x.java.s7.utils.StaticHelper.serializeTiaTimeOfDay", io, _value)' '4']
+ ]
+ ['55' DateTime
+ [manual dateTime 'value' 'STATIC_CALL("org.apache.plc4x.java.s7.utils.StaticHelper.parseTiaDateTime", io)' 'STATIC_CALL("org.apache.plc4x.java.s7.utils.StaticHelper.serializeTiaDateTime", io, _value)' '8']
+ ]
+ ]
+]
+
+[enum int 8 'COTPTpduSize' [uint 16 'sizeInBytes']
['0x07' SIZE_128 ['128']]
['0x08' SIZE_256 ['256']]
['0x09' SIZE_512 ['512']]
@@ -285,34 +394,51 @@
['0x09' OCTET_STRING ['false']]
]
-[enum int 8 'TransportSize' [uint 8 'sizeCode', uint 8 'sizeInBytes', TransportSize 'baseType', DataTransportSize 'dataTransportSize']
- ['0x01' BOOL ['X' , '1' , 'null' , 'DataTransportSize.BIT']]
- ['0x02' BYTE ['B' , '1' , 'null' , 'DataTransportSize.BYTE_WORD_DWORD']]
- ['0x04' WORD ['W' , '2' , 'null' , 'DataTransportSize.BYTE_WORD_DWORD']]
- ['0x06' DWORD ['D' , '4' , 'WORD' , 'DataTransportSize.BYTE_WORD_DWORD']]
- ['0x00' LWORD ['X' , '8' , 'null' , 'null']]
- ['0x05' INT ['W' , '2' , 'null' , 'DataTransportSize.BYTE_WORD_DWORD']]
- ['0x05' UINT ['W' , '2' , 'INT' , 'DataTransportSize.BYTE_WORD_DWORD']]
- ['0x02' SINT ['B' , '1' , 'INT' , 'DataTransportSize.BYTE_WORD_DWORD']]
- ['0x02' USINT ['B' , '1' , 'INT' , 'DataTransportSize.BYTE_WORD_DWORD']]
- ['0x07' DINT ['D' , '4' , 'INT' , 'DataTransportSize.BYTE_WORD_DWORD']]
- ['0x07' UDINT ['D' , '4' , 'INT' , 'DataTransportSize.BYTE_WORD_DWORD']]
- ['0x00' LINT ['X' , '8' , 'INT' , 'null']]
- ['0x00' ULINT ['X' , '16' , 'INT' , 'null']]
- ['0x08' REAL ['D' , '4' , 'null' , 'DataTransportSize.BYTE_WORD_DWORD']]
- ['0x00' LREAL ['X' , '8' , 'REAL' , 'null']]
- ['0x0B' TIME ['X' , '4' , 'null' , 'null']]
- ['0x00' LTIME ['X' , '8' , 'TIME' , 'null']]
- ['0x02' DATE ['X' , '2' , 'null' , 'DataTransportSize.BYTE_WORD_DWORD']]
- ['0x02' TIME_OF_DAY ['X' , '4' , 'null' , 'DataTransportSize.BYTE_WORD_DWORD']]
- ['0x02' DATE_AND_TIME ['X' , '8' , 'null' , 'null']]
- ['0x03' CHAR ['B' , '1' , 'null' , 'DataTransportSize.BYTE_WORD_DWORD']]
- ['0x13' WCHAR ['X' , '2' , 'null' , 'null']]
- ['0x03' STRING ['X' , '1' , 'null' , 'DataTransportSize.BYTE_WORD_DWORD']]
- ['0x00' WSTRING ['X' , '1' , 'null' , 'null']]
+[enum int 8 'DeviceGroup'
+ ['0x01' PG_OR_PC]
+ ['0x02' OS ]
+ ['0x03' OTHERS ]
+]
+
+[enum int 8 'TransportSize' [uint 8 'sizeCode', uint 8 'sizeInBytes', TransportSize 'baseType', DataTransportSize 'dataTransportSize', uint 8 'dataProtocolId', bit 'supported_S7_300', bit 'supported_S7_400', bit 'supported_S7_1200', bit 'supported_S7_1500', bit 'supported_LOGO']
+ // Bit Strings
+ ['0x01' BOOL ['X' , '1' , 'null' , 'DataTransportSize.BIT' , '01' , 'true' , 'true' , 'true' , 'true' , 'true' ]]
+ ['0x02' BYTE ['B' , '1' , 'null' , 'DataTransportSize.BYTE_WORD_DWORD' , '11' , 'true' , 'true' , 'true' , 'true' , 'true' ]]
+ ['0x04' WORD ['W' , '2' , 'null' , 'DataTransportSize.BYTE_WORD_DWORD' , '12' , 'true' , 'true' , 'true' , 'true' , 'true' ]]
+ ['0x06' DWORD ['D' , '4' , 'TransportSize.WORD' , 'DataTransportSize.BYTE_WORD_DWORD' , '13' , 'true' , 'true' , 'true' , 'true' , 'true' ]]
+ ['0x00' LWORD ['X' , '8' , 'null' , 'null' , '14' , 'false' , 'false' , 'false' , 'true' , 'false' ]]
+
+ // Integer values
+ // INT and UINT moved out of order as the enum constant INT needs to be generated before it's used in java
+ ['0x05' INT ['W' , '2' , 'null' , 'DataTransportSize.INTEGER' , '23' , 'true' , 'true' , 'true' , 'true' , 'true' ]]
+ ['0x05' UINT ['W' , '2' , 'TransportSize.INT' , 'DataTransportSize.INTEGER' , '24' , 'false' , 'false' , 'true' , 'true' , 'true' ]]
+ // ...
+ ['0x02' SINT ['B' , '1' , 'TransportSize.INT' , 'DataTransportSize.BYTE_WORD_DWORD' , '21' , 'false' , 'false' , 'true' , 'true' , 'true' ]]
+ ['0x02' USINT ['B' , '1' , 'TransportSize.INT' , 'DataTransportSize.BYTE_WORD_DWORD' , '22' , 'false' , 'false' , 'true' , 'true' , 'true' ]]
+ ['0x07' DINT ['D' , '4' , 'TransportSize.INT' , 'DataTransportSize.INTEGER' , '25' , 'true' , 'true' , 'true' , 'true' , 'true' ]]
+ ['0x07' UDINT ['D' , '4' , 'TransportSize.INT' , 'DataTransportSize.INTEGER' , '26' , 'false' , 'false' , 'true' , 'true' , 'true' ]]
+ ['0x00' LINT ['X' , '8' , 'TransportSize.INT' , 'null' , '27' , 'false' , 'false' , 'false' , 'true' , 'false' ]]
+ ['0x00' ULINT ['X' , '16' , 'TransportSize.INT' , 'null' , '28' , 'false' , 'false' , 'false' , 'true' , 'false' ]]
+
+ // Floating point values
+ ['0x08' REAL ['D' , '4' , 'null' , 'DataTransportSize.BYTE_WORD_DWORD' , '31' , 'true' , 'true' , 'true' , 'true' , 'true' ]]
+ ['0x30' LREAL ['X' , '8' , 'TransportSize.REAL' , 'null' , '32' , 'false' , 'false' , 'true' , 'true' , 'false' ]]
+
+ // Characters and Strings
+ ['0x03' CHAR ['B' , '1' , 'null' , 'DataTransportSize.BYTE_WORD_DWORD' , '41' , 'true' , 'true' , 'true' , 'true' , 'true' ]]
+ ['0x13' WCHAR ['X' , '2' , 'null' , 'null' , '42' , 'false' , 'false' , 'true' , 'true' , 'true' ]]
+ ['0x03' STRING ['X' , '1' , 'null' , 'DataTransportSize.BYTE_WORD_DWORD' , '43' , 'true' , 'true' , 'true' , 'true' , 'true' ]]
+ ['0x00' WSTRING ['X' , '1' , 'null' , 'null' , '44' , 'false' , 'false' , 'true' , 'true' , 'true' ]]
+
+ // Dates and time values
+ ['0x0B' TIME ['X' , '4' , 'null' , 'null' , '51' , 'true' , 'true' , 'true' , 'true' , 'true' ]]
+ ['0x00' LTIME ['X' , '8' , 'TransportSize.TIME' , 'null' , '52' , 'false' , 'false' , 'false' , 'true' , 'false' ]]
+ ['0x02' DATE ['X' , '2' , 'null' , 'DataTransportSize.BYTE_WORD_DWORD' , '53' , 'true' , 'true' , 'true' , 'true' , 'true' ]]
+ ['0x02' TIME_OF_DAY ['X' , '4' , 'null' , 'DataTransportSize.BYTE_WORD_DWORD' , '54' , 'true' , 'true' , 'true' , 'true' , 'true' ]]
+ ['0x02' DATE_AND_TIME ['X' , '8' , 'null' , 'null' , '55' , 'true' , 'true' , 'false' , 'true' , 'false' ]]
]
-[enum int 8 'MemoryArea' [string 'shortName']
+[enum int 8 'MemoryArea' [string 24 'utf8' 'shortName']
['0x1C' COUNTERS ['C']]
['0x1D' TIMERS ['T']]
['0x80' DIRECT_PERIPHERAL_ACCESS ['D']]
@@ -334,6 +460,15 @@
['0x09' OCTET_STRING ['false']]
]
+[enum int 8 'DataTransportErrorCode'
+ ['0x00' RESERVED ]
+ ['0xFF' OK ]
+ ['0x03' ACCESS_DENIED ]
+ ['0x05' INVALID_ADDRESS ]
+ ['0x06' DATA_TYPE_NOT_SUPPORTED]
+ ['0x0A' NOT_FOUND ]
+]
+
[enum int 4 'SzlModuleTypeClass'
['0x0' CPU]
['0x4' IM]