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 <[email protected]> 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); + } + + + +}
