You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by cd...@apache.org on 2020/03/09 11:33:54 UTC

[plc4x] branch develop updated (8aae234 -> e73e7c3)

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

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


    from 8aae234  Update blogs-videos-and-slides.adoc
     new db74d11  - Changed the generated code to use getSizeInBits and keep getSizeInBytes as a convenience method (Needed if data types are not byte aligned)
     new 96da9fa  - Added the value range check also to single item requests
     new e73e7c3  - Made the serial chanel configurable (baud-rate, data-bits, stop-bits, parity)

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:
 .../resources/templates/java/pojo-template.ftlh    |  16 ++-
 .../java/api/model/PlcSubscriptionHandle.java      |   1 +
 .../knxnetip/protocol/KnxNetIpProtocolLogic.java   |   1 +
 .../plc4x/java/modbus/field/ModbusField.java       |   1 +
 .../plc4x/java/modbus/field/ModbusFieldCoil.java   |   1 +
 .../java/modbus/field/ModbusFieldHandler.java      |   7 +-
 .../apache/plc4x/java/spi/generation/Message.java  |   2 +
 .../plc4x/java/transport/serial/SerialChannel.java |  10 +-
 .../java/transport/serial/SerialChannelConfig.java | 109 +++++++++++++++++++++
 .../transport/serial/SerialChannelFactory.java     |   4 +
 .../transport/serial/SerialChannelHandler.java     |   8 +-
 .../transport/serial/SerialChannelOptions.java}    |  30 +++---
 .../transport/serial/SerialPollingSelector.java    |  18 ++--
 .../serial/SerialTransportConfiguration.java       |  15 +++
 14 files changed, 185 insertions(+), 38 deletions(-)
 create mode 100644 plc4j/transports/serial/src/main/java/org/apache/plc4x/java/transport/serial/SerialChannelConfig.java
 copy plc4j/{utils/pcap-shared/src/main/java/org/apache/plc4x/java/utils/pcap/netty/config/PcapChannelOption.java => transports/serial/src/main/java/org/apache/plc4x/java/transport/serial/SerialChannelOptions.java} (52%)


[plc4x] 02/03: - Added the value range check also to single item requests

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

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

commit 96da9fa71de8a6fec928c3b83e43479b03014c6a
Author: Christofer Dutz <ch...@c-ware.de>
AuthorDate: Mon Mar 9 12:32:04 2020 +0100

    - Added the value range check also to single item requests
---
 .../main/java/org/apache/plc4x/java/modbus/field/ModbusField.java  | 1 +
 .../java/org/apache/plc4x/java/modbus/field/ModbusFieldCoil.java   | 1 +
 .../org/apache/plc4x/java/modbus/field/ModbusFieldHandler.java     | 7 ++++++-
 3 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/field/ModbusField.java b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/field/ModbusField.java
index 2edce00..933dad6 100644
--- a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/field/ModbusField.java
+++ b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/field/ModbusField.java
@@ -71,4 +71,5 @@ public abstract class ModbusField implements PlcField {
             "quantity=" + quantity +
             '}';
     }
+
 }
diff --git a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/field/ModbusFieldCoil.java b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/field/ModbusFieldCoil.java
index 72b8c17..97906c2 100644
--- a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/field/ModbusFieldCoil.java
+++ b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/field/ModbusFieldCoil.java
@@ -42,4 +42,5 @@ public class ModbusFieldCoil extends ModbusField {
         Integer quantity = quantityString != null ? Integer.valueOf(quantityString) : null;
         return new ModbusFieldCoil(address, quantity);
     }
+
 }
diff --git a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/field/ModbusFieldHandler.java b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/field/ModbusFieldHandler.java
index 22fe420..e16a16d 100644
--- a/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/field/ModbusFieldHandler.java
+++ b/plc4j/drivers/modbus/src/main/java/org/apache/plc4x/java/modbus/field/ModbusFieldHandler.java
@@ -127,7 +127,12 @@ public class ModbusFieldHandler extends DefaultPlcFieldHandler {
     @Override
     public PlcValue encodeShort(PlcField field, Object[] values) {
         if(values.length == 1) {
-            return new PlcShort(((Number) values[0]).shortValue());
+            Number numberValue = (Number) values[0];
+            // Intentionally checking the next larger type.
+            if((numberValue.intValue() < Short.MIN_VALUE) || (numberValue.intValue() > Short.MAX_VALUE)) {
+                throw new PlcInvalidFieldException("Value of " + numberValue.toString() + " exceeds the boundaries of a short value.");
+            }
+            return new PlcShort(numberValue.shortValue());
         } else {
             List<PlcShort> shorts = new ArrayList<>(values.length);
             for (Object value : values) {


[plc4x] 03/03: - Made the serial chanel configurable (baud-rate, data-bits, stop-bits, parity)

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

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

commit e73e7c375001c753dd1a485336fb970e03510396
Author: Christofer Dutz <ch...@c-ware.de>
AuthorDate: Mon Mar 9 12:33:33 2020 +0100

    - Made the serial chanel configurable (baud-rate, data-bits, stop-bits, parity)
---
 .../java/api/model/PlcSubscriptionHandle.java      |   1 +
 .../knxnetip/protocol/KnxNetIpProtocolLogic.java   |   1 +
 .../plc4x/java/transport/serial/SerialChannel.java |  10 +-
 .../java/transport/serial/SerialChannelConfig.java | 109 +++++++++++++++++++++
 .../transport/serial/SerialChannelFactory.java     |   4 +
 .../transport/serial/SerialChannelHandler.java     |   8 +-
 .../transport/serial/SerialChannelOptions.java     |  49 +++++++++
 .../transport/serial/SerialPollingSelector.java    |  18 ++--
 .../serial/SerialTransportConfiguration.java       |  15 +++
 9 files changed, 196 insertions(+), 19 deletions(-)

diff --git a/plc4j/api/src/main/java/org/apache/plc4x/java/api/model/PlcSubscriptionHandle.java b/plc4j/api/src/main/java/org/apache/plc4x/java/api/model/PlcSubscriptionHandle.java
index 285ded8..7bfdfd5 100644
--- a/plc4j/api/src/main/java/org/apache/plc4x/java/api/model/PlcSubscriptionHandle.java
+++ b/plc4j/api/src/main/java/org/apache/plc4x/java/api/model/PlcSubscriptionHandle.java
@@ -34,4 +34,5 @@ import java.util.function.Consumer;
 public interface PlcSubscriptionHandle {
 
     PlcConsumerRegistration register(Consumer<PlcSubscriptionEvent> consumer);
+
 }
diff --git a/plc4j/drivers/knxnetip/src/main/java/org/apache/plc4x/java/knxnetip/protocol/KnxNetIpProtocolLogic.java b/plc4j/drivers/knxnetip/src/main/java/org/apache/plc4x/java/knxnetip/protocol/KnxNetIpProtocolLogic.java
index fe11eb8..4163760 100644
--- a/plc4j/drivers/knxnetip/src/main/java/org/apache/plc4x/java/knxnetip/protocol/KnxNetIpProtocolLogic.java
+++ b/plc4j/drivers/knxnetip/src/main/java/org/apache/plc4x/java/knxnetip/protocol/KnxNetIpProtocolLogic.java
@@ -367,6 +367,7 @@ public class KnxNetIpProtocolLogic extends Plc4xProtocolBase<KNXNetIPMessage> im
 
     protected void publishEvent(GroupAddress groupAddress, PlcValue plcValue) {
         // Create a subscription event from the input.
+        // TODO: Check this ... this is sort of not really right ...
         final PlcSubscriptionEvent event = new DefaultPlcSubscriptionEvent(Instant.now(),
             Collections.singletonMap("knxData", Pair.of(PlcResponseCode.OK, plcValue)));
 
diff --git a/plc4j/transports/serial/src/main/java/org/apache/plc4x/java/transport/serial/SerialChannel.java b/plc4j/transports/serial/src/main/java/org/apache/plc4x/java/transport/serial/SerialChannel.java
index c331d5a..b9d5ee6 100644
--- a/plc4j/transports/serial/src/main/java/org/apache/plc4x/java/transport/serial/SerialChannel.java
+++ b/plc4j/transports/serial/src/main/java/org/apache/plc4x/java/transport/serial/SerialChannel.java
@@ -50,7 +50,7 @@ import java.util.concurrent.RejectedExecutionException;
 public class SerialChannel extends AbstractNioByteChannel implements DuplexChannel {
 
     private static final Logger logger = LoggerFactory.getLogger(SerialChannel.class);
-    private final ChannelConfig config;
+    private final SerialChannelConfig config;
 
     private final VoidChannelPromise unsafeVoidPromise = new VoidChannelPromise(this, false);
     private boolean readPending = false; // Did we receive an EOF?
@@ -74,7 +74,7 @@ public class SerialChannel extends AbstractNioByteChannel implements DuplexChann
      */
     protected SerialChannel(Channel parent, SelectableChannel ch) {
         super(parent, ch);
-        config = new DefaultChannelConfig(this);
+        config = new SerialChannelConfig(this);
         pipeline = newChannelPipeline();
     }
 
@@ -169,7 +169,7 @@ public class SerialChannel extends AbstractNioByteChannel implements DuplexChann
             if (((SerialSocketAddress) remoteAddress).getIdentifier().startsWith("TEST")) {
                 comPort = SerialChannelHandler.DummyHandler.INSTANCE;
             } else {
-                comPort = new SerialChannelHandler.SerialPortHandler(remoteAddress);
+                comPort = new SerialChannelHandler.SerialPortHandler(remoteAddress, config);
             }
             logger.debug("Using Com Port {}, trying to open port", comPort.getIdentifier());
             if (comPort.open()) {
@@ -409,8 +409,8 @@ public class SerialChannel extends AbstractNioByteChannel implements DuplexChann
             SerialChannel.this.remoteAddress = remoteAddress;
             eventLoop().execute(() -> {
                 try {
-                    final boolean sucess = doConnect(remoteAddress, localAddress);
-                    if (sucess) {
+                    final boolean success = doConnect(remoteAddress, localAddress);
+                    if (success) {
                         // Send a message to the pipeline
                         pipeline().fireChannelActive();
                         // Finally, close the promise
diff --git a/plc4j/transports/serial/src/main/java/org/apache/plc4x/java/transport/serial/SerialChannelConfig.java b/plc4j/transports/serial/src/main/java/org/apache/plc4x/java/transport/serial/SerialChannelConfig.java
new file mode 100644
index 0000000..ec1d04b
--- /dev/null
+++ b/plc4j/transports/serial/src/main/java/org/apache/plc4x/java/transport/serial/SerialChannelConfig.java
@@ -0,0 +1,109 @@
+/*
+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
+
+  http://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.java.transport.serial;
+
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelConfig;
+import io.netty.channel.ChannelOption;
+import io.netty.channel.DefaultChannelConfig;
+
+import java.util.Map;
+
+public class SerialChannelConfig extends DefaultChannelConfig implements ChannelConfig {
+
+    private int baudRate;
+    private int dataBits;
+    private int stopBits;
+    private int parityBits;
+
+    public SerialChannelConfig(Channel channel) {
+        super(channel);
+    }
+
+    @Override
+    public Map<ChannelOption<?>, Object> getOptions() {
+        return getOptions(super.getOptions(),
+            SerialChannelOptions.BAUD_RATE, SerialChannelOptions.DATA_BITS,
+            SerialChannelOptions.STOP_BITS, SerialChannelOptions.PARITY_BITS);
+    }
+
+    @Override
+    public <T> boolean setOption(ChannelOption<T> option, T value) {
+        if(option == SerialChannelOptions.BAUD_RATE) {
+            if(value instanceof Integer) {
+                baudRate = (Integer) value;
+                return true;
+            }
+            return false;
+        } else if(option == SerialChannelOptions.DATA_BITS) {
+            if(value instanceof Integer) {
+                dataBits = (Integer) value;
+                return true;
+            }
+            return false;
+        } else if(option == SerialChannelOptions.STOP_BITS) {
+            if(value instanceof Integer) {
+                stopBits = (Integer) value;
+                return true;
+            }
+            return false;
+        } else if(option == SerialChannelOptions.PARITY_BITS) {
+            if(value instanceof Integer) {
+                parityBits = (Integer) value;
+                return true;
+            }
+            return false;
+        } else {
+            return super.setOption(option, value);
+        }
+    }
+
+    public int getBaudRate() {
+        return baudRate;
+    }
+
+    public void setBaudRate(int baudRate) {
+        this.baudRate = baudRate;
+    }
+
+    public int getDataBits() {
+        return dataBits;
+    }
+
+    public void setDataBits(int dataBits) {
+        this.dataBits = dataBits;
+    }
+
+    public int getStopBits() {
+        return stopBits;
+    }
+
+    public void setStopBits(int stopBits) {
+        this.stopBits = stopBits;
+    }
+
+    public int getParityBits() {
+        return parityBits;
+    }
+
+    public void setParityBits(int parityBits) {
+        this.parityBits = parityBits;
+    }
+
+}
diff --git a/plc4j/transports/serial/src/main/java/org/apache/plc4x/java/transport/serial/SerialChannelFactory.java b/plc4j/transports/serial/src/main/java/org/apache/plc4x/java/transport/serial/SerialChannelFactory.java
index 846d458..2ca6155 100644
--- a/plc4j/transports/serial/src/main/java/org/apache/plc4x/java/transport/serial/SerialChannelFactory.java
+++ b/plc4j/transports/serial/src/main/java/org/apache/plc4x/java/transport/serial/SerialChannelFactory.java
@@ -54,6 +54,10 @@ public class SerialChannelFactory extends NettyChannelFactory implements HasConf
     public void configureBootstrap(Bootstrap bootstrap) {
         if(configuration != null) {
             logger.info("Configuring Bootstrap with {}", configuration);
+            bootstrap.option(SerialChannelOptions.BAUD_RATE, configuration.getBaudRate());
+            bootstrap.option(SerialChannelOptions.DATA_BITS, configuration.getNumDataBits());
+            bootstrap.option(SerialChannelOptions.STOP_BITS, configuration.getNumStopBits());
+            bootstrap.option(SerialChannelOptions.PARITY_BITS, configuration.getParityBits());
         }
     }
 
diff --git a/plc4j/transports/serial/src/main/java/org/apache/plc4x/java/transport/serial/SerialChannelHandler.java b/plc4j/transports/serial/src/main/java/org/apache/plc4x/java/transport/serial/SerialChannelHandler.java
index 6b5bb2b..91c0e65 100644
--- a/plc4j/transports/serial/src/main/java/org/apache/plc4x/java/transport/serial/SerialChannelHandler.java
+++ b/plc4j/transports/serial/src/main/java/org/apache/plc4x/java/transport/serial/SerialChannelHandler.java
@@ -116,17 +116,21 @@ public abstract class SerialChannelHandler {
 
     public static class SerialPortHandler extends SerialChannelHandler {
 
+        private SerialChannelConfig config;
         private SerialPort comPort;
 
-        public SerialPortHandler(SocketAddress address) {
+        public SerialPortHandler(SocketAddress address, SerialChannelConfig config) {
             super(address);
+            this.config = config;
+            // Get the serial port described by the path/name in the address.
             comPort = SerialPort.getCommPort(((SerialSocketAddress) address).getIdentifier());
         }
 
         @Override
         public boolean open() {
             if (comPort.openPort()) {
-                comPort.setComPortParameters(19200, 8, SerialPort.ONE_STOP_BIT, SerialPort.NO_PARITY);
+                comPort.setComPortParameters(config.getBaudRate(), config.getDataBits(),
+                    config.getStopBits(), config.getParityBits());
                 return true;
             }
             return false;
diff --git a/plc4j/transports/serial/src/main/java/org/apache/plc4x/java/transport/serial/SerialChannelOptions.java b/plc4j/transports/serial/src/main/java/org/apache/plc4x/java/transport/serial/SerialChannelOptions.java
new file mode 100644
index 0000000..f6ff45f
--- /dev/null
+++ b/plc4j/transports/serial/src/main/java/org/apache/plc4x/java/transport/serial/SerialChannelOptions.java
@@ -0,0 +1,49 @@
+/*
+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
+
+  http://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.java.transport.serial;
+
+import io.netty.channel.ChannelOption;
+
+public class SerialChannelOptions {
+
+    /**
+     * Option to configure the baud rate.
+     */
+    public static final ChannelOption<Integer> BAUD_RATE =
+        ChannelOption.valueOf(Integer.class, "BAUD_RATE");
+
+    /**
+     * Option to configure the number of data bits.
+     */
+    public static final ChannelOption<Integer> DATA_BITS =
+        ChannelOption.valueOf(Integer.class, "DATA_BITS");
+
+    /**
+     * Option to configure the number of stop bits.
+     */
+    public static final ChannelOption<Integer> STOP_BITS =
+        ChannelOption.valueOf(Integer.class, "STOP_BITS");
+
+    /**
+     * Option to configure the number of parity bits.
+     */
+    public static final ChannelOption<Integer> PARITY_BITS =
+        ChannelOption.valueOf(Integer.class, "PARITY_BITS");
+
+}
diff --git a/plc4j/transports/serial/src/main/java/org/apache/plc4x/java/transport/serial/SerialPollingSelector.java b/plc4j/transports/serial/src/main/java/org/apache/plc4x/java/transport/serial/SerialPollingSelector.java
index 854d8a9..26f1af1 100644
--- a/plc4j/transports/serial/src/main/java/org/apache/plc4x/java/transport/serial/SerialPollingSelector.java
+++ b/plc4j/transports/serial/src/main/java/org/apache/plc4x/java/transport/serial/SerialPollingSelector.java
@@ -25,7 +25,6 @@ import org.apache.commons.lang3.NotImplementedException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.io.IOException;
 import java.nio.channels.SelectionKey;
 import java.nio.channels.Selector;
 import java.nio.channels.spi.AbstractSelectableChannel;
@@ -94,7 +93,7 @@ class SerialPollingSelector extends AbstractSelector {
     }
 
     @Override
-    public int selectNow() throws IOException {
+    public int selectNow() {
         // throw new NotImplementedException("");
         logger.debug("selectNow()");
         // check if one channel is active
@@ -102,18 +101,13 @@ class SerialPollingSelector extends AbstractSelector {
     }
 
     @Override
-    public int select(long timeout) throws IOException {
-        logger.debug("select({})", timeout);
-        if (events.size() > 0) {
+    public int select(long timeout) {
+        if (!events.isEmpty()) {
             return events.size();
         }
         this.selectPromise = new DefaultPromise<>(executor);
         try {
-            if (selectPromise.await(timeout)) {
-                logger.debug("Promise was cancelled, new Events should be there.");
-            } else {
-                logger.debug("Promise timed out, expecting no new events.");
-            }
+            selectPromise.await(timeout);
         } catch (InterruptedException e) {
             Thread.currentThread().interrupt();
             throw new RuntimeException("Was interrupted", e);
@@ -122,7 +116,7 @@ class SerialPollingSelector extends AbstractSelector {
     }
 
     @Override
-    public int select() throws IOException {
+    public int select() {
         throw new NotImplementedException("");
     }
 
@@ -151,7 +145,7 @@ class SerialPollingSelector extends AbstractSelector {
     }
 
     @Override
-    protected void implCloseSelector() throws IOException {
+    protected void implCloseSelector() {
         // TODO should we do something here?
     }
 
diff --git a/plc4j/transports/serial/src/main/java/org/apache/plc4x/java/transport/serial/SerialTransportConfiguration.java b/plc4j/transports/serial/src/main/java/org/apache/plc4x/java/transport/serial/SerialTransportConfiguration.java
index 9c7478f..15b44b8 100644
--- a/plc4j/transports/serial/src/main/java/org/apache/plc4x/java/transport/serial/SerialTransportConfiguration.java
+++ b/plc4j/transports/serial/src/main/java/org/apache/plc4x/java/transport/serial/SerialTransportConfiguration.java
@@ -18,8 +18,23 @@ under the License.
 */
 package org.apache.plc4x.java.transport.serial;
 
+import com.fazecast.jSerialComm.SerialPort;
 import org.apache.plc4x.java.spi.transport.TransportConfiguration;
 
 public interface SerialTransportConfiguration extends TransportConfiguration {
 
+    int getBaudRate();
+
+    default int getNumDataBits() {
+        return 8;
+    }
+
+    default int getNumStopBits() {
+        return SerialPort.ONE_STOP_BIT;
+    }
+
+    default int getParityBits() {
+        return SerialPort.NO_PARITY;
+    }
+
 }


[plc4x] 01/03: - Changed the generated code to use getSizeInBits and keep getSizeInBytes as a convenience method (Needed if data types are not byte aligned)

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

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

commit db74d1182324c41fa7eb0c7e1ec8dd59bb52d60a
Author: Christofer Dutz <ch...@c-ware.de>
AuthorDate: Mon Mar 9 12:21:17 2020 +0100

    - Changed the generated code to use getSizeInBits and keep getSizeInBytes as a convenience method (Needed if data types are not byte aligned)
---
 .../src/main/resources/templates/java/pojo-template.ftlh | 16 +++++++++++-----
 .../org/apache/plc4x/java/spi/generation/Message.java    |  2 ++
 2 files changed, 13 insertions(+), 5 deletions(-)

diff --git a/build-utils/language-java/src/main/resources/templates/java/pojo-template.ftlh b/build-utils/language-java/src/main/resources/templates/java/pojo-template.ftlh
index a0bb32c..c689e0a 100644
--- a/build-utils/language-java/src/main/resources/templates/java/pojo-template.ftlh
+++ b/build-utils/language-java/src/main/resources/templates/java/pojo-template.ftlh
@@ -124,7 +124,13 @@ public<#if type.abstract> abstract</#if> class ${typeName}<#if type.parentType??
     @Override
     @JsonIgnore
     public int getLengthInBytes() {
-        int lengthInBits = <#if type.parentType??>super.getLengthInBytes() * 8<#else>0</#if>;
+        return getLengthInBits() / 8;
+    }
+
+    @Override
+    @JsonIgnore
+    public int getLengthInBits() {
+        int lengthInBits = <#if type.parentType??>super.getLengthInBits()<#else>0</#if>;
 <#list type.fields as field>
 <#switch field.typeName>
     <#case "array">
@@ -135,7 +141,7 @@ public<#if type.abstract> abstract</#if> class ${typeName}<#if type.parentType??
         <#else>
         if(${field.name} != null) {
             for(Message element : ${field.name}) {
-                lengthInBits += element.getLengthInBytes() * 8;
+                lengthInBits += element.getLengthInBits();
             }
         }
         </#if>
@@ -182,7 +188,7 @@ public<#if type.abstract> abstract</#if> class ${typeName}<#if type.parentType??
         <#if helper.isSimpleType(field.type)>
             lengthInBits += ${field.type.sizeInBits};
         <#else>
-            lengthInBits += ${field.name}.getLengthInBytes() * 8;
+            lengthInBits += ${field.name}.getLengthInBits();
         </#if>
         }
         <#break>
@@ -205,7 +211,7 @@ public<#if type.abstract> abstract</#if> class ${typeName}<#if type.parentType??
         <#if helper.isSimpleType(field.type)>
         lengthInBits += ${field.type.sizeInBits};
         <#else>
-        lengthInBits += ${field.name}.getLengthInBytes() * 8;
+        lengthInBits += ${field.name}.getLengthInBits();
         </#if>
         <#break>
     <#case "switch">
@@ -219,7 +225,7 @@ public<#if type.abstract> abstract</#if> class ${typeName}<#if type.parentType??
 </#switch>
 </#list>
 
-        return lengthInBits / 8;
+        return lengthInBits;
     }
 
     public PlcValue toPlcValue() {
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/Message.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/Message.java
index 84c1bbc..7d9afef 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/Message.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/Message.java
@@ -25,6 +25,8 @@ public interface Message {
 
     int getLengthInBytes();
 
+    int getLengthInBits();
+
     PlcValue toPlcValue();
 
     MessageIO<? extends Message, ? extends Message> getMessageIO();