You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by cg...@apache.org on 2023/11/29 00:34:12 UTC
(plc4x) branch feature/s7strings created (now b9b9307baa)
This is an automated email from the ASF dual-hosted git repository.
cgarcia pushed a change to branch feature/s7strings
in repository https://gitbox.apache.org/repos/asf/plc4x.git
at b9b9307baa Support for reading and writing to STRING type memory areas. Example of use is included.
This branch includes the following new commits:
new b9b9307baa Support for reading and writing to STRING type memory areas. Example of use is included.
The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
(plc4x) 01/01: Support for reading and writing to STRING type memory areas. Example of use is included.
Posted by cg...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
cgarcia pushed a commit to branch feature/s7strings
in repository https://gitbox.apache.org/repos/asf/plc4x.git
commit b9b9307baa094e23447fc5e3671de10d0d821875
Author: Cesar Garcia <ce...@ceos.com.ve>
AuthorDate: Tue Nov 28 20:33:24 2023 -0400
Support for reading and writing to STRING type memory areas. Example of use is included.
---
.../java/s7/readwrite/optimizer/S7Optimizer.java | 27 +-
.../s7/readwrite/protocol/S7ProtocolLogic.java | 332 +++++++++++++++-
.../plc4x/java/s7/readwrite/tag/S7ClkTag.java | 2 +-
.../java/s7/readwrite/tag/S7PlcTagHandler.java | 6 +-
.../plc4x/java/s7/readwrite/tag/S7StringTag.java | 131 +++++++
.../apache/plc4x/java/s7/readwrite/tag/S7Tag.java | 105 +++--
.../plc4j/s7event/PlcReadWriteStrings.java | 434 +++++++++++++++++++++
7 files changed, 961 insertions(+), 76 deletions(-)
diff --git a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/optimizer/S7Optimizer.java b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/optimizer/S7Optimizer.java
index 47bc4b8821..0487f65f94 100644
--- a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/optimizer/S7Optimizer.java
+++ b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/optimizer/S7Optimizer.java
@@ -38,6 +38,8 @@ import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
+import java.util.Map;
+import org.apache.plc4x.java.s7.readwrite.tag.S7StringTag;
public class S7Optimizer extends BaseOptimizer {
@@ -63,16 +65,26 @@ public class S7Optimizer extends BaseOptimizer {
int curResponseSize = EMPTY_READ_RESPONSE_SIZE;
// List of all items in the current request.
+
LinkedHashMap<String, PlcTag> curTags = new LinkedHashMap<>();
for (String tagName : readRequest.getTagNames()) {
-
+
+ //TODO: Individual processing of these types of tags. like S7StringTag
if ((readRequest.getTag(tagName) instanceof S7SzlTag) ||
(readRequest.getTag(tagName) instanceof S7ClkTag)) {
curTags.put(tagName, readRequest.getTag(tagName));
continue;
}
-
+
+ if ((readRequest.getTag(tagName) instanceof S7StringTag)) {
+ LinkedHashMap<String, PlcTag> strTags = new LinkedHashMap<>();
+ strTags.put(tagName, readRequest.getTag(tagName));
+ processedRequests.add(new DefaultPlcReadRequest(
+ ((DefaultPlcReadRequest) readRequest).getReader(), strTags));
+ continue;
+ }
+
S7Tag tag = (S7Tag) readRequest.getTag(tagName);
int readRequestItemSize = S7_ADDRESS_ANY_SIZE;
@@ -142,6 +154,17 @@ public class S7Optimizer extends BaseOptimizer {
LinkedHashMap<String, TagValueItem> curTags = new LinkedHashMap<>();
for (String tagName : writeRequest.getTagNames()) {
+
+ if ((writeRequest.getTag(tagName) instanceof S7StringTag)) {
+ LinkedHashMap<String, TagValueItem> strTags = new LinkedHashMap<>();
+ strTags.put(tagName,
+ new TagValueItem(writeRequest.getTag(tagName),
+ writeRequest.getPlcValue(tagName)));
+ processedRequests.add(new DefaultPlcWriteRequest(
+ ((DefaultPlcWriteRequest) writeRequest).getWriter(), strTags));
+ continue;
+ }
+
S7Tag tag = (S7Tag) writeRequest.getTag(tagName);
PlcValue value = writeRequest.getPlcValue(tagName);
diff --git a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/protocol/S7ProtocolLogic.java b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/protocol/S7ProtocolLogic.java
index 032948be18..4bfed9bb73 100644
--- a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/protocol/S7ProtocolLogic.java
+++ b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/protocol/S7ProtocolLogic.java
@@ -54,6 +54,7 @@ import org.slf4j.LoggerFactory;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.*;
@@ -61,6 +62,7 @@ import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
+import java.util.logging.Level;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
@@ -306,6 +308,17 @@ public class S7ProtocolLogic extends Plc4xProtocolBase<TPKTPacket> {
new S7PayloadUserData(payloadItems));
return toPlcReadResponse(readRequest, readInternal(s7MessageRequest));
+ } else if (request.getTags().get(0) instanceof S7StringTag) {
+
+ List<S7ParameterReadVarRequest> parameterItems = new ArrayList<>(request.getNumberOfTags());
+ List<S7PayloadUserDataItem> payloadItems = new ArrayList<>(request.getNumberOfTags());
+ encodePlcStringReadRequest(request, parameterItems, payloadItems);
+
+ final S7MessageRequest s7MessageRequest = new S7MessageRequest(-1,
+ parameterItems.get(0),
+ null);
+
+ return toPlcReadResponse(readRequest, readInternal(s7MessageRequest));
}
@@ -414,6 +427,13 @@ public class S7ProtocolLogic extends Plc4xProtocolBase<TPKTPacket> {
if (!clkTags.isEmpty()) {
return writeClk(writeRequest);
}
+
+ List<String> strTags = request.getTagNames().stream()
+ .filter(t -> request.getTag(t) instanceof S7StringTag)
+ .collect(Collectors.toList());
+ if (!strTags.isEmpty()) {
+ return writeString(writeRequest);
+ }
List<S7VarRequestParameterItem> parameterItems = new ArrayList<>(request.getNumberOfTags());
List<S7VarPayloadDataItem> payloadItems = new ArrayList<>(request.getNumberOfTags());
@@ -524,6 +544,56 @@ public class S7ProtocolLogic extends Plc4xProtocolBase<TPKTPacket> {
return future;
}
+ //TODO: Clean code
+ public CompletableFuture<PlcWriteResponse> writeString(PlcWriteRequest writeRequest) {
+ CompletableFuture<PlcWriteResponse> future = new CompletableFuture<>();
+ DefaultPlcWriteRequest request = (DefaultPlcWriteRequest) writeRequest;
+
+ List<S7VarRequestParameterItem> parameterItems = new ArrayList<>(request.getNumberOfTags());
+ List<S7VarPayloadDataItem> payloadItems = new ArrayList<>(request.getNumberOfTags());
+
+ encodePlcStringWriteRequest((DefaultPlcWriteRequest) writeRequest,
+ parameterItems, payloadItems);
+
+ final int tpduId = tpduGenerator.getAndIncrement();
+ // If we've reached the max value for a 16 bit transaction identifier, reset back to 1
+ if (tpduGenerator.get() == 0xFFFF) {
+ tpduGenerator.set(1);
+ }
+
+ TPKTPacket tpktPacket = new TPKTPacket(
+ new COTPPacketData(
+ null,
+ new S7MessageRequest(tpduId,
+ new S7ParameterWriteVarRequest(parameterItems),
+ new S7PayloadWriteVarRequest(payloadItems)
+ ),
+ true,
+ (byte) tpduId
+ )
+ );
+
+ // Start a new request-transaction (Is ended in the response-handler)
+ RequestTransactionManager.RequestTransaction transaction = tm.startRequest();
+ transaction.submit(() -> context.sendRequest(tpktPacket)
+ .onTimeout(new TransactionErrorCallback<>(future, transaction))
+ .onError(new TransactionErrorCallback<>(future, transaction))
+ .expectResponse(TPKTPacket.class, REQUEST_TIMEOUT)
+ .check(p -> p.getPayload() instanceof COTPPacketData)
+ .unwrap(p -> ((COTPPacketData) p.getPayload()))
+ .unwrap(COTPPacket::getPayload)
+ .check(p -> p.getTpduReference() == tpduId)
+ .handle(p -> {
+ try {
+ future.complete(((PlcWriteResponse) decodeWriteResponse(p, writeRequest)));
+ } catch (PlcProtocolException e) {
+ logger.warn("Error sending 'write' message: '{}'", e.getMessage(), e);
+ }
+ // Finish the request-transaction.
+ transaction.endRequest();
+ }));
+ return future;
+ }
@Override
public CompletableFuture<PlcSubscriptionResponse> subscribe(PlcSubscriptionRequest subscriptionRequest) {
@@ -1340,6 +1410,9 @@ public class S7ProtocolLogic extends Plc4xProtocolBase<TPKTPacket> {
// });
}
+ /*
+ *
+ */
private void encodePlcClkRequest(DefaultPlcReadRequest request,
List<S7ParameterUserDataItem> parameterItems,
List<S7PayloadUserDataItem> payloadItems) {
@@ -1370,12 +1443,13 @@ public class S7ProtocolLogic extends Plc4xProtocolBase<TPKTPacket> {
payloadItems.add(payload);
}
-
+ /*
+ *
+ */
private void encodePlcClkSetRequest(DefaultPlcWriteRequest request,
List<S7ParameterUserDataItem> parameterItems,
List<S7PayloadUserDataItem> payloadItems) {
-
S7ParameterUserDataItemCPUFunctions parameter = new S7ParameterUserDataItemCPUFunctions(
(short) 0x11, //Method
(byte) 0x04, //FunctionType
@@ -1404,6 +1478,207 @@ public class S7ProtocolLogic extends Plc4xProtocolBase<TPKTPacket> {
}
+ /*
+ * +-------------------+
+ * Byte n | Maximum length | (intMaxChars)
+ * +-------------------+
+ * Byte n+1 | Current Length | (intActualChars)
+ * +-------------------+
+ * Byte n+2 | 1st character | \ \
+ * +-------------------+ | |
+ * Byte n+3 | 2st character | | Current |
+ * +-------------------+ > |
+ * Byte ... | ... | | length | Maximum
+ * +-------------------+ | >
+ * Byte n+m+1 | mth character | / | length
+ * +-------------------+ |
+ * Byte ... | ... | |
+ * +-------------------+ |
+ * Byte ... | ... | /
+ * +-------------------+
+ * Reading text strings in two steps:
+ * 1. For the operation on texts, you must first evaluate the
+ * space created on DB of type STRING or WSTRING.
+ * 2. The first two bytes have the maximum number of characters (bytes)
+ * available to store text strings (intMaxChars) and the number of
+ * characters available (intActualChars).
+ * 3. In the specific case of reading, only the characters defined
+ * by "intActualChars" are recovered.
+ * TODO: Maximum waiting time managed by system variables.
+ */
+ private void encodePlcStringReadRequest(DefaultPlcReadRequest request,
+ List<S7ParameterReadVarRequest> parameterItems,
+ List<S7PayloadUserDataItem> payloadItems) {
+
+ int intMaxChars = 0;
+ int intActualChars = 0;
+
+ final S7StringTag tag = (S7StringTag) request.getTags().get(0);
+
+ //Read the max length and actual size.
+
+ final S7MessageRequest readRequest = new S7MessageRequest(1,new S7ParameterReadVarRequest(
+ List.of(new S7VarRequestParameterItemAddress(
+ new S7AddressAny(
+ TransportSize.BYTE,
+ 2,
+ tag.getBlockNumber(),
+ MemoryArea.DATA_BLOCKS,
+ tag.getByteOffset(),
+ tag.getBitOffset()
+ ))
+
+ )), null);
+
+ CompletableFuture<S7Message> future = readInternal(readRequest);
+
+ try {
+ S7Message get = future.get(2000, TimeUnit.MILLISECONDS);
+ final S7VarPayloadDataItem payload = (S7VarPayloadDataItem)((S7PayloadReadVarResponse) get.getPayload()).getItems().get(0);
+ //intMaxChars = Byte.toUnsignedInt(payload.getData()[0]);
+ intActualChars = Byte.toUnsignedInt(payload.getData()[1]);
+ } catch (InterruptedException ex) {
+ logger.info(ex.getMessage());
+ } catch (ExecutionException ex) {
+ logger.info(ex.getMessage());
+ } catch (TimeoutException ex) {
+ logger.info(ex.getMessage());
+ }
+
+ //Create the message structure for the user request.
+
+ S7ParameterReadVarRequest parameter = new S7ParameterReadVarRequest(
+ List.of(new S7VarRequestParameterItemAddress(
+ new S7AddressAny(
+ TransportSize.BYTE,
+ intActualChars,
+ tag.getBlockNumber(),
+ MemoryArea.DATA_BLOCKS,
+ tag.getByteOffset()+2,
+ tag.getBitOffset()
+ ))
+
+ ));
+
+ parameterItems.clear();
+ parameterItems.add(parameter);
+
+ payloadItems.clear();
+
+ }
+
+
+ /*
+ * +-------------------+
+ * Byte n | Maximum length | (intMaxChars)
+ * +-------------------+
+ * Byte n+1 | Current Length | (intActualChars)
+ * +-------------------+
+ * Byte n+2 | 1st character | \ \
+ * +-------------------+ | |
+ * Byte n+3 | 2st character | | Current |
+ * +-------------------+ > |
+ * Byte ... | ... | | length | Maximum
+ * +-------------------+ | >
+ * Byte n+m+1 | mth character | / | length
+ * +-------------------+ |
+ * Byte ... | ... | |
+ * +-------------------+ |
+ * Byte ... | ... | /
+ * +-------------------+
+ * Reading text strings in two steps:
+ * 1. For the operation on texts, you must first evaluate the
+ * space created on DB of type STRING or WSTRING.
+ * 2. The first two bytes have the maximum number of characters (bytes)
+ * available to store text strings (intMaxChars) and the number of
+ * characters available (intActualChars).
+ * 3. In the specific case of write string, only the max characters defined
+ * by "intMaxChars" are writed.
+ * TODO: Maximum waiting time managed by system variables.
+ */
+ private void encodePlcStringWriteRequest(DefaultPlcWriteRequest request,
+ List<S7VarRequestParameterItem> parameterItems,
+ List<S7VarPayloadDataItem> payloadItems) {
+
+ int intMaxChars = 0;
+ int intActualChars = 0;
+
+ final S7StringTag tag = (S7StringTag) request.getTags().get(0);
+
+ //Read the max length and actual size.
+
+ final S7MessageRequest readRequest = new S7MessageRequest(1,new S7ParameterReadVarRequest(
+ List.of(new S7VarRequestParameterItemAddress(
+ new S7AddressAny(
+ TransportSize.BYTE,
+ 2,
+ tag.getBlockNumber(),
+ MemoryArea.DATA_BLOCKS,
+ tag.getByteOffset(),
+ tag.getBitOffset()
+ ))
+
+ )), null);
+
+ CompletableFuture<S7Message> future = readInternal(readRequest);
+
+ try {
+ S7Message get = future.get(2000, TimeUnit.MILLISECONDS);
+ final S7VarPayloadDataItem payload = (S7VarPayloadDataItem)((S7PayloadReadVarResponse) get.getPayload()).getItems().get(0);
+ intMaxChars = Byte.toUnsignedInt(payload.getData()[0]); //payload.getData()[0] & 0xFF
+ intActualChars = Byte.toUnsignedInt(payload.getData()[1]);
+ } catch (InterruptedException ex) {
+ logger.info(ex.getMessage());
+ } catch (ExecutionException ex) {
+ logger.info(ex.getMessage());
+ } catch (TimeoutException ex) {
+ logger.info(ex.getMessage());
+ }
+
+ //Create the message structure for the user request.
+
+ parameterItems.clear();
+ payloadItems.clear();
+
+ Iterator<String> iter = request.getTagNames().iterator();
+
+ String tagName;
+ PlcValue plcValue;
+ while (iter.hasNext()) {
+ tagName = iter.next();
+ final S7StringTag tagRef = (S7StringTag) request.getTag(tagName);
+ plcValue = request.getPlcValue(tagName);
+
+ //Check if String
+ String strValue = plcValue.getString();
+ if (strValue.length() > intMaxChars) {
+ strValue = strValue.substring(0, intMaxChars);
+ plcValue = new PlcSTRING(strValue);
+ }
+
+ S7Address s7Address = new S7AddressAny(
+ tagRef.getDataType().BYTE,
+ strValue.length() + 2,
+ tagRef.getBlockNumber(),
+ tagRef.getMemoryArea(),
+ tagRef.getByteOffset(),
+ tagRef.getBitOffset());
+
+ parameterItems.add(new S7VarRequestParameterItemAddress(s7Address));
+
+ ByteBuffer byteBuffer = ByteBuffer.allocate(strValue.length() + 2);
+ byteBuffer.put((byte) intMaxChars);
+ byteBuffer.put((byte) strValue.length());
+ byteBuffer.put(strValue.getBytes());
+
+ DataTransportSize transportSize = DataTransportSize.BYTE_WORD_DWORD;
+
+ payloadItems.add(new S7VarPayloadDataItem(DataTransportErrorCode.OK, transportSize, byteBuffer.array()/*, hasNext*/));
+ }
+
+ }
+
+
/**
* This method is only called when there is no Response Handler.
*/
@@ -1622,7 +1897,17 @@ public class S7ProtocolLogic extends Plc4xProtocolBase<TPKTPacket> {
}
//TODO: Reemsambling message.
- if (responseMessage instanceof S7MessageUserData) {
+ if (responseMessage instanceof S7MessageResponseData) {
+ for (String tagName : plcReadRequest.getTagNames()) {
+ if (plcReadRequest.getTag(tagName) instanceof S7StringTag) {
+ PlcValue plcValue = null;
+ PlcResponseCode responseCode = PlcResponseCode.INTERNAL_ERROR;
+ List<PlcValue> plcValues = new LinkedList<>();
+ ResponseItem<PlcValue> result = new ResponseItem<>(responseCode, plcValue);
+ values.put(tagName, result);
+ }
+ }
+ } else if (responseMessage instanceof S7MessageUserData) {
S7PayloadUserData payload = (S7PayloadUserData) responseMessage.getPayload();
if (plcReadRequest.getNumberOfTags() != payload.getItems().size()) {
@@ -1725,15 +2010,18 @@ public class S7ProtocolLogic extends Plc4xProtocolBase<TPKTPacket> {
dt.getMsec() * 1000000)));
plcValue = new PlcList(plcValues);
}
-
+
ResponseItem<PlcValue> result = new ResponseItem<>(responseCode, plcValue);
values.put(tagName, result);
index++;
}
+
+
return new DefaultPlcReadResponse(plcReadRequest, values);
}
+
// In all other cases all went well.
S7PayloadReadVarResponse payload = (S7PayloadReadVarResponse) responseMessage.getPayload();
@@ -1748,20 +2036,32 @@ public class S7ProtocolLogic extends Plc4xProtocolBase<TPKTPacket> {
List<S7VarPayloadDataItem> payloadItems = payload.getItems();
int index = 0;
+ PlcResponseCode responseCode = null;
+ PlcValue plcValue = null;
for (String tagName : plcReadRequest.getTagNames()) {
- S7Tag tag = (S7Tag) plcReadRequest.getTag(tagName);
- S7VarPayloadDataItem payloadItem = payloadItems.get(index);
-
- PlcResponseCode responseCode = decodeResponseCode(payloadItem.getReturnCode());
- PlcValue plcValue = null;
- ByteBuf data = Unpooled.wrappedBuffer(payloadItem.getData());
- if (responseCode == PlcResponseCode.OK) {
- try {
- plcValue = parsePlcValue(tag, data);
- } catch (Exception e) {
- throw new PlcProtocolException("Error decoding PlcValue", e);
+
+ if (plcReadRequest.getTag(tagName) instanceof S7StringTag) {
+
+ final S7VarPayloadDataItem payloadItem = payloadItems.get(index);
+ responseCode = decodeResponseCode(payloadItem.getReturnCode());
+ plcValue = new PlcSTRING(new String(payloadItem.getData(), StandardCharsets.UTF_8));
+
+ } else {
+ S7Tag tag = (S7Tag) plcReadRequest.getTag(tagName);
+ S7VarPayloadDataItem payloadItem = payloadItems.get(index);
+
+ responseCode = decodeResponseCode(payloadItem.getReturnCode());
+ plcValue = null;
+
+ ByteBuf data = Unpooled.wrappedBuffer(payloadItem.getData());
+ if (responseCode == PlcResponseCode.OK) {
+ try {
+ plcValue = parsePlcValue(tag, data);
+ } catch (Exception e) {
+ throw new PlcProtocolException("Error decoding PlcValue", e);
+ }
}
- }
+ };
ResponseItem<PlcValue> result = new ResponseItem<>(responseCode, plcValue);
values.put(tagName, result);
index++;
diff --git a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/tag/S7ClkTag.java b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/tag/S7ClkTag.java
index 2644737efb..c998d6f12f 100644
--- a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/tag/S7ClkTag.java
+++ b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/tag/S7ClkTag.java
@@ -84,7 +84,7 @@ public class S7ClkTag implements PlcTag {
public static boolean matches(String address) {
return CLK_ADDRESS_PATTERN.matcher(address).matches() ||
- CLKF_ADDRESS_PATTERN.matcher(address).matches();
+ CLKF_ADDRESS_PATTERN.matcher(address).matches();
}
public static S7ClkTag of(String address) {
diff --git a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/tag/S7PlcTagHandler.java b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/tag/S7PlcTagHandler.java
index 05b748df0b..4a43836a3a 100644
--- a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/tag/S7PlcTagHandler.java
+++ b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/tag/S7PlcTagHandler.java
@@ -27,14 +27,16 @@ public class S7PlcTagHandler implements PlcTagHandler {
@Override
public PlcTag parseTag(String tagAddress) {
- if (S7Tag.matches(tagAddress)) {
- return S7Tag.of(tagAddress);
+ if (S7StringTag.matches(tagAddress)) {
+ return S7StringTag.of(tagAddress);
} else if (S7SubscriptionTag.matches(tagAddress)) {
return S7SubscriptionTag.of(tagAddress);
} else if (S7ClkTag.matches(tagAddress)) {
return S7ClkTag.of(tagAddress);
} else if (S7SzlTag.matches(tagAddress)) {
return S7SzlTag.of(tagAddress);
+ } else if (S7Tag.matches(tagAddress)) {
+ return S7Tag.of(tagAddress);
}
throw new PlcInvalidTagException(tagAddress);
}
diff --git a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/tag/S7StringTag.java b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/tag/S7StringTag.java
index 23614677ec..4e81fb0da2 100644
--- a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/tag/S7StringTag.java
+++ b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/tag/S7StringTag.java
@@ -25,8 +25,35 @@ import org.apache.plc4x.java.spi.generation.SerializationException;
import org.apache.plc4x.java.spi.generation.WriteBuffer;
import java.nio.charset.StandardCharsets;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import org.apache.plc4x.java.api.exceptions.PlcInvalidTagException;
+import static org.apache.plc4x.java.s7.readwrite.tag.S7Tag.BIT_OFFSET;
+import static org.apache.plc4x.java.s7.readwrite.tag.S7Tag.BLOCK_NUMBER;
+import static org.apache.plc4x.java.s7.readwrite.tag.S7Tag.BYTE_OFFSET;
+import static org.apache.plc4x.java.s7.readwrite.tag.S7Tag.DATA_TYPE;
+import static org.apache.plc4x.java.s7.readwrite.tag.S7Tag.NUM_ELEMENTS;
+import static org.apache.plc4x.java.s7.readwrite.tag.S7Tag.STRING_LENGTH;
+import static org.apache.plc4x.java.s7.readwrite.tag.S7Tag.TRANSFER_SIZE_CODE;
+import static org.apache.plc4x.java.s7.readwrite.tag.S7Tag.checkByteOffset;
+import static org.apache.plc4x.java.s7.readwrite.tag.S7Tag.checkDataBlockNumber;
+import static org.apache.plc4x.java.s7.readwrite.tag.S7Tag.getSizeCode;
public class S7StringTag extends S7Tag {
+
+ private static final Pattern DATA_BLOCK_STRING =
+ Pattern.compile("^%DB(?<blockNumber>\\d{1,5}):(?<byteOffset>\\d{1,7})(.(?<bitOffset>[0-7]))?:(?<dataType>STRING|WSTRING)?");
+
+ private static final Pattern DATA_BLOCK_STRING_SHORT =
+ Pattern.compile("^%DB(?<blockNumber>\\d{1,5}).DB(?<transferSizeCode>[XBWD]?)(?<byteOffset>\\d{1,7})(.(?<bitOffset>[0-7]))?:(?<dataType>STRING|WSTRING)?");
+
+ private static final Pattern DATA_BLOCK_STRING_ADDRESS_PATTERN =
+ Pattern.compile("^%DB(?<blockNumber>\\d{1,5}).DB(?<transferSizeCode>[XBWD]?)(?<byteOffset>\\d{1,7})(.(?<bitOffset>[0-7]))?:(?<dataType>STRING|WSTRING)\\((?<stringLength>\\d{1,3})\\)(\\[(?<numElements>\\d+)])?");
+
+ private static final Pattern DATA_BLOCK_STRING_SHORT_PATTERN =
+ Pattern.compile("^%DB(?<blockNumber>\\d{1,5}):(?<byteOffset>\\d{1,7})(.(?<bitOffset>[0-7]))?:(?<dataType>STRING|WSTRING)\\((?<stringLength>\\d{1,3})\\)(\\[(?<numElements>\\d+)])?");
+
+
private final int stringLength;
@@ -42,6 +69,14 @@ public class S7StringTag extends S7Tag {
return stringLength;
}
+ public static boolean matches(String address) {
+ return DATA_BLOCK_STRING.matcher(address).matches() ||
+ DATA_BLOCK_STRING_SHORT.matcher(address).matches() ||
+ DATA_BLOCK_STRING_ADDRESS_PATTERN.matcher(address).matches() ||
+ DATA_BLOCK_STRING_SHORT_PATTERN.matcher(address).matches();
+ }
+
+
@Override
public void serialize(WriteBuffer writeBuffer) throws SerializationException {
writeBuffer.pushContext(getClass().getSimpleName());
@@ -64,5 +99,101 @@ public class S7StringTag extends S7Tag {
writeBuffer.popContext(getClass().getSimpleName());
}
+
+ public static S7StringTag of(String address) {
+ Matcher matcher;
+
+ if ((matcher = DATA_BLOCK_STRING_SHORT.matcher(address)).matches()) {
+ TransportSize dataType = TransportSize.valueOf(matcher.group(DATA_TYPE));
+ int stringLength = -1;
+ MemoryArea memoryArea = MemoryArea.DATA_BLOCKS;
+ int blockNumber = checkDataBlockNumber(Integer.parseInt(matcher.group(BLOCK_NUMBER)));
+ Short transferSizeCode = getSizeCode(matcher.group(TRANSFER_SIZE_CODE));
+ int byteOffset = checkByteOffset(Integer.parseInt(matcher.group(BYTE_OFFSET)));
+ byte bitOffset = 0;
+ if (matcher.group(BIT_OFFSET) != null) {
+ bitOffset = Byte.parseByte(matcher.group(BIT_OFFSET));
+ } else if (dataType == TransportSize.BOOL) {
+ throw new PlcInvalidTagException("Expected bit offset for BOOL parameters.");
+ }
+ int numElements = 1;
+// if (matcher.group(NUM_ELEMENTS) != null) {
+// numElements = Integer.parseInt(matcher.group(NUM_ELEMENTS));
+// }
+
+ if ((transferSizeCode != null) && (dataType.getShortName() != transferSizeCode)) {
+ throw new PlcInvalidTagException("Transfer size code '" + transferSizeCode +
+ "' doesn't match specified data type '" + dataType.name() + "'");
+ }
+
+ return new S7StringTag(dataType, memoryArea, blockNumber, byteOffset, bitOffset, numElements, stringLength);
+
+ } else if ((matcher = DATA_BLOCK_STRING.matcher(address)).matches()) {
+ TransportSize dataType = TransportSize.valueOf(matcher.group(DATA_TYPE));
+ int stringLength = Integer.parseInt(matcher.group(STRING_LENGTH));
+ MemoryArea memoryArea = MemoryArea.DATA_BLOCKS;
+ int blockNumber = checkDataBlockNumber(Integer.parseInt(matcher.group(BLOCK_NUMBER)));
+ Short transferSizeCode = getSizeCode(matcher.group(TRANSFER_SIZE_CODE));
+ int byteOffset = checkByteOffset(Integer.parseInt(matcher.group(BYTE_OFFSET)));
+ byte bitOffset = 0;
+ if (matcher.group(BIT_OFFSET) != null) {
+ bitOffset = Byte.parseByte(matcher.group(BIT_OFFSET));
+ } else if (dataType == TransportSize.BOOL) {
+ throw new PlcInvalidTagException("Expected bit offset for BOOL parameters.");
+ }
+ int numElements = 1;
+ if (matcher.group(NUM_ELEMENTS) != null) {
+ numElements = Integer.parseInt(matcher.group(NUM_ELEMENTS));
+ }
+
+ if ((transferSizeCode != null) && (dataType.getShortName() != transferSizeCode)) {
+ throw new PlcInvalidTagException("Transfer size code '" + transferSizeCode +
+ "' doesn't match specified data type '" + dataType.name() + "'");
+ }
+
+ return new S7StringTag(dataType, memoryArea, blockNumber, byteOffset, bitOffset, numElements, stringLength);
+
+ } else if ((matcher = DATA_BLOCK_STRING_ADDRESS_PATTERN.matcher(address)).matches()) {
+ TransportSize dataType = TransportSize.valueOf(matcher.group(DATA_TYPE));
+ int stringLength = Integer.parseInt(matcher.group(STRING_LENGTH));
+ MemoryArea memoryArea = MemoryArea.DATA_BLOCKS;
+ int blockNumber = checkDataBlockNumber(Integer.parseInt(matcher.group(BLOCK_NUMBER)));
+ Short transferSizeCode = getSizeCode(matcher.group(TRANSFER_SIZE_CODE));
+ int byteOffset = checkByteOffset(Integer.parseInt(matcher.group(BYTE_OFFSET)));
+ byte bitOffset = 0;
+ if (matcher.group(BIT_OFFSET) != null) {
+ bitOffset = Byte.parseByte(matcher.group(BIT_OFFSET));
+ } else if (dataType == TransportSize.BOOL) {
+ throw new PlcInvalidTagException("Expected bit offset for BOOL parameters.");
+ }
+ int numElements = 1;
+ if (matcher.group(NUM_ELEMENTS) != null) {
+ numElements = Integer.parseInt(matcher.group(NUM_ELEMENTS));
+ }
+
+ if ((transferSizeCode != null) && (dataType.getShortName() != transferSizeCode)) {
+ throw new PlcInvalidTagException("Transfer size code '" + transferSizeCode +
+ "' doesn't match specified data type '" + dataType.name() + "'");
+ }
+
+ return new S7StringTag(dataType, memoryArea, blockNumber, byteOffset, bitOffset, numElements, stringLength);
+ } else if ((matcher = DATA_BLOCK_STRING_SHORT_PATTERN.matcher(address)).matches()) {
+ TransportSize dataType = TransportSize.valueOf(matcher.group(DATA_TYPE));
+ int stringLength = Integer.parseInt(matcher.group(STRING_LENGTH));
+ MemoryArea memoryArea = MemoryArea.DATA_BLOCKS;
+ int blockNumber = checkDataBlockNumber(Integer.parseInt(matcher.group(BLOCK_NUMBER)));
+ int byteOffset = checkByteOffset(Integer.parseInt(matcher.group(BYTE_OFFSET)));
+ byte bitOffset = 0;
+ int numElements = 1;
+ if (matcher.group(NUM_ELEMENTS) != null) {
+ numElements = Integer.parseInt(matcher.group(NUM_ELEMENTS));
+ }
+
+ return new S7StringTag(dataType, memoryArea, blockNumber,
+ byteOffset, bitOffset, numElements, stringLength);
+ }
+
+ return null;
+ }
}
diff --git a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/tag/S7Tag.java b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/tag/S7Tag.java
index 31ff6e3492..26c7917ac4 100644
--- a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/tag/S7Tag.java
+++ b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/tag/S7Tag.java
@@ -52,23 +52,19 @@ public class S7Tag implements PlcTag, Serializable {
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 DATA_BLOCK_STRING_ADDRESS_PATTERN =
- Pattern.compile("^%DB(?<blockNumber>\\d{1,5}).DB(?<transferSizeCode>[XBWD]?)(?<byteOffset>\\d{1,7})(.(?<bitOffset>[0-7]))?:(?<dataType>STRING|WSTRING)\\((?<stringLength>\\d{1,3})\\)(\\[(?<numElements>\\d+)])?");
- private static final Pattern DATA_BLOCK_STRING_SHORT_PATTERN =
- Pattern.compile("^%DB(?<blockNumber>\\d{1,5}):(?<byteOffset>\\d{1,7})(.(?<bitOffset>[0-7]))?:(?<dataType>STRING|WSTRING)\\((?<stringLength>\\d{1,3})\\)(\\[(?<numElements>\\d+)])?");
private static final Pattern PLC_PROXY_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 STRING_LENGTH = "stringLength";
- private static final String TRANSFER_SIZE_CODE = "transferSizeCode";
- private static final String BLOCK_NUMBER = "blockNumber";
- private static final String BYTE_OFFSET = "byteOffset";
- private static final String BIT_OFFSET = "bitOffset";
- private static final String NUM_ELEMENTS = "numElements";
- private static final String MEMORY_AREA = "memoryArea";
+ protected static final String DATA_TYPE = "dataType";
+ protected static final String STRING_LENGTH = "stringLength";
+ protected static final String TRANSFER_SIZE_CODE = "transferSizeCode";
+ protected static final String BLOCK_NUMBER = "blockNumber";
+ protected static final String BYTE_OFFSET = "byteOffset";
+ protected static final String BIT_OFFSET = "bitOffset";
+ protected static final String NUM_ELEMENTS = "numElements";
+ protected static final String MEMORY_AREA = "memoryArea";
private final TransportSize dataType;
private final MemoryArea memoryArea;
@@ -136,8 +132,6 @@ public class S7Tag implements PlcTag, Serializable {
public static boolean matches(String tagString) {
return
- DATA_BLOCK_STRING_ADDRESS_PATTERN.matcher(tagString).matches() ||
- DATA_BLOCK_STRING_SHORT_PATTERN.matcher(tagString).matches() ||
DATA_BLOCK_ADDRESS_PATTERN.matcher(tagString).matches() ||
DATA_BLOCK_SHORT_PATTERN.matcher(tagString).matches() ||
PLC_PROXY_ADDRESS_PATTERN.matcher(tagString).matches() ||
@@ -146,45 +140,46 @@ public class S7Tag implements PlcTag, Serializable {
public static S7Tag of(String tagString) {
Matcher matcher;
- if ((matcher = DATA_BLOCK_STRING_ADDRESS_PATTERN.matcher(tagString)).matches()) {
- TransportSize dataType = TransportSize.valueOf(matcher.group(DATA_TYPE));
- int stringLength = Integer.parseInt(matcher.group(STRING_LENGTH));
- MemoryArea memoryArea = MemoryArea.DATA_BLOCKS;
- int blockNumber = checkDataBlockNumber(Integer.parseInt(matcher.group(BLOCK_NUMBER)));
- Short transferSizeCode = getSizeCode(matcher.group(TRANSFER_SIZE_CODE));
- int byteOffset = checkByteOffset(Integer.parseInt(matcher.group(BYTE_OFFSET)));
- byte bitOffset = 0;
- if (matcher.group(BIT_OFFSET) != null) {
- bitOffset = Byte.parseByte(matcher.group(BIT_OFFSET));
- } else if (dataType == TransportSize.BOOL) {
- throw new PlcInvalidTagException("Expected bit offset for BOOL parameters.");
- }
- int numElements = 1;
- if (matcher.group(NUM_ELEMENTS) != null) {
- numElements = Integer.parseInt(matcher.group(NUM_ELEMENTS));
- }
-
- if ((transferSizeCode != null) && (dataType.getShortName() != transferSizeCode)) {
- throw new PlcInvalidTagException("Transfer size code '" + transferSizeCode +
- "' doesn't match specified data type '" + dataType.name() + "'");
- }
-
- return new S7StringTag(dataType, memoryArea, blockNumber, byteOffset, bitOffset, numElements, stringLength);
- } else if ((matcher = DATA_BLOCK_STRING_SHORT_PATTERN.matcher(tagString)).matches()) {
- TransportSize dataType = TransportSize.valueOf(matcher.group(DATA_TYPE));
- int stringLength = Integer.parseInt(matcher.group(STRING_LENGTH));
- MemoryArea memoryArea = MemoryArea.DATA_BLOCKS;
- int blockNumber = checkDataBlockNumber(Integer.parseInt(matcher.group(BLOCK_NUMBER)));
- int byteOffset = checkByteOffset(Integer.parseInt(matcher.group(BYTE_OFFSET)));
- byte bitOffset = 0;
- int numElements = 1;
- if (matcher.group(NUM_ELEMENTS) != null) {
- numElements = Integer.parseInt(matcher.group(NUM_ELEMENTS));
- }
-
- return new S7StringTag(dataType, memoryArea, blockNumber,
- byteOffset, bitOffset, numElements, stringLength);
- } else if ((matcher = DATA_BLOCK_ADDRESS_PATTERN.matcher(tagString)).matches()) {
+// if ((matcher = DATA_BLOCK_STRING_ADDRESS_PATTERN.matcher(tagString)).matches()) {
+// TransportSize dataType = TransportSize.valueOf(matcher.group(DATA_TYPE));
+// int stringLength = Integer.parseInt(matcher.group(STRING_LENGTH));
+// MemoryArea memoryArea = MemoryArea.DATA_BLOCKS;
+// int blockNumber = checkDataBlockNumber(Integer.parseInt(matcher.group(BLOCK_NUMBER)));
+// Short transferSizeCode = getSizeCode(matcher.group(TRANSFER_SIZE_CODE));
+// int byteOffset = checkByteOffset(Integer.parseInt(matcher.group(BYTE_OFFSET)));
+// byte bitOffset = 0;
+// if (matcher.group(BIT_OFFSET) != null) {
+// bitOffset = Byte.parseByte(matcher.group(BIT_OFFSET));
+// } else if (dataType == TransportSize.BOOL) {
+// throw new PlcInvalidTagException("Expected bit offset for BOOL parameters.");
+// }
+// int numElements = 1;
+// if (matcher.group(NUM_ELEMENTS) != null) {
+// numElements = Integer.parseInt(matcher.group(NUM_ELEMENTS));
+// }
+//
+// if ((transferSizeCode != null) && (dataType.getShortName() != transferSizeCode)) {
+// throw new PlcInvalidTagException("Transfer size code '" + transferSizeCode +
+// "' doesn't match specified data type '" + dataType.name() + "'");
+// }
+//
+// return new S7StringTag(dataType, memoryArea, blockNumber, byteOffset, bitOffset, numElements, stringLength);
+//// } else if ((matcher = DATA_BLOCK_STRING_SHORT_PATTERN.matcher(tagString)).matches()) {
+//// TransportSize dataType = TransportSize.valueOf(matcher.group(DATA_TYPE));
+//// int stringLength = Integer.parseInt(matcher.group(STRING_LENGTH));
+//// MemoryArea memoryArea = MemoryArea.DATA_BLOCKS;
+//// int blockNumber = checkDataBlockNumber(Integer.parseInt(matcher.group(BLOCK_NUMBER)));
+//// int byteOffset = checkByteOffset(Integer.parseInt(matcher.group(BYTE_OFFSET)));
+//// byte bitOffset = 0;
+//// int numElements = 1;
+//// if (matcher.group(NUM_ELEMENTS) != null) {
+//// numElements = Integer.parseInt(matcher.group(NUM_ELEMENTS));
+//// }
+////
+//// return new S7StringTag(dataType, memoryArea, blockNumber,
+//// byteOffset, bitOffset, numElements, stringLength);
+// } else
+ if ((matcher = DATA_BLOCK_ADDRESS_PATTERN.matcher(tagString)).matches()) {
TransportSize dataType = TransportSize.valueOf(matcher.group(DATA_TYPE));
MemoryArea memoryArea = MemoryArea.DATA_BLOCKS;
Short transferSizeCode = getSizeCode(matcher.group(TRANSFER_SIZE_CODE));
@@ -280,7 +275,7 @@ public class S7Tag implements PlcTag, Serializable {
* @param blockNumber given DataBlockNumber
* @return given blockNumber if Ok, throws PlcInvalidTagException otherwise
*/
- private static int checkDataBlockNumber(int blockNumber) {
+ protected static int checkDataBlockNumber(int blockNumber) {
// TODO: check the value or add reference - limit eventually depending on active S7 --> make a case selection
if (blockNumber > 64000 || blockNumber < 1) {
throw new PlcInvalidTagException("DataBlock numbers larger than 64000 or smaller than 1 are not supported.");
@@ -294,7 +289,7 @@ public class S7Tag implements PlcTag, Serializable {
* @param byteOffset given byteOffset
* @return given byteOffset if Ok, throws PlcInvalidTagException otherwise
*/
- private static int checkByteOffset(int byteOffset) {
+ protected static int checkByteOffset(int byteOffset) {
// TODO: check the value or add reference
if (byteOffset > 2097151 || byteOffset < 0) {
throw new PlcInvalidTagException("ByteOffset must be smaller than 2097151 and positive.");
diff --git a/plc4j/examples/plc4j-s7event/src/main/java/org/apache/plc4x/examples/plc4j/s7event/PlcReadWriteStrings.java b/plc4j/examples/plc4j-s7event/src/main/java/org/apache/plc4x/examples/plc4j/s7event/PlcReadWriteStrings.java
new file mode 100644
index 0000000000..e86f296eff
--- /dev/null
+++ b/plc4j/examples/plc4j-s7event/src/main/java/org/apache/plc4x/examples/plc4j/s7event/PlcReadWriteStrings.java
@@ -0,0 +1,434 @@
+/*
+ * 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.
+ */
+package org.apache.plc4x.examples.plc4j.s7event;
+
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import org.apache.commons.lang3.time.StopWatch;
+import org.apache.plc4x.java.DefaultPlcDriverManager;
+import org.apache.plc4x.java.api.exceptions.PlcConnectionException;
+import org.apache.plc4x.java.api.listener.ConnectionStateListener;
+import org.apache.plc4x.java.api.messages.PlcReadRequest;
+import org.apache.plc4x.java.api.messages.PlcReadResponse;
+import org.apache.plc4x.java.api.messages.PlcWriteRequest;
+import org.apache.plc4x.java.api.messages.PlcWriteResponse;
+import org.apache.plc4x.java.api.types.PlcResponseCode;
+import org.apache.plc4x.java.s7.readwrite.protocol.S7HPlcConnection;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/*
+*
+* Example of connection to a S7-400.
+* The connection is supervised.
+* Plc: SIMATIC S7-400
+* Model: CPU 417
+* Part number: 6ES7 417-4XT05-0AB0
+* Firmware version: 5.1.0
+* CP1: 6GK7 443-1EX11-0XE0
+* CP2: 6GK7 443-1EX20-0XB0
+*
+* For the following program, the DB400 must be installed in the PLC,
+* with the following chains and the indicated lengths.
+*
+* DB400
+* STRING001 - STRING[254]
+* STRING002 - STRING[172]
+* STRING003 - STRING[1]
+* STRING004 - STRING[0]
+* STRING005 - STRING[32]
+* STRING006 - STRING[64]
+* STRING007 - STRING[0]
+* STRING008 - STRING[1]
+* STRING009 - STRING[2]
+* STRING010 - STRING[3]
+* STRING011 - STRING[4]
+* STRING012 - STRING[5]
+* STRING013 - STRING[6]
+* STRING014 - STRING[7]
+* STRING015 - STRING[8]
+*/
+public class PlcReadWriteStrings implements ConnectionStateListener {
+
+ private static final Logger logger = LoggerFactory.getLogger(PlcReadWriteStrings.class);
+ private static final long DELAY = 1000L;
+
+ private static String TEST_STRING00 = "";
+ private static String TEST_STRING01 = "Y";
+ private static String TEST_STRING02 = "YZ";
+ private static String TEST_STRING08 = "01234567";
+ private static String TEST_STRING254 =
+ "01234567890123456789012345678901234567890123456789"+
+ "01234567890123456789012345678901234567890123456789"+
+ "01234567890123456789012345678901234567890123456789"+
+ "01234567890123456789012345678901234567890123456789"+
+ "01234567890123456789012345678901234567890123456789"+
+ "0123";
+
+ private S7HPlcConnection connection = null;
+ private AtomicBoolean isConnected = new AtomicBoolean(false);
+
+ private String[] tags = new String[]{"STRING007","STRING008","STRING009",
+ "STRING010","STRING011","STRING012",
+ "STRING013","STRING014","STRING015"};
+
+ /**
+ * @param args the command line arguments
+ */
+ public static void main(String[] args) throws Exception {
+ System.setProperty(org.slf4j.simple.SimpleLogger.DEFAULT_LOG_LEVEL_KEY, "Debug");
+
+ PlcReadWriteStrings device = new PlcReadWriteStrings();
+ device.run();
+ }
+
+ public void run() throws IOException {
+ logger.info("*****************************************************");
+ logger.info("* Example of connection and read to a Simatic S7-400H");
+ logger.info("* Plc: SIMATIC S7-400");
+ logger.info("* Model: CPU 417");
+ logger.info("* Part number: 6ES7 417-4XT05-0AB0");
+ logger.info("* Firmware version: 5.1.0");
+ logger.info("* CP1: 6GK7 443-1EX11-0XE0");
+ logger.info("* CP2: 6GK7 443-1EX20-0XB0");
+ logger.info("*");
+ logger.info("* Note: . ");
+ logger.info("* . ");
+ logger.info("*****************************************************");
+
+ OpenConnection("s7://10.10.1.80/10.10.1.81?remote-rack=0&"
+ + "remote-slot=3&remote-rack2=0&remote-slot=4&"
+ + "controller-type=S7_400&read-timeout=16&"
+ + "ping=true&ping-time=8&retry-time=3"); //(01)
+
+ logger.info("*****************************************************");
+ logger.info("* 1. Once the connection is executed, it must read");
+ logger.info("* the data contained in the address.");
+ logger.info("* URL to:s7://10.10.1.80/10.10.1.81?remote-rack=0&");
+ logger.info(" remote-slot=3&remote-rack2=0&remote-slot=4&");
+ logger.info(" controller-type=S7_400&read-timeout=8&");
+ logger.info(" ping=true&ping-time=2&retry-time=3");
+ logger.info("* Press [ENTER]");
+ logger.info("*****************************************************");
+
+ Read(); //(01.1)
+
+ logger.info("*****************************************************");
+ logger.info("* 2. Turn off/on PLC! This will cause the connection");
+ logger.info("* handlers to be lost. ");
+ logger.info("* This simulates connection loss due to lack of ");
+ logger.info("* traffic, which is handled by OS. ");
+ logger.info("* When reading is executed, the driver must activate");
+ logger.info("* the reconnection process internally.");
+ logger.info("* In this operation the reading is lost, but ");
+ logger.info("* the reconnection process begins.");
+ logger.info("* Press [ENTER]");
+ logger.info("*****************************************************");
+ System.in.read();
+
+ Write();
+
+ logger.info("*****************************************************");
+ logger.info("* Write null string.. Clean the DB in ST7/TIA.");
+ logger.info("* Press [ENTER]");
+ logger.info("*****************************************************");
+ System.in.read();
+ SafeWrite(TEST_STRING00);
+ SafeRead(TEST_STRING00);
+
+
+ logger.info("*****************************************************");
+ logger.info("* Write one character string.. Clean the DB in ST7/TIA.");
+ logger.info("* Press [ENTER]");
+ logger.info("*****************************************************");
+ System.in.read();
+ SafeWrite(TEST_STRING01);
+ SafeRead(TEST_STRING01);
+
+
+ logger.info("*****************************************************");
+ logger.info("* Write two character string.. Clean the DB in ST7/TIA.");
+ logger.info("* Press [ENTER]");
+ logger.info("*****************************************************");
+ System.in.read();
+ SafeWrite(TEST_STRING02);
+ SafeRead(TEST_STRING02);
+
+
+ logger.info("*****************************************************");
+ logger.info("* Write eigth character string.. Clean the DB in ST7/TIA");
+ logger.info("* Press [ENTER]");
+ logger.info("*****************************************************");
+ System.in.read();
+ SafeWrite(TEST_STRING08);
+ SafeRead(TEST_STRING08);
+
+
+ logger.info("*****************************************************");
+ logger.info("* Write 254 character string.. Clean the DB in ST7/TIA");
+ logger.info("* Press [ENTER]");
+ logger.info("*****************************************************");
+ System.in.read();
+ SafeWrite(TEST_STRING254);
+ SafeRead(TEST_STRING254);
+
+
+ logger.info("*****************************************************");
+ logger.info("* 8. And we close the connection.");
+ logger.info("* Press [ENTER]");
+ logger.info("*****************************************************");
+ System.in.read();
+
+ CloseConnection(); //(08.1)
+
+ }
+
+
+ /***************************************************************************
+ * Under normal conditions, the driver expects you to have the PLC
+ * connected to the network to start operations.
+ * If a connection to the PLC cannot be established, an exception of type
+ * "PlcConnectionException" is generated, which must be handled by your
+ * application. In this example it waits for a connection to exist.
+ * When you disconnect the "connection", the S7 driver will take care of the
+ * connection and reconnection process if necessary.
+ * The internal wait time for the connection is one (01) second.
+ ***************************************************************************/
+ private void OpenConnection(String url) {
+ int retrys = 0;
+ StopWatch watch = new StopWatch();
+ watch.start();
+ while (null == connection) {
+ try {
+ connection =(S7HPlcConnection) new DefaultPlcDriverManager().
+ getConnection(url);
+ connection.addEventListener(this);
+ while (!connection.isConnected());
+ watch.stop();
+
+ isConnected.set( connection.isConnected());
+
+ logger.info("Time elapse for connection: {} in ms, with " +
+ "rettrys: {}",watch.getTime(), retrys);
+
+ } catch (PlcConnectionException ex) {
+ logger.info(ex.getMessage());
+ //Avoid excessive CPU consumption
+ try {
+ TimeUnit.MILLISECONDS.sleep(DELAY);
+ } catch (InterruptedException ie) {
+ Thread.currentThread().interrupt();
+ }
+ retrys++;
+ }
+ }
+
+ }
+
+ /***************************************************************************
+ * When the connection is closed, pending tasks and transactions are
+ * completed.
+ * The rest of the work should be sent to the GC.
+ ***************************************************************************/
+ private void CloseConnection() {
+ if (null == connection) return;
+ isConnected.set(false);
+ try {
+ connection.close();
+ connection = null; //GC do you job!.
+
+ } catch (PlcConnectionException ex) {
+ logger.info("CloseConnection: " + ex.getMessage());
+ }
+ }
+
+ /***************************************************************************
+ * The reading process is standard. In case of an exception,
+ * the user must take the appropriate actions, but "do not close
+ * the connection":
+ ***************************************************************************/
+ private void Read() {
+ if (!isConnected.get()) return;
+ try {
+ final PlcReadRequest.Builder readrequest = connection.readRequestBuilder(); //(01)
+ readrequest.addTagAddress("TAG01", "%DB400.DBX0.0:STRING"); //(02)
+ readrequest.addTagAddress("TAG06", "%DB400.DBX470.0:STRING"); //(02)
+ readrequest.addTagAddress("TAG02", "%MB190:BYTE"); //(02)
+
+ final PlcReadRequest rr = readrequest.build(); //(03)
+ final PlcReadResponse response; //(04)
+ response = rr.execute().get(); //(05)
+
+ if (response.getResponseCode("TAG01") == PlcResponseCode.OK) { //(06)
+ logger.info("Value1: " + response.getString("TAG01"));
+ logger.info("Value2: " + response.getString("TAG06"));
+ logger.info("Value3: " + response.getString("TAG02"));
+ } else {
+ logger.info("Problem reading...");
+ }
+ } catch (Exception ex) { //(07)
+ logger.info("Read: " + ex.getMessage());
+ };
+ }
+
+ /***************************************************************************
+ * The reading process is standard. In case of an exception,
+ * the user must take the appropriate actions, but "do not close
+ * the connection":
+ ***************************************************************************/
+ private void Write() {
+ if (!isConnected.get()) return;
+ try {
+ final PlcWriteRequest.Builder writeRequest = connection.writeRequestBuilder(); //(01)
+ writeRequest.addTagAddress("TAG01", "%DB400.DBX0.0:STRING",TEST_STRING254 ); //(02)
+ writeRequest.addTagAddress("TAG06", "%DB400.DBX470.0:STRING",TEST_STRING254 ); //(02)
+ writeRequest.addTagAddress("TAG08", "%DB400.DBX436.0:STRING",TEST_STRING254 ); //(02)
+
+ final PlcWriteRequest wr = writeRequest.build(); //(03)
+ final PlcWriteResponse response; //(04)
+ response = wr.execute().get(); //(05)
+
+ if (response.getResponseCode("TAG01") == PlcResponseCode.OK) { //(06)
+ logger.info("TAG01 Write sucefull...");
+ } else {
+ logger.info("TAG01 Problem reading...");
+ }
+
+ if (response.getResponseCode("TAG06") == PlcResponseCode.OK) { //(06)
+ logger.info("TAG06 Write sucefull...");
+ } else {
+ logger.info("TAG06 Problem reading...");
+ }
+
+ if (response.getResponseCode("TAG08") == PlcResponseCode.OK) { //(06)
+ logger.info("TAG07 Write sucefull...");
+ } else {
+ logger.info("TAG07 Problem reading...");
+ }
+
+ } catch (Exception ex) { //(07)
+ logger.info("Read: " + ex.getMessage());
+ };
+ }
+
+ /***************************************************************************
+ * Write the String "str" to the different test memory areas.
+ * No overlap of contents should be shown.
+ ***************************************************************************/
+ private void SafeWrite(String str) {
+ if (!isConnected.get()) return;
+ try {
+ final PlcWriteRequest.Builder writeRequest = connection.writeRequestBuilder(); //(01)
+ writeRequest.addTagAddress(tags[0], "%DB400.DBX536.0:STRING",str); //(02)
+ writeRequest.addTagAddress(tags[1], "%DB400.DBX538.0:STRING",str); //(02)
+ writeRequest.addTagAddress(tags[2], "%DB400.DBX542.0:STRING",str); //(02)
+ writeRequest.addTagAddress(tags[3], "%DB400.DBX546.0:STRING",str); //(02)
+ writeRequest.addTagAddress(tags[4], "%DB400.DBX552.0:STRING",str); //(02)
+ writeRequest.addTagAddress(tags[5], "%DB400.DBX558.0:STRING",str); //(02)
+ writeRequest.addTagAddress(tags[6], "%DB400.DBX566.0:STRING",str); //(02)
+ writeRequest.addTagAddress(tags[7], "%DB400.DBX574.0:STRING",str); //(02)
+ writeRequest.addTagAddress(tags[8], "%DB400.DBX584.0:STRING",str); //(02)
+
+ final PlcWriteRequest wr = writeRequest.build(); //(03)
+ final PlcWriteResponse response; //(04)
+ response = wr.execute().get(); //(05)
+
+ for (String tag:tags) {
+ if (response.getResponseCode(tag) == PlcResponseCode.OK) //(06)
+ logger.info(tag + " Write sucefull...");
+ }
+
+ } catch (Exception ex) { //(07)
+ logger.info("Read: " + ex.getMessage());
+ };
+ }
+
+ /***************************************************************************
+ * The reading process is standard.
+ * Each "value" obtained from the PLC is compared with "str".
+ * If everything is fine, it should indicate a successful reading.
+ ***************************************************************************/
+ private void SafeRead(String str) {
+ int index = 0;
+ int pos = 0;
+ if (!isConnected.get()) return;
+ try {
+ final PlcReadRequest.Builder readRequest = connection.readRequestBuilder(); //(01)
+ readRequest.addTagAddress(tags[0], "%DB400.DBX536.0:STRING"); //(02)
+ readRequest.addTagAddress(tags[1], "%DB400.DBX538.0:STRING"); //(02)
+ readRequest.addTagAddress(tags[2], "%DB400.DBX542.0:STRING"); //(02)
+ readRequest.addTagAddress(tags[3], "%DB400.DBX546.0:STRING"); //(02)
+ readRequest.addTagAddress(tags[4], "%DB400.DBX552.0:STRING"); //(02)
+ readRequest.addTagAddress(tags[5], "%DB400.DBX558.0:STRING"); //(02)
+ readRequest.addTagAddress(tags[6], "%DB400.DBX566.0:STRING"); //(02)
+ readRequest.addTagAddress(tags[7], "%DB400.DBX574.0:STRING"); //(02)
+ readRequest.addTagAddress(tags[8], "%DB400.DBX584.0:STRING"); //(02)
+
+ final PlcReadRequest rr = readRequest.build(); //(03)
+ final PlcReadResponse response; //(04)
+ response = rr.execute().get(); //(05)
+
+
+ for (String tag:tags) {
+ if (response.getResponseCode(tag) == PlcResponseCode.OK){
+ pos = (index <= str.length())?index:str.length();
+ if (response.getString(tag).equals(str.substring(0, pos))){
+ logger.info(tag + " Read sucefull...");
+ } else {
+ logger.info(tag + ": " + response.getString(tag) + " : " + str.substring(0, index));
+ }
+ }
+ index++;
+ }
+
+ } catch (Exception ex) { //(07)
+ logger.info("Read: " + ex.getMessage());
+ };
+ }
+
+ /***************************************************************************
+ * This method is called when the driver makes an internal TCP connection.
+ * The first connection of the driver does not generate this event.
+ * In the case of high availability systems, this signal should be used
+ * to restart subscriptions to events, alarms, etc.
+ ***************************************************************************/
+ @Override
+ public void connected() {
+ logger.info("*****************************************************");
+ logger.info("*************** Plc is connected. *******************");
+ logger.info("*****************************************************");
+ isConnected.set(true);
+ }
+
+ /***************************************************************************
+ * This method is called when there is a physical disconnection of the driver
+ * Check the monitoring parameters given in the URL during connection.
+ ***************************************************************************/
+ @Override
+ public void disconnected() {
+ logger.info("*****************************************************");
+ logger.info("*************** Plc is disconnected. ****************");
+ logger.info("*****************************************************");
+ isConnected.set(false);
+ }
+
+
+
+}