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 2021/12/23 15:17:10 UTC

[plc4x] branch feature/mqtt5_support created (now 3a46821)

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

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


      at 3a46821  feature: started implementing an mspec for the mqtt5 protocol.

This branch includes the following new commits:

     new c21998d  fix: Made it possible to use enum types in arrays, made at least simple fields also support encoding feature: added support for variable length uint 32 encoding (varLenUint32)
     new 3a46821  feature: started implementing an mspec for the mqtt5 protocol.

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


[plc4x] 01/02: fix: Made it possible to use enum types in arrays, made at least simple fields also support encoding feature: added support for variable length uint 32 encoding (varLenUint32)

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

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

commit c21998dde654673aec113e6a6a002d8fbf0c5334
Author: cdutz <ch...@c-ware.de>
AuthorDate: Thu Dec 23 16:14:46 2021 +0100

    fix: Made it possible to use enum types in arrays, made at least simple fields also support encoding
    feature: added support for variable length uint 32 encoding (varLenUint32)
---
 .../language/java/JavaLanguageTemplateHelper.java  | 25 ++++++++++++++++++++++
 .../templates/java/model-template.java.ftlh        | 16 ++++++++++++--
 .../plc4x/java/spi/codegen/FieldCommons.java       | 17 +++++++++++++++
 .../java/spi/codegen/fields/FieldWriterArray.java  | 12 +++++++++++
 .../spi/codegen/fields/FieldWriterFactory.java     |  4 ++++
 .../codegen/io/DataReaderSimpleUnsignedLong.java   | 10 +++++++--
 .../codegen/io/DataWriterSimpleUnsignedLong.java   | 10 +++++++--
 .../plc4x/java/spi/generation/ReadBuffer.java      | 17 +++++++++++++++
 .../plc4x/java/spi/generation/WriteBuffer.java     | 15 +++++++++++++
 9 files changed, 120 insertions(+), 6 deletions(-)

diff --git a/code-generation/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java b/code-generation/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java
index a0a6a72..db1a478 100644
--- a/code-generation/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java
+++ b/code-generation/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java
@@ -1135,6 +1135,31 @@ public class JavaLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHe
             variableLiteral.getChild().map(child -> "." + toVariableExpressionRest(field, resultType, child)).orElse(""));
     }
 
+    public String getSizeInBits(TypedField field, List<Argument> parserArguments) {
+        String encoding = null;
+        final Optional<Term> encodingOptional = field.getEncoding();
+        if (encodingOptional.isPresent()) {
+            encoding = toParseExpression(field, field.getType(), encodingOptional.get(), parserArguments);
+        }
+        if(field.getType().isSimpleTypeReference()) {
+            final SimpleTypeReference simpleTypeReference = field.getType().asSimpleTypeReference().orElseThrow();
+            if(encoding != null) {
+                if("\"varLenUint32\"".equals(encoding)) {
+                    if((simpleTypeReference.getSizeInBits() != 32) && (simpleTypeReference.getBaseType() == SimpleTypeReference.SimpleBaseType.UINT)) {
+                        throw new RuntimeException("varLenUint32 currently only supported for 'unit 32' typed fields");
+                    }
+                    String fieldName = field.asNamedField().orElseThrow().getName();
+                    return "(" + fieldName + " <= 0x7F) ? 8 : (" + fieldName + " <= 0xFF7F) ? 16 : (" + fieldName + " <= 0xFFFF7F) ? 24 : (" + fieldName + " <= 0xFFFFFF7FL) ? 32 : -1";
+                } else {
+                    throw new RuntimeException("Unsupported encoding '" + encoding + "'");
+                }
+            } else {
+                return "" + simpleTypeReference.getSizeInBits();
+            }
+        }
+        throw new RuntimeException("getSizeInBits only supported for simple types.");
+    }
+
     public String getSizeInBits(ComplexTypeDefinition complexTypeDefinition, List<Argument> parserArguments) {
         int sizeInBits = 0;
         StringBuilder sb = new StringBuilder();
diff --git a/code-generation/language-java/src/main/resources/templates/java/model-template.java.ftlh b/code-generation/language-java/src/main/resources/templates/java/model-template.java.ftlh
index 07dc000..c2f3364 100644
--- a/code-generation/language-java/src/main/resources/templates/java/model-template.java.ftlh
+++ b/code-generation/language-java/src/main/resources/templates/java/model-template.java.ftlh
@@ -54,6 +54,8 @@ import static org.apache.plc4x.java.spi.codegen.fields.FieldWriterFactory.*;
 import org.apache.plc4x.java.api.value.*;
 import org.apache.plc4x.java.spi.codegen.io.DataWriterComplexDefault;
 import org.apache.plc4x.java.spi.codegen.io.DataWriterEnumDefault;
+import org.apache.plc4x.java.spi.codegen.WithOption;
+import org.apache.plc4x.java.spi.generation.ByteOrder;
 import org.apache.plc4x.java.spi.generation.Message;
 import org.apache.plc4x.java.spi.generation.MessageIO;
 import org.apache.plc4x.java.spi.generation.SerializationException;
@@ -191,6 +193,8 @@ public<#if type.isDiscriminatedParentTypeDefinition()> abstract</#if> class ${ty
                         writeByteArrayField("${namedField.name}", ${namedField.name}, writeByteArray(writeBuffer, 8));
                         <#elseif arrayField.type.isSimpleTypeReference()>
                         writeSimpleTypeArrayField("${namedField.name}", ${namedField.name}, ${helper.getDataWriterCall(typedField.type, namedField.name)});
+                        <#elseif helper.isEnumTypeReference(arrayField.type)>
+                        writeEnumTypeArrayField("${namedField.name}", ${namedField.name}, ${helper.getEnumDataWriterCall(typedField.type, namedField.name, "value")});
                         <#else>
                         writeComplexTypeArrayField("${namedField.name}", ${namedField.name}, writeBuffer);
                         </#if>
@@ -281,7 +285,7 @@ public<#if type.isDiscriminatedParentTypeDefinition()> abstract</#if> class ${ty
                         <#assign namedField = field.asNamedField().orElseThrow()>
 
                         // Simple Field (${namedField.name})
-                        <#if helper.isEnumTypeReference(typedField.type)>writeSimpleEnumField("${namedField.name}", "${helper.getLanguageTypeNameForField(field)}", ${namedField.name}, ${helper.getEnumDataWriterCall(typedField.type, namedField.name, "value")});<#else>writeSimpleField("${namedField.name}", ${simpleField.name}, ${helper.getDataWriterCall(typedField.type, namedField.name)});</#if>
+                        <#if helper.isEnumTypeReference(typedField.type)>writeSimpleEnumField("${namedField.name}", "${helper.getLanguageTypeNameForField(field)}", ${namedField.name}, ${helper.getEnumDataWriterCall(typedField.type, namedField.name, "value")});<#else>writeSimpleField("${namedField.name}", ${simpleField.name}, ${helper.getDataWriterCall(typedField.type, namedField.name)}${helper.getFieldOptions(typedField, parserArguments)});</#if>
                         <#break>
                     <#case "switch">
                         <#assign switchField = field.asSwitchField().orElseThrow()>
@@ -330,11 +334,19 @@ public<#if type.isDiscriminatedParentTypeDefinition()> abstract</#if> class ${ty
             <#assign complexTypeReference = arrayField.type.asComplexTypeReference().orElseThrow()>
             for(${complexTypeReference.name} element : ${arrayField.name}) {
                 boolean last = ++i >= ${arrayField.name}.size();
+                <#if helper.isEnumField(field)>
+                lengthInBits += ${helper.getEnumBaseTypeReference(arrayField.type).sizeInBits};
+                <#else>
                 lengthInBits += element.getLengthInBits();
+                </#if>
             }
         <#else>
             for(Message element : ${arrayField.name}) {
+                <#if helper.isEnumField(field)>
+                lengthInBits += ${helper.getEnumBaseTypeReference(arrayField.type).sizeInBits};
+                <#else>
                 lengthInBits += element.getLengthInBits();
+                </#if>
             }
         </#if>
         }
@@ -450,7 +462,7 @@ public<#if type.isDiscriminatedParentTypeDefinition()> abstract</#if> class ${ty
                 <#assign vstringTypeReference = simpleTypeReference.asVstringTypeReference().orElseThrow()>
         lengthInBits += ${helper.toSerializationExpression(simpleField, helper.intTypeReference, vstringTypeReference.getLengthExpression(), parserArguments)};
             <#else>
-        lengthInBits += ${simpleTypeReference.sizeInBits};
+        lengthInBits += ${helper.getSizeInBits(simpleField, parserArguments)};
             </#if>
         <#elseif helper.isEnumField(field)>
         lengthInBits += ${helper.getEnumBaseTypeReference(simpleField.type).sizeInBits};
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/FieldCommons.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/FieldCommons.java
index 5225f60..66d4ab3 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/FieldCommons.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/FieldCommons.java
@@ -75,6 +75,23 @@ public interface FieldCommons {
         }
     }
 
+    default Optional<String> extractEncoding(WithReaderArgs... readerArgs) {
+        return extractEncoding(Stream.of(readerArgs).map(WithReaderWriterArgs.class::cast).toArray(WithReaderWriterArgs[]::new));
+    }
+
+    default Optional<String> extractEncoding(WithWriterArgs... writerArgs) {
+        return extractEncoding(Stream.of(writerArgs).map(WithReaderWriterArgs.class::cast).toArray(WithReaderWriterArgs[]::new));
+    }
+
+    default Optional<String> extractEncoding(WithReaderWriterArgs... readerWriterArgs) {
+        for (WithReaderWriterArgs arg : readerWriterArgs) {
+            if (arg instanceof withOptionEncoding) {
+                return Optional.of(((withOptionEncoding) arg).encoding());
+            }
+        }
+        return Optional.empty();
+    }
+
     @FunctionalInterface
     interface RunParseWrapped<T> {
         T run() throws ParseException;
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldWriterArray.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldWriterArray.java
index d1fdce0..474bcd2 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldWriterArray.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldWriterArray.java
@@ -56,4 +56,16 @@ public class FieldWriterArray<T> implements FieldCommons {
         }, writeBuffer, extractByteOder(writerArgs).orElse(null));
     }
 
+    public void writeEnumTypeArrayField(String logicalName, List<T> values, DataWriter<T> dataWriter, WithWriterArgs... writerArgs) throws SerializationException {
+        switchSerializeByteOrderIfNecessary(() -> {
+            if (values != null) {
+                dataWriter.pushContext(logicalName, WithReaderWriterArgs.WithRenderAsList(true));
+                for (T value : values) {
+                    dataWriter.write("value", value, writerArgs);
+                }
+                dataWriter.popContext(logicalName, WithReaderWriterArgs.WithRenderAsList(true));
+            }
+        }, dataWriter, extractByteOder(writerArgs).orElse(null));
+    }
+
 }
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldWriterFactory.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldWriterFactory.java
index 2fd10c2..8ca7a67 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldWriterFactory.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/fields/FieldWriterFactory.java
@@ -39,6 +39,10 @@ public class FieldWriterFactory {
         new FieldWriterArray<Message>().writeComplexTypeArrayField(logicalName, value, writeBuffer, writerArgs);
     }
 
+    public static <T> void writeEnumTypeArrayField(String logicalName, List<T> value, DataWriter<T> dataWriter, WithWriterArgs... writerArgs) throws SerializationException {
+        new FieldWriterArray<T>().writeEnumTypeArrayField(logicalName, value, dataWriter, writerArgs);
+    }
+
     public static <T> void writeByteArrayField(String logicalName, byte[] value, DataWriter<byte[]> dataWriter, WithWriterArgs... writerArgs) throws SerializationException {
         new FieldWriterArray<T>().writeByteArrayField(logicalName, value, dataWriter, writerArgs);
     }
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleUnsignedLong.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleUnsignedLong.java
index d36ba98..5d42da7 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleUnsignedLong.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataReaderSimpleUnsignedLong.java
@@ -18,11 +18,12 @@
  */
 package org.apache.plc4x.java.spi.codegen.io;
 
+import org.apache.plc4x.java.spi.codegen.FieldCommons;
 import org.apache.plc4x.java.spi.generation.ParseException;
 import org.apache.plc4x.java.spi.generation.ReadBuffer;
 import org.apache.plc4x.java.spi.generation.WithReaderArgs;
 
-public class DataReaderSimpleUnsignedLong extends DataReaderSimpleBase<Long> {
+public class DataReaderSimpleUnsignedLong extends DataReaderSimpleBase<Long> implements FieldCommons {
 
     public DataReaderSimpleUnsignedLong(ReadBuffer readBuffer, int bitLength) {
         super(readBuffer, bitLength);
@@ -30,7 +31,12 @@ public class DataReaderSimpleUnsignedLong extends DataReaderSimpleBase<Long> {
 
     @Override
     public Long read(String logicalName, WithReaderArgs... readerArgs) throws ParseException  {
-        return readBuffer.readUnsignedLong(logicalName, bitLength, readerArgs);
+        String encoding = extractEncoding(readerArgs).orElse(null);
+        if("varLenUint32".equals(encoding)) {
+            return readBuffer.readVariableLengthUnsignedInteger(logicalName, bitLength, readerArgs);
+        } else {
+            return readBuffer.readUnsignedLong(logicalName, bitLength, readerArgs);
+        }
     }
 
 }
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataWriterSimpleUnsignedLong.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataWriterSimpleUnsignedLong.java
index 7d3e1e6..cbc917c 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataWriterSimpleUnsignedLong.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/codegen/io/DataWriterSimpleUnsignedLong.java
@@ -18,11 +18,12 @@
  */
 package org.apache.plc4x.java.spi.codegen.io;
 
+import org.apache.plc4x.java.spi.codegen.FieldCommons;
 import org.apache.plc4x.java.spi.generation.SerializationException;
 import org.apache.plc4x.java.spi.generation.WithWriterArgs;
 import org.apache.plc4x.java.spi.generation.WriteBuffer;
 
-public class DataWriterSimpleUnsignedLong extends DataWriterSimpleBase<Long> {
+public class DataWriterSimpleUnsignedLong extends DataWriterSimpleBase<Long> implements FieldCommons {
 
     public DataWriterSimpleUnsignedLong(WriteBuffer writeBuffer, int bitLength) {
         super(writeBuffer, bitLength);
@@ -30,7 +31,12 @@ public class DataWriterSimpleUnsignedLong extends DataWriterSimpleBase<Long> {
 
     @Override
     public void write(String logicalName, Long value, WithWriterArgs... writerArgs) throws SerializationException {
-        writeBuffer.writeUnsignedLong(logicalName, bitLength, value, writerArgs);
+        String encoding = extractEncoding(writerArgs).orElse(null);
+        if("varLenUint32".equals(encoding)) {
+            writeBuffer.writeVariableLengthUnsignedInteger(logicalName, bitLength, value, writerArgs);
+        } else {
+            writeBuffer.writeUnsignedLong(logicalName, bitLength, value, writerArgs);
+        }
     }
 
 }
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBuffer.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBuffer.java
index 5bc4246..2c635ff 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBuffer.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBuffer.java
@@ -80,6 +80,23 @@ public interface ReadBuffer extends ByteOrderAware {
         return readUnsignedBigInteger("", bitLength);
     }
 
+    default long readVariableLengthUnsignedInteger(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException {
+        long value = readUnsignedShort(8);
+        if(value >= 0x7F) {
+            value = (value << 8) | (readUnsignedShort(8));
+            if(value >= 0xFF7F) {
+                value = (value << 8) | (readUnsignedShort(8));
+                if(value >= 0xFFFF7F) {
+                    value = (value << 8) | (readUnsignedShort(8));
+                    if(value >= 0xFFFFFF7F) {
+                        throw new ParseException("Value too big for variable length 32 bit unsigned integer");
+                    }
+                }
+            }
+        }
+        return value;
+    }
+
     byte readSignedByte(String logicalName, int bitLength, WithReaderArgs... readerArgs) throws ParseException;
 
     default byte readSignedByte(int bitLength) throws ParseException {
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WriteBuffer.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WriteBuffer.java
index 7cf9eca..e953311 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WriteBuffer.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WriteBuffer.java
@@ -78,6 +78,21 @@ public interface WriteBuffer extends ByteOrderAware {
         writeUnsignedBigInteger("", bitLength, value);
     }
 
+    default void writeVariableLengthUnsignedInteger(String logicalName, int maxBitLength, Long value, WithWriterArgs... writerArgs) throws SerializationException {
+        if((value <= 0x7F) && (maxBitLength >= 8)) {
+            writeUnsignedShort(8, value.byteValue());
+        } else if((value <= 0xFF7F) && (maxBitLength >= 16)) {
+            writeUnsignedInt(16, value.shortValue());
+        } else if((value <= 0xFFFF7F) && (maxBitLength >= 24)) {
+            writeUnsignedLong(24, value.intValue());
+        } else if((value <= 0xFFFFFF7FL) && (maxBitLength >= 32)) {
+            // TODO: This sucks, I know ...
+            writeUnsignedBigInteger(32, new BigInteger(value.toString()));
+        } else {
+            throw new SerializationException("Error serializing variable length unsigned int with value " + value);
+        }
+    }
+
     void writeSignedByte(String logicalName, int bitLength, byte value, WithWriterArgs... writerArgs) throws SerializationException;
 
     default void writeSignedByte(int bitLength, byte value) throws SerializationException {

[plc4x] 02/02: feature: started implementing an mspec for the mqtt5 protocol.

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

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

commit 3a4682109439fdff04c0640f9e2979d4a54d4121
Author: cdutz <ch...@c-ware.de>
AuthorDate: Thu Dec 23 16:15:29 2021 +0100

    feature: started implementing an mspec for the mqtt5 protocol.
---
 protocols/mqtt/pom.xml                             |  43 ++
 .../apache/plc4x/protocol/mqtt/MqttProtocol.java   |  45 +++
 ...e.plc4x.plugins.codegenerator.protocol.Protocol |  19 +
 .../src/main/resources/protocols/mqtt/mqtt.mspec   | 438 +++++++++++++++++++++
 .../protocols/mqtt/ParserSerializerTestsuite.xml   |  81 ++++
 protocols/pom.xml                                  |   1 +
 sandbox/mqtt/mqtt-c/pom.xml                        | 319 +++++++++++++++
 sandbox/mqtt/mqtt-cs/pom.xml                       | 138 +++++++
 sandbox/mqtt/mqtt-go/pom.xml                       | 352 +++++++++++++++++
 sandbox/mqtt/mqtt-java/pom.xml                     | 116 ++++++
 .../mqtt/readwrite/MqttParserSerializerTest.java   |  29 ++
 sandbox/mqtt/pom.xml                               |  41 ++
 sandbox/pom.xml                                    |   1 +
 13 files changed, 1623 insertions(+)

diff --git a/protocols/mqtt/pom.xml b/protocols/mqtt/pom.xml
new file mode 100644
index 0000000..fb41ef5
--- /dev/null
+++ b/protocols/mqtt/pom.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.plc4x</groupId>
+    <artifactId>plc4x-protocols</artifactId>
+    <version>0.10.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>plc4x-protocols-mqtt</artifactId>
+
+  <name>Protocols: MQTT</name>
+  <description>Base protocol specifications for the MQTT protocol</description>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.plc4x</groupId>
+      <artifactId>plc4x-code-generation-protocol-base-mspec</artifactId>
+      <version>0.10.0-SNAPSHOT</version>
+    </dependency>
+  </dependencies>
+
+</project>
\ No newline at end of file
diff --git a/protocols/mqtt/src/main/java/org/apache/plc4x/protocol/mqtt/MqttProtocol.java b/protocols/mqtt/src/main/java/org/apache/plc4x/protocol/mqtt/MqttProtocol.java
new file mode 100644
index 0000000..8482f5d
--- /dev/null
+++ b/protocols/mqtt/src/main/java/org/apache/plc4x/protocol/mqtt/MqttProtocol.java
@@ -0,0 +1,45 @@
+/*
+ * 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.protocol.mqtt;
+
+import org.apache.plc4x.plugins.codegenerator.language.mspec.parser.MessageFormatParser;
+import org.apache.plc4x.plugins.codegenerator.protocol.Protocol;
+import org.apache.plc4x.plugins.codegenerator.types.definitions.TypeDefinition;
+import org.apache.plc4x.plugins.codegenerator.types.exceptions.GenerationException;
+
+import java.io.InputStream;
+import java.util.Map;
+
+public class MqttProtocol implements Protocol {
+
+    @Override
+    public String getName() {
+        return "mqtt";
+    }
+
+    @Override
+    public Map<String, TypeDefinition> getTypeDefinitions() throws GenerationException {
+        InputStream schemaInputStream = MqttProtocol.class.getResourceAsStream("/protocols/mqtt/mqtt.mspec");
+        if(schemaInputStream == null) {
+            throw new GenerationException("Error loading message-format schema for protocol '" + getName() + "'");
+        }
+        return new MessageFormatParser().parse(schemaInputStream);
+    }
+
+}
diff --git a/protocols/mqtt/src/main/resources/META-INF/services/org.apache.plc4x.plugins.codegenerator.protocol.Protocol b/protocols/mqtt/src/main/resources/META-INF/services/org.apache.plc4x.plugins.codegenerator.protocol.Protocol
new file mode 100644
index 0000000..287fe27
--- /dev/null
+++ b/protocols/mqtt/src/main/resources/META-INF/services/org.apache.plc4x.plugins.codegenerator.protocol.Protocol
@@ -0,0 +1,19 @@
+#
+# 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.
+#
+org.apache.plc4x.protocol.mqtt.MqttProtocol
diff --git a/protocols/mqtt/src/main/resources/protocols/mqtt/mqtt.mspec b/protocols/mqtt/src/main/resources/protocols/mqtt/mqtt.mspec
new file mode 100644
index 0000000..94879f8
--- /dev/null
+++ b/protocols/mqtt/src/main/resources/protocols/mqtt/mqtt.mspec
@@ -0,0 +1,438 @@
+/*
+ * 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.
+ */
+
+[discriminatedType MQTT_ControlPacket    byteOrder='BIG_ENDIAN'
+    [discriminator MQTT_ControlPacketType packetType                                        ]
+    [abstract uint 8 remainingLength                                                        ]
+    [typeSwitch packetType
+        ['CONNECT' MQTT_ControlPacket_CONNECT
+            // Fixed Header
+            [reserved uint 4                 '0x0'                                          ]
+            [simple   uint 8                 remainingLength                                ]
+            // Variable Header
+            [simple   MQTT_String            protocolName                                   ]
+            [simple   uint 8                 protocolVersion                                ]
+            // Connect flags start
+            [simple   bit                    userNameFlagSet                                ]
+            [simple   bit                    passwordFlagSet                                ]
+            [simple   bit                    willRetainFlagSet                              ]
+            [simple   uint 2                 willQosLevel                                   ]
+            [simple   bit                    willFlagSet                                    ]
+            // Actually a session start ...
+            [simple   bit                    cleanStartFlagSet                              ]
+            [reserved bit                    'false'                                        ]
+            // Connect flags end
+            [simple   uint 16                keepAlive                                      ]
+
+            // Properties
+            [simple   uint 32                propertyLength        encoding='"varLenUint32"']
+            [array    MQTT_Property          properties     length 'propertyLength'         ]
+
+            // Payload
+            [simple   MQTT_String            clientId                                       ]
+            // TODO: If willFlagSet is true, the will properties come here (3.1.3.2)
+            // TODO: If willFlagSet is true, the will topic comes here (3.1.3.3)
+            // TODO: If willFlagSet is true, the will payload comes here (3.1.3.4)
+            // If userNameFlagSet, here comes the username. (String)
+            [optional MQTT_String            username       'userNameFlagSet'               ]
+            // If passwordFlagSet, here comes the password. (String)
+            [optional MQTT_String            password       'passwordFlagSet'               ]
+        ]
+        ['CONNACK' MQTT_ControlPacket_CONNACK
+            // Fixed Header
+            [reserved uint 4                 '0x0'                                          ]
+            [simple   uint 8                 remainingLength                                ]
+            // Variable Header
+            // Acknowledge flags start
+            [reserved uint 7                 '0x00'                                         ]
+            [simple   bit                    sessionPresentFlagSet                          ]
+            // Acknowledge flags end
+            [simple   MQTT_ReasonCode        reasonCode                                     ]
+
+            // Properties
+            [optional uint 32                propertyLength 'remainingLength - curPos < 4'       encoding='"varLenUint32"']
+            [array    MQTT_Property          properties     length '(propertyLength != null) ? propertyLength : 0']
+        ]
+        ['PUBLISH' MQTT_ControlPacket_PUBLISH
+            // Fixed Header
+            [simple   bit                    dup                                            ]
+            [simple   MQTT_QOS               qos                                            ]
+            [simple   bit                    retain                                         ]
+            [simple   uint 8                 remainingLength                                ]
+            // Variable Header
+            [simple   MQTT_String            topicName                                      ]
+            [optional uint 16                packetIdentifier 'qos != MQTT_QOS.AT_MOST_ONCE']
+
+            // Properties
+            [optional uint 32                propertyLength 'remainingLength - curPos < 4'       encoding='"varLenUint32"']
+            [array    MQTT_Property          properties     length '(propertyLength != null) ? propertyLength : 0']
+
+            // Payload
+            [array    byte                   payload      count 'remainingLength - curPos'  ]
+        ]
+        // Used if QOS = 1
+        ['PUBACK' MQTT_ControlPacket_PUBACK
+            // Fixed Header
+            [reserved uint 4                 '0x0'                                          ]
+            [simple   uint 8                 remainingLength                                ]
+            // Variable Header
+            [simple   uint 16                packetIdentifier                               ]
+            [optional MQTT_ReasonCode        reasonCode     'remainingLength - curPos < 3'  ]
+
+            // Properties
+            [optional uint 32                propertyLength 'remainingLength - curPos < 4'       encoding='"varLenUint32"']
+            [array    MQTT_Property          properties     length '(propertyLength != null) ? propertyLength : 0']
+        ]
+        // Used if QOS = 2
+        ['PUBREC' MQTT_ControlPacket_PUBREC
+            // Fixed Header
+            [reserved uint 4                 '0x0'                                          ]
+            [simple   uint 8                 remainingLength                                ]
+            // Variable Header
+            [simple   uint 16                packetIdentifier                               ]
+            [optional MQTT_ReasonCode        reasonCode     'remainingLength - curPos < 3'  ]
+
+            // Properties
+            [optional uint 32                propertyLength 'remainingLength - curPos < 4'       encoding='"varLenUint32"']
+            [array    MQTT_Property          properties     length '(propertyLength != null) ? propertyLength : 0']
+        ]
+        ['PUBREL' MQTT_ControlPacket_PUBREL
+            // Fixed Header
+            [reserved uint 4                 '0x0'                                          ]
+            [simple   uint 8                 remainingLength                                ]
+            // Variable Header
+            [simple   uint 16                packetIdentifier                               ]
+            [optional MQTT_ReasonCode        reasonCode     'remainingLength - curPos < 3'  ]
+
+            // Properties
+            [optional uint 32                propertyLength 'remainingLength - curPos < 4'       encoding='"varLenUint32"']
+            [array    MQTT_Property          properties     length '(propertyLength != null) ? propertyLength : 0']
+        ]
+        ['PUBCOMP' MQTT_ControlPacket_PUBCOMP
+            // Fixed Header
+            [reserved uint 4                 '0x0'                                          ]
+            [simple   uint 8                 remainingLength                                ]
+            // Variable Header
+            [simple   uint 16                packetIdentifier                               ]
+            [optional MQTT_ReasonCode        reasonCode     'remainingLength - curPos < 3'  ]
+
+            // Properties
+            [optional uint 32                propertyLength 'remainingLength - curPos < 4'       encoding='"varLenUint32"']
+            [array    MQTT_Property          properties     length '(propertyLength != null) ? propertyLength : 0']
+        ]
+        ['SUBSCRIBE' MQTT_ControlPacket_SUBSCRIBE
+            // Fixed Header
+            [reserved uint 4                 '0x0'                                          ]
+            [simple   uint 8                 remainingLength                                ]
+            // Variable Header
+            [simple   uint 16                packetIdentifier                               ]
+
+            // Properties
+            [optional uint 32                propertyLength 'remainingLength - curPos < 4'       encoding='"varLenUint32"']
+            [array    MQTT_Property          properties     length '(propertyLength != null) ? propertyLength : 0']
+
+            // Payload
+            [array    Filter                 filters      count 'remainingLength - curPos'  ]
+        ]
+        ['SUBACK' MQTT_ControlPacket_SUBACK
+            // Fixed Header
+            [reserved uint 4                 '0x0'                                          ]
+            [simple   uint 8                 remainingLength                                ]
+            // Variable Header
+            [simple   uint 16                packetIdentifier                               ]
+
+            // Properties
+            [optional uint 32                propertyLength 'remainingLength - curPos < 4'       encoding='"varLenUint32"']
+            [array    MQTT_Property          properties     length '(propertyLength != null) ? propertyLength : 0']
+
+            // Payload
+            [array    MQTT_ReasonCode        results        count 'remainingLength - curPos'    ]
+        ]
+        ['UNSUBSCRIBE' MQTT_ControlPacket_UNSUBSCRIBE
+            // Fixed Header
+            [reserved uint 4                 '0x0'                                              ]
+            [simple   uint 8                 remainingLength                                    ]
+            // Variable Header
+            [simple   uint 16                packetIdentifier                                   ]
+
+            // Properties
+            [optional uint 32                propertyLength 'remainingLength - curPos < 4'       encoding='"varLenUint32"']
+            [array    MQTT_Property          properties     length '(propertyLength != null) ? propertyLength : 0']
+
+            // Payload
+            [array    MQTT_String            filters        count 'remainingLength - curPos'    ]
+        ]
+        ['UNSUBACK' MQTT_ControlPacket_UNSUBACK
+            // Fixed Header
+            [reserved uint 4                 '0x0'                                              ]
+            [simple   uint 8                 remainingLength                                    ]
+            // Variable Header
+            [simple   uint 16                packetIdentifier                                   ]
+
+            // Properties
+            [optional uint 32                propertyLength 'remainingLength - curPos < 4'       encoding='"varLenUint32"']
+            [array    MQTT_Property          properties     length '(propertyLength != null) ? propertyLength : 0']
+
+            // Payload
+            [array    MQTT_ReasonCode        results        count 'remainingLength - curPos'    ]
+        ]
+        ['PINGREQ' MQTT_ControlPacket_PINGREQ
+            // Fixed Header
+            [reserved uint 4                 '0x0'                                              ]
+            [simple   uint 8                 remainingLength                                    ]
+        ]
+        ['PINGRESP' MQTT_ControlPacket_PINGRESP
+            // Fixed Header
+            [reserved uint 4                 '0x0'                                              ]
+            [simple   uint 8                 remainingLength                                    ]
+        ]
+        ['DISCONNECT' MQTT_ControlPacket_DISCONNECT
+            // Fixed Header
+            [reserved uint 4                 '0x0'                                              ]
+            [simple   uint 8                 remainingLength                                    ]
+            // Variable Header
+            [simple   MQTT_ReasonCode        reason                                             ]
+        ]
+        ['AUTH' MQTT_ControlPacket_AUTH
+            // Fixed Header
+            [reserved uint 4                 '0x0'                                              ]
+            [simple   uint 8                 remainingLength                                    ]
+            // Variable Header
+            [simple   MQTT_ReasonCode        reason                                             ]
+
+            // Properties
+            [optional uint 32                propertyLength 'remainingLength - curPos < 4'       encoding='"varLenUint32"']
+            [array    MQTT_Property          properties     length '(propertyLength != null) ? propertyLength : 0']
+        ]
+    ]
+]
+
+[discriminatedType MQTT_Property
+    [simple MQTT_PropertyType propertyType]
+    [typeSwitch propertyType
+        ['PAYLOAD_FORMAT_INDICATOR'          MQTT_Property_PAYLOAD_FORMAT_INDICATOR
+            [simple uint 8                   value                              ]
+        ]
+        ['MESSAGE_EXPIRY_INTERVAL'           MQTT_Property_MESSAGE_EXPIRY_INTERVAL
+            [simple uint 32                  value                              ]
+        ]
+        ['CONTENT_TYPE'                      MQTT_Property_CONTENT_TYPE
+            [simple   MQTT_String            value                              ]
+        ]
+        ['RESPONSE_TOPIC'                    MQTT_Property_RESPONSE_TOPIC
+            [simple   MQTT_String            value                              ]
+        ]
+        ['CORRELATION_DATA'                  MQTT_Property_CORRELATION_DATA
+            // TODO: Find out what "Binary Data" means ...
+        ]
+        ['SUBSCRIPTION_IDENTIFIER'           MQTT_Property_SUBSCRIPTION_IDENTIFIER
+            [simple uint 32                  value     encoding='"varLenUint32"']
+        ]
+        ['SESSION_EXPIRY_INTERVAL'           MQTT_Property_EXPIRY_INTERVAL
+            [simple uint 32                  value                              ]
+        ]
+        ['ASSIGNED_CLIENT_IDENTIFIER'        MQTT_Property_ASSIGNED_CLIENT_IDENTIFIER
+            [simple   MQTT_String            value                              ]
+        ]
+        ['SERVER_KEEP_ALIVE'                 MQTT_Property_SERVER_KEEP_ALIVE
+            [simple uint 16                  value                              ]
+        ]
+        ['AUTHENTICATION_METHOD'             MQTT_Property_AUTHENTICATION_METHOD
+            [simple   MQTT_String            value                              ]
+        ]
+        ['AUTHENTICATION_DATA'               MQTT_Property_AUTHENTICATION_DATA
+            // TODO: Find out what "Binary Data" means ...
+        ]
+        ['REQUEST_PROBLEM_INFORMATION'       MQTT_Property_REQUEST_PROBLEM_INFORMATION
+            // TODO: Probably an enum
+            [simple uint 8                   value                              ]
+        ]
+        ['WILL_DELAY_INTERVAL'               MQTT_Property_WILL_DELAY_INTERVAL
+            [simple uint 32                  value                              ]
+        ]
+        ['REQUEST_RESPONSE_INFORMATION'      MQTT_Property_REQUEST_RESPONSE_INFORMATION
+            // TODO: Probably an enum
+            [simple uint 8                   value                              ]
+        ]
+        ['RESPONSE_INFORMATION'              MQTT_Property_RESPONSE_INFORMATION
+            [simple   MQTT_String            value                              ]
+        ]
+        ['SERVER_REFERENCE'                  MQTT_Property_SERVER_REFERENCE
+            [simple   MQTT_String            value                              ]
+        ]
+        ['REASON_STRING'                     MQTT_Property_REASON_STRING
+            [simple   MQTT_String            value                              ]
+        ]
+        ['RECEIVE_MAXIMUM'                   MQTT_Property_RECEIVE_MAXIMUM
+            [simple uint 16                  value                              ]
+        ]
+        ['TOPIC_ALIAS_MAXIMUM'               MQTT_Property_TOPIC_ALIAS_MAXIMUM
+            [simple uint 16                  value                              ]
+        ]
+        ['TOPIC_ALIAS'                       MQTT_Property_TOPIC_ALIAS
+            [simple uint 16                  value                              ]
+        ]
+        ['MAXIMUM_QOS'                       MQTT_Property_MAXIMUM_QOS
+            [simple uint 8                   value                              ]
+        ]
+        ['RETAIN_AVAILABLE'                  MQTT_Property_RETAIN_AVAILABLE
+            [simple uint 8                   value                              ]
+        ]
+        ['USER_PROPERTY'                     MQTT_Property_USER_PROPERTY
+            [simple   MQTT_String            name                               ]
+            [simple   MQTT_String            value                              ]
+        ]
+        ['MAXIMUM_PACKET_SIZE'               MQTT_Property_MAXIMUM_PACKET_SIZE
+            [simple uint 32                  value                              ]
+        ]
+        ['WILDCARD_SUBSCRIPTION_AVAILABLE'   MQTT_Property_WILDCARD_SUBSCRIPTION_AVAILABLE
+            [simple uint 8                   value                              ]
+        ]
+        ['SUBSCRIPTION_IDENTIFIER_AVAILABLE' MQTT_Property_SUBSCRIPTION_IDENTIFIER_AVAILABLE
+            [simple uint 8                   value                              ]
+        ]
+        ['SHARED_SUBSCRIPTION_AVAILABLE'     MQTT_Property_SHARED_SUBSCRIPTION_AVAILABLE
+            [simple uint 8                   value                              ]
+        ]
+    ]
+]
+
+[type Filter
+    [simple   MQTT_String         filter        ]
+    // Subscription Options Start
+    [reserved uint 2              '0x0'         ]
+    // Don't forward to clients with a client id equal to the sending one
+    [simple   MQTT_RetainHandling retainHandling]
+    [simple   bit                 retain        ]
+    [simple   bit                 noLocal       ]
+    [simple   MQTT_QOS            maxQos        ]
+    // Subscription Options End
+]
+
+[type MQTT_String
+    [implicit uint 16                stringLength 'STR_LEN(value)']
+    [simple   vstring 'stringLength * 8' value                        ]
+]
+
+[enum uint 4 MQTT_ControlPacketType
+    ['0x0' RESERVED   ]
+    ['0x1' CONNECT    ]
+    ['0x2' CONNACK    ]
+    ['0x3' PUBLISH    ]
+    ['0x4' PUBACK     ]
+    ['0x5' PUBREC     ]
+    ['0x6' PUBREL     ]
+    ['0x7' PUBCOMP    ]
+    ['0x8' SUBSCRIBE  ]
+    ['0x9' SUBACK     ]
+    ['0xA' UNSUBSCRIBE]
+    ['0xB' UNSUBACK   ]
+    ['0xC' PINGREQ    ]
+    ['0xD' PINGRESP   ]
+    ['0xE' DISCONNECT ]
+    ['0xF' AUTH       ]
+]
+
+[enum uint 8 MQTT_PropertyType
+    ['0x01' PAYLOAD_FORMAT_INDICATOR         ]
+    ['0x02' MESSAGE_EXPIRY_INTERVAL          ]
+    ['0x03' CONTENT_TYPE                     ]
+    ['0x08' RESPONSE_TOPIC                   ]
+    ['0x09' CORRELATION_DATA                 ]
+    ['0x0B' SUBSCRIPTION_IDENTIFIER          ]
+    ['0x11' SESSION_EXPIRY_INTERVAL          ]
+    ['0x12' ASSIGNED_CLIENT_IDENTIFIER       ]
+    ['0x13' SERVER_KEEP_ALIVE                ]
+    ['0x15' AUTHENTICATION_METHOD            ]
+    ['0x16' AUTHENTICATION_DATA              ]
+    ['0x17' REQUEST_PROBLEM_INFORMATION      ]
+    ['0x18' WILL_DELAY_INTERVAL              ]
+    ['0x19' REQUEST_RESPONSE_INFORMATION     ]
+    ['0x1A' RESPONSE_INFORMATION             ]
+    ['0x1C' SERVER_REFERENCE                 ]
+    ['0x1F' REASON_STRING                    ]
+    ['0x21' RECEIVE_MAXIMUM                  ]
+    ['0x22' TOPIC_ALIAS_MAXIMUM              ]
+    ['0x23' TOPIC_ALIAS                      ]
+    ['0x24' MAXIMUM_QOS                      ]
+    ['0x25' RETAIN_AVAILABLE                 ]
+    ['0x26' USER_PROPERTY                    ]
+    ['0x27' MAXIMUM_PACKET_SIZE              ]
+    ['0x28' WILDCARD_SUBSCRIPTION_AVAILABLE  ]
+    ['0x29' SUBSCRIPTION_IDENTIFIER_AVAILABLE]
+    ['0x2A' SHARED_SUBSCRIPTION_AVAILABLE    ]
+]
+
+[enum uint 8 MQTT_ReasonCode                       (bit connackResponse, bit pubackPubrecResponse, bit pubrelPubcompResponse, bit subackResponse, bit unsubackResponse, bit disconnectReason, bit authReason)
+    ['0X00' SUCCESS                                ['true'             , 'true'                  , 'true'                   , 'true'            , 'true'              , 'true'              , 'true'       ]]
+    ['0X01' GRANTED_QOS_1                          ['false'            , 'false'                 , 'false'                  , 'true'            , 'false'             , 'false'             , 'false'      ]]
+    ['0X02' GRANTED_QOS_2                          ['false'            , 'false'                 , 'false'                  , 'true'            , 'false'             , 'false'             , 'false'      ]]
+    ['0X04' DISCONNECT_WITH_WILL_MESSAGE           ['false'            , 'false'                 , 'false'                  , 'false'           , 'false'             , 'true'              , 'false'      ]]
+    ['0x10' NO_MATCHING_SUBSCRIBERS                ['false'            , 'true'                  , 'false'                  , 'false'           , 'false'             , 'false'             , 'false'      ]]
+    ['0x11' NO_SUBSCRIPTION_EXISTED                ['false'            , 'false'                 , 'false'                  , 'false'           , 'true'              , 'false'             , 'false'      ]]
+    ['0X18' CONTINUE_AUTHENTICATION                ['false'            , 'false'                 , 'false'                  , 'false'           , 'false'             , 'false'             , 'true'       ]]
+    ['0X19' RE_AUTHENTICATE                        ['false'            , 'false'                 , 'false'                  , 'false'           , 'false'             , 'false'             , 'true'       ]]
+    ['0X80' UNSPECIFIED_ERROR                      ['true'             , 'true'                  , 'false'                  , 'true'            , 'true'              , 'true'              , 'false'      ]]
+    ['0X81' MALFORMED_PACKET                       ['true'             , 'false'                 , 'false'                  , 'false'           , 'false'             , 'true'              , 'false'      ]]
+    ['0X82' PROTOCOL_ERROR                         ['true'             , 'false'                 , 'false'                  , 'false'           , 'false'             , 'true'              , 'false'      ]]
+    ['0X83' IMPLEMENTATION_SPECIFIC_ERROR          ['true'             , 'true'                  , 'false'                  , 'true'            , 'true'              , 'true'              , 'false'      ]]
+    ['0X84' UNSUPPORTED_PROTOCOL_VERSION           ['true'             , 'false'                 , 'false'                  , 'false'           , 'false'             , 'false'             , 'false'      ]]
+    ['0X85' CLIENT_IDENTIFIER_NOT_VALID            ['true'             , 'false'                 , 'false'                  , 'false'           , 'false'             , 'false'             , 'false'      ]]
+    ['0X86' BAD_USER_NAME_OR_PASSWORD              ['true'             , 'false'                 , 'false'                  , 'false'           , 'false'             , 'false'             , 'false'      ]]
+    ['0X87' NOT_AUTHORIZED                         ['true'             , 'true'                  , 'false'                  , 'true'            , 'true'              , 'true'              , 'false'      ]]
+    ['0X88' SERVER_UNAVAILABLE                     ['true'             , 'false'                 , 'false'                  , 'false'           , 'false'             , 'false'             , 'false'      ]]
+    ['0X89' SERVER_BUSY                            ['true'             , 'false'                 , 'false'                  , 'false'           , 'false'             , 'true'              , 'false'      ]]
+    ['0X8A' BANNED                                 ['true'             , 'false'                 , 'false'                  , 'false'           , 'false'             , 'false'             , 'false'      ]]
+    ['0X8B' SERVER_SHUTTING_DOWN                   ['false'            , 'false'                 , 'false'                  , 'false'           , 'false'             , 'true'              , 'false'      ]]
+    ['0X8C' BAD_AUTHENTICATION_METHOD              ['true'             , 'false'                 , 'false'                  , 'false'           , 'false'             , 'false'             , 'false'      ]]
+    ['0X8D' KEEP_ALIVE_TIMEOUT                     ['false'            , 'false'                 , 'false'                  , 'false'           , 'false'             , 'true'              , 'false'      ]]
+    ['0X8E' SESSION_TAKEN_OVER                     ['false'            , 'false'                 , 'false'                  , 'false'           , 'false'             , 'true'              , 'false'      ]]
+    ['0X8F' TOPIC_FILTER_INVALID                   ['false'            , 'false'                 , 'false'                  , 'true'            , 'true'              , 'true'              , 'false'      ]]
+    ['0X90' TOPIC_NAME_INVALID                     ['true'             , 'true'                  , 'false'                  , 'false'           , 'false'             , 'true'              , 'false'      ]]
+    ['0X91' PACKET_IDENTIFIER_IN_USE               ['false'            , 'true'                  , 'false'                  , 'true'            , 'true'              , 'false'             , 'false'      ]]
+    ['0X92' PACKET_IDENTIFIER_NOT_FOUND            ['false'            , 'false'                 , 'true'                   , 'false'           , 'false'             , 'false'             , 'false'      ]]
+    ['0X93' RECEIVE_MAXIMUM_EXCEEDED               ['false'            , 'false'                 , 'false'                  , 'false'           , 'false'             , 'true'              , 'false'      ]]
+    ['0X94' TOPIC_ALIAS_INVALID                    ['false'            , 'false'                 , 'false'                  , 'false'           , 'false'             , 'true'              , 'false'      ]]
+    ['0X95' PACKET_TOO_LARGE                       ['true'             , 'false'                 , 'false'                  , 'false'           , 'false'             , 'true'              , 'false'      ]]
+    ['0X96' MESSAGE_RATE_TO_HIGH                   ['false'            , 'false'                 , 'false'                  , 'false'           , 'false'             , 'true'              , 'false'      ]]
+    ['0X97' QUOTA_EXCEEDED                         ['true'             , 'true'                  , 'false'                  , 'true'            , 'false'             , 'true'              , 'false'      ]]
+    ['0X98' ADMINISTRATIVE_ACTION                  ['false'            , 'false'                 , 'false'                  , 'false'           , 'false'             , 'true'              , 'false'      ]]
+    ['0X99' PAYLOAD_FORMAT_INVALID                 ['true'             , 'true'                  , 'false'                  , 'false'           , 'false'             , 'true'              , 'false'      ]]
+    ['0X9A' RETAIN_NOT_SUPPORTED                   ['true'             , 'false'                 , 'false'                  , 'false'           , 'false'             , 'true'              , 'false'      ]]
+    ['0X9B' QOS_NOT_SUPPORTED                      ['true'             , 'false'                 , 'false'                  , 'false'           , 'false'             , 'true'              , 'false'      ]]
+    ['0X9C' USE_ANOTHER_SERVER                     ['true'             , 'false'                 , 'false'                  , 'false'           , 'false'             , 'true'              , 'false'      ]]
+    ['0X9D' SERVER_MOVED                           ['true'             , 'false'                 , 'false'                  , 'false'           , 'false'             , 'true'              , 'false'      ]]
+    ['0X9E' SHARED_SUBSCRIPTIONS_NOT_SUPPORTED     ['false'            , 'false'                 , 'false'                  , 'true'            , 'false'             , 'true'              , 'false'      ]]
+    ['0X9F' CONNECTION_RATE_EXCEEDED               ['true'             , 'false'                 , 'false'                  , 'false'           , 'false'             , 'true'              , 'false'      ]]
+    ['0XA0' MAXIMUM_CONNECT_TIME                   ['false'            , 'false'                 , 'false'                  , 'false'           , 'false'             , 'true'              , 'false'      ]]
+    ['0XA1' SUBSCRIPTION_IDENTIFIERS_NOT_SUPPORTED ['false'            , 'false'                 , 'false'                  , 'true'            , 'false'             , 'true'              , 'false'      ]]
+    ['0XA2' WILDCARD_SUBSCRIPTIONS_NOT_SUPPORTED   ['false'            , 'false'                 , 'false'                  , 'true'            , 'false'             , 'true'              , 'false'      ]]
+]
+
+[enum uint 2 MQTT_QOS
+    ['0x0' AT_MOST_ONCE ]
+    ['0x1' AT_LEAST_ONCE]
+    ['0x2' EXACTLY_ONCE ]
+]
+
+[enum uint 2 MQTT_RetainHandling
+    ['0x0' SEND_RETAINED_MESSAGES_AT_THE_TIME_OF_THE_SUBSCRIBE                                  ]
+    ['0x1' SEND_RETAINED_MESSAGES_AT_SUBSCRIBE_ONLY_IF_THE_SUBSCRIPTION_DOES_NOT_CURRENTLY_EXIST]
+    ['0x2' DO_NOT_SEND_RETAINED_MESSAGES_AT_THE_TIME_OF_SUBSCRIBE                               ]
+]
diff --git a/protocols/mqtt/src/test/resources/protocols/mqtt/ParserSerializerTestsuite.xml b/protocols/mqtt/src/test/resources/protocols/mqtt/ParserSerializerTestsuite.xml
new file mode 100644
index 0000000..1719da4
--- /dev/null
+++ b/protocols/mqtt/src/test/resources/protocols/mqtt/ParserSerializerTestsuite.xml
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+  -->
+<test:testsuite xmlns:test="https://plc4x.apache.org/schemas/parser-serializer-testsuite.xsd"
+                byteOrder="BIG_ENDIAN">
+
+  <name>MQTT5</name>
+
+  <protocolName>mqtt</protocolName>
+  <outputFlavor>read-write</outputFlavor>
+
+  <testcase>
+    <name>MQTT Connection Request</name>
+    <raw>101d00044d51545405c200050000066c776d71747400037472790003747279</raw>
+    <root-type>MQTT_ControlPacket</root-type>
+    <xml>
+      <MQTT_ControlPacket>
+        <packetType>
+          <MQTT_ControlPacketType dataType="uint" bitLength="4" stringRepresentation="CONNECT">1</MQTT_ControlPacketType>
+        </packetType>
+        <MQTT_ControlPacket_CONNECT>
+          <reserved dataType="uint" bitLength="4">0</reserved>
+          <remainingLength dataType="uint" bitLength="8">29</remainingLength>
+          <protocolName>
+            <MQTT_String>
+              <stringLength dataType="uint" bitLength="16">4</stringLength>
+              <value dataType="string" bitLength="32" encoding="UTF-8">MQTT</value>
+            </MQTT_String>
+          </protocolName>
+          <protocolVersion dataType="uint" bitLength="8">5</protocolVersion>
+          <userNameFlagSet dataType="bit" bitLength="1">true</userNameFlagSet>
+          <passwordFlagSet dataType="bit" bitLength="1">true</passwordFlagSet>
+          <willRetainFlagSet dataType="bit" bitLength="1">false</willRetainFlagSet>
+          <willQosLevel dataType="uint" bitLength="2">0</willQosLevel>
+          <willFlagSet dataType="bit" bitLength="1">false</willFlagSet>
+          <cleanStartFlagSet dataType="bit" bitLength="1">true</cleanStartFlagSet>
+          <reserved dataType="bit" bitLength="1">false</reserved>
+          <keepAlive dataType="uint" bitLength="16">5</keepAlive>
+          <value dataType="uint" bitLength="8">0</value>
+          <properties isList="true">
+          </properties>
+          <clientId>
+            <MQTT_String>
+              <stringLength dataType="uint" bitLength="16">6</stringLength>
+              <value dataType="string" bitLength="48" encoding="UTF-8">lwmqtt</value>
+            </MQTT_String>
+          </clientId>
+          <username>
+            <MQTT_String>
+              <stringLength dataType="uint" bitLength="16">3</stringLength>
+              <value dataType="string" bitLength="24" encoding="UTF-8">try</value>
+            </MQTT_String>
+          </username>
+          <password>
+            <MQTT_String>
+              <stringLength dataType="uint" bitLength="16">3</stringLength>
+              <value dataType="string" bitLength="24" encoding="UTF-8">try</value>
+            </MQTT_String>
+          </password>
+        </MQTT_ControlPacket_CONNECT>
+      </MQTT_ControlPacket>
+    </xml>
+  </testcase>
+
+</test:testsuite>
\ No newline at end of file
diff --git a/protocols/pom.xml b/protocols/pom.xml
index 268f669..ea21e96 100644
--- a/protocols/pom.xml
+++ b/protocols/pom.xml
@@ -44,6 +44,7 @@
     <module>genericcan</module>
     <module>knxnetip</module>
     <module>modbus</module>
+    <module>mqtt</module>
     <module>opcua</module>
     <module>plc4x</module>
     <module>profinet</module>
diff --git a/sandbox/mqtt/mqtt-c/pom.xml b/sandbox/mqtt/mqtt-c/pom.xml
new file mode 100644
index 0000000..4e8fc83
--- /dev/null
+++ b/sandbox/mqtt/mqtt-c/pom.xml
@@ -0,0 +1,319 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.plc4x.sandbox</groupId>
+    <artifactId>test-plc4x-mqtt</artifactId>
+    <version>0.10.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>test-plc4x-mqtt-c</artifactId>
+  <packaging>pom</packaging>
+  <name>Sandbox: Test MQTT Driver: C</name>
+
+  <properties>
+    <unity.version>2.5.2</unity.version>
+    <option.with-proxies>OFF</option.with-proxies>
+  </properties>
+
+  <!--
+    Notes:
+    - It turns out that the default version of CMake the cmake-maven-plugin uses is too
+    old to detect the recent boost version. So we need to manually download a newer version
+    and tell the plugin to use that instead.
+    - As downloading and building boost takes quite some time, we only do this, if no
+    target/lib/boost is found.
+  -->
+
+  <profiles>
+    <!-- Profile for linux -->
+    <profile>
+      <id>os-unix</id>
+      <activation>
+        <os>
+          <family>unix</family>
+        </os>
+      </activation>
+      <!-- Make the cmake executable executable -->
+      <build>
+        <plugins>
+          <plugin>
+            <groupId>org.codehaus.mojo</groupId>
+            <artifactId>exec-maven-plugin</artifactId>
+            <executions>
+              <execution>
+                <id>make-cmake-executable</id>
+                <phase>process-sources</phase>
+                <goals>
+                  <goal>exec</goal>
+                </goals>
+                <configuration>
+                  <basedir>${cmake.root}</basedir>
+                  <executable>chmod</executable>
+                  <arguments>
+                    <argument>+x</argument>
+                    <argument>cmake</argument>
+                  </arguments>
+                </configuration>
+              </execution>
+            </executions>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+    <!-- Profile for mac -->
+    <profile>
+      <id>os-mac</id>
+      <activation>
+        <os>
+          <family>mac</family>
+        </os>
+      </activation>
+      <!-- Make the cmake executable executable -->
+      <build>
+        <plugins>
+          <plugin>
+            <groupId>org.codehaus.mojo</groupId>
+            <artifactId>exec-maven-plugin</artifactId>
+            <executions>
+              <execution>
+                <id>make-cmake-executable</id>
+                <phase>process-sources</phase>
+                <goals>
+                  <goal>exec</goal>
+                </goals>
+                <configuration>
+                  <basedir>${cmake.root}</basedir>
+                  <executable>chmod</executable>
+                  <arguments>
+                    <argument>+x</argument>
+                    <argument>cmake</argument>
+                  </arguments>
+                </configuration>
+              </execution>
+            </executions>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+  </profiles>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>com.googlecode.maven-download-plugin</groupId>
+        <artifactId>download-maven-plugin</artifactId>
+        <executions>
+          <!-- First download the cmake binaries -->
+          <execution>
+            <id>get-cmake</id>
+            <phase>generate-sources</phase>
+            <goals>
+              <goal>wget</goal>
+            </goals>
+            <configuration>
+              <url>${cmake.url}</url>
+              <unpack>true</unpack>
+              <outputDirectory>${project.build.directory}</outputDirectory>
+            </configuration>
+          </execution>
+          <!--
+            Get additional stuff we need for the build.
+          -->
+          <execution>
+            <id>get-unity</id>
+            <phase>generate-sources</phase>
+            <goals>
+              <goal>wget</goal>
+            </goals>
+            <configuration>
+              <url>https://github.com/ThrowTheSwitch/Unity/archive/v${unity.version}.zip</url>
+              <unpack>true</unpack>
+              <outputDirectory>${project.build.directory}/dependency</outputDirectory>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      <!--
+        Generate the driver code.
+      -->
+      <plugin>
+        <groupId>org.apache.plc4x.plugins</groupId>
+        <artifactId>plc4x-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>generate-driver-mqtt</id>
+            <phase>generate-sources</phase>
+            <goals>
+              <goal>generate-driver</goal>
+            </goals>
+            <configuration>
+              <protocolName>mqtt</protocolName>
+              <languageName>c</languageName>
+              <outputFlavor>read-write</outputFlavor>
+              <outputDir>${project.basedir}/generated-sources</outputDir>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      <!--
+        Do the actual build.
+      -->
+      <plugin>
+        <groupId>com.googlecode.cmake-maven-project</groupId>
+        <artifactId>cmake-maven-plugin</artifactId>
+        <executions>
+          <!-- TODO: Commented out for now as when running in jenkins for code analysis, the second run would overwrite the results of the first -->
+          <!-- Generate the configuration for the main compilation -->
+          <!--execution>
+            <id>cmake-generate-compile</id>
+            <phase>compile</phase>
+            <goals>
+              <goal>generate</goal>
+            </goals>
+          </execution>
+          <!- Compile the main code ->
+          <execution>
+            <id>cmake-execute-compile</id>
+            <phase>compile</phase>
+            <goals>
+              <goal>compile</goal>
+            </goals>
+          </execution-->
+          <!-- Generate the configuration for the test compilation -->
+          <!--execution>
+            <id>cmake-generate-test-compile</id>
+            <phase>test-compile</phase>
+            <goals>
+              <goal>generate</goal>
+            </goals>
+            <configuration>
+              <options>
+                <option>-DUNITY_VERSION:STRING=${unity.version}</option>
+                <option>-DBUILD_PHASE=test-compile</option>
+              </options>
+            </configuration>
+          </execution-->
+          <!-- Compile the test code -->
+          <!--execution>
+            <id>cmake-execute-test-compile</id>
+            <phase>test-compile</phase>
+            <goals>
+              <goal>compile</goal>
+            </goals>
+          </execution-->
+        </executions>
+        <configuration>
+          <!--
+            We need to use a newer version of cmake, so disable downloading
+            and tell the plugin where to find that version.
+          -->
+          <downloadBinaries>false</downloadBinaries>
+          <cmakeDir>${cmake.root}</cmakeDir>
+          <!--
+            Actually the path to the CMakeList.txt file which then again
+            tells to tool where to find the sources.
+          -->
+          <sourcePath>${project.basedir}</sourcePath>
+          <!--
+            Path to where the build configuration is generated
+            (This directory is then used in the compile step to actually perform the build)
+          -->
+          <targetPath>${project.build.directory}/build</targetPath>
+          <!--
+            Name of the generator the compile step will be executing.
+          -->
+          <generator>${cmake.generator}</generator>
+          <!-- The directory where the "generate" step generated the build configuration -->
+          <projectDirectory>${project.build.directory}/build</projectDirectory>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>exec-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>run-tests</id>
+            <phase>test</phase>
+            <goals>
+              <goal>exec</goal>
+            </goals>
+            <configuration>
+              <basedir>${project.build.directory}/build</basedir>
+              <executable>${cmake.root}/ctest</executable>
+              <arguments>
+                <argument>--extra-verbose</argument>
+              </arguments>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+
+      <!-- For this module deploying maven artifacts doesn't make any sense -->
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-deploy-plugin</artifactId>
+        <configuration>
+          <skip>true</skip>
+        </configuration>
+      </plugin>
+    </plugins>
+    <!--
+      Developers working in plc4c will probably use an IDE like CLion to edit just this
+      Part of the project. These IDEs generate some work-directories we need to exclude.
+    -->
+    <pluginManagement>
+      <plugins>
+        <plugin>
+          <groupId>org.apache.rat</groupId>
+          <artifactId>apache-rat-plugin</artifactId>
+          <configuration>
+            <excludes combine.children="append">
+              <exclude>cmake-*/**</exclude>
+            </excludes>
+          </configuration>
+        </plugin>
+      </plugins>
+    </pluginManagement>
+  </build>
+
+  <!-- This dependency is just to ensure thrift is built first -->
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.plc4x</groupId>
+      <artifactId>plc4x-code-generation-language-c</artifactId>
+      <version>0.10.0-SNAPSHOT</version>
+      <!-- Scope is 'provided' as this way it's not shipped with the driver -->
+      <scope>provided</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.plc4x</groupId>
+      <artifactId>plc4x-protocols-mqtt</artifactId>
+      <version>0.10.0-SNAPSHOT</version>
+      <!-- Scope is 'provided' as this way it's not shipped with the driver -->
+      <scope>provided</scope>
+    </dependency>
+  </dependencies>
+
+</project>
\ No newline at end of file
diff --git a/sandbox/mqtt/mqtt-cs/pom.xml b/sandbox/mqtt/mqtt-cs/pom.xml
new file mode 100644
index 0000000..b5cdb3d
--- /dev/null
+++ b/sandbox/mqtt/mqtt-cs/pom.xml
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.plc4x.sandbox</groupId>
+    <artifactId>test-plc4x-mqtt</artifactId>
+    <version>0.10.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>test-plc4x-mqtt-cs</artifactId>
+  <packaging>pom</packaging>
+  <name>Sandbox: Test MQTT Driver: C#</name>
+
+  <!-- Disabled for now as C# support is currently not installed in Apache SonarQube -->
+  <!--properties>
+    <sonar.language>c#</sonar.language>
+  </properties-->
+
+  <build>
+    <plugins>
+      <!-- Copy the test-resources in here -->
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-dependency-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>unpack-protocol-test-suites</id>
+            <phase>generate-resources</phase>
+            <goals>
+              <goal>unpack</goal>
+            </goals>
+            <configuration>
+              <artifactItems>
+                <artifactItem>
+                  <groupId>org.apache.plc4x</groupId>
+                  <artifactId>plc4x-protocols-mqtt</artifactId>
+                  <classifier>tests</classifier>
+                  <type>test-jar</type>
+                  <outputDirectory>${project.basedir}/drivers/mqtt/resources</outputDirectory>
+                  <includes>**/*.xml</includes>
+                  <excludes>META-INF/**,org/**</excludes>
+                </artifactItem>
+              </artifactItems>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+
+      <!--
+        Generate the driver code.
+      -->
+      <plugin>
+        <groupId>org.apache.plc4x.plugins</groupId>
+        <artifactId>plc4x-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>generate-driver-mqtt</id>
+            <phase>generate-sources</phase>
+            <goals>
+              <goal>generate-driver</goal>
+            </goals>
+            <configuration>
+              <protocolName>mqtt</protocolName>
+              <languageName>C#</languageName>
+              <outputFlavor>read-write</outputFlavor>
+              <outputDir>${project.basedir}/drivers/mqtt/src</outputDir>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+
+      <!-- Build the project -->
+      <!--plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>exec-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>dotnet-build</id>
+            <phase>compile</phase>
+            <goals>
+              <goal>exec</goal>
+            </goals>
+            <configuration>
+              <executable>dotnet</executable>
+              <workingDirectory>${project.basedir}</workingDirectory>
+              <arguments>
+                <argument>build</argument>
+                <argument>plc4net.sln</argument>
+                <argument>- -configuration=Debug</argument>
+                <argument>- -output=${project.build.directory}/build</argument>
+                <argument>-p:Version=${project.version}</argument>
+              </arguments>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin-->
+    </plugins>
+  </build>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.plc4x</groupId>
+      <artifactId>plc4x-code-generation-language-cs</artifactId>
+      <version>0.10.0-SNAPSHOT</version>
+      <!-- Scope is 'provided' as this way it's not shipped with the driver -->
+      <scope>provided</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.plc4x</groupId>
+      <artifactId>plc4x-protocols-mqtt</artifactId>
+      <version>0.10.0-SNAPSHOT</version>
+      <!-- Scope is 'provided' as this way it's not shipped with the driver -->
+      <scope>provided</scope>
+    </dependency>
+  </dependencies>
+
+</project>
\ No newline at end of file
diff --git a/sandbox/mqtt/mqtt-go/pom.xml b/sandbox/mqtt/mqtt-go/pom.xml
new file mode 100644
index 0000000..5f7caf1
--- /dev/null
+++ b/sandbox/mqtt/mqtt-go/pom.xml
@@ -0,0 +1,352 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.plc4x.sandbox</groupId>
+    <artifactId>test-plc4x-mqtt</artifactId>
+    <version>0.10.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>test-plc4x-mqtt-go</artifactId>
+  <!--packaging>mvn-golang</packaging-->
+  <packaging>pom</packaging>
+  <name>Sandbox: Test MQTT Driver: Go</name>
+
+  <properties>
+    <!-- Tell Sonar where to find the sources -->
+    <sonar.sources>cmd,examples,internal,pkg</sonar.sources>
+  </properties>
+
+  <build>
+    <sourceDirectory>cmd</sourceDirectory>
+    <plugins>
+      <!--
+        Copy the test-resources in here
+      -->
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-dependency-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>unpack-protocol-test-suites</id>
+            <phase>generate-resources</phase>
+            <goals>
+              <goal>unpack</goal>
+            </goals>
+            <configuration>
+              <artifactItems>
+                <artifactItem>
+                  <groupId>org.apache.plc4x</groupId>
+                  <artifactId>plc4x-protocols-mqtt</artifactId>
+                  <classifier>tests</classifier>
+                  <type>test-jar</type>
+                  <outputDirectory>${project.basedir}/assets/testing</outputDirectory>
+                  <includes>**/*.xml</includes>
+                  <excludes>META-INF/**</excludes>
+                </artifactItem>
+              </artifactItems>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+
+      <!--
+        Generate the driver code.
+      -->
+      <plugin>
+        <groupId>org.apache.plc4x.plugins</groupId>
+        <artifactId>plc4x-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>generate-driver-mqtt</id>
+            <phase>generate-sources</phase>
+            <goals>
+              <goal>generate-driver</goal>
+            </goals>
+            <configuration>
+              <protocolName>mqtt</protocolName>
+              <languageName>go</languageName>
+              <outputFlavor>read-write</outputFlavor>
+              <outputDir>${project.basedir}/internal</outputDir>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+
+      <!--plugin>
+        <groupId>com.igormaznitsa</groupId>
+        <artifactId>mvn-golang-wrapper</artifactId>
+        <version>2.3.9</version>
+        <extensions>true</extensions>
+        <executions>
+
+          <!- - Downloads the dependencies of the project - ->
+          <execution>
+            <id>default-get</id>
+            <phase>initialize</phase>
+            <goals>
+              <goal>get</goal>
+            </goals>
+          </execution>
+
+          <!- - Make sure the "stringer" extension as well als the "licenser" is downloaded - ->
+          <execution>
+            <id>get-tools</id>
+            <phase>initialize</phase>
+            <goals>
+              <goal>get</goal>
+            </goals>
+            <configuration>
+              <packages>
+                <package>golang.org/x/tools/cmd/stringer</package>
+                <package>github.com/elastic/go-licenser</package>
+              </packages>
+            </configuration>
+          </execution>
+
+          <!- - Run the go code-generation - ->
+          <execution>
+            <id>default-generate</id>
+            <phase>generate-sources</phase>
+            <goals>
+              <goal>generate</goal>
+            </goals>
+            <configuration>
+              <packages>
+                <!- - We want to format every package here so we don't get dirty commits - ->
+                <package>./...</package>
+              </packages>
+            </configuration>
+          </execution>
+
+          <!- - Add the apache license header to stuff generated by the stringer - ->
+          <!- -
+            NOTE: Don't try merging the following 4 executions ...
+                  It doesn't work by merging the "packages" sections
+          - ->
+          <execution>
+            <id>add-license</id>
+            <phase>process-sources</phase>
+            <goals>
+              <goal>custom</goal>
+            </goals>
+            <configuration>
+              <exec>go-licenser</exec>
+              <customCommand>-licensor</customCommand>
+              <buildFlags>
+                <flag>Apache Software Foundation (ASF)</flag>
+              </buildFlags>
+              <packages>
+                <package>internal/plc4go/mqtt/fieldtype_string.go</package>
+              </packages>
+            </configuration>
+          </execution>
+
+          <!- - Processes code that uses old APIs and rewrites them use newer ones - ->
+          <execution>
+            <id>default-fix</id>
+            <phase>process-sources</phase>
+            <goals>
+              <goal>fix</goal>
+            </goals>
+          </execution>
+
+          <!- - Format the codebase correctly (this mainly has an effect on generated code) - ->
+          <execution>
+            <id>default-fmt</id>
+            <phase>process-sources</phase>
+            <goals>
+              <goal>fmt</goal>
+            </goals>
+            <configuration>
+              <packages>
+                <!- - We want to format every package here so we don't get dirty commits - ->
+                <package>./...</package>
+              </packages>
+            </configuration>
+          </execution>
+
+          <!- - Get all dependencies for test cases - ->
+          <execution>
+            <id>get-test-dependencies</id>
+            <phase>generate-test-sources</phase>
+            <goals>
+              <goal>get</goal>
+            </goals>
+            <configuration>
+              <buildFlags>
+                <flag>-t</flag>
+              </buildFlags>
+              <packages>
+                <package>./...</package>
+              </packages>
+            </configuration>
+          </execution>
+
+          <!- - Make sure the xunit generator as well as gotestsum is installed - ->
+          <execution>
+            <id>test-get</id>
+            <phase>process-test-resources</phase>
+            <goals>
+              <goal>get</goal>
+            </goals>
+            <configuration>
+              <packages>
+                <package>github.com/tebeka/go2xunit</package>
+                <package>gotest.tools/gotestsum</package>
+              </packages>
+            </configuration>
+          </execution>
+
+          <!- - Check all tests with producing report file in Golang format - ->
+          <execution>
+            <id>default-test</id>
+            <phase>test</phase>
+            <!- - TODO: Which goal?!? - ->
+            <configuration>
+              <buildFlags>
+                <flag>-v</flag>
+              </buildFlags>
+              <outLogFile>test-out-verbose.log</outLogFile>
+              <ignoreErrorExitCode>true</ignoreErrorExitCode>
+              <packages>
+                <package>./...</package>
+              </packages>
+            </configuration>
+          </execution>
+
+          <execution>
+            <id>readable-test</id>
+            <!- - TODO: Possibly move to test or prepare-package - ->
+            <phase>test</phase>
+            <goals>
+              <goal>custom</goal>
+            </goals>
+            <configuration>
+              <exec>gotestsum</exec>
+              <customCommand>-f</customCommand>
+              <buildFlags>
+                <flag>short</flag>
+              </buildFlags>
+              <packages>
+                <package>./...</package>
+              </packages>
+            </configuration>
+          </execution>
+
+          <!- - Convert generated test report into xunit format and save as file - ->
+          <execution>
+            <id>makeXUnitReport</id>
+            <phase>test</phase>
+            <goals>
+              <goal>custom</goal>
+            </goals>
+            <configuration>
+              <skip>${skipTests}</skip>
+              <exec>go2xunit</exec>
+              <customCommand>-fail</customCommand>
+              <buildFlags>
+                <flag>-input</flag>
+                <flag>${project.build.directory}${file.separator}reports${file.separator}test-out-verbose.log</flag>
+                <flag>-output</flag>
+              </buildFlags>
+              <echo>
+                <info>XUnit report saved as ${xunit.report}</info>
+              </echo>
+              <packages>
+                <package>target${file.separator}surefire-reports${file.separator}xuint.xml</package>
+              </packages>
+            </configuration>
+          </execution>
+
+          <execution>
+            <id>run-go-vet</id>
+            <phase>verify</phase>
+            <goals>
+              <goal>vet</goal>
+            </goals>
+          </execution>
+        </executions>
+        <configuration>
+          <packages>
+            <package>github.com/apache/plc4x/plc4go/cmd/main</package>
+          </packages>
+          <sources>${project.basedir}</sources>
+          <verbose>true</verbose>
+        </configuration>
+      </plugin-->
+
+      <!--
+        Create surefire folder for report
+      -->
+      <!--plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-antrun-plugin</artifactId>
+        <version>3.0.0</version>
+        <executions>
+          <execution>
+            <id>generate-sources</id>
+            <phase>generate-sources</phase>
+            <goals>
+              <goal>run</goal>
+            </goals>
+            <configuration>
+              <target>
+                <mkdir dir="target${file.separator}surefire-reports" />
+              </target>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin-->
+
+      <!-- For this module deploying maven artifacts doesn't make any sense -->
+      <!--plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-deploy-plugin</artifactId>
+        <configuration>
+          <skip>true</skip>
+        </configuration>
+      </plugin-->
+    </plugins>
+  </build>
+
+  <!-- This dependency is just to ensure thrift is built first -->
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.plc4x</groupId>
+      <artifactId>plc4x-code-generation-language-go</artifactId>
+      <version>0.10.0-SNAPSHOT</version>
+      <!-- Scope is 'provided' as this way it's not shipped with the driver -->
+      <scope>provided</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.plc4x</groupId>
+      <artifactId>plc4x-protocols-mqtt</artifactId>
+      <version>0.10.0-SNAPSHOT</version>
+      <!-- Scope is 'provided' as this way it's not shipped with the driver -->
+      <scope>provided</scope>
+    </dependency>
+  </dependencies>
+
+</project>
\ No newline at end of file
diff --git a/sandbox/mqtt/mqtt-java/pom.xml b/sandbox/mqtt/mqtt-java/pom.xml
new file mode 100644
index 0000000..ddf884e
--- /dev/null
+++ b/sandbox/mqtt/mqtt-java/pom.xml
@@ -0,0 +1,116 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.plc4x.sandbox</groupId>
+    <artifactId>test-plc4x-mqtt</artifactId>
+    <version>0.10.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>test-plc4x-mqtt-java</artifactId>
+  <name>Sandbox: Test MQTT Driver: Java</name>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.plc4x.plugins</groupId>
+        <artifactId>plc4x-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>generate-driver</id>
+            <phase>generate-sources</phase>
+            <goals>
+              <goal>generate-driver</goal>
+            </goals>
+            <configuration>
+              <protocolName>mqtt</protocolName>
+              <languageName>java</languageName>
+              <outputFlavor>read-write</outputFlavor>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.plc4x</groupId>
+      <artifactId>plc4j-api</artifactId>
+      <version>0.10.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.plc4x</groupId>
+      <artifactId>plc4j-spi</artifactId>
+      <version>0.10.0-SNAPSHOT</version>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.plc4x</groupId>
+      <artifactId>plc4j-transport-tcp</artifactId>
+      <version>0.10.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.plc4x</groupId>
+      <artifactId>plc4j-transport-raw-socket</artifactId>
+      <version>0.10.0-SNAPSHOT</version>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.plc4x</groupId>
+      <artifactId>plc4j-utils-test-utils</artifactId>
+      <version>0.10.0-SNAPSHOT</version>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>ch.qos.logback</groupId>
+      <artifactId>logback-classic</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.plc4x</groupId>
+      <artifactId>plc4x-code-generation-language-java</artifactId>
+      <version>0.10.0-SNAPSHOT</version>
+      <!-- Scope is 'provided' as this way it's not shipped with the driver -->
+      <scope>provided</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.plc4x</groupId>
+      <artifactId>plc4x-protocols-mqtt</artifactId>
+      <version>0.10.0-SNAPSHOT</version>
+      <!-- Scope is 'provided' as this way it's not shipped with the driver -->
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.plc4x</groupId>
+      <artifactId>plc4x-protocols-mqtt</artifactId>
+      <version>0.10.0-SNAPSHOT</version>
+      <classifier>tests</classifier>
+      <type>test-jar</type>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+</project>
diff --git a/sandbox/mqtt/mqtt-java/src/test/java/org/apache/plc4x/java/mqtt/readwrite/MqttParserSerializerTest.java b/sandbox/mqtt/mqtt-java/src/test/java/org/apache/plc4x/java/mqtt/readwrite/MqttParserSerializerTest.java
new file mode 100644
index 0000000..0d72840
--- /dev/null
+++ b/sandbox/mqtt/mqtt-java/src/test/java/org/apache/plc4x/java/mqtt/readwrite/MqttParserSerializerTest.java
@@ -0,0 +1,29 @@
+/*
+ * 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.mqtt.readwrite;
+
+import org.apache.plc4x.test.parserserializer.ParserSerializerTestsuiteRunner;
+
+public class MqttParserSerializerTest extends ParserSerializerTestsuiteRunner {
+
+    public MqttParserSerializerTest() {
+        super("/protocols/mqtt/ParserSerializerTestsuite.xml");
+    }
+
+}
diff --git a/sandbox/mqtt/pom.xml b/sandbox/mqtt/pom.xml
new file mode 100644
index 0000000..7cc4053
--- /dev/null
+++ b/sandbox/mqtt/pom.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.plc4x.sandbox</groupId>
+    <artifactId>plc4x-sandbox</artifactId>
+    <version>0.10.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>test-plc4x-mqtt</artifactId>
+  <packaging>pom</packaging>
+
+  <name>Sandbox: Test MQTT Driver</name>
+
+  <modules>
+    <module>mqtt-c</module>
+    <module>mqtt-cs</module>
+    <module>mqtt-go</module>
+    <module>mqtt-java</module>
+  </modules>
+
+</project>
diff --git a/sandbox/pom.xml b/sandbox/pom.xml
index 80ffbca..22abe69 100644
--- a/sandbox/pom.xml
+++ b/sandbox/pom.xml
@@ -37,6 +37,7 @@
   <modules>
     <module>code-gen</module>
     <module>discovery</module>
+    <module>mqtt</module>
     <module>plc-simulator</module>
 
     <module>test-java-bacnetip-driver</module>