This is an automated email from the ASF dual-hosted git repository. sruehl pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/incubator-plc4x.git
The following commit(s) were added to refs/heads/master by this push: new 8e19212 several small fixes on ads protocol 8e19212 is described below commit 8e192122734bda4882f126fb69822d5aa4cf4454 Author: Sebastian Rühl <sru...@apache.org> AuthorDate: Thu Apr 26 15:24:19 2018 +0200 several small fixes on ads protocol --- .../api/commands/AdsDeviceNotificationRequest.java | 2 +- .../java/ads/api/commands/types/AdsReturnCode.java | 2 +- .../java/ads/api/commands/types/TimeStamp.java | 4 +-- .../plc4x/java/ads/api/generic/types/AmsPort.java | 21 ++++++------- .../plc4x/java/ads/api/generic/types/Command.java | 6 ++-- .../java/ads/api/util/UnsignedIntLEByteValue.java | 14 ++++----- .../ads/api/util/UnsignedShortLEByteValue.java | 14 +++++---- .../ads/connection/AdsSerialPlcConnection.java | 4 +-- .../java/ads/protocol/Ads2PayloadProtocol.java | 3 +- .../plc4x/java/ads/protocol/Plc4x2AdsProtocol.java | 34 +++++++++++++++++++--- .../ads/protocol/util/LittleEndianDecoder.java | 5 ++-- .../ads/protocol/util/LittleEndianEncoder.java | 1 + 12 files changed, 69 insertions(+), 41 deletions(-) diff --git a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/api/commands/AdsDeviceNotificationRequest.java b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/api/commands/AdsDeviceNotificationRequest.java index 6b75109..583673c 100644 --- a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/api/commands/AdsDeviceNotificationRequest.java +++ b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/api/commands/AdsDeviceNotificationRequest.java @@ -75,7 +75,7 @@ public class AdsDeviceNotificationRequest extends AdsAbstractRequest { for (LengthSupplier supplier : adsStampHeaders) { aggregateLength += supplier.getCalculatedLength(); } - return aggregateLength; + return aggregateLength + Stamps.NUM_BYTES; }; } diff --git a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/api/commands/types/AdsReturnCode.java b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/api/commands/types/AdsReturnCode.java index 6c6c982..edadf21 100644 --- a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/api/commands/types/AdsReturnCode.java +++ b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/api/commands/types/AdsReturnCode.java @@ -33,7 +33,7 @@ public enum AdsReturnCode { ADS_CODE_3(0x3, 3, "Allocation locked memory error"), ADS_CODE_4(0x4, 4, "Insert mailbox error", "No ADS mailbox was available to process this message.", "Reduce the number of ADS calls (e.g ADS-Sum commands or Max Delay Parameter)"), ADS_CODE_5(0x5, 5, "Wrong receive HMSG"), - ADS_CODE_6(0x6, 6, "target port not foundADS ", "Server not started"), + ADS_CODE_6(0x6, 6, "target port not found", "ADS Server not started"), ADS_CODE_7(0x7, 7, "target machine not found", "Missing ADS routes"), ADS_CODE_8(0x8, 8, "Unknown command ID"), ADS_CODE_9(0x9, 9, "Bad task ID"), diff --git a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/api/commands/types/TimeStamp.java b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/api/commands/types/TimeStamp.java index c0ce2f0..fc283b5 100644 --- a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/api/commands/types/TimeStamp.java +++ b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/api/commands/types/TimeStamp.java @@ -121,11 +121,11 @@ public class TimeStamp extends ByteValue { return of(values); } - private BigInteger getBigIntegerValue() { + public BigInteger getBigIntegerValue() { return bigIntegerValue; } - private Date getAsDate() { + public Date getAsDate() { return new Date(winTimeToJava(bigIntegerValue).longValue()); } diff --git a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/api/generic/types/AmsPort.java b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/api/generic/types/AmsPort.java index 9346b9f..5ae3123 100644 --- a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/api/generic/types/AmsPort.java +++ b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/api/generic/types/AmsPort.java @@ -19,9 +19,8 @@ package org.apache.plc4x.java.ads.api.generic.types; import io.netty.buffer.ByteBuf; -import org.apache.plc4x.java.ads.api.util.ByteValue; +import org.apache.plc4x.java.ads.api.util.UnsignedShortLEByteValue; -import java.nio.ByteBuffer; import java.util.regex.Pattern; /** @@ -30,15 +29,18 @@ import java.util.regex.Pattern; * @see <a href="https://infosys.beckhoff.com/content/1033/tcadscommon/html/tcadscommon_identadsdevice.htm?id=3991659524769593444">ADS device identification</a> */ @SuppressWarnings("unused") // Due to predefined ports -public class AmsPort extends ByteValue { +public class AmsPort extends UnsignedShortLEByteValue { public static final Pattern AMS_PORT_PATTERN = Pattern.compile("\\d+"); - public static final int NUM_BYTES = 2; + public static final int NUM_BYTES = UnsignedShortLEByteValue.UNSIGNED_SHORT_LE_NUM_BYTES; private AmsPort(byte... value) { super(value); - assertLength(NUM_BYTES); + } + + private AmsPort(int value) { + super(value); } public static AmsPort of(byte... values) { @@ -46,12 +48,7 @@ public class AmsPort extends ByteValue { } public static AmsPort of(int port) { - checkUnsignedBounds(port, NUM_BYTES); - return new AmsPort(ByteBuffer.allocate(NUM_BYTES) - // LE - .put((byte) (port & 0xff)) - .put((byte) (port >> 8 & 0xff)) - .array()); + return new AmsPort(port); } public static AmsPort of(String port) { @@ -67,7 +64,7 @@ public class AmsPort extends ByteValue { @Override public String toString() { - return Integer.toString(getBytes()[1] << 8 | getBytes()[0] & 0xff); + return String.valueOf(getAsInt()); } public static class ReservedPorts { diff --git a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/api/generic/types/Command.java b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/api/generic/types/Command.java index 9a5a2a7..779a15e 100644 --- a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/api/generic/types/Command.java +++ b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/api/generic/types/Command.java @@ -24,6 +24,7 @@ import org.apache.plc4x.java.ads.api.util.ByteReadable; import org.apache.plc4x.java.ads.api.util.ByteValue; import java.nio.ByteBuffer; +import java.nio.ByteOrder; import java.util.Arrays; import static java.lang.Integer.toHexString; @@ -60,9 +61,8 @@ public enum Command implements ByteReadable { ByteValue.checkUnsignedBounds(value, NUM_BYTES); this.intValue = value; this.value = ByteBuffer.allocate(NUM_BYTES) - // LE - .put((byte) (value & 0xff)) - .put((byte) (value >> 8 & 0xff)) + .order(ByteOrder.LITTLE_ENDIAN) + .putShort((short) (value & 0xffff)) .array(); } diff --git a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/api/util/UnsignedIntLEByteValue.java b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/api/util/UnsignedIntLEByteValue.java index db477b9..1740c3e 100644 --- a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/api/util/UnsignedIntLEByteValue.java +++ b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/api/util/UnsignedIntLEByteValue.java @@ -21,6 +21,7 @@ package org.apache.plc4x.java.ads.api.util; import io.netty.buffer.ByteBuf; import java.nio.ByteBuffer; +import java.nio.ByteOrder; import static java.lang.Long.toHexString; import static org.apache.commons.lang3.StringUtils.leftPad; @@ -34,12 +35,13 @@ public abstract class UnsignedIntLEByteValue extends ByteValue { protected UnsignedIntLEByteValue(byte... value) { super(value); assertLength(UNSIGNED_INT_LE_NUM_BYTES); - longValue = getBytes()[3] << 24 | getBytes()[2] << 16 | getBytes()[1] << 8 | getBytes()[0]; + longValue = ByteBuffer.wrap(value) + .order(ByteOrder.LITTLE_ENDIAN) + .getInt(); } protected UnsignedIntLEByteValue(long value) { super(ofLong(value)); - checkUnsignedBounds(value, UNSIGNED_INT_LE_NUM_BYTES); longValue = value; } @@ -52,12 +54,10 @@ public abstract class UnsignedIntLEByteValue extends ByteValue { } private static byte[] ofLong(long value) { + checkUnsignedBounds(value, UNSIGNED_INT_LE_NUM_BYTES); return ByteBuffer.allocate(UNSIGNED_INT_LE_NUM_BYTES) - // LE - .put((byte) (value & 0xff)) - .put((byte) (value >> 8 & 0xff)) - .put((byte) (value >> 16 & 0xff)) - .put((byte) (value >> 24 & 0xff)) + .order(ByteOrder.LITTLE_ENDIAN) + .putInt((int) (value & 0xffff_ffff)) .array(); } diff --git a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/api/util/UnsignedShortLEByteValue.java b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/api/util/UnsignedShortLEByteValue.java index 9a43332..70b59f0 100644 --- a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/api/util/UnsignedShortLEByteValue.java +++ b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/api/util/UnsignedShortLEByteValue.java @@ -21,6 +21,7 @@ package org.apache.plc4x.java.ads.api.util; import io.netty.buffer.ByteBuf; import java.nio.ByteBuffer; +import java.nio.ByteOrder; import static java.lang.Integer.toHexString; import static org.apache.commons.lang3.StringUtils.leftPad; @@ -34,12 +35,13 @@ public abstract class UnsignedShortLEByteValue extends ByteValue { protected UnsignedShortLEByteValue(byte... value) { super(value); assertLength(UNSIGNED_SHORT_LE_NUM_BYTES); - intValue = getBytes()[1] << 8 | getBytes()[0] & 0xff; + intValue = ByteBuffer.wrap(value) + .order(ByteOrder.LITTLE_ENDIAN) + .getShort(); } protected UnsignedShortLEByteValue(int value) { super(ofInt(value)); - checkUnsignedBounds(value, UNSIGNED_SHORT_LE_NUM_BYTES); intValue = value; } @@ -51,11 +53,11 @@ public abstract class UnsignedShortLEByteValue extends ByteValue { this(byteBuf.readUnsignedShortLE()); } - private static byte[] ofInt(long value) { + private static byte[] ofInt(int value) { + checkUnsignedBounds(value, UNSIGNED_SHORT_LE_NUM_BYTES); return ByteBuffer.allocate(UNSIGNED_SHORT_LE_NUM_BYTES) - // LE - .put((byte) (value & 0xff)) - .put((byte) (value >> 8 & 0xff)) + .order(ByteOrder.LITTLE_ENDIAN) + .putShort((short) (value & 0xffff)) .array(); } diff --git a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/connection/AdsSerialPlcConnection.java b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/connection/AdsSerialPlcConnection.java index 8b68e6e..f322847 100644 --- a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/connection/AdsSerialPlcConnection.java +++ b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/connection/AdsSerialPlcConnection.java @@ -56,9 +56,9 @@ public class AdsSerialPlcConnection extends AdsAbstractPlcConnection { protected void initChannel(Channel channel) { // Build the protocol stack for communicating with the ads protocol. ChannelPipeline pipeline = channel.pipeline(); - pipeline.addLast(new Plc4x2AdsProtocol(targetAmsNetId, targetAmsPort, sourceAmsNetId, sourceAmsPort)); - pipeline.addLast(new Ads2PayloadProtocol()); pipeline.addLast(new Payload2SerialProtocol()); + pipeline.addLast(new Ads2PayloadProtocol()); + pipeline.addLast(new Plc4x2AdsProtocol(targetAmsNetId, targetAmsPort, sourceAmsNetId, sourceAmsPort)); } }; } diff --git a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/protocol/Ads2PayloadProtocol.java b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/protocol/Ads2PayloadProtocol.java index 0cfc43d..3b7633c 100644 --- a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/protocol/Ads2PayloadProtocol.java +++ b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/protocol/Ads2PayloadProtocol.java @@ -261,7 +261,8 @@ public class Ads2PayloadProtocol extends MessageToMessageCodec<ByteBuf, AmsPacke if (stamps.getAsLong() > Integer.MAX_VALUE) { throw new IllegalStateException("Overflow in datalength: " + stamps.getAsLong()); } - ByteBuf adsDeviceNotificationBuffer = commandBuffer.readBytes((int) length.getAsLong()); + // Note: the length includes the 4 Bytes of stamps which we read already so we substract. + ByteBuf adsDeviceNotificationBuffer = commandBuffer.readBytes((int) length.getAsLong() - Stamps.NUM_BYTES); List<AdsStampHeader> adsStampHeaders = new ArrayList<>((int) stamps.getAsLong()); for (int i = 1; i <= stamps.getAsLong(); i++) { AdsStampHeader adsStampHeader = handleStampHeader(adsDeviceNotificationBuffer); diff --git a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/protocol/Plc4x2AdsProtocol.java b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/protocol/Plc4x2AdsProtocol.java index 2f4ef45..c11c819 100644 --- a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/protocol/Plc4x2AdsProtocol.java +++ b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/protocol/Plc4x2AdsProtocol.java @@ -20,10 +20,7 @@ package org.apache.plc4x.java.ads.protocol; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.MessageToMessageCodec; -import org.apache.plc4x.java.ads.api.commands.AdsReadRequest; -import org.apache.plc4x.java.ads.api.commands.AdsReadResponse; -import org.apache.plc4x.java.ads.api.commands.AdsWriteRequest; -import org.apache.plc4x.java.ads.api.commands.AdsWriteResponse; +import org.apache.plc4x.java.ads.api.commands.*; import org.apache.plc4x.java.ads.api.commands.types.*; import org.apache.plc4x.java.ads.api.generic.AmsPacket; import org.apache.plc4x.java.ads.api.generic.types.AmsNetId; @@ -49,10 +46,12 @@ import org.slf4j.LoggerFactory; import java.io.IOException; import java.util.Collections; +import java.util.LinkedList; import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicLong; +import java.util.function.Consumer; import static org.apache.plc4x.java.ads.protocol.util.LittleEndianDecoder.decodeData; import static org.apache.plc4x.java.ads.protocol.util.LittleEndianEncoder.encodeData; @@ -65,6 +64,8 @@ public class Plc4x2AdsProtocol extends MessageToMessageCodec<AmsPacket, PlcReque private final ConcurrentMap<Long, PlcRequestContainer<PlcRequest, PlcResponse>> requests; + private List<Consumer<AdsDeviceNotificationRequest>> deviceNotificationListeners; + private final AmsNetId targetAmsNetId; private final AmsPort targetAmsPort; private final AmsNetId sourceAmsNetId; @@ -76,6 +77,7 @@ public class Plc4x2AdsProtocol extends MessageToMessageCodec<AmsPacket, PlcReque this.sourceAmsNetId = sourceAmsNetId; this.sourceAmsPort = sourceAmsPort; this.requests = new ConcurrentHashMap<>(); + this.deviceNotificationListeners = new LinkedList<>(); } @Override @@ -165,6 +167,11 @@ public class Plc4x2AdsProtocol extends MessageToMessageCodec<AmsPacket, PlcReque @Override protected void decode(ChannelHandlerContext channelHandlerContext, AmsPacket amsPacket, List<Object> out) throws Exception { + if (amsPacket instanceof AdsDeviceNotificationRequest) { + LOGGER.debug("Received notification {}", amsPacket); + handleAdsDeviceNotificationRequest((AdsDeviceNotificationRequest) amsPacket); + return; + } PlcRequestContainer<PlcRequest, PlcResponse> plcRequestContainer = requests.remove(amsPacket.getAmsHeader().getInvokeId().getAsLong()); if (plcRequestContainer == null) { LOGGER.info("Unmapped packet received {}", amsPacket); @@ -196,6 +203,25 @@ public class Plc4x2AdsProtocol extends MessageToMessageCodec<AmsPacket, PlcReque } } + private void handleAdsDeviceNotificationRequest(AdsDeviceNotificationRequest adsDeviceNotificationRequest) { + for (Consumer<AdsDeviceNotificationRequest> deviceNotificationListener : deviceNotificationListeners) { + try { + deviceNotificationListener.accept(adsDeviceNotificationRequest); + } catch (RuntimeException e) { + LOGGER.error("Exception received from {} while handling {}", deviceNotificationListener, adsDeviceNotificationRequest, e); + } + } + } + + public boolean addConsumer(Consumer<AdsDeviceNotificationRequest> adsDeviceNotificationRequestConsumer) { + return deviceNotificationListeners.add(adsDeviceNotificationRequestConsumer); + } + + public boolean removeConsumer(Consumer<AdsDeviceNotificationRequest> adsDeviceNotificationRequestConsumer) { + return deviceNotificationListeners.remove(adsDeviceNotificationRequestConsumer); + } + + @SuppressWarnings("unchecked") private PlcResponse decodeWriteResponse(AdsWriteResponse responseMessage, PlcRequestContainer<PlcRequest, PlcResponse> requestContainer) { PlcWriteRequest plcWriteRequest = (PlcWriteRequest) requestContainer.getRequest(); diff --git a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/protocol/util/LittleEndianDecoder.java b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/protocol/util/LittleEndianDecoder.java index 3362b15..8394cdf 100644 --- a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/protocol/util/LittleEndianDecoder.java +++ b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/protocol/util/LittleEndianDecoder.java @@ -27,6 +27,7 @@ import java.util.Date; import java.util.LinkedList; import java.util.List; +// TODO: we might user ByteBuffer.wrap(buffer).order(ByteOrder.LITTLE_ENDIAN).putInt(port).asArray() etc public class LittleEndianDecoder { private LittleEndianDecoder() { @@ -49,7 +50,7 @@ public class LittleEndianDecoder { } else if (datatype == Byte.class) { result.add(byteOne); i += 1; - } else if (datatype == Short.class) { + } else if (datatype == Short.class) { decodeShort(adsData, i, result); i += 2; } else if (datatype == Integer.class) { @@ -82,7 +83,7 @@ public class LittleEndianDecoder { private static void decodeShort(byte[] adsData, int i, List<Object> result) { byte byteOne = adsData[i]; - byte byteTwo = adsData[i+1]; + byte byteTwo = adsData[i + 1]; result.add((short) ((byteOne & 0xff) | ((byteTwo & 0xff) << 8))); } diff --git a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/protocol/util/LittleEndianEncoder.java b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/protocol/util/LittleEndianEncoder.java index f196e2e..7ee8cbe 100644 --- a/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/protocol/util/LittleEndianEncoder.java +++ b/plc4j/protocols/ads/src/main/java/org/apache/plc4x/java/ads/protocol/util/LittleEndianEncoder.java @@ -32,6 +32,7 @@ import java.util.Calendar; import java.util.Date; import java.util.stream.Stream; +// TODO: we might user ByteBuffer.wrap(buffer).order(ByteOrder.LITTLE_ENDIAN).putInt(port).asArray() etc public class LittleEndianEncoder { private LittleEndianEncoder() { -- To stop receiving notification emails like this one, please contact sru...@apache.org.