You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by sr...@apache.org on 2022/11/04 15:45:29 UTC

[plc4x] branch develop updated (37d8880cb -> 6cd52d208)

This is an automated email from the ASF dual-hosted git repository.

sruehl pushed a change to branch develop
in repository https://gitbox.apache.org/repos/asf/plc4x.git


    from 37d8880cb feat(plc-simulator/bacnet): initial bacnet plc-simulator
     new c1f170093 feat(plc-simulator/bacnet): bacnet simulator is now able to return a valid hard coded response
     new 3577f8bfd fix(plc4j/bacnet): fix static helper creating wrong requests
     new 6cd52d208 feat(plc-simulator): add I-AM response to whois

The 3 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.


Summary of changes:
 .../bacnetip/readwrite/utils/StaticHelper.java     |  18 ++-
 .../server/bacnet/BacnetServerModule.java          |  59 ++++----
 .../bacnet/protocol/BacnetServerAdapter.java       | 167 +++++++++++++++++++--
 3 files changed, 196 insertions(+), 48 deletions(-)


[plc4x] 03/03: feat(plc-simulator): add I-AM response to whois

Posted by sr...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sruehl pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/plc4x.git

commit 6cd52d2087d02ac312d0cf7d7fc52e5241b83021
Author: Sebastian Rühl <sr...@apache.org>
AuthorDate: Fri Nov 4 16:45:21 2022 +0100

    feat(plc-simulator): add I-AM response to whois
---
 .../bacnet/protocol/BacnetServerAdapter.java       | 168 ++++++++++++---------
 1 file changed, 97 insertions(+), 71 deletions(-)

diff --git a/plc4j/utils/plc-simulator/src/main/java/org/apache/plc4x/simulator/server/bacnet/protocol/BacnetServerAdapter.java b/plc4j/utils/plc-simulator/src/main/java/org/apache/plc4x/simulator/server/bacnet/protocol/BacnetServerAdapter.java
index 92dfe3fb4..b04ad7582 100644
--- a/plc4j/utils/plc-simulator/src/main/java/org/apache/plc4x/simulator/server/bacnet/protocol/BacnetServerAdapter.java
+++ b/plc4j/utils/plc-simulator/src/main/java/org/apache/plc4x/simulator/server/bacnet/protocol/BacnetServerAdapter.java
@@ -34,6 +34,12 @@ public class BacnetServerAdapter extends ChannelInboundHandlerAdapter {
 
     private Context context;
 
+    // TODO: make configurable
+    private static int DEVICE_INSTANCE = 4711;
+
+    // TODO: make configurable
+    private static int DEVICE_ID = 815;
+
     public BacnetServerAdapter(Context context) {
         LOGGER.info("Creating adapter with context {}", context);
     }
@@ -46,6 +52,8 @@ public class BacnetServerAdapter extends ChannelInboundHandlerAdapter {
 
     @Override
     public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
+        System.out.println("Got request");
+        System.out.println(msg);
         if (!(msg instanceof BVLC)) {
             return;
         }
@@ -86,92 +94,110 @@ public class BacnetServerAdapter extends ChannelInboundHandlerAdapter {
         BVLCOriginalUnicastNPDU bvlcOriginalUnicastNPDU = (BVLCOriginalUnicastNPDU) bvlc;
         // TODO: get messageTypeField
         APDU apdu = bvlcOriginalUnicastNPDU.getNpdu().getApdu();
-        if (!(apdu instanceof APDUConfirmedRequest)) {
-            // TODO: write useful error
-            ctx.writeAndFlush(new BVLCOriginalUnicastNPDU(
+        if (apdu instanceof APDUUnconfirmedRequest) {
+            APDUUnconfirmedRequest apduUnconfirmedRequest = (APDUUnconfirmedRequest) apdu;
+            BACnetUnconfirmedServiceRequest serviceRequest = apduUnconfirmedRequest.getServiceRequest();
+            if (serviceRequest instanceof BACnetUnconfirmedServiceRequestWhoIs) {
+                BACnetUnconfirmedServiceRequestWhoIs baCnetUnconfirmedServiceRequestWhoIs = (BACnetUnconfirmedServiceRequestWhoIs) serviceRequest;
+                if (baCnetUnconfirmedServiceRequestWhoIs.getDeviceInstanceRangeLowLimit() != null) {
+                    if (DEVICE_INSTANCE < baCnetUnconfirmedServiceRequestWhoIs.getDeviceInstanceRangeLowLimit().getActualValue().longValue()) {
+                        // Ignoring because we out if limit
+                        return;
+                    }
+                }
+                if (baCnetUnconfirmedServiceRequestWhoIs.getDeviceInstanceRangeHighLimit() != null) {
+                    if (DEVICE_INSTANCE > baCnetUnconfirmedServiceRequestWhoIs.getDeviceInstanceRangeHighLimit().getActualValue().longValue()) {
+                        // Ignoring because we out if limit
+                        return;
+                    }
+                }
+                BVLCOriginalUnicastNPDU response = new BVLCOriginalUnicastNPDU(
+                    new NPDU(
+                        (short) 1,
+                        new NPDUControl(false, false, false, false, NPDUNetworkPriority.NORMAL_MESSAGE),
+                        null,
+                        null,
+                        null,
+                        null,
+                        null,
+                        null,
+                        null,
+                        null,
+                        new APDUUnconfirmedRequest(
+                            new BACnetUnconfirmedServiceRequestIAm(
+                                StaticHelper.createBACnetApplicationTagObjectIdentifier(BACnetObjectType.DEVICE.getValue(), DEVICE_INSTANCE),
+                                StaticHelper.createBACnetApplicationTagUnsignedInteger(1024),
+                                StaticHelper.creatBACnetSegmentationTagged(BACnetSegmentation.NO_SEGMENTATION),
+                                StaticHelper.createBACnetVendorIdApplicationTagged(BACnetVendorId.MAPPED.getVendorId()),
+                                0
+                            ),
+                            0
+                        ),
+                        0
+                    ),
+                    0
+                );
+                System.out.println("Writing response");
+                System.out.println(response);
+                ctx.writeAndFlush(response).addListener((ChannelFutureListener) f -> {
+                    if (!f.isSuccess()) {
+                        f.cause().printStackTrace();
+                    }
+                });
+            } else {
+                throw new Exception(apdu.getClass() + " not set supported");
+            }
+        } else if (apdu instanceof APDUConfirmedRequest) {
+            APDUConfirmedRequest apduConfirmedRequest = (APDUConfirmedRequest) apdu;
+            // TODO: just handle read for now
+            BVLCOriginalUnicastNPDU response = new BVLCOriginalUnicastNPDU(
                 new NPDU(
                     (short) 1,
-                    new NPDUControl(true, false, false, false, NPDUNetworkPriority.NORMAL_MESSAGE),
-                    0,
-                    (short) 0,
+                    new NPDUControl(false, false, false, false, NPDUNetworkPriority.NORMAL_MESSAGE),
                     null,
-                    0,
-                    (short) 0,
                     null,
-                    (short) 0,
                     null,
-                    new APDUError(
-                        (short) 0,
-                        BACnetConfirmedServiceChoice.READ_PROPERTY,
-                        new BACnetErrorGeneral(new Error(
-                            new ErrorClassTagged(new BACnetTagHeader((byte) 0, TagClass.APPLICATION_TAGS, (byte) 1, (short) 0, (short) 0, 0, 0L), ErrorClass.COMMUNICATION, 0, (short) 0, TagClass.APPLICATION_TAGS),
-                            new ErrorCodeTagged(new BACnetTagHeader((byte) 0, TagClass.APPLICATION_TAGS, (byte) 1, (short) 0, (short) 0, 0, 0L), ErrorCode.VENDOR_PROPRIETARY_VALUE, 0, (short) 0, TagClass.APPLICATION_TAGS)
-                        )),
+                    null,
+                    null,
+                    null,
+                    null,
+                    null,
+                    new APDUComplexAck(
+                        false,
+                        false,
+                        apduConfirmedRequest.getInvokeId(),
+                        null,
+                        null,
+                        new BACnetServiceAckReadProperty(
+                            StaticHelper.createBACnetContextTagObjectIdentifier((byte) 0, 2, 1L),
+                            StaticHelper.createBACnetPropertyIdentifierTagged((byte) 1, 85),
+                            null,
+                            new BACnetConstructedDataAnalogValuePresentValue(
+                                StaticHelper.createBACnetOpeningTag((short) 3),
+                                StaticHelper.createBACnetTagHeaderBalanced(true, (short) 3, 3L),
+                                StaticHelper.createBACnetClosingTag((short) 3),
+                                StaticHelper.createBACnetApplicationTagReal(101L),
+                                null,
+                                null
+                            ),
+                            0L
+                        ),
+                        null,
+                        null,
                         0
                     ),
                     0
                 ),
                 0
-            )).addListener((ChannelFutureListener) f -> {
+            );
+            System.out.println("Writing response");
+            System.out.println(response);
+            ctx.writeAndFlush(response).addListener((ChannelFutureListener) f -> {
                 if (!f.isSuccess()) {
                     f.cause().printStackTrace();
                 }
             });
-            return;
         }
-        APDUConfirmedRequest apduConfirmedRequest = (APDUConfirmedRequest) apdu;
-        // TODO: implement me
-        System.out.println("Got request");
-        System.out.println(msg);
-        BVLCOriginalUnicastNPDU response = new BVLCOriginalUnicastNPDU(
-            new NPDU(
-                (short) 1,
-                new NPDUControl(false, false, false, false, NPDUNetworkPriority.NORMAL_MESSAGE),
-                null,
-                null,
-                null,
-                null,
-                null,
-                null,
-                null,
-                null,
-                new APDUComplexAck(
-                    false,
-                    false,
-                    apduConfirmedRequest.getInvokeId(),
-                    null,
-                    null,
-                    new BACnetServiceAckReadProperty(
-                        StaticHelper.createBACnetContextTagObjectIdentifier((byte) 0, 2, 1L),
-                        StaticHelper.createBACnetPropertyIdentifierTagged((byte) 1, 85),
-                        null,
-                        new BACnetConstructedDataAnalogValuePresentValue(
-                            StaticHelper.createBACnetOpeningTag((short) 3),
-                            StaticHelper.createBACnetTagHeaderBalanced(true, (short) 3, 3L),
-                            StaticHelper.createBACnetClosingTag((short) 3),
-                            StaticHelper.createBACnetApplicationTagReal(101L),
-                            null,
-                            null
-                        ),
-                        0L
-                    ),
-                    null,
-                    null,
-                    0
-                ),
-                0
-            ),
-            0
-        );
-        System.out.println("Writing response");
-        System.out.println(response);
-        ctx.writeAndFlush(response).addListener((ChannelFutureListener) f -> {
-            if (!f.isSuccess()) {
-                f.cause().printStackTrace();
-            }
-        });
-        ;
     }
 
-
 }


[plc4x] 02/03: fix(plc4j/bacnet): fix static helper creating wrong requests

Posted by sr...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sruehl pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/plc4x.git

commit 3577f8bfd2036eeda7319d5198212ad78f54d094
Author: Sebastian Rühl <sr...@apache.org>
AuthorDate: Fri Nov 4 16:45:00 2022 +0100

    fix(plc4j/bacnet): fix static helper creating wrong requests
---
 .../java/bacnetip/readwrite/utils/StaticHelper.java    | 18 +++++++++++++++---
 1 file changed, 15 insertions(+), 3 deletions(-)

diff --git a/plc4j/drivers/bacnet/src/main/java/org/apache/plc4x/java/bacnetip/readwrite/utils/StaticHelper.java b/plc4j/drivers/bacnet/src/main/java/org/apache/plc4x/java/bacnetip/readwrite/utils/StaticHelper.java
index 4b3ce0c43..c494461ca 100644
--- a/plc4j/drivers/bacnet/src/main/java/org/apache/plc4x/java/bacnetip/readwrite/utils/StaticHelper.java
+++ b/plc4j/drivers/bacnet/src/main/java/org/apache/plc4x/java/bacnetip/readwrite/utils/StaticHelper.java
@@ -161,6 +161,14 @@ public class StaticHelper {
             if (!BACnetConfirmedServiceRequestReinitializeDeviceReinitializedStateOfDevice.isDefined((short) rawValue))
                 return BACnetConfirmedServiceRequestReinitializeDeviceReinitializedStateOfDevice.VENDOR_PROPRIETARY_VALUE;
             return BACnetConfirmedServiceRequestReinitializeDeviceReinitializedStateOfDevice.enumForValue((short) rawValue);
+        } else if (declaringClass == BACnetSegmentation.class) {
+            if (!BACnetSegmentation.isDefined((short) rawValue))
+                LOGGER.error("{} not defined for segmentation falling back to no segmentation", rawValue);
+            return BACnetSegmentation.NO_SEGMENTATION;
+        } else if (declaringClass == BACnetVendorId.class) {
+            if (!BACnetVendorId.isDefined((short) rawValue))
+                return BACnetVendorId.UNKNOWN_VENDOR;
+            return BACnetVendorId.enumForValue((short) rawValue);
         } else {
             LOGGER.warn("using reflection for {}", declaringClass);
             Optional<Method> enumForValue = Arrays.stream(declaringClass.getDeclaredMethods()).filter(method -> method.getName().equals("enumForValue")).findAny();
@@ -242,6 +250,10 @@ public class StaticHelper {
             valueValue = ((BACnetConfirmedServiceRequestReinitializeDeviceReinitializedStateOfDevice) value).getValue();
         } else if (value.getDeclaringClass() == BACnetConfirmedServiceRequestDeviceCommunicationControlEnableDisable.class) {
             valueValue = ((BACnetConfirmedServiceRequestDeviceCommunicationControlEnableDisable) value).getValue();
+        } else if (value.getDeclaringClass() == BACnetSegmentation.class) {
+            valueValue = ((BACnetSegmentation) value).getValue();
+        } else if (value.getDeclaringClass() == BACnetVendorId.class) {
+            valueValue = ((BACnetVendorId) value).getValue();
         } else {
             LOGGER.warn("using reflection for {}", value.getDeclaringClass());
             try {
@@ -437,7 +449,7 @@ public class StaticHelper {
     }
 
     public static BACnetApplicationTagObjectIdentifier createBACnetApplicationTagObjectIdentifier(int objectType, long instance) {
-        BACnetTagHeader header = new BACnetTagHeader((byte) BACnetDataType.SIGNED_INTEGER.getValue(), TagClass.APPLICATION_TAGS, (byte) 4, null, null, null, null);
+        BACnetTagHeader header = new BACnetTagHeader((byte) BACnetDataType.BACNET_OBJECT_IDENTIFIER.getValue(), TagClass.APPLICATION_TAGS, (byte) 4, null, null, null, null);
         BACnetObjectType objectTypeEnum = BACnetObjectType.enumForValue(objectType);
         int proprietaryValue = 0;
         if (objectType >= 128 || !BACnetObjectType.isDefined(objectType)) {
@@ -494,8 +506,8 @@ public class StaticHelper {
     }
 
     public static BACnetSegmentationTagged creatBACnetSegmentationTagged(BACnetSegmentation value) {
-        BACnetTagHeader header = createBACnetTagHeaderBalanced(false, (byte) 0, 1);
-        return new BACnetSegmentationTagged(header, value, (short) 0, TagClass.APPLICATION_TAGS);
+        BACnetTagHeader header = createBACnetTagHeaderBalanced(false, (byte) 9, 1);
+        return new BACnetSegmentationTagged(header, value, (short) 9, TagClass.APPLICATION_TAGS);
     }
 
     public static BACnetApplicationTagBoolean createBACnetApplicationTagBoolean(boolean value) {


[plc4x] 01/03: feat(plc-simulator/bacnet): bacnet simulator is now able to return a valid hard coded response

Posted by sr...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sruehl pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/plc4x.git

commit c1f1700932da9b2f0db523a8a2f10b1e85bde6e8
Author: Sebastian Rühl <sr...@apache.org>
AuthorDate: Fri Nov 4 14:27:55 2022 +0100

    feat(plc-simulator/bacnet): bacnet simulator is now able to return a valid hard coded response
---
 .../server/bacnet/BacnetServerModule.java          |  59 +++++----
 .../bacnet/protocol/BacnetServerAdapter.java       | 137 +++++++++++++++++++--
 2 files changed, 153 insertions(+), 43 deletions(-)

diff --git a/plc4j/utils/plc-simulator/src/main/java/org/apache/plc4x/simulator/server/bacnet/BacnetServerModule.java b/plc4j/utils/plc-simulator/src/main/java/org/apache/plc4x/simulator/server/bacnet/BacnetServerModule.java
index f5a504778..8c69793ed 100644
--- a/plc4j/utils/plc-simulator/src/main/java/org/apache/plc4x/simulator/server/bacnet/BacnetServerModule.java
+++ b/plc4j/utils/plc-simulator/src/main/java/org/apache/plc4x/simulator/server/bacnet/BacnetServerModule.java
@@ -19,35 +19,28 @@
 package org.apache.plc4x.simulator.server.bacnet;
 
 import io.netty.bootstrap.Bootstrap;
-import io.netty.bootstrap.ServerBootstrap;
 import io.netty.buffer.ByteBuf;
-import io.netty.channel.*;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelInitializer;
+import io.netty.channel.ChannelOption;
+import io.netty.channel.EventLoopGroup;
 import io.netty.channel.nio.NioEventLoopGroup;
-import io.netty.channel.socket.SocketChannel;
+import io.netty.channel.socket.DatagramPacket;
 import io.netty.channel.socket.nio.NioDatagramChannel;
-import io.netty.channel.socket.nio.NioServerSocketChannel;
-import io.netty.handler.codec.DatagramPacketDecoder;
-import io.netty.handler.codec.DatagramPacketEncoder;
 import io.netty.handler.codec.MessageToMessageDecoder;
 import io.netty.handler.codec.MessageToMessageEncoder;
 import org.apache.plc4x.java.bacnetip.BacNetIpDriver;
 import org.apache.plc4x.java.bacnetip.readwrite.BVLC;
 import org.apache.plc4x.java.bacnetip.readwrite.BacnetConstants;
-import org.apache.plc4x.java.cbus.CBusDriver;
-import org.apache.plc4x.java.cbus.readwrite.CBusConstants;
-import org.apache.plc4x.java.cbus.readwrite.CBusMessage;
-import org.apache.plc4x.java.cbus.readwrite.CBusOptions;
-import org.apache.plc4x.java.cbus.readwrite.RequestContext;
 import org.apache.plc4x.java.spi.connection.GeneratedProtocolMessageCodec;
 import org.apache.plc4x.java.spi.generation.ByteOrder;
-import org.apache.plc4x.java.spi.generation.ReadBufferByteBased;
-import org.apache.plc4x.java.spi.generation.WriteBufferByteBased;
 import org.apache.plc4x.simulator.PlcSimulatorConfig;
 import org.apache.plc4x.simulator.exceptions.SimulatorException;
 import org.apache.plc4x.simulator.model.Context;
 import org.apache.plc4x.simulator.server.ServerModule;
 import org.apache.plc4x.simulator.server.bacnet.protocol.BacnetServerAdapter;
 
+import java.net.InetSocketAddress;
 import java.util.List;
 
 public class BacnetServerModule implements ServerModule {
@@ -88,24 +81,28 @@ public class BacnetServerModule implements ServerModule {
                 .handler(new ChannelInitializer<NioDatagramChannel>() {
                     @Override
                     public void initChannel(NioDatagramChannel channel) {
-                        ChannelPipeline pipeline = channel.pipeline();
-                        pipeline.addLast(new DatagramPacketDecoder(new MessageToMessageDecoder<ByteBuf>() {
-                            @Override
-                            protected void decode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) throws Exception {
-                                byte[] bytes = new byte[msg.readableBytes()];
-                                msg.readBytes(bytes);
-                                out.add(BVLC.staticParse(new ReadBufferByteBased(bytes)));
-                            }
-                        }));
-                        pipeline.addLast(new DatagramPacketEncoder<>(new MessageToMessageEncoder<BVLC>() {
-                            @Override
-                            protected void encode(ChannelHandlerContext ctx, BVLC msg, List<Object> out) throws Exception {
-                                WriteBufferByteBased writeBuffer = new WriteBufferByteBased(msg.getLengthInBytes());
-                                msg.serialize(writeBuffer);
-                                out.add(writeBuffer.getBytes());
-                            }
-                        }));
-                        pipeline.addLast(new BacnetServerAdapter(context));
+                        channel.pipeline()
+                            .addLast(new MessageToMessageDecoder<DatagramPacket>() {
+                                @Override
+                                protected void decode(ChannelHandlerContext ctx, DatagramPacket msg, List<Object> out) throws Exception {
+                                    final ByteBuf content = msg.content();
+                                    out.add(content.retain());
+                                }
+                            })
+                            .addLast(new MessageToMessageEncoder<ByteBuf>() {
+                                @Override
+                                protected void encode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) throws Exception {
+                                    msg.retain();
+                                    // TODO: find better way to implement request response
+                                    out.add(new DatagramPacket(msg, new InetSocketAddress("192.168.178.102", 47808)));
+                                }
+                            })
+                            .addLast(new GeneratedProtocolMessageCodec<>(BVLC.class,
+                                BVLC::staticParse, ByteOrder.BIG_ENDIAN,
+                                null,
+                                new BacNetIpDriver.ByteLengthEstimator(),
+                                new BacNetIpDriver.CorruptPackageCleaner()))
+                            .addLast(new BacnetServerAdapter(context));
                     }
                 });
 
diff --git a/plc4j/utils/plc-simulator/src/main/java/org/apache/plc4x/simulator/server/bacnet/protocol/BacnetServerAdapter.java b/plc4j/utils/plc-simulator/src/main/java/org/apache/plc4x/simulator/server/bacnet/protocol/BacnetServerAdapter.java
index 39da9a67a..92dfe3fb4 100644
--- a/plc4j/utils/plc-simulator/src/main/java/org/apache/plc4x/simulator/server/bacnet/protocol/BacnetServerAdapter.java
+++ b/plc4j/utils/plc-simulator/src/main/java/org/apache/plc4x/simulator/server/bacnet/protocol/BacnetServerAdapter.java
@@ -18,24 +18,16 @@
  */
 package org.apache.plc4x.simulator.server.bacnet.protocol;
 
+import io.netty.channel.ChannelFutureListener;
 import io.netty.channel.ChannelHandlerContext;
 import io.netty.channel.ChannelInboundHandlerAdapter;
-import org.apache.plc4x.java.bacnetip.readwrite.BVLC;
-import org.apache.plc4x.java.cbus.readwrite.*;
+import org.apache.plc4x.java.bacnetip.readwrite.Error;
+import org.apache.plc4x.java.bacnetip.readwrite.*;
+import org.apache.plc4x.java.bacnetip.readwrite.utils.StaticHelper;
 import org.apache.plc4x.simulator.model.Context;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.concurrent.ScheduledFuture;
-import java.util.concurrent.ThreadLocalRandom;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantLock;
-
 public class BacnetServerAdapter extends ChannelInboundHandlerAdapter {
 
     private static final Logger LOGGER = LoggerFactory.getLogger(BacnetServerAdapter.class);
@@ -57,8 +49,129 @@ public class BacnetServerAdapter extends ChannelInboundHandlerAdapter {
         if (!(msg instanceof BVLC)) {
             return;
         }
+        BVLC bvlc = (BVLC) msg;
+        if (!(bvlc instanceof BVLCOriginalUnicastNPDU)) {
+            // TODO: write useful error
+            ctx.writeAndFlush(new BVLCOriginalUnicastNPDU(
+                new NPDU(
+                    (short) 1,
+                    new NPDUControl(true, false, false, false, NPDUNetworkPriority.NORMAL_MESSAGE),
+                    0,
+                    (short) 0,
+                    null,
+                    0,
+                    (short) 0,
+                    null,
+                    (short) 0,
+                    null,
+                    new APDUError(
+                        (short) 0,
+                        BACnetConfirmedServiceChoice.READ_PROPERTY,
+                        new BACnetErrorGeneral(new Error(
+                            new ErrorClassTagged(new BACnetTagHeader((byte) 0, TagClass.APPLICATION_TAGS, (byte) 1, (short) 0, (short) 0, 0, 0L), ErrorClass.COMMUNICATION, 0, (short) 0, TagClass.APPLICATION_TAGS),
+                            new ErrorCodeTagged(new BACnetTagHeader((byte) 0, TagClass.APPLICATION_TAGS, (byte) 1, (short) 0, (short) 0, 0, 0L), ErrorCode.VENDOR_PROPRIETARY_VALUE, 0, (short) 0, TagClass.APPLICATION_TAGS)
+                        )),
+                        0
+                    ),
+                    0
+                ),
+                0
+            )).addListener((ChannelFutureListener) f -> {
+                if (!f.isSuccess()) {
+                    f.cause().printStackTrace();
+                }
+            });
+            return;
+        }
+        BVLCOriginalUnicastNPDU bvlcOriginalUnicastNPDU = (BVLCOriginalUnicastNPDU) bvlc;
+        // TODO: get messageTypeField
+        APDU apdu = bvlcOriginalUnicastNPDU.getNpdu().getApdu();
+        if (!(apdu instanceof APDUConfirmedRequest)) {
+            // TODO: write useful error
+            ctx.writeAndFlush(new BVLCOriginalUnicastNPDU(
+                new NPDU(
+                    (short) 1,
+                    new NPDUControl(true, false, false, false, NPDUNetworkPriority.NORMAL_MESSAGE),
+                    0,
+                    (short) 0,
+                    null,
+                    0,
+                    (short) 0,
+                    null,
+                    (short) 0,
+                    null,
+                    new APDUError(
+                        (short) 0,
+                        BACnetConfirmedServiceChoice.READ_PROPERTY,
+                        new BACnetErrorGeneral(new Error(
+                            new ErrorClassTagged(new BACnetTagHeader((byte) 0, TagClass.APPLICATION_TAGS, (byte) 1, (short) 0, (short) 0, 0, 0L), ErrorClass.COMMUNICATION, 0, (short) 0, TagClass.APPLICATION_TAGS),
+                            new ErrorCodeTagged(new BACnetTagHeader((byte) 0, TagClass.APPLICATION_TAGS, (byte) 1, (short) 0, (short) 0, 0, 0L), ErrorCode.VENDOR_PROPRIETARY_VALUE, 0, (short) 0, TagClass.APPLICATION_TAGS)
+                        )),
+                        0
+                    ),
+                    0
+                ),
+                0
+            )).addListener((ChannelFutureListener) f -> {
+                if (!f.isSuccess()) {
+                    f.cause().printStackTrace();
+                }
+            });
+            return;
+        }
+        APDUConfirmedRequest apduConfirmedRequest = (APDUConfirmedRequest) apdu;
         // TODO: implement me
+        System.out.println("Got request");
         System.out.println(msg);
+        BVLCOriginalUnicastNPDU response = new BVLCOriginalUnicastNPDU(
+            new NPDU(
+                (short) 1,
+                new NPDUControl(false, false, false, false, NPDUNetworkPriority.NORMAL_MESSAGE),
+                null,
+                null,
+                null,
+                null,
+                null,
+                null,
+                null,
+                null,
+                new APDUComplexAck(
+                    false,
+                    false,
+                    apduConfirmedRequest.getInvokeId(),
+                    null,
+                    null,
+                    new BACnetServiceAckReadProperty(
+                        StaticHelper.createBACnetContextTagObjectIdentifier((byte) 0, 2, 1L),
+                        StaticHelper.createBACnetPropertyIdentifierTagged((byte) 1, 85),
+                        null,
+                        new BACnetConstructedDataAnalogValuePresentValue(
+                            StaticHelper.createBACnetOpeningTag((short) 3),
+                            StaticHelper.createBACnetTagHeaderBalanced(true, (short) 3, 3L),
+                            StaticHelper.createBACnetClosingTag((short) 3),
+                            StaticHelper.createBACnetApplicationTagReal(101L),
+                            null,
+                            null
+                        ),
+                        0L
+                    ),
+                    null,
+                    null,
+                    0
+                ),
+                0
+            ),
+            0
+        );
+        System.out.println("Writing response");
+        System.out.println(response);
+        ctx.writeAndFlush(response).addListener((ChannelFutureListener) f -> {
+            if (!f.isSuccess()) {
+                f.cause().printStackTrace();
+            }
+        });
+        ;
     }
 
+
 }