You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by cd...@apache.org on 2020/08/25 12:01:56 UTC

[plc4x] 02/02: - Split up the s7 driver code into multiple files to be better manageable.

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

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

commit 28877a8f9b4b68d38c13740d19e103962dd9bd5f
Author: Christofer Dutz <ch...@c-ware.de>
AuthorDate: Tue Aug 25 14:01:44 2020 +0200

    - Split up the s7 driver code into multiple files to be better manageable.
---
 sandbox/plc4c/drivers/s7/CMakeLists.txt            |    6 +
 sandbox/plc4c/drivers/s7/include/plc4c/driver_s7.h |    2 +
 .../s7/include/plc4c/driver_s7_encode_decode.h     |   45 +
 .../drivers/s7/include/plc4c/driver_s7_packets.h   |   55 +
 .../plc4c/drivers/s7/include/plc4c/driver_s7_sm.h  |   47 +
 sandbox/plc4c/drivers/s7/src/driver_s7.c           | 1232 +-------------------
 .../plc4c/drivers/s7/src/driver_s7_encode_decode.c |  339 ++++++
 sandbox/plc4c/drivers/s7/src/driver_s7_packets.c   |  443 +++++++
 .../plc4c/drivers/s7/src/driver_s7_sm_connect.c    |  333 ++++++
 .../plc4c/drivers/s7/src/driver_s7_sm_disconnect.c |   81 ++
 sandbox/plc4c/drivers/s7/src/driver_s7_sm_read.c   |  120 ++
 sandbox/plc4c/drivers/s7/src/driver_s7_sm_write.c  |  123 ++
 .../plc4c/spi/include/plc4c/spi/types_private.h    |    2 +-
 13 files changed, 1598 insertions(+), 1230 deletions(-)

diff --git a/sandbox/plc4c/drivers/s7/CMakeLists.txt b/sandbox/plc4c/drivers/s7/CMakeLists.txt
index 4a7eab0..28ca689 100644
--- a/sandbox/plc4c/drivers/s7/CMakeLists.txt
+++ b/sandbox/plc4c/drivers/s7/CMakeLists.txt
@@ -25,6 +25,12 @@ file(GLOB generatedSources "${PLC4C_ROOT_DIR}/generated-sources/s7/src/*.c")
 
 add_library(plc4c-driver-s7
         src/driver_s7.c
+        src/driver_s7_encode_decode.c
+        src/driver_s7_packets.c
+        src/driver_s7_sm_connect.c
+        src/driver_s7_sm_disconnect.c
+        src/driver_s7_sm_read.c
+        src/driver_s7_sm_write.c
         ${generatedSources})
 
 target_link_libraries(plc4c-driver-s7
diff --git a/sandbox/plc4c/drivers/s7/include/plc4c/driver_s7.h b/sandbox/plc4c/drivers/s7/include/plc4c/driver_s7.h
index 947c0d8..78bd46d 100644
--- a/sandbox/plc4c/drivers/s7/include/plc4c/driver_s7.h
+++ b/sandbox/plc4c/drivers/s7/include/plc4c/driver_s7.h
@@ -54,6 +54,8 @@ struct plc4c_driver_s7_config {
   uint8_t max_amq_caller;
   uint8_t max_amq_callee;
   plc4c_driver_s7_controller_type controller_type;
+
+  uint16_t pdu_id;
 };
 typedef struct plc4c_driver_s7_config plc4c_driver_s7_config;
 
diff --git a/sandbox/plc4c/drivers/s7/include/plc4c/driver_s7_encode_decode.h b/sandbox/plc4c/drivers/s7/include/plc4c/driver_s7_encode_decode.h
new file mode 100644
index 0000000..9cb6558
--- /dev/null
+++ b/sandbox/plc4c/drivers/s7/include/plc4c/driver_s7_encode_decode.h
@@ -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.
+ */
+#ifndef PLC4C_DRIVER_S7_ENCODE_DECODE_H_
+#define PLC4C_DRIVER_S7_ENCODE_DECODE_H_
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdlib.h>
+
+#include "plc4c/driver_s7.h"
+#include "s7_var_request_parameter_item.h"
+
+uint16_t plc4c_driver_s7_encode_tsap_id(
+    plc4c_driver_s7_device_group device_group, uint8_t rack, uint8_t slot);
+
+uint16_t plc4c_driver_s7_get_nearest_matching_tpdu_size(uint16_t pdu_size);
+
+plc4c_driver_s7_controller_type decode_controller_type(char* article_number);
+
+plc4c_return_code decode_byte(const char* from_ptr, const char* to_ptr, uint8_t* value);
+
+plc4c_return_code parseAddress(
+    char* address, plc4c_s7_read_write_s7_var_request_parameter_item** item);
+
+#ifdef __cplusplus
+}
+#endif
+#endif  // PLC4C_DRIVER_S7_ENCODE_DECODE_H_
\ No newline at end of file
diff --git a/sandbox/plc4c/drivers/s7/include/plc4c/driver_s7_packets.h b/sandbox/plc4c/drivers/s7/include/plc4c/driver_s7_packets.h
new file mode 100644
index 0000000..587c75a
--- /dev/null
+++ b/sandbox/plc4c/drivers/s7/include/plc4c/driver_s7_packets.h
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+#ifndef PLC4C_DRIVER_S7_PACKETS_H_
+#define PLC4C_DRIVER_S7_PACKETS_H_
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <plc4c/types.h>
+
+#include "tpkt_packet.h"
+#include "plc4c/driver_s7.h"
+
+plc4c_return_code send_packet(plc4c_connection* connection,
+                              plc4c_s7_read_write_tpkt_packet* packet);
+plc4c_return_code receive_packet(plc4c_connection* connection,
+                                 plc4c_s7_read_write_tpkt_packet** packet);
+
+plc4c_return_code createCOTPConnectionRequest(
+    plc4c_driver_s7_config* configuration,
+    plc4c_s7_read_write_tpkt_packet** cotp_connect_request_packet);
+plc4c_return_code createS7ConnectionRequest(
+    plc4c_driver_s7_config* configuration,
+    plc4c_s7_read_write_tpkt_packet** s7_connect_request_packet);
+plc4c_return_code createS7IdentifyRemoteRequest(
+    plc4c_s7_read_write_tpkt_packet** s7_identify_remote_request_packet);
+plc4c_return_code createS7ReadRequest(
+    plc4c_read_request* read_request,
+    plc4c_s7_read_write_tpkt_packet** s7_read_request_packet);
+plc4c_return_code createS7WriteRequest(
+    plc4c_write_request* write_request,
+    plc4c_s7_read_write_tpkt_packet** s7_write_request_packet);
+plc4c_return_code parseAddress(
+    char* address, plc4c_s7_read_write_s7_var_request_parameter_item** item);
+
+#ifdef __cplusplus
+}
+#endif
+#endif  // PLC4C_DRIVER_S7_PACKETS_H_
\ No newline at end of file
diff --git a/sandbox/plc4c/drivers/s7/include/plc4c/driver_s7_sm.h b/sandbox/plc4c/drivers/s7/include/plc4c/driver_s7_sm.h
new file mode 100644
index 0000000..a6a9530
--- /dev/null
+++ b/sandbox/plc4c/drivers/s7/include/plc4c/driver_s7_sm.h
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+#ifndef PLC4C_DRIVER_S7_SM_H_
+#define PLC4C_DRIVER_S7_SM_H_
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <plc4c/types.h>
+#include <plc4c/spi/types_private.h>
+
+plc4c_return_code plc4c_driver_s7_connect_function(
+    plc4c_connection* connection, plc4c_system_task** task);
+
+plc4c_return_code plc4c_driver_s7_disconnect_function(
+    plc4c_connection* connection, plc4c_system_task** task);
+
+plc4c_return_code plc4c_driver_s7_read_function(
+    plc4c_read_request_execution* read_request_execution,
+    plc4c_system_task** task);
+void plc4c_driver_s7_free_read_response(plc4c_read_response* response);
+
+plc4c_return_code plc4c_driver_s7_write_function(
+    plc4c_write_request_execution* write_request_execution,
+    plc4c_system_task** task);
+void plc4c_driver_s7_free_write_response(plc4c_write_response* response);
+
+#ifdef __cplusplus
+}
+#endif
+#endif  // PLC4C_DRIVER_S7_SM_H_
\ No newline at end of file
diff --git a/sandbox/plc4c/drivers/s7/src/driver_s7.c b/sandbox/plc4c/drivers/s7/src/driver_s7.c
index 84e7aa1..6ac453a 100644
--- a/sandbox/plc4c/drivers/s7/src/driver_s7.c
+++ b/sandbox/plc4c/drivers/s7/src/driver_s7.c
@@ -13,725 +13,15 @@
   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
+  specific language governing permiSchreib' missions and limitations
   under the License.
 */
 
-#include <cotp_protocol_class.h>
 #include <ctype.h>
-#include <plc4c/driver_s7.h>
-#include <plc4c/plc4c.h>
-#include <plc4c/spi/types_private.h>
 #include <stdlib.h>
 #include <string.h>
-#include <tpkt_packet.h>
-
-#define MIN(x, y) (((x) < (y)) ? (x) : (y))
-
-// State definitions
-enum plc4c_driver_s7_connect_states {
-  PLC4C_DRIVER_S7_CONNECT_INIT,
-  PLC4C_DRIVER_S7_CONNECT_SEND_COTP_CONNECT_REQUEST,
-  PLC4C_DRIVER_S7_CONNECT_RECEIVE_COTP_CONNECT_RESPONSE,
-  PLC4C_DRIVER_S7_CONNECT_SEND_S7_CONNECT_REQUEST,
-  PLC4C_DRIVER_S7_CONNECT_RECEIVE_S7_CONNECT_RESPONSE,
-  PLC4C_DRIVER_S7_CONNECT_SEND_S7_IDENTIFICATION_REQUEST,
-  PLC4C_DRIVER_S7_CONNECT_RECEIVE_S7_IDENTIFICATION_RESPONSE,
-  PLC4C_DRIVER_S7_CONNECT_FINISHED
-};
-
-enum plc4c_driver_s7_disconnect_states {
-  PLC4C_DRIVER_S7_DISCONNECT_INIT,
-  PLC4C_DRIVER_S7_DISCONNECT_WAIT_TASKS_FINISHED,
-  PLC4C_DRIVER_S7_DISCONNECT_FINISHED
-};
-
-enum plc4c_driver_s7_read_states {
-  PLC4C_DRIVER_S7_READ_INIT,
-  PLC4C_DRIVER_S7_READ_FINISHED
-};
-
-enum plc4c_driver_s7_write_states {
-  PLC4C_DRIVER_S7_WRITE_INIT,
-  PLC4C_DRIVER_S7_WRITE_FINISHED
-};
-
-int16_t plc4c_driver_s7_select_message_function(uint8_t* buffer_data,
-                                                uint16_t buffer_length) {
-  // If the packet doesn't start with 0x03, it's a corrupt package.
-  if (buffer_length >= 1) {
-    // The buffer seems to be corrupt, try to find a sequence of 0x03 0x00
-    // and return the negative number of bytes needed to find that or the
-    // number of bytes in the buffer so it will simply clean the buffer
-    // completely.
-    if (*buffer_data != 0x03) {
-      for (int i = 1; i < (buffer_length - 1); i++) {
-        buffer_data++;
-        if ((*buffer_data == 0x03) && (*(buffer_data + 1) == 0x00)) {
-          // We've found a potential new packet start.
-          return -(i - 1);
-        }
-      }
-      // We didn't find a new start, delete the entire content except the last
-      // byte (as this could be the start of the next frame and we couldn't
-      // confirm this.
-      return -(buffer_length - 1);
-    }
-  }
-  // The length information is located in bytes 3 and 4
-  if (buffer_length >= 4) {
-    uint16_t packet_length =
-        (((uint16_t) * (buffer_data + (uint8_t)2)) << (uint16_t)8) |
-        ((uint16_t) * (buffer_data + 3));
-    if (buffer_length >= packet_length) {
-      return packet_length;
-    }
-    // 8192 is the maximum pdu size, so if the value is larger, the packet is
-    // probably corrupt.
-    if (packet_length > 8192) {
-      for (int i = 1; i < (buffer_length - 1); i++) {
-        buffer_data++;
-        if ((*buffer_data == 0x03) && (*(buffer_data + 1) == 0x00)) {
-          // We've found a potential new packet start.
-          return -(i - 1);
-        }
-      }
-      return -(buffer_length - 1);
-    }
-  }
-  // In all other cases, we'll just have to wait for the next time.
-  return 0;
-}
-
-uint16_t plc4c_driver_s7_encode_tsap_id(
-    plc4c_driver_s7_device_group device_group, uint8_t rack, uint8_t slot) {
-  return (((uint16_t)device_group) << 8) | (((uint16_t)rack & 0x000F) << 4) |
-         ((uint16_t)slot & 0x000F);
-}
-
-uint16_t plc4c_driver_s7_get_nearest_matching_tpdu_size(uint16_t pdu_size) {
-  for (int i = 0; i < plc4c_s7_read_write_cotp_tpdu_size_num_values(); i++) {
-    uint16_t cur_value =
-        plc4c_s7_read_write_cotp_tpdu_size_get_size_in_bytes(i);
-    if (cur_value >= pdu_size) {
-      return cur_value;
-    }
-  }
-  return 0;
-}
-
-plc4c_driver_s7_controller_type decode_controller_type(char* article_number) {
-  char* prefix = "6ES7 ";
-  // If this article-number doesn't start with this prefix, we can't decode it.
-  if (strncmp(prefix, article_number, strlen(prefix)) != 0) {
-    return PLC4C_DRIVER_S7_CONTROLLER_TYPE_ANY;
-  }
-  char model = *(article_number + 5);
-  switch (model) {
-    case 2:
-      return PLC4C_DRIVER_S7_CONTROLLER_TYPE_S7_1200;
-    case 5:
-      return PLC4C_DRIVER_S7_CONTROLLER_TYPE_S7_1500;
-    case 3:
-      return PLC4C_DRIVER_S7_CONTROLLER_TYPE_S7_300;
-    case 4:
-      return PLC4C_DRIVER_S7_CONTROLLER_TYPE_S7_400;
-    default:
-      return PLC4C_DRIVER_S7_CONTROLLER_TYPE_ANY;
-  }
-}
-
-uint8_t decode_hex_char(char c) {
-  if (('0' <= c) && (c <= '9')) {
-    return c - 48;
-  }
-  if (('A' <= c) && (c <= 'D')) {
-    return c - 55;
-  }
-  return -1;
-}
-
-plc4c_return_code decode_byte(char* from_ptr, char* to_ptr, uint8_t* value) {
-  if (to_ptr - from_ptr != 2) {
-    return INTERNAL_ERROR;
-  }
-
-  uint8_t first_char = decode_hex_char(*from_ptr);
-  uint8_t second_char = decode_hex_char(*(from_ptr + 1));
-  if ((first_char == -1) || (second_char == -1)) {
-    return INTERNAL_ERROR;
-  }
-  *value = (first_char << 4) | second_char;
-  return OK;
-}
-
-plc4c_return_code send_packet(plc4c_connection* connection,
-                              plc4c_s7_read_write_tpkt_packet* packet) {
-  // Get the size required to contain the serialized form of this packet.
-  uint16_t packet_size =
-      plc4c_s7_read_write_tpkt_packet_length_in_bytes(packet);
-
-  // Serialize this message to a byte-array.
-  plc4c_spi_write_buffer* write_buffer;
-  plc4c_return_code return_code =
-      plc4c_spi_write_buffer_create(packet_size, &write_buffer);
-  if (return_code != OK) {
-    return return_code;
-  }
-  plc4c_s7_read_write_tpkt_packet_serialize(write_buffer, packet);
-
-  // Now send this to the recipient.
-  return_code = connection->transport->send_message(write_buffer);
-  if (return_code != OK) {
-    return return_code;
-  }
-
-  return OK;
-}
-
-plc4c_return_code receive_packet(plc4c_connection* connection,
-                                 plc4c_s7_read_write_tpkt_packet** packet) {
-  // Get a response from the transport.
-  plc4c_spi_read_buffer* read_buffer;
-  plc4c_return_code return_code = connection->transport->select_message(
-      plc4c_driver_s7_select_message_function, &read_buffer);
-  if (return_code != OK) {
-    return return_code;
-  }
-
-  // Parse the given data.
-  *packet = NULL;
-  return_code = plc4c_s7_read_write_tpkt_packet_parse(read_buffer, packet);
-  if (return_code != OK) {
-    return return_code;
-  }
-
-  return OK;
-}
-
-// Declare the functions for which the definition will come later ...
-plc4c_return_code createCOTPConnectionRequest(
-    plc4c_driver_s7_config* configuration,
-    plc4c_s7_read_write_tpkt_packet** cotp_connect_request_packet);
-plc4c_return_code createS7ConnectionRequest(
-    plc4c_driver_s7_config* configuration,
-    plc4c_s7_read_write_tpkt_packet** s7_connect_request_packet);
-plc4c_return_code createS7IdentifyRemoteRequest(
-    plc4c_s7_read_write_tpkt_packet** s7_identify_remote_request_packet);
-plc4c_return_code createS7ReadRequest(
-    plc4c_read_request* read_request,
-    plc4c_s7_read_write_tpkt_packet** s7_read_request_packet);
-plc4c_return_code createS7WriteRequest(
-    plc4c_write_request* write_request,
-    plc4c_s7_read_write_tpkt_packet** s7_write_request_packet);
-plc4c_return_code parseAddress(
-    char* address, plc4c_s7_read_write_s7_var_request_parameter_item** item);
-
-/**
- * State machine function for establishing a connection to a remote S7 device.
- * @param task the current system task
- * @return return code of the current state machine step execution
- */
-plc4c_return_code plc4c_driver_s7_connect_machine_function(
-    plc4c_system_task* task) {
-  plc4c_connection* connection = task->context;
-  if (connection == NULL) {
-    return INTERNAL_ERROR;
-  }
-  // If we were already connected, return an error
-  if (plc4c_connection_get_connected(connection)) {
-    return ALREADY_CONNECTED;
-  }
-  plc4c_driver_s7_config* configuration = connection->configuration;
-
-  switch (task->state_id) {
-    // Initialize some internal data-structures.
-    case PLC4C_DRIVER_S7_CONNECT_INIT: {
-      // Calculate some internal settings from the values provided in the
-      // configuration.
-      configuration->calling_tsap_id = plc4c_driver_s7_encode_tsap_id(
-          PLC4C_DRIVER_S7_DEVICE_GROUP_OTHERS, configuration->local_rack,
-          configuration->local_slot);
-      configuration->called_tsap_id = plc4c_driver_s7_encode_tsap_id(
-          PLC4C_DRIVER_S7_DEVICE_GROUP_PG_OR_PC, configuration->remote_rack,
-          configuration->remote_slot);
-      configuration->cotp_tpdu_size =
-          plc4c_driver_s7_get_nearest_matching_tpdu_size(
-              configuration->pdu_size);
-      configuration->pdu_size = configuration->cotp_tpdu_size - 16;
-
-      task->state_id = PLC4C_DRIVER_S7_CONNECT_SEND_COTP_CONNECT_REQUEST;
-      break;
-    }
-    // Send a COTP connection request.
-    case PLC4C_DRIVER_S7_CONNECT_SEND_COTP_CONNECT_REQUEST: {
-      // Get a COTP connection response for the settings in the config.
-      plc4c_s7_read_write_tpkt_packet* cotp_connect_request_packet;
-      plc4c_return_code return_code = createCOTPConnectionRequest(
-          configuration, &cotp_connect_request_packet);
-      if (return_code != OK) {
-        return return_code;
-      }
-
-      // Send the packet to the remote.
-      return_code = send_packet(connection, cotp_connect_request_packet);
-      if (return_code != OK) {
-        return return_code;
-      }
-
-      task->state_id = PLC4C_DRIVER_S7_CONNECT_RECEIVE_COTP_CONNECT_RESPONSE;
-      break;
-    }
-    // Receive a COTP connection response.
-    case PLC4C_DRIVER_S7_CONNECT_RECEIVE_COTP_CONNECT_RESPONSE: {
-      // Read a response packet.
-      plc4c_s7_read_write_tpkt_packet* cotp_connect_response_packet;
-      plc4c_return_code return_code =
-          receive_packet(connection, &cotp_connect_response_packet);
-      // If we haven't read enough to process a full message, just try again
-      // next time.
-      if (return_code == UNFINISHED) {
-        return OK;
-      } else if (return_code != OK) {
-        return return_code;
-      }
-
-      // Check if the packet has the right type
-      if (cotp_connect_response_packet->payload->_type !=
-          plc4c_s7_read_write_cotp_packet_type_plc4c_s7_read_write_cotp_packet_connection_response) {
-        return INTERNAL_ERROR;
-      }
-
-      // Extract the information for: called-tsap-id, calling-tsap-id and
-      // tpdu-size.
-      plc4c_list_element* parameter_element =
-          cotp_connect_response_packet->payload->parameters->tail;
-      do {
-        plc4c_s7_read_write_cotp_parameter* parameter =
-            parameter_element->value;
-        switch (parameter->_type) {
-          case plc4c_s7_read_write_cotp_parameter_type_plc4c_s7_read_write_cotp_parameter_tpdu_size: {
-            configuration->cotp_tpdu_size =
-                parameter->cotp_parameter_tpdu_size_tpdu_size;
-            break;
-          }
-          case plc4c_s7_read_write_cotp_parameter_type_plc4c_s7_read_write_cotp_parameter_calling_tsap: {
-            configuration->calling_tsap_id =
-                parameter->cotp_parameter_calling_tsap_tsap_id;
-            break;
-          }
-          case plc4c_s7_read_write_cotp_parameter_type_plc4c_s7_read_write_cotp_parameter_called_tsap: {
-            configuration->called_tsap_id =
-                parameter->cotp_parameter_called_tsap_tsap_id;
-            break;
-          }
-          default: {
-            break;
-          }
-        }
-      } while (parameter_element != NULL);
-
-      // If we got the expected response, continue with the next higher level
-      // of connection.
-      task->state_id = PLC4C_DRIVER_S7_CONNECT_SEND_S7_CONNECT_REQUEST;
-      break;
-    }
-    // Send a S7 connection request.
-    case PLC4C_DRIVER_S7_CONNECT_SEND_S7_CONNECT_REQUEST: {
-      plc4c_s7_read_write_tpkt_packet* s7_connect_request_packet;
-      plc4c_return_code return_code =
-          createS7ConnectionRequest(configuration, &s7_connect_request_packet);
-      if (return_code != OK) {
-        return return_code;
-      }
-
-      // Send the packet to the remote.
-      return_code = send_packet(connection, s7_connect_request_packet);
-      if (return_code != OK) {
-        return return_code;
-      }
-
-      task->state_id = PLC4C_DRIVER_S7_CONNECT_RECEIVE_S7_CONNECT_RESPONSE;
-      break;
-    }
-    // Receive a S7 connection response.
-    case PLC4C_DRIVER_S7_CONNECT_RECEIVE_S7_CONNECT_RESPONSE: {
-      // Read a response packet.
-      plc4c_s7_read_write_tpkt_packet* s7_connect_response_packet;
-      plc4c_return_code return_code =
-          receive_packet(connection, &s7_connect_response_packet);
-      // If we haven't read enough to process a full message, just try again
-      // next time.
-      if (return_code == UNFINISHED) {
-        return OK;
-      } else if (return_code != OK) {
-        return return_code;
-      }
-
-      // Check if the packet has the right type
-      if (s7_connect_response_packet->payload->_type !=
-          plc4c_s7_read_write_cotp_packet_type_plc4c_s7_read_write_cotp_packet_data) {
-        return INTERNAL_ERROR;
-      }
-      if (s7_connect_response_packet->payload->payload->_type !=
-          plc4c_s7_read_write_s7_message_type_plc4c_s7_read_write_s7_message_response) {
-        return INTERNAL_ERROR;
-      }
-      if (s7_connect_response_packet->payload->payload->parameter->_type !=
-          plc4c_s7_read_write_s7_parameter_type_plc4c_s7_read_write_s7_parameter_setup_communication) {
-        return INTERNAL_ERROR;
-      }
-
-      // Extract and save the information for:
-      // max-amq-caller, max-amq-callee, pdu-size.
-      configuration->pdu_size =
-          s7_connect_response_packet->payload->payload->parameter
-              ->s7_parameter_setup_communication_pdu_length;
-      configuration->max_amq_caller =
-          s7_connect_response_packet->payload->payload->parameter
-              ->s7_parameter_setup_communication_max_amq_caller;
-      configuration->max_amq_callee =
-          s7_connect_response_packet->payload->payload->parameter
-              ->s7_parameter_setup_communication_max_amq_callee;
-
-      // If no controller is explicitly selected, detect it.
-      if (configuration->controller_type !=
-          PLC4C_DRIVER_S7_CONTROLLER_TYPE_ANY) {
-        task->state_id = PLC4C_DRIVER_S7_CONNECT_SEND_S7_IDENTIFICATION_REQUEST;
-      }
-      // If a controller is explicitly selected, we're done connecting.
-      else {
-        task->state_id = PLC4C_DRIVER_S7_CONNECT_FINISHED;
-      }
-      break;
-    }
-    // Send a S7 identification request.
-    case PLC4C_DRIVER_S7_CONNECT_SEND_S7_IDENTIFICATION_REQUEST: {
-      plc4c_s7_read_write_tpkt_packet* s7_identify_remote_request_packet;
-      plc4c_return_code return_code =
-          createS7IdentifyRemoteRequest(&s7_identify_remote_request_packet);
-      if (return_code != OK) {
-        return return_code;
-      }
-
-      // Send the packet to the remote.
-      return_code = send_packet(connection, s7_identify_remote_request_packet);
-      if (return_code != OK) {
-        return return_code;
-      }
-
-      task->state_id =
-          PLC4C_DRIVER_S7_CONNECT_RECEIVE_S7_IDENTIFICATION_RESPONSE;
-      break;
-    }
-    // Receive a S7 identification response.
-    case PLC4C_DRIVER_S7_CONNECT_RECEIVE_S7_IDENTIFICATION_RESPONSE: {
-      // Read a response packet.
-      plc4c_s7_read_write_tpkt_packet* s7_identify_remote_response_packet;
-      plc4c_return_code return_code =
-          receive_packet(connection, &s7_identify_remote_response_packet);
-      // If we haven't read enough to process a full message, just try again
-      // next time.
-      if (return_code == UNFINISHED) {
-        return OK;
-      } else if (return_code != OK) {
-        return return_code;
-      }
-
-      // Check if the packet has the right type
-      if (s7_identify_remote_response_packet->payload->_type !=
-          plc4c_s7_read_write_cotp_packet_type_plc4c_s7_read_write_cotp_packet_data) {
-        return INTERNAL_ERROR;
-      }
-      if (s7_identify_remote_response_packet->payload->payload->_type !=
-          plc4c_s7_read_write_s7_message_type_plc4c_s7_read_write_s7_message_user_data) {
-        return INTERNAL_ERROR;
-      }
-      if (s7_identify_remote_response_packet->payload->payload->payload
-              ->_type !=
-          plc4c_s7_read_write_s7_payload_type_plc4c_s7_read_write_s7_payload_user_data) {
-        return INTERNAL_ERROR;
-      }
-
-      plc4c_list_element* cur_item =
-          s7_identify_remote_response_packet->payload->payload->payload
-              ->s7_payload_user_data_items->tail;
-      while (cur_item != NULL) {
-        plc4c_s7_read_write_s7_payload_user_data_item* item = cur_item->value;
-        if (item->_type ==
-            plc4c_s7_read_write_s7_payload_user_data_item_type_plc4c_s7_read_write_s7_payload_user_data_item_cpu_function_read_szl_response) {
-          plc4c_list_element* szl_item =
-              item->s7_payload_user_data_item_cpu_function_read_szl_response_items
-                  ->head;
-          while (szl_item != NULL) {
-            plc4c_s7_read_write_szl_data_tree_item* data_tree_item =
-                szl_item->value;
-            if (data_tree_item->item_index == 0x0001) {
-              char* article_number = list_to_string(data_tree_item->mlfb);
-              if (article_number != NULL) {
-                configuration->controller_type =
-                    decode_controller_type(article_number);
-                free(article_number);
-              } else {
-                configuration->controller_type =
-                    PLC4C_DRIVER_S7_CONTROLLER_TYPE_ANY;
-              }
-            }
-            szl_item = szl_item->next;
-          }
-        }
-
-        cur_item = cur_item->next;
-      }
-
-      task->state_id = PLC4C_DRIVER_S7_CONNECT_FINISHED;
-      break;
-    }
-    // Clean up some internal data-structures.
-    case PLC4C_DRIVER_S7_CONNECT_FINISHED: {
-      plc4c_connection_set_connected(connection, true);
-      task->completed = true;
-      break;
-    }
-    // If an unexpected state id was received, this is not really something
-    // we can recover from.
-    default: {
-      task->completed = true;
-      return INTERNAL_ERROR;
-    }
-  }
-  return OK;
-}
-
-plc4c_return_code plc4c_driver_s7_disconnect_machine_function(
-    plc4c_system_task* task) {
-  plc4c_connection* connection = task->context;
-  if (connection == NULL) {
-    return INTERNAL_ERROR;
-  }
-
-  switch (task->state_id) {
-    case PLC4C_DRIVER_S7_DISCONNECT_INIT: {
-      plc4c_connection_set_disconnect(connection, true);
-      task->state_id = PLC4C_DRIVER_S7_DISCONNECT_WAIT_TASKS_FINISHED;
-      break;
-    }
-    case PLC4C_DRIVER_S7_DISCONNECT_WAIT_TASKS_FINISHED: {
-      // The disconnect system-task also counts.
-      if (plc4c_connection_get_running_tasks_count(connection) == 1) {
-        plc4c_connection_set_connected(connection, false);
-        task->completed = true;
-        task->state_id = PLC4C_DRIVER_S7_DISCONNECT_FINISHED;
-      }
-      break;
-    }
-    case PLC4C_DRIVER_S7_DISCONNECT_FINISHED: {
-      // Do nothing
-      break;
-    }
-    default: {
-      return INTERNAL_ERROR;
-    }
-  }
-  return OK;
-}
-
-plc4c_return_code plc4c_driver_s7_read_machine_function(
-    plc4c_system_task* task) {
-  plc4c_read_request_execution* read_request_execution = task->context;
-  if (read_request_execution == NULL) {
-    return INTERNAL_ERROR;
-  }
-  plc4c_read_request* read_request = read_request_execution->read_request;
-  if (read_request == NULL) {
-    return INTERNAL_ERROR;
-  }
-  plc4c_connection* connection = task->context;
-  if (connection == NULL) {
-    return INTERNAL_ERROR;
-  }
-
-  switch (task->state_id) {
-    case PLC4C_DRIVER_S7_READ_INIT: {
-      task->completed = true;
-
-      plc4c_s7_read_write_tpkt_packet* s7_read_request_packet;
-      plc4c_return_code return_code =
-          createS7ReadRequest(read_request, &s7_read_request_packet);
-      if (return_code != OK) {
-        return return_code;
-      }
-
-      // Send the packet to the remote.
-      return_code = send_packet(connection, s7_read_request_packet);
-      if (return_code != OK) {
-        return return_code;
-      }
-
-      task->state_id = PLC4C_DRIVER_S7_READ_FINISHED;
-      break;
-    }
-    case PLC4C_DRIVER_S7_READ_FINISHED: {
-      // Read a response packet.
-      plc4c_s7_read_write_tpkt_packet* s7_read_response_packet;
-      plc4c_return_code return_code =
-          receive_packet(connection, &s7_read_response_packet);
-      // If we haven't read enough to process a full message, just try again
-      // next time.
-      if (return_code == UNFINISHED) {
-        return OK;
-      } else if (return_code != OK) {
-        return return_code;
-      }
-
-      // TODO: Check the response ...
-
-      task->completed = true;
-      break;
-    }
-  }
-  return OK;
-}
-
-plc4c_return_code plc4c_driver_s7_write_machine_function(
-    plc4c_system_task* task) {
-  plc4c_write_request_execution* write_request_execution = task->context;
-  if (write_request_execution == NULL) {
-    return INTERNAL_ERROR;
-  }
-  plc4c_write_request* write_request = write_request_execution->write_request;
-  if (write_request == NULL) {
-    return INTERNAL_ERROR;
-  }
-  plc4c_connection* connection = task->context;
-  if (connection == NULL) {
-    return INTERNAL_ERROR;
-  }
-
-  switch (task->state_id) {
-    case PLC4C_DRIVER_S7_WRITE_INIT: {
-      task->completed = true;
-
-      plc4c_s7_read_write_tpkt_packet* s7_write_request_packet;
-      plc4c_return_code return_code =
-          createS7WriteRequest(write_request, &s7_write_request_packet);
-      if (return_code != OK) {
-        return return_code;
-      }
-
-      // Send the packet to the remote.
-      return_code = send_packet(connection, s7_write_request_packet);
-      if (return_code != OK) {
-        return return_code;
-      }
-
-      task->state_id = PLC4C_DRIVER_S7_WRITE_FINISHED;
-      break;
-    }
-    case PLC4C_DRIVER_S7_WRITE_FINISHED: {
-      // Read a response packet.
-      plc4c_s7_read_write_tpkt_packet* s7_write_response_packet;
-      plc4c_return_code return_code =
-          receive_packet(connection, &s7_write_response_packet);
-      // If we haven't read enough to process a full message, just try again
-      // next time.
-      if (return_code == UNFINISHED) {
-        return OK;
-      } else if (return_code != OK) {
-        return return_code;
-      }
-
-      // TODO: Check the response ...
-
-      task->completed = true;
-      break;
-    }
-  }
-  return OK;
-}
-
-plc4c_return_code plc4c_driver_s7_connect_function(plc4c_connection* connection,
-                                                   plc4c_system_task** task) {
-  plc4c_system_task* new_task = malloc(sizeof(plc4c_system_task));
-  // There's nothing to do here, so no need for a state-machine.
-  new_task->state_id = PLC4C_DRIVER_S7_CONNECT_INIT;
-  new_task->state_machine_function = &plc4c_driver_s7_connect_machine_function;
-  new_task->completed = false;
-  new_task->context = connection;
-  new_task->connection = connection;
-  *task = new_task;
-  return OK;
-}
-
-plc4c_return_code plc4c_driver_s7_disconnect_function(
-    plc4c_connection* connection, plc4c_system_task** task) {
-  plc4c_system_task* new_task = malloc(sizeof(plc4c_system_task));
-  new_task->state_id = PLC4C_DRIVER_S7_DISCONNECT_INIT;
-  new_task->state_machine_function =
-      &plc4c_driver_s7_disconnect_machine_function;
-  new_task->completed = false;
-  new_task->context = connection;
-  new_task->connection = connection;
-  *task = new_task;
-  return OK;
-}
-
-plc4c_return_code plc4c_driver_s7_read_function(
-    plc4c_read_request_execution* read_request_execution,
-    plc4c_system_task** task) {
-  plc4c_system_task* new_task = malloc(sizeof(plc4c_system_task));
-  new_task->state_id = PLC4C_DRIVER_S7_READ_INIT;
-  new_task->state_machine_function = &plc4c_driver_s7_read_machine_function;
-  new_task->completed = false;
-  new_task->context = read_request_execution;
-  new_task->connection = read_request_execution->system_task->connection;
-  *task = new_task;
-  return OK;
-}
-
-void plc4c_driver_s7_free_read_response_item(
-    plc4c_list_element* read_item_element) {
-  plc4c_response_value_item* value_item =
-      (plc4c_response_value_item*)read_item_element->value;
-  plc4c_data_destroy(value_item->value);
-  value_item->value = NULL;
-}
-
-void plc4c_driver_s7_free_read_response(plc4c_read_response* response) {
-  // the request will be cleaned up elsewhere
-  plc4c_utils_list_delete_elements(response->items,
-                                   &plc4c_driver_s7_free_read_response_item);
-}
-
-plc4c_return_code plc4c_driver_s7_write_function(
-    plc4c_write_request_execution* write_request_execution,
-    plc4c_system_task** task) {
-  plc4c_system_task* new_task = malloc(sizeof(plc4c_system_task));
-  new_task->state_id = PLC4C_DRIVER_S7_WRITE_INIT;
-  new_task->state_machine_function = &plc4c_driver_s7_write_machine_function;
-  new_task->completed = false;
-  new_task->context = write_request_execution;
-  new_task->connection = write_request_execution->system_task->connection;
-  *task = new_task;
-  return OK;
-}
-
-void plc4c_driver_s7_free_write_response_item(
-    plc4c_list_element* write_item_element) {
-  plc4c_response_value_item* value_item =
-      (plc4c_response_value_item*)write_item_element->value;
-  // do not delete the plc4c_item
-  // we also, in THIS case don't delete the random value which isn't really
-  // a pointer
-  // free(value_item->value);
-  value_item->value = NULL;
-}
-
-void plc4c_driver_s7_free_write_response(plc4c_write_response* response) {
-  // the request will be cleaned up elsewhere
-  plc4c_utils_list_delete_elements(response->response_items,
-                                   &plc4c_driver_s7_free_write_response_item);
-}
+#include "plc4c/driver_s7.h"
+#include "plc4c/driver_s7_sm.h"
 
 plc4c_driver* plc4c_driver_s7_create() {
   plc4c_driver* driver = (plc4c_driver*)malloc(sizeof(plc4c_driver));
@@ -751,519 +41,3 @@ plc4c_driver* plc4c_driver_s7_create() {
   driver->free_unsubscription_response_function = NULL;
   return driver;
 }
-
-////////////////////////////////////////////////////////////////////////////////
-// Helpers for preparing the different packets
-////////////////////////////////////////////////////////////////////////////////
-
-plc4c_return_code createCOTPConnectionRequest(
-    plc4c_driver_s7_config* configuration,
-    plc4c_s7_read_write_tpkt_packet** cotp_connect_request_packet) {
-  *cotp_connect_request_packet =
-      malloc(sizeof(plc4c_s7_read_write_tpkt_packet));
-  if (*cotp_connect_request_packet == NULL) {
-    return NO_MEMORY;
-  }
-  (*cotp_connect_request_packet)->payload =
-      malloc(sizeof(plc4c_s7_read_write_cotp_packet));
-  if ((*cotp_connect_request_packet)->payload == NULL) {
-    return NO_MEMORY;
-  }
-  (*cotp_connect_request_packet)->payload->_type =
-      plc4c_s7_read_write_cotp_packet_type_plc4c_s7_read_write_cotp_packet_connection_request;
-  (*cotp_connect_request_packet)
-      ->payload->cotp_packet_connection_request_destination_reference = 0x0000;
-  (*cotp_connect_request_packet)
-      ->payload->cotp_packet_connection_request_source_reference = 0x000F;
-  (*cotp_connect_request_packet)
-      ->payload->cotp_packet_connection_request_protocol_class =
-      plc4c_s7_read_write_cotp_protocol_class_CLASS_0;
-
-  // Add the COTP parameters: Called TSAP, Calling TSAP and TPDU Size.
-  plc4c_utils_list_create(
-      &((*cotp_connect_request_packet)->payload->parameters));
-  plc4c_s7_read_write_cotp_parameter* called_tsap_parameter =
-      malloc(sizeof(plc4c_s7_read_write_cotp_parameter));
-  if (called_tsap_parameter == NULL) {
-    return NO_MEMORY;
-  }
-  called_tsap_parameter->_type =
-      plc4c_s7_read_write_cotp_parameter_type_plc4c_s7_read_write_cotp_parameter_called_tsap;
-  called_tsap_parameter->cotp_parameter_called_tsap_tsap_id =
-      configuration->called_tsap_id;
-
-  plc4c_utils_list_insert_head_value(
-      (*cotp_connect_request_packet)->payload->parameters,
-      called_tsap_parameter);
-  plc4c_s7_read_write_cotp_parameter* calling_tsap_parameter =
-      malloc(sizeof(plc4c_s7_read_write_cotp_parameter));
-  if (calling_tsap_parameter == NULL) {
-    return NO_MEMORY;
-  }
-  calling_tsap_parameter->_type =
-      plc4c_s7_read_write_cotp_parameter_type_plc4c_s7_read_write_cotp_parameter_calling_tsap;
-  calling_tsap_parameter->cotp_parameter_calling_tsap_tsap_id =
-      configuration->calling_tsap_id;
-
-  plc4c_utils_list_insert_head_value(
-      (*cotp_connect_request_packet)->payload->parameters,
-      calling_tsap_parameter);
-  plc4c_s7_read_write_cotp_parameter* tpdu_size_parameter =
-      malloc(sizeof(plc4c_s7_read_write_cotp_parameter));
-  if (tpdu_size_parameter == NULL) {
-    return NO_MEMORY;
-  }
-  tpdu_size_parameter->_type =
-      plc4c_s7_read_write_cotp_parameter_type_plc4c_s7_read_write_cotp_parameter_tpdu_size;
-  tpdu_size_parameter->cotp_parameter_tpdu_size_tpdu_size =
-      configuration->cotp_tpdu_size;
-
-  plc4c_utils_list_insert_head_value(
-      (*cotp_connect_request_packet)->payload->parameters, tpdu_size_parameter);
-
-  // For a COTP connection request, there is no payload.
-  (*cotp_connect_request_packet)->payload->payload = NULL;
-
-  return OK;
-}
-
-plc4c_return_code createS7ConnectionRequest(
-    plc4c_driver_s7_config* configuration,
-    plc4c_s7_read_write_tpkt_packet** s7_connect_request_packet) {
-  *s7_connect_request_packet = malloc(sizeof(plc4c_s7_read_write_tpkt_packet));
-  if (*s7_connect_request_packet == NULL) {
-    return NO_MEMORY;
-  }
-  (*s7_connect_request_packet)->payload =
-      malloc(sizeof(plc4c_s7_read_write_cotp_packet));
-  if ((*s7_connect_request_packet)->payload == NULL) {
-    return NO_MEMORY;
-  }
-  (*s7_connect_request_packet)->payload->_type =
-      plc4c_s7_read_write_cotp_packet_type_plc4c_s7_read_write_cotp_packet_data;
-  (*s7_connect_request_packet)->payload->parameters = NULL;
-  (*s7_connect_request_packet)->payload->cotp_packet_data_eot = true;
-  (*s7_connect_request_packet)->payload->cotp_packet_data_tpdu_ref = 1;
-
-  (*s7_connect_request_packet)->payload->payload =
-      malloc(sizeof(plc4c_s7_read_write_s7_message));
-  if ((*s7_connect_request_packet)->payload->payload == NULL) {
-    return NO_MEMORY;
-  }
-  (*s7_connect_request_packet)->payload->payload->_type =
-      plc4c_s7_read_write_s7_message_type_plc4c_s7_read_write_s7_message_request;
-  (*s7_connect_request_packet)->payload->payload->parameter =
-      malloc(sizeof(plc4c_s7_read_write_s7_parameter));
-  if ((*s7_connect_request_packet)->payload->payload->parameter == NULL) {
-    return NO_MEMORY;
-  }
-  (*s7_connect_request_packet)->payload->payload->parameter->_type =
-      plc4c_s7_read_write_s7_parameter_type_plc4c_s7_read_write_s7_parameter_setup_communication;
-  (*s7_connect_request_packet)
-      ->payload->payload->parameter
-      ->s7_parameter_setup_communication_max_amq_callee =
-      configuration->max_amq_callee;
-  (*s7_connect_request_packet)
-      ->payload->payload->parameter
-      ->s7_parameter_setup_communication_max_amq_caller =
-      configuration->max_amq_caller;
-  (*s7_connect_request_packet)
-      ->payload->payload->parameter
-      ->s7_parameter_setup_communication_pdu_length = configuration->pdu_size;
-
-  return OK;
-}
-
-plc4c_return_code createS7IdentifyRemoteRequest(
-    plc4c_s7_read_write_tpkt_packet** s7_identify_remote_request_packet) {
-  *s7_identify_remote_request_packet =
-      malloc(sizeof(plc4c_s7_read_write_tpkt_packet));
-  if (*s7_identify_remote_request_packet == NULL) {
-    return NO_MEMORY;
-  }
-  (*s7_identify_remote_request_packet)->payload =
-      malloc(sizeof(plc4c_s7_read_write_cotp_packet));
-  if ((*s7_identify_remote_request_packet)->payload == NULL) {
-    return NO_MEMORY;
-  }
-  (*s7_identify_remote_request_packet)->payload->_type =
-      plc4c_s7_read_write_cotp_packet_type_plc4c_s7_read_write_cotp_packet_data;
-  (*s7_identify_remote_request_packet)->payload->parameters = NULL;
-  (*s7_identify_remote_request_packet)->payload->cotp_packet_data_eot = true;
-  (*s7_identify_remote_request_packet)->payload->cotp_packet_data_tpdu_ref = 2;
-
-  (*s7_identify_remote_request_packet)->payload->payload =
-      malloc(sizeof(plc4c_s7_read_write_s7_message));
-  if ((*s7_identify_remote_request_packet)->payload->payload == NULL) {
-    return NO_MEMORY;
-  }
-  (*s7_identify_remote_request_packet)->payload->payload->_type =
-      plc4c_s7_read_write_s7_message_type_plc4c_s7_read_write_s7_message_user_data;
-  (*s7_identify_remote_request_packet)->payload->payload->parameter =
-      malloc(sizeof(plc4c_s7_read_write_s7_parameter));
-  if ((*s7_identify_remote_request_packet)->payload->payload->parameter ==
-      NULL) {
-    return NO_MEMORY;
-  }
-  (*s7_identify_remote_request_packet)->payload->payload->parameter->_type =
-      plc4c_s7_read_write_s7_parameter_type_plc4c_s7_read_write_s7_parameter_user_data;
-
-  plc4c_utils_list_create(
-      &((*s7_identify_remote_request_packet)
-            ->payload->payload->parameter->s7_parameter_user_data_items));
-  plc4c_s7_read_write_s7_parameter_user_data_item* parameter_item =
-      malloc(sizeof(plc4c_s7_read_write_s7_parameter_user_data_item));
-  parameter_item->_type =
-      plc4c_s7_read_write_s7_parameter_user_data_item_type_plc4c_s7_read_write_s7_parameter_user_data_item_cpu_functions;
-  parameter_item->s7_parameter_user_data_item_cpu_functions_method = 0x11;
-  parameter_item->s7_parameter_user_data_item_cpu_functions_cpu_function_type =
-      0x4;
-  parameter_item->s7_parameter_user_data_item_cpu_functions_cpu_function_group =
-      0x4;
-  parameter_item->s7_parameter_user_data_item_cpu_functions_cpu_subfunction =
-      0x01;
-  parameter_item->s7_parameter_user_data_item_cpu_functions_sequence_number =
-      0x00;
-  parameter_item
-      ->s7_parameter_user_data_item_cpu_functions_data_unit_reference_number =
-      NULL;
-  parameter_item->s7_parameter_user_data_item_cpu_functions_last_data_unit =
-      NULL;
-  parameter_item->s7_parameter_user_data_item_cpu_functions_error_code = NULL;
-  plc4c_utils_list_insert_head_value(
-      (*s7_identify_remote_request_packet)
-          ->payload->payload->parameter->s7_parameter_user_data_items,
-      parameter_item);
-
-  plc4c_utils_list_create(
-      &((*s7_identify_remote_request_packet)
-            ->payload->payload->payload->s7_payload_user_data_items));
-  plc4c_s7_read_write_s7_payload_user_data_item* payload_item =
-      malloc(sizeof(plc4c_s7_read_write_s7_payload_user_data_item));
-  payload_item->_type =
-      plc4c_s7_read_write_s7_payload_user_data_item_type_plc4c_s7_read_write_s7_payload_user_data_item_cpu_function_read_szl_request;
-  payload_item->return_code = plc4c_s7_read_write_data_transport_error_code_OK;
-  payload_item->transport_size =
-      plc4c_s7_read_write_data_transport_size_OCTET_STRING;
-  payload_item->szl_index = 0x0000;
-  payload_item->szl_id = malloc(sizeof(plc4c_s7_read_write_szl_id));
-  if (payload_item->szl_id == NULL) {
-    return NO_MEMORY;
-  }
-  payload_item->szl_id->type_class =
-      plc4c_s7_read_write_szl_module_type_class_CPU;
-  payload_item->szl_id->sublist_extract = 0x00;
-  payload_item->szl_id->sublist_list =
-      plc4c_s7_read_write_szl_sublist_MODULE_IDENTIFICATION;
-
-  return OK;
-}
-
-plc4c_return_code createS7ReadRequest(
-    plc4c_read_request* read_request,
-    plc4c_s7_read_write_tpkt_packet** s7_read_request_packet) {
-  *s7_read_request_packet = malloc(sizeof(s7_read_request_packet));
-  if (*s7_read_request_packet == NULL) {
-    return NO_MEMORY;
-  }
-
-  (*s7_read_request_packet)->payload =
-      malloc(sizeof(plc4c_s7_read_write_cotp_packet));
-  (*s7_read_request_packet)->payload->_type =
-      plc4c_s7_read_write_cotp_packet_type_plc4c_s7_read_write_cotp_packet_data;
-  // TODO: generate a tpdu_id
-  (*s7_read_request_packet)->payload->cotp_packet_data_tpdu_ref = 1;
-  (*s7_read_request_packet)->payload->cotp_packet_data_eot = true;
-  (*s7_read_request_packet)->payload->payload =
-      malloc(sizeof(plc4c_s7_read_write_s7_message));
-  (*s7_read_request_packet)->payload->payload->_type =
-      plc4c_s7_read_write_s7_message_type_plc4c_s7_read_write_s7_message_request;
-  (*s7_read_request_packet)->payload->payload->parameter =
-      malloc(sizeof(plc4c_s7_read_write_s7_parameter));
-  (*s7_read_request_packet)->payload->payload->parameter->_type =
-      plc4c_s7_read_write_s7_parameter_type_plc4c_s7_read_write_s7_parameter_read_var_request;
-  plc4c_utils_list_create(
-      &(*s7_read_request_packet)
-           ->payload->payload->parameter->s7_parameter_read_var_request_items);
-
-  plc4c_list_element* item = read_request->items->tail;
-  while (item != NULL) {
-    // Get the item address from the API request.
-    char* itemAddress = item->value;
-
-    // Create the item ...
-    plc4c_s7_read_write_s7_var_request_parameter_item* request_item;
-    plc4c_return_code return_code = parseAddress(itemAddress, &request_item);
-    if (return_code != OK) {
-      return return_code;
-    }
-
-    // Add the new item to the request.
-    plc4c_utils_list_insert_head_value(
-        (*s7_read_request_packet)
-            ->payload->payload->parameter->s7_parameter_read_var_request_items,
-        request_item);
-
-    item = item->next;
-  }
-
-  return OK;
-}
-
-plc4c_return_code parseAddress(
-    char* address, plc4c_s7_read_write_s7_var_request_parameter_item** item) {
-  uint8_t string_length;
-
-  *item = malloc(sizeof(plc4c_s7_read_write_s7_var_request_parameter_item));
-  (*item)->_type =
-      plc4c_s7_read_write_s7_var_request_parameter_item_type_plc4c_s7_read_write_s7_var_request_parameter_item_address;
-
-  // Java Regexp:
-  // ADDRESS_PATTERN =
-  // ^%(?<memoryArea>.)(?<transferSizeCode>[XBWD]?)(?<byteOffset>\d{1,7})(.(?<bitOffset>[0-7]))?:(?<dataType>[a-zA-Z_]+)(\[(?<numElements>\d+)])?
-  // DATA_BLOCK_ADDRESS_PATTERN =
-  // ^%DB(?<blockNumber>\d{1,5}).DB(?<transferSizeCode>[XBWD]?)(?<byteOffset>\d{1,7})(.(?<bitOffset>[0-7]))?:(?<dataType>[a-zA-Z_]+)(\[(?<numElements>\d+)])?
-  // DATA_BLOCK_SHORT_PATTERN =
-  // ^%DB(?<blockNumber>\d{1,5}).(?<byteOffset>\d{1,7})(.(?<bitOffset>[0-7]))?:(?<dataType>[a-zA-Z_]+)(\[(?<numElements>\d+)])?
-  // DATA_BLOCK_STRING_ADDRESS_PATTERN =
-  // ^%DB(?<blockNumber>\d{1,5}).DB(?<transferSizeCode>[XBWD]?)(?<byteOffset>\d{1,7}):STRING\((?<stringLength>\d{1,3})\)(\[(?<numElements>\d+)])?
-  // DATA_BLOCK_STRING_SHORT_PATTERN =
-  // ^%DB(?<blockNumber>\d{1,5}):(?<byteOffset>\d{1,7}):STRING\((?<stringLength>\d{1,3})\)(\[(?<numElements>\d+)])?
-
-  // PLC_PROXY_ADDRESS_PATTERN =
-  // [0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2}
-  //
-  // Parser logic
-  char* cur_pos = address;
-  char* last_pos = address;
-  // - Does it start with "%"?
-  if (*cur_pos == '%') {
-    cur_pos++;
-
-    char* memory_area = NULL;
-    char* block_number = NULL;
-    char* transfer_size_code = NULL;
-    char* byte_offset = NULL;
-    char* bit_offset = NULL;
-    char* data_type = NULL;
-    char* string_length = NULL;
-    char* num_elements = NULL;
-
-    ////////////////////////////////////////////////////////////////////////////
-    // First extract the different parts of the address
-    ////////////////////////////////////////////////////////////////////////////
-
-    if (!isalpha(*cur_pos)) {
-      return INVALID_ADDRESS;
-    }
-
-    last_pos = cur_pos;
-    while (isalpha(*cur_pos)) {
-      cur_pos++;
-    }
-    int len = cur_pos - last_pos;
-    memory_area = malloc(sizeof(char) * (len + 1));
-    strncpy(memory_area, last_pos, len);
-    //*(memory_area + len + 1) = '/0';
-
-    // If it's a DB-block, get the block_number
-    if (strcmp(memory_area, "DB") == 0) {
-      last_pos = cur_pos;
-      while (isdigit(*cur_pos)) {
-        cur_pos++;
-      }
-      len = cur_pos - last_pos;
-      block_number = malloc(sizeof(char) * (len + 1));
-      strncpy(block_number, last_pos, len);
-
-      // Skip the "."
-      cur_pos++;
-    }
-
-    // If the next is not a digit it might be DB, DB{transferSizeCode}
-    // or {transferSizeCode}
-    if (!isdigit(*cur_pos)) {
-      last_pos = cur_pos;
-      while (!isdigit(*cur_pos)) {
-        cur_pos++;
-      }
-      len = cur_pos - last_pos;
-      // If it's at least 2 digits long, it's DB{transferSizeCode} or
-      // "DB". So we get rid of the "DB" prefix, as this has no value for us.
-      if (len >= 2) {
-        last_pos += 2;
-      }
-      // If it's 1 or 3 long it contains a "transferSizeCode", which is just
-      // one char long.
-      if ((len == 1) || (len == 3)) {
-        transfer_size_code = malloc(sizeof(char) * 2);
-        *transfer_size_code = *last_pos;
-        *(transfer_size_code + 1) = '\0';
-      }
-    }
-
-    // Next comes the byte_offset
-    last_pos = cur_pos;
-    while (isdigit(*cur_pos)) {
-      cur_pos++;
-    }
-    len = cur_pos - last_pos;
-    byte_offset = malloc(sizeof(char) * (len + 1));
-    strncpy(byte_offset, last_pos, len);
-
-    // Parse the bit_offset
-    if (*cur_pos == '.') {
-      cur_pos++;
-      // Next comes the byte_offset
-      last_pos = cur_pos;
-      while (isdigit(*cur_pos)) {
-        cur_pos++;
-      }
-      len = cur_pos - last_pos;
-      bit_offset = malloc(sizeof(char) * (len + 1));
-      strncpy(bit_offset, last_pos, len);
-    }
-
-    // Skip the ":" char.
-    cur_pos++;
-
-    // Next comes the data_type
-    last_pos = cur_pos;
-    while (isalpha(*cur_pos)) {
-      cur_pos++;
-    }
-    len = cur_pos - last_pos;
-    data_type = malloc(sizeof(char) * (len + 1));
-    strncpy(data_type, last_pos, len);
-
-    if ((*cur_pos == '(') && (strcmp(data_type, "STRING"))) {
-      // Next comes the string_length
-      last_pos = cur_pos;
-      while (isalpha(*cur_pos)) {
-        cur_pos++;
-      }
-      len = cur_pos - last_pos;
-      string_length = malloc(sizeof(char) * (len + 1));
-      strncpy(string_length, last_pos, len);
-
-      // Skip the ")"
-      cur_pos++;
-    }
-
-    if (*cur_pos == '[') {
-      // Next comes the num_elements
-      cur_pos++;
-      last_pos = cur_pos;
-      while (isdigit(*cur_pos)) {
-        cur_pos++;
-      }
-      len = cur_pos - last_pos;
-      num_elements = malloc(sizeof(char) * (len + 1));
-      strncpy(num_elements, last_pos, len);
-    }
-
-    ////////////////////////////////////////////////////////////////////////////
-    // Now parse the contents.
-    ////////////////////////////////////////////////////////////////////////////
-
-    plc4c_s7_read_write_s7_address* any_address = malloc(sizeof(plc4c_s7_read_write_s7_address));
-
-    for(int i = 0; i < plc4c_s7_read_write_memory_area_num_values(); i++) {
-      plc4c_s7_read_write_memory_area ma = plc4c_s7_read_write_memory_area_value_for_index(i);
-      if(strcmp(plc4c_s7_read_write_memory_area_get_short_name(ma), memory_area) == 0) {
-        any_address->s7_address_any_area = ma;
-        break;
-      }
-    }
-
-    if (block_number != NULL) {
-      any_address->s7_address_any_db_number = strtol(block_number, 0, 10);
-    } else {
-      any_address->s7_address_any_db_number = 0;
-    }
-
-    any_address->s7_address_any_byte_address = strtol(byte_offset, 0, 10);
-
-    if (bit_offset != NULL) {
-      any_address->s7_address_any_bit_address = strtol(bit_offset, 0, 10);
-    } else {
-      any_address->s7_address_any_bit_address = 0;
-    }
-
-    any_address->s7_address_any_transport_size =
-        plc4c_s7_read_write_transport_size_value_of(data_type);
-
-    if (num_elements != NULL) {
-      any_address->s7_address_any_number_of_elements =
-          strtol(num_elements, 0, 10);
-    } else {
-      any_address->s7_address_any_number_of_elements = 1;
-    }
-
-    if (any_address->s7_address_any_transport_size ==
-         plc4c_s7_read_write_transport_size_STRING) {
-      if (string_length != NULL) {
-        any_address->s7_address_any_number_of_elements =
-            strtol(string_length, 0, 10) *
-                any_address->s7_address_any_number_of_elements;
-      } else if (any_address->s7_address_any_transport_size ==
-                 plc4c_s7_read_write_transport_size_STRING) {
-        any_address->s7_address_any_number_of_elements =
-            254 * any_address->s7_address_any_number_of_elements;
-      }
-    }
-
-    // Check the optional transport size code.
-    if(transfer_size_code != NULL) {
-      if(plc4c_s7_read_write_transport_size_get_size_code(any_address->s7_address_any_transport_size) != *transfer_size_code) {
-        return INVALID_ADDRESS;
-      }
-    }
-
-    (*item)->s7_var_request_parameter_item_address_address = any_address;
-  }
-  // - Else -> PLC_PROXY_ADDRESS_PATTERN
-  else {
-    //   - parse the sequence of 2 digit Hex numbers into an array of 10 bytes
-    uint8_t* raw_data = malloc(sizeof(uint8_t) * 10);
-    if (raw_data == NULL) {
-      return NO_MEMORY;
-    }
-    cur_pos += 2;
-    for (int i = 0; i < 10; i++) {
-      plc4c_return_code return_code =
-          decode_byte(last_pos, cur_pos, raw_data + i);
-      if (return_code != OK) {
-        return return_code;
-      }
-      if (i < 9) {
-        if (*cur_pos != '-') {
-          return INVALID_ADDRESS;
-        }
-        // Move to the next segment.
-        last_pos += 3;
-        cur_pos += 3;
-      }
-    }
-    //   - create a plc4c_spi_read_buffer from the 10 byte array
-    plc4c_spi_read_buffer* read_buffer;
-    plc4c_return_code return_code =
-        plc4c_spi_read_buffer_create(raw_data, 10, &read_buffer);
-    if (return_code != OK) {
-      return return_code;
-    }
-    //   - plc4c_s7_read_write_s7_var_request_parameter_item_parse function to
-    //   parse the byte array
-    //   - directly add the resulting struct to the request
-    plc4c_s7_read_write_s7_address_parse(
-        read_buffer, &(*item)->s7_var_request_parameter_item_address_address);
-  }
-
-  return OK;
-}
-
-plc4c_return_code createS7WriteRequest(
-    plc4c_write_request* write_request,
-    plc4c_s7_read_write_tpkt_packet** s7_write_request_packet) {
-  return OK;
-}
diff --git a/sandbox/plc4c/drivers/s7/src/driver_s7_encode_decode.c b/sandbox/plc4c/drivers/s7/src/driver_s7_encode_decode.c
new file mode 100644
index 0000000..5ee6966
--- /dev/null
+++ b/sandbox/plc4c/drivers/s7/src/driver_s7_encode_decode.c
@@ -0,0 +1,339 @@
+/*
+  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 permiSchreib' missions and limitations
+  under the License.
+*/
+
+#include <cotp_protocol_class.h>
+#include <ctype.h>
+#include <plc4c/driver_s7.h>
+#include <plc4c/spi/types_private.h>
+#include <stdlib.h>
+#include <string.h>
+#include <tpkt_packet.h>
+
+uint16_t plc4c_driver_s7_encode_tsap_id(
+    plc4c_driver_s7_device_group device_group, uint8_t rack, uint8_t slot) {
+  return (device_group << 8) |
+         ((uint16_t) ((uint16_t) rack & (uint16_t) 0x000F) << (uint16_t) 4) |
+         ((uint16_t) slot & (uint16_t) 0x000F);
+}
+
+uint16_t plc4c_driver_s7_get_nearest_matching_tpdu_size(uint16_t pdu_size) {
+  for (int i = 0; i < plc4c_s7_read_write_cotp_tpdu_size_num_values(); i++) {
+    uint16_t cur_value =
+        plc4c_s7_read_write_cotp_tpdu_size_get_size_in_bytes(i);
+    if (cur_value >= pdu_size) {
+      return cur_value;
+    }
+  }
+  return 0;
+}
+
+plc4c_driver_s7_controller_type decode_controller_type(char* article_number) {
+  char* prefix = "6ES7 ";
+  // If this article-number doesn't start with this prefix, we can't decode it.
+  if (strncmp(prefix, article_number, strlen(prefix)) != 0) {
+    return PLC4C_DRIVER_S7_CONTROLLER_TYPE_ANY;
+  }
+  char model = *(article_number + 5);
+  switch (model) {
+    case 2:
+      return PLC4C_DRIVER_S7_CONTROLLER_TYPE_S7_1200;
+    case 5:
+      return PLC4C_DRIVER_S7_CONTROLLER_TYPE_S7_1500;
+    case 3:
+      return PLC4C_DRIVER_S7_CONTROLLER_TYPE_S7_300;
+    case 4:
+      return PLC4C_DRIVER_S7_CONTROLLER_TYPE_S7_400;
+    default:
+      return PLC4C_DRIVER_S7_CONTROLLER_TYPE_ANY;
+  }
+}
+
+int8_t decode_hex_char(char c) {
+  if (('0' <= c) && (c <= '9')) {
+    return c - 48;
+  }
+  if (('A' <= c) && (c <= 'D')) {
+    return c - 55;
+  }
+  return -1;
+}
+
+plc4c_return_code decode_byte(const char* from_ptr, const char* to_ptr, uint8_t* value) {
+  if (to_ptr - from_ptr != 2) {
+    return INTERNAL_ERROR;
+  }
+
+  int8_t first_char = decode_hex_char(*from_ptr);
+  int8_t second_char = decode_hex_char(*(from_ptr + 1));
+  if ((first_char == -1) || (second_char == -1)) {
+    return INTERNAL_ERROR;
+  }
+  *value = ((uint8_t) ((uint8_t) first_char << (uint8_t) 4)) | (uint8_t) second_char;
+  return OK;
+}
+
+plc4c_return_code parseAddress(
+    char* address, plc4c_s7_read_write_s7_var_request_parameter_item** item) {
+
+  *item = malloc(sizeof(plc4c_s7_read_write_s7_var_request_parameter_item));
+  (*item)->_type =
+      plc4c_s7_read_write_s7_var_request_parameter_item_type_plc4c_s7_read_write_s7_var_request_parameter_item_address;
+
+  // Java Regexp:
+  // ADDRESS_PATTERN =
+  // ^%(?<memoryArea>.)(?<transferSizeCode>[XBWD]?)(?<byteOffset>\d{1,7})(.(?<bitOffset>[0-7]))?:(?<dataType>[a-zA-Z_]+)(\[(?<numElements>\d+)])?
+  // DATA_BLOCK_ADDRESS_PATTERN =
+  // ^%DB(?<blockNumber>\d{1,5}).DB(?<transferSizeCode>[XBWD]?)(?<byteOffset>\d{1,7})(.(?<bitOffset>[0-7]))?:(?<dataType>[a-zA-Z_]+)(\[(?<numElements>\d+)])?
+  // DATA_BLOCK_SHORT_PATTERN =
+  // ^%DB(?<blockNumber>\d{1,5}).(?<byteOffset>\d{1,7})(.(?<bitOffset>[0-7]))?:(?<dataType>[a-zA-Z_]+)(\[(?<numElements>\d+)])?
+  // DATA_BLOCK_STRING_ADDRESS_PATTERN =
+  // ^%DB(?<blockNumber>\d{1,5}).DB(?<transferSizeCode>[XBWD]?)(?<byteOffset>\d{1,7}):STRING\((?<stringLength>\d{1,3})\)(\[(?<numElements>\d+)])?
+  // DATA_BLOCK_STRING_SHORT_PATTERN =
+  // ^%DB(?<blockNumber>\d{1,5}):(?<byteOffset>\d{1,7}):STRING\((?<stringLength>\d{1,3})\)(\[(?<numElements>\d+)])?
+  // PLC_PROXY_ADDRESS_PATTERN =
+  // [0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2}-[0-9A-F]{2}
+
+  // Parser logic
+  char* cur_pos = address;
+  char* last_pos = address;
+  // - Does it start with "%"?
+  if (*cur_pos == '%') {
+    cur_pos++;
+
+    char* memory_area = NULL;
+    char* block_number = NULL;
+    char* transfer_size_code = NULL;
+    char* byte_offset = NULL;
+    char* bit_offset = NULL;
+    char* data_type = NULL;
+    char* string_length = NULL;
+    char* num_elements = NULL;
+
+    ////////////////////////////////////////////////////////////////////////////
+    // First extract the different parts of the address
+    ////////////////////////////////////////////////////////////////////////////
+
+    if (!isalpha(*cur_pos)) {
+      return INVALID_ADDRESS;
+    }
+
+    last_pos = cur_pos;
+    while (isalpha(*cur_pos)) {
+      cur_pos++;
+    }
+    uint16_t len = cur_pos - last_pos;
+    memory_area = malloc(sizeof(char) * (len + 1));
+    strncpy(memory_area, last_pos, len);
+    //*(memory_area + len + 1) = '/0';
+
+    // If it's a DB-block, get the block_number
+    if (strcmp(memory_area, "DB") == 0) {
+      last_pos = cur_pos;
+      while (isdigit(*cur_pos)) {
+        cur_pos++;
+      }
+      len = cur_pos - last_pos;
+      block_number = malloc(sizeof(char) * (len + 1));
+      strncpy(block_number, last_pos, len);
+
+      // Skip the "."
+      cur_pos++;
+    }
+
+    // If the next is not a digit it might be DB, DB{transferSizeCode}
+    // or {transferSizeCode}
+    if (!isdigit(*cur_pos)) {
+      last_pos = cur_pos;
+      while (!isdigit(*cur_pos)) {
+        cur_pos++;
+      }
+      len = cur_pos - last_pos;
+      // If it's at least 2 digits long, it's DB{transferSizeCode} or
+      // "DB". So we get rid of the "DB" prefix, as this has no value for us.
+      if (len >= 2) {
+        last_pos += 2;
+      }
+      // If it's 1 or 3 long it contains a "transferSizeCode", which is just
+      // one char long.
+      if ((len == 1) || (len == 3)) {
+        transfer_size_code = malloc(sizeof(char) * 2);
+        *transfer_size_code = *last_pos;
+        *(transfer_size_code + 1) = '\0';
+      }
+    }
+
+    // Next comes the byte_offset
+    last_pos = cur_pos;
+    while (isdigit(*cur_pos)) {
+      cur_pos++;
+    }
+    len = cur_pos - last_pos;
+    byte_offset = malloc(sizeof(char) * (len + 1));
+    strncpy(byte_offset, last_pos, len);
+
+    // Parse the bit_offset
+    if (*cur_pos == '.') {
+      cur_pos++;
+      // Next comes the byte_offset
+      last_pos = cur_pos;
+      while (isdigit(*cur_pos)) {
+        cur_pos++;
+      }
+      len = cur_pos - last_pos;
+      bit_offset = malloc(sizeof(char) * (len + 1));
+      strncpy(bit_offset, last_pos, len);
+    }
+
+    // Skip the ":" char.
+    cur_pos++;
+
+    // Next comes the data_type
+    last_pos = cur_pos;
+    while (isalpha(*cur_pos)) {
+      cur_pos++;
+    }
+    len = cur_pos - last_pos;
+    data_type = malloc(sizeof(char) * (len + 1));
+    strncpy(data_type, last_pos, len);
+
+    if ((*cur_pos == '(') && (strcmp(data_type, "STRING") == 0)) {
+      // Next comes the string_length
+      last_pos = cur_pos;
+      while (isalpha(*cur_pos)) {
+        cur_pos++;
+      }
+      len = cur_pos - last_pos;
+      string_length = malloc(sizeof(char) * (len + 1));
+      strncpy(string_length, last_pos, len);
+
+      // Skip the ")"
+      cur_pos++;
+    }
+
+    if (*cur_pos == '[') {
+      // Next comes the num_elements
+      cur_pos++;
+      last_pos = cur_pos;
+      while (isdigit(*cur_pos)) {
+        cur_pos++;
+      }
+      len = cur_pos - last_pos;
+      num_elements = malloc(sizeof(char) * (len + 1));
+      strncpy(num_elements, last_pos, len);
+    }
+
+    ////////////////////////////////////////////////////////////////////////////
+    // Now parse the contents.
+    ////////////////////////////////////////////////////////////////////////////
+
+    plc4c_s7_read_write_s7_address* any_address = malloc(sizeof(plc4c_s7_read_write_s7_address));
+
+    for(int i = 0; i < plc4c_s7_read_write_memory_area_num_values(); i++) {
+      plc4c_s7_read_write_memory_area ma = plc4c_s7_read_write_memory_area_value_for_index(i);
+      if(strcmp(plc4c_s7_read_write_memory_area_get_short_name(ma), memory_area) == 0) {
+        any_address->s7_address_any_area = ma;
+        break;
+      }
+    }
+
+    if (block_number != NULL) {
+      any_address->s7_address_any_db_number = strtol(block_number, 0, 10);
+    } else {
+      any_address->s7_address_any_db_number = 0;
+    }
+
+    any_address->s7_address_any_byte_address = strtol(byte_offset, 0, 10);
+
+    if (bit_offset != NULL) {
+      any_address->s7_address_any_bit_address = strtol(bit_offset, 0, 10);
+    } else {
+      any_address->s7_address_any_bit_address = 0;
+    }
+
+    any_address->s7_address_any_transport_size =
+        plc4c_s7_read_write_transport_size_value_of(data_type);
+
+    if (num_elements != NULL) {
+      any_address->s7_address_any_number_of_elements =
+          strtol(num_elements, 0, 10);
+    } else {
+      any_address->s7_address_any_number_of_elements = 1;
+    }
+
+    if (any_address->s7_address_any_transport_size ==
+         plc4c_s7_read_write_transport_size_STRING) {
+      if (string_length != NULL) {
+        any_address->s7_address_any_number_of_elements =
+            strtol(string_length, 0, 10) *
+                any_address->s7_address_any_number_of_elements;
+      } else if (any_address->s7_address_any_transport_size ==
+                 plc4c_s7_read_write_transport_size_STRING) {
+        any_address->s7_address_any_number_of_elements =
+            254 * any_address->s7_address_any_number_of_elements;
+      }
+    }
+
+    // Check the optional transport size code.
+    if(transfer_size_code != NULL) {
+      if(plc4c_s7_read_write_transport_size_get_size_code(any_address->s7_address_any_transport_size) != *transfer_size_code) {
+        return INVALID_ADDRESS;
+      }
+    }
+
+    (*item)->s7_var_request_parameter_item_address_address = any_address;
+  }
+  // - Else -> PLC_PROXY_ADDRESS_PATTERN
+  else {
+    //   - parse the sequence of 2 digit Hex numbers into an array of 10 bytes
+    uint8_t* raw_data = malloc(sizeof(uint8_t) * 10);
+    if (raw_data == NULL) {
+      return NO_MEMORY;
+    }
+    cur_pos += 2;
+    for (int i = 0; i < 10; i++) {
+      plc4c_return_code return_code =
+          decode_byte(last_pos, cur_pos, raw_data + i);
+      if (return_code != OK) {
+        return return_code;
+      }
+      if (i < 9) {
+        if (*cur_pos != '-') {
+          return INVALID_ADDRESS;
+        }
+        // Move to the next segment.
+        last_pos += 3;
+        cur_pos += 3;
+      }
+    }
+    //   - create a plc4c_spi_read_buffer from the 10 byte array
+    plc4c_spi_read_buffer* read_buffer;
+    plc4c_return_code return_code =
+        plc4c_spi_read_buffer_create(raw_data, 10, &read_buffer);
+    if (return_code != OK) {
+      return return_code;
+    }
+    //   - plc4c_s7_read_write_s7_var_request_parameter_item_parse function to
+    //   parse the byte array
+    //   - directly add the resulting struct to the request
+    plc4c_s7_read_write_s7_address_parse(
+        read_buffer, &(*item)->s7_var_request_parameter_item_address_address);
+  }
+
+  return OK;
+}
diff --git a/sandbox/plc4c/drivers/s7/src/driver_s7_packets.c b/sandbox/plc4c/drivers/s7/src/driver_s7_packets.c
new file mode 100644
index 0000000..6337cd8
--- /dev/null
+++ b/sandbox/plc4c/drivers/s7/src/driver_s7_packets.c
@@ -0,0 +1,443 @@
+/*
+  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 permiSchreib' missions and limitations
+  under the License.
+*/
+
+#include <cotp_protocol_class.h>
+#include <ctype.h>
+#include <plc4c/driver_s7.h>
+#include <plc4c/spi/types_private.h>
+#include <stdlib.h>
+#include <string.h>
+#include <tpkt_packet.h>
+
+#include "plc4c/driver_s7_encode_decode.h"
+
+int16_t plc4c_driver_s7_select_message_function(uint8_t* buffer_data,
+                                                uint16_t buffer_length) {
+  // If the packet doesn't start with 0x03, it's a corrupt package.
+  if (buffer_length >= 1) {
+    // The buffer seems to be corrupt, try to find a sequence of 0x03 0x00
+    // and return the negative number of bytes needed to find that or the
+    // number of bytes in the buffer so it will simply clean the buffer
+    // completely.
+    if (*buffer_data != 0x03) {
+      for (int i = 1; i < (buffer_length - 1); i++) {
+        buffer_data++;
+        if ((*buffer_data == 0x03) && (*(buffer_data + 1) == 0x00)) {
+          // We've found a potential new packet start.
+          return -(i - 1);
+        }
+      }
+      // We didn't find a new start, delete the entire content except the last
+      // byte (as this could be the start of the next frame and we couldn't
+      // confirm this.
+      return -(buffer_length - 1);
+    }
+  }
+  // The length information is located in bytes 3 and 4
+  if (buffer_length >= 4) {
+    uint16_t packet_length =
+        ((uint16_t) (buffer_data + 2) << 8) |
+        ((uint16_t) (buffer_data + 3));
+    if (buffer_length >= packet_length) {
+      return packet_length;
+    }
+    // 8192 is the maximum pdu size, so if the value is larger, the packet is
+    // probably corrupt.
+    if (packet_length > 8192) {
+      for (int i = 1; i < (buffer_length - 1); i++) {
+        buffer_data++;
+        if ((*buffer_data == 0x03) && (*(buffer_data + 1) == 0x00)) {
+          // We've found a potential new packet start.
+          return -(i - 1);
+        }
+      }
+      return -(buffer_length - 1);
+    }
+  }
+  // In all other cases, we'll just have to wait for the next time.
+  return 0;
+}
+
+plc4c_return_code send_packet(plc4c_connection* connection,
+                              plc4c_s7_read_write_tpkt_packet* packet) {
+  // Get the size required to contain the serialized form of this packet.
+  uint16_t packet_size =
+      plc4c_s7_read_write_tpkt_packet_length_in_bytes(packet);
+
+  // Serialize this message to a byte-array.
+  plc4c_spi_write_buffer* write_buffer;
+  plc4c_return_code return_code =
+      plc4c_spi_write_buffer_create(packet_size, &write_buffer);
+  if (return_code != OK) {
+    return return_code;
+  }
+  plc4c_s7_read_write_tpkt_packet_serialize(write_buffer, packet);
+
+  // Now send this to the recipient.
+  return_code = connection->transport->send_message(write_buffer);
+  if (return_code != OK) {
+    return return_code;
+  }
+
+  return OK;
+}
+
+plc4c_return_code receive_packet(plc4c_connection* connection,
+                                 plc4c_s7_read_write_tpkt_packet** packet) {
+  // Get a response from the transport.
+  plc4c_spi_read_buffer* read_buffer;
+  plc4c_return_code return_code = connection->transport->select_message(
+      plc4c_driver_s7_select_message_function, &read_buffer);
+  if (return_code != OK) {
+    return return_code;
+  }
+
+  // Parse the given data.
+  *packet = NULL;
+  return_code = plc4c_s7_read_write_tpkt_packet_parse(read_buffer, packet);
+  if (return_code != OK) {
+    return return_code;
+  }
+
+  return OK;
+}
+
+plc4c_return_code createCOTPConnectionRequest(
+    plc4c_driver_s7_config* configuration,
+    plc4c_s7_read_write_tpkt_packet** cotp_connect_request_packet) {
+  *cotp_connect_request_packet =
+      malloc(sizeof(plc4c_s7_read_write_tpkt_packet));
+  if (*cotp_connect_request_packet == NULL) {
+    return NO_MEMORY;
+  }
+  (*cotp_connect_request_packet)->payload =
+      malloc(sizeof(plc4c_s7_read_write_cotp_packet));
+  if ((*cotp_connect_request_packet)->payload == NULL) {
+    return NO_MEMORY;
+  }
+  (*cotp_connect_request_packet)->payload->_type =
+      plc4c_s7_read_write_cotp_packet_type_plc4c_s7_read_write_cotp_packet_connection_request;
+  (*cotp_connect_request_packet)
+      ->payload->cotp_packet_connection_request_destination_reference = 0x0000;
+  (*cotp_connect_request_packet)
+      ->payload->cotp_packet_connection_request_source_reference = 0x000F;
+  (*cotp_connect_request_packet)
+      ->payload->cotp_packet_connection_request_protocol_class =
+      plc4c_s7_read_write_cotp_protocol_class_CLASS_0;
+
+  // Add the COTP parameters: Called TSAP, Calling TSAP and TPDU Size.
+  plc4c_utils_list_create(
+      &((*cotp_connect_request_packet)->payload->parameters));
+  plc4c_s7_read_write_cotp_parameter* called_tsap_parameter =
+      malloc(sizeof(plc4c_s7_read_write_cotp_parameter));
+  if (called_tsap_parameter == NULL) {
+    return NO_MEMORY;
+  }
+  called_tsap_parameter->_type =
+      plc4c_s7_read_write_cotp_parameter_type_plc4c_s7_read_write_cotp_parameter_called_tsap;
+  called_tsap_parameter->cotp_parameter_called_tsap_tsap_id =
+      configuration->called_tsap_id;
+
+  plc4c_utils_list_insert_head_value(
+      (*cotp_connect_request_packet)->payload->parameters,
+      called_tsap_parameter);
+  plc4c_s7_read_write_cotp_parameter* calling_tsap_parameter =
+      malloc(sizeof(plc4c_s7_read_write_cotp_parameter));
+  if (calling_tsap_parameter == NULL) {
+    return NO_MEMORY;
+  }
+  calling_tsap_parameter->_type =
+      plc4c_s7_read_write_cotp_parameter_type_plc4c_s7_read_write_cotp_parameter_calling_tsap;
+  calling_tsap_parameter->cotp_parameter_calling_tsap_tsap_id =
+      configuration->calling_tsap_id;
+
+  plc4c_utils_list_insert_head_value(
+      (*cotp_connect_request_packet)->payload->parameters,
+      calling_tsap_parameter);
+  plc4c_s7_read_write_cotp_parameter* tpdu_size_parameter =
+      malloc(sizeof(plc4c_s7_read_write_cotp_parameter));
+  if (tpdu_size_parameter == NULL) {
+    return NO_MEMORY;
+  }
+  tpdu_size_parameter->_type =
+      plc4c_s7_read_write_cotp_parameter_type_plc4c_s7_read_write_cotp_parameter_tpdu_size;
+  tpdu_size_parameter->cotp_parameter_tpdu_size_tpdu_size =
+      configuration->cotp_tpdu_size;
+
+  plc4c_utils_list_insert_head_value(
+      (*cotp_connect_request_packet)->payload->parameters, tpdu_size_parameter);
+
+  // For a COTP connection request, there is no payload.
+  (*cotp_connect_request_packet)->payload->payload = NULL;
+
+  return OK;
+}
+
+plc4c_return_code createS7ConnectionRequest(
+    plc4c_driver_s7_config* configuration,
+    plc4c_s7_read_write_tpkt_packet** s7_connect_request_packet) {
+  *s7_connect_request_packet = malloc(sizeof(plc4c_s7_read_write_tpkt_packet));
+  if (*s7_connect_request_packet == NULL) {
+    return NO_MEMORY;
+  }
+  (*s7_connect_request_packet)->payload =
+      malloc(sizeof(plc4c_s7_read_write_cotp_packet));
+  if ((*s7_connect_request_packet)->payload == NULL) {
+    return NO_MEMORY;
+  }
+  (*s7_connect_request_packet)->payload->_type =
+      plc4c_s7_read_write_cotp_packet_type_plc4c_s7_read_write_cotp_packet_data;
+  (*s7_connect_request_packet)->payload->parameters = NULL;
+  (*s7_connect_request_packet)->payload->cotp_packet_data_eot = true;
+  (*s7_connect_request_packet)->payload->cotp_packet_data_tpdu_ref = 1;
+
+  (*s7_connect_request_packet)->payload->payload =
+      malloc(sizeof(plc4c_s7_read_write_s7_message));
+  if ((*s7_connect_request_packet)->payload->payload == NULL) {
+    return NO_MEMORY;
+  }
+  (*s7_connect_request_packet)->payload->payload->_type =
+      plc4c_s7_read_write_s7_message_type_plc4c_s7_read_write_s7_message_request;
+  (*s7_connect_request_packet)->payload->payload->parameter =
+      malloc(sizeof(plc4c_s7_read_write_s7_parameter));
+  if ((*s7_connect_request_packet)->payload->payload->parameter == NULL) {
+    return NO_MEMORY;
+  }
+  (*s7_connect_request_packet)->payload->payload->parameter->_type =
+      plc4c_s7_read_write_s7_parameter_type_plc4c_s7_read_write_s7_parameter_setup_communication;
+  (*s7_connect_request_packet)
+      ->payload->payload->parameter
+      ->s7_parameter_setup_communication_max_amq_callee =
+      configuration->max_amq_callee;
+  (*s7_connect_request_packet)
+      ->payload->payload->parameter
+      ->s7_parameter_setup_communication_max_amq_caller =
+      configuration->max_amq_caller;
+  (*s7_connect_request_packet)
+      ->payload->payload->parameter
+      ->s7_parameter_setup_communication_pdu_length = configuration->pdu_size;
+
+  return OK;
+}
+
+plc4c_return_code createS7IdentifyRemoteRequest(
+    plc4c_s7_read_write_tpkt_packet** s7_identify_remote_request_packet) {
+  *s7_identify_remote_request_packet =
+      malloc(sizeof(plc4c_s7_read_write_tpkt_packet));
+  if (*s7_identify_remote_request_packet == NULL) {
+    return NO_MEMORY;
+  }
+  (*s7_identify_remote_request_packet)->payload =
+      malloc(sizeof(plc4c_s7_read_write_cotp_packet));
+  if ((*s7_identify_remote_request_packet)->payload == NULL) {
+    return NO_MEMORY;
+  }
+  (*s7_identify_remote_request_packet)->payload->_type =
+      plc4c_s7_read_write_cotp_packet_type_plc4c_s7_read_write_cotp_packet_data;
+  (*s7_identify_remote_request_packet)->payload->parameters = NULL;
+  (*s7_identify_remote_request_packet)->payload->cotp_packet_data_eot = true;
+  (*s7_identify_remote_request_packet)->payload->cotp_packet_data_tpdu_ref = 2;
+
+  (*s7_identify_remote_request_packet)->payload->payload =
+      malloc(sizeof(plc4c_s7_read_write_s7_message));
+  if ((*s7_identify_remote_request_packet)->payload->payload == NULL) {
+    return NO_MEMORY;
+  }
+  (*s7_identify_remote_request_packet)->payload->payload->_type =
+      plc4c_s7_read_write_s7_message_type_plc4c_s7_read_write_s7_message_user_data;
+  (*s7_identify_remote_request_packet)->payload->payload->parameter =
+      malloc(sizeof(plc4c_s7_read_write_s7_parameter));
+  if ((*s7_identify_remote_request_packet)->payload->payload->parameter ==
+      NULL) {
+    return NO_MEMORY;
+  }
+  (*s7_identify_remote_request_packet)->payload->payload->parameter->_type =
+      plc4c_s7_read_write_s7_parameter_type_plc4c_s7_read_write_s7_parameter_user_data;
+
+  plc4c_utils_list_create(
+      &((*s7_identify_remote_request_packet)
+            ->payload->payload->parameter->s7_parameter_user_data_items));
+  plc4c_s7_read_write_s7_parameter_user_data_item* parameter_item =
+      malloc(sizeof(plc4c_s7_read_write_s7_parameter_user_data_item));
+  parameter_item->_type =
+      plc4c_s7_read_write_s7_parameter_user_data_item_type_plc4c_s7_read_write_s7_parameter_user_data_item_cpu_functions;
+  parameter_item->s7_parameter_user_data_item_cpu_functions_method = 0x11;
+  parameter_item->s7_parameter_user_data_item_cpu_functions_cpu_function_type =
+      0x4;
+  parameter_item->s7_parameter_user_data_item_cpu_functions_cpu_function_group =
+      0x4;
+  parameter_item->s7_parameter_user_data_item_cpu_functions_cpu_subfunction =
+      0x01;
+  parameter_item->s7_parameter_user_data_item_cpu_functions_sequence_number =
+      0x00;
+  parameter_item
+      ->s7_parameter_user_data_item_cpu_functions_data_unit_reference_number =
+      NULL;
+  parameter_item->s7_parameter_user_data_item_cpu_functions_last_data_unit =
+      NULL;
+  parameter_item->s7_parameter_user_data_item_cpu_functions_error_code = NULL;
+  plc4c_utils_list_insert_head_value(
+      (*s7_identify_remote_request_packet)
+          ->payload->payload->parameter->s7_parameter_user_data_items,
+      parameter_item);
+
+  plc4c_utils_list_create(
+      &((*s7_identify_remote_request_packet)
+            ->payload->payload->payload->s7_payload_user_data_items));
+  plc4c_s7_read_write_s7_payload_user_data_item* payload_item =
+      malloc(sizeof(plc4c_s7_read_write_s7_payload_user_data_item));
+  payload_item->_type =
+      plc4c_s7_read_write_s7_payload_user_data_item_type_plc4c_s7_read_write_s7_payload_user_data_item_cpu_function_read_szl_request;
+  payload_item->return_code = plc4c_s7_read_write_data_transport_error_code_OK;
+  payload_item->transport_size =
+      plc4c_s7_read_write_data_transport_size_OCTET_STRING;
+  payload_item->szl_index = 0x0000;
+  payload_item->szl_id = malloc(sizeof(plc4c_s7_read_write_szl_id));
+  if (payload_item->szl_id == NULL) {
+    return NO_MEMORY;
+  }
+  payload_item->szl_id->type_class =
+      plc4c_s7_read_write_szl_module_type_class_CPU;
+  payload_item->szl_id->sublist_extract = 0x00;
+  payload_item->szl_id->sublist_list =
+      plc4c_s7_read_write_szl_sublist_MODULE_IDENTIFICATION;
+
+  return OK;
+}
+
+plc4c_return_code createS7ReadRequest(
+    plc4c_read_request* read_request,
+    plc4c_s7_read_write_tpkt_packet** s7_read_request_packet) {
+  plc4c_driver_s7_config* configuration =
+      read_request->connection->configuration;
+
+  *s7_read_request_packet = malloc(sizeof(s7_read_request_packet));
+  if (*s7_read_request_packet == NULL) {
+    return NO_MEMORY;
+  }
+
+  (*s7_read_request_packet)->payload =
+      malloc(sizeof(plc4c_s7_read_write_cotp_packet));
+  (*s7_read_request_packet)->payload->_type =
+      plc4c_s7_read_write_cotp_packet_type_plc4c_s7_read_write_cotp_packet_data;
+  (*s7_read_request_packet)->payload->cotp_packet_data_tpdu_ref =
+      configuration->pdu_id++;
+  (*s7_read_request_packet)->payload->cotp_packet_data_eot = true;
+  (*s7_read_request_packet)->payload->payload =
+      malloc(sizeof(plc4c_s7_read_write_s7_message));
+  (*s7_read_request_packet)->payload->payload->_type =
+      plc4c_s7_read_write_s7_message_type_plc4c_s7_read_write_s7_message_request;
+  (*s7_read_request_packet)->payload->payload->parameter =
+      malloc(sizeof(plc4c_s7_read_write_s7_parameter));
+  (*s7_read_request_packet)->payload->payload->parameter->_type =
+      plc4c_s7_read_write_s7_parameter_type_plc4c_s7_read_write_s7_parameter_read_var_request;
+  plc4c_utils_list_create(
+      &(*s7_read_request_packet)
+           ->payload->payload->parameter->s7_parameter_read_var_request_items);
+
+  plc4c_list_element* item = read_request->items->tail;
+  while (item != NULL) {
+    // Get the item address from the API request.
+    char* itemAddress = item->value;
+
+    // Create the item ...
+    plc4c_s7_read_write_s7_var_request_parameter_item* request_item;
+    plc4c_return_code return_code = parseAddress(itemAddress, &request_item);
+    if (return_code != OK) {
+      return return_code;
+    }
+
+    // Add the new item to the request.
+    plc4c_utils_list_insert_head_value(
+        (*s7_read_request_packet)
+            ->payload->payload->parameter->s7_parameter_read_var_request_items,
+        request_item);
+
+    item = item->next;
+  }
+
+  return OK;
+}
+
+plc4c_return_code createS7WriteRequest(
+    plc4c_write_request* write_request,
+    plc4c_s7_read_write_tpkt_packet** s7_write_request_packet) {
+  plc4c_driver_s7_config* configuration =
+      write_request->connection->configuration;
+
+  *s7_write_request_packet = malloc(sizeof(s7_write_request_packet));
+  if (*s7_write_request_packet == NULL) {
+    return NO_MEMORY;
+  }
+
+  (*s7_write_request_packet)->payload =
+      malloc(sizeof(plc4c_s7_read_write_cotp_packet));
+  (*s7_write_request_packet)->payload->_type =
+      plc4c_s7_read_write_cotp_packet_type_plc4c_s7_read_write_cotp_packet_data;
+  (*s7_write_request_packet)->payload->cotp_packet_data_tpdu_ref =
+      configuration->pdu_id++;
+  (*s7_write_request_packet)->payload->cotp_packet_data_eot = true;
+  (*s7_write_request_packet)->payload->payload =
+      malloc(sizeof(plc4c_s7_read_write_s7_message));
+  (*s7_write_request_packet)->payload->payload->_type =
+      plc4c_s7_read_write_s7_message_type_plc4c_s7_read_write_s7_message_request;
+  (*s7_write_request_packet)->payload->payload->parameter =
+      malloc(sizeof(plc4c_s7_read_write_s7_parameter));
+  (*s7_write_request_packet)->payload->payload->parameter->_type =
+      plc4c_s7_read_write_s7_parameter_type_plc4c_s7_read_write_s7_parameter_write_var_request;
+  plc4c_utils_list_create(
+      &(*s7_write_request_packet)
+          ->payload->payload->parameter->s7_parameter_read_var_request_items);
+
+  plc4c_list_element* item = write_request->items->tail;
+  while (item != NULL) {
+    // Get the item address from the API request.
+    char* itemAddress = item->value;
+
+    // Create the item ...
+    plc4c_s7_read_write_s7_var_request_parameter_item* request_item;
+    plc4c_return_code return_code = parseAddress(itemAddress, &request_item);
+    if (return_code != OK) {
+      return return_code;
+    }
+
+    // Add the new item to the request.
+    plc4c_utils_list_insert_head_value(
+        (*s7_write_request_packet)
+            ->payload->payload->parameter->s7_parameter_read_var_request_items,
+        request_item);
+
+    item = item->next;
+  }
+
+  (*s7_write_request_packet)->payload->payload->payload =
+      malloc(sizeof(plc4c_s7_read_write_s7_payload));
+  if((*s7_write_request_packet)->payload->payload->payload == NULL) {
+    return NO_MEMORY;
+  }
+  (*s7_write_request_packet)->payload->payload->payload->_type =
+      plc4c_s7_read_write_s7_payload_type_plc4c_s7_read_write_s7_payload_write_var_request;
+  plc4c_utils_list_create(
+      &(*s7_write_request_packet)->payload->payload->payload->s7_payload_write_var_request_items);
+
+  // TODO: Implement the value encoding ...
+  // TODO: Add all the encoded item values ...
+
+  return OK;
+}
diff --git a/sandbox/plc4c/drivers/s7/src/driver_s7_sm_connect.c b/sandbox/plc4c/drivers/s7/src/driver_s7_sm_connect.c
new file mode 100644
index 0000000..04d3a19
--- /dev/null
+++ b/sandbox/plc4c/drivers/s7/src/driver_s7_sm_connect.c
@@ -0,0 +1,333 @@
+/*
+  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 permiSchreib' missions and limitations
+  under the License.
+*/
+
+#include <ctype.h>
+#include <plc4c/plc4c.h>
+#include <plc4c/spi/types_private.h>
+#include <stdlib.h>
+#include <string.h>
+#include "plc4c/driver_s7.h"
+#include "plc4c/driver_s7_encode_decode.h"
+#include "plc4c/driver_s7_packets.h"
+#include "cotp_protocol_class.h"
+#include "tpkt_packet.h"
+
+enum plc4c_driver_s7_connect_states {
+  PLC4C_DRIVER_S7_CONNECT_INIT,
+  PLC4C_DRIVER_S7_CONNECT_SEND_COTP_CONNECT_REQUEST,
+  PLC4C_DRIVER_S7_CONNECT_RECEIVE_COTP_CONNECT_RESPONSE,
+  PLC4C_DRIVER_S7_CONNECT_SEND_S7_CONNECT_REQUEST,
+  PLC4C_DRIVER_S7_CONNECT_RECEIVE_S7_CONNECT_RESPONSE,
+  PLC4C_DRIVER_S7_CONNECT_SEND_S7_IDENTIFICATION_REQUEST,
+  PLC4C_DRIVER_S7_CONNECT_RECEIVE_S7_IDENTIFICATION_RESPONSE,
+  PLC4C_DRIVER_S7_CONNECT_FINISHED
+};
+
+/**
+ * State machine function for establishing a connection to a remote S7 device.
+ * @param task the current system task
+ * @return return code of the current state machine step execution
+ */
+plc4c_return_code plc4c_driver_s7_connect_machine_function(
+    plc4c_system_task* task) {
+  plc4c_connection* connection = task->context;
+  if (connection == NULL) {
+    return INTERNAL_ERROR;
+  }
+  // If we were already connected, return an error
+  if (plc4c_connection_get_connected(connection)) {
+    return ALREADY_CONNECTED;
+  }
+  plc4c_driver_s7_config* configuration = connection->configuration;
+
+  // Initialize the pdu id (The first messages are hard-coded)
+  configuration->pdu_id = 4;
+
+  switch (task->state_id) {
+    // Initialize some internal data-structures.
+    case PLC4C_DRIVER_S7_CONNECT_INIT: {
+      // Calculate some internal settings from the values provided in the
+      // configuration.
+      configuration->calling_tsap_id = plc4c_driver_s7_encode_tsap_id(
+          PLC4C_DRIVER_S7_DEVICE_GROUP_OTHERS, configuration->local_rack,
+          configuration->local_slot);
+      configuration->called_tsap_id = plc4c_driver_s7_encode_tsap_id(
+          PLC4C_DRIVER_S7_DEVICE_GROUP_PG_OR_PC, configuration->remote_rack,
+          configuration->remote_slot);
+      configuration->cotp_tpdu_size =
+          plc4c_driver_s7_get_nearest_matching_tpdu_size(
+              configuration->pdu_size);
+      configuration->pdu_size = configuration->cotp_tpdu_size - 16;
+
+      task->state_id = PLC4C_DRIVER_S7_CONNECT_SEND_COTP_CONNECT_REQUEST;
+      break;
+    }
+    // Send a COTP connection request.
+    case PLC4C_DRIVER_S7_CONNECT_SEND_COTP_CONNECT_REQUEST: {
+      // Get a COTP connection response for the settings in the config.
+      plc4c_s7_read_write_tpkt_packet* cotp_connect_request_packet;
+      plc4c_return_code return_code = createCOTPConnectionRequest(
+          configuration, &cotp_connect_request_packet);
+      if (return_code != OK) {
+        return return_code;
+      }
+
+      // Send the packet to the remote.
+      return_code = send_packet(connection, cotp_connect_request_packet);
+      if (return_code != OK) {
+        return return_code;
+      }
+
+      task->state_id = PLC4C_DRIVER_S7_CONNECT_RECEIVE_COTP_CONNECT_RESPONSE;
+      break;
+    }
+    // Receive a COTP connection response.
+    case PLC4C_DRIVER_S7_CONNECT_RECEIVE_COTP_CONNECT_RESPONSE: {
+      // Read a response packet.
+      plc4c_s7_read_write_tpkt_packet* cotp_connect_response_packet;
+      plc4c_return_code return_code =
+          receive_packet(connection, &cotp_connect_response_packet);
+      // If we haven't read enough to process a full message, just try again
+      // next time.
+      if (return_code == UNFINISHED) {
+        return OK;
+      } else if (return_code != OK) {
+        return return_code;
+      }
+
+      // Check if the packet has the right type
+      if (cotp_connect_response_packet->payload->_type !=
+          plc4c_s7_read_write_cotp_packet_type_plc4c_s7_read_write_cotp_packet_connection_response) {
+        return INTERNAL_ERROR;
+      }
+
+      // Extract the information for: called-tsap-id, calling-tsap-id and
+      // tpdu-size.
+      plc4c_list_element* parameter_element =
+          cotp_connect_response_packet->payload->parameters->tail;
+      while (parameter_element != NULL) {
+        plc4c_s7_read_write_cotp_parameter* parameter =
+            parameter_element->value;
+        switch (parameter->_type) {
+          case plc4c_s7_read_write_cotp_parameter_type_plc4c_s7_read_write_cotp_parameter_tpdu_size: {
+            configuration->cotp_tpdu_size =
+                parameter->cotp_parameter_tpdu_size_tpdu_size;
+            break;
+          }
+          case plc4c_s7_read_write_cotp_parameter_type_plc4c_s7_read_write_cotp_parameter_calling_tsap: {
+            configuration->calling_tsap_id =
+                parameter->cotp_parameter_calling_tsap_tsap_id;
+            break;
+          }
+          case plc4c_s7_read_write_cotp_parameter_type_plc4c_s7_read_write_cotp_parameter_called_tsap: {
+            configuration->called_tsap_id =
+                parameter->cotp_parameter_called_tsap_tsap_id;
+            break;
+          }
+          default: {
+            break;
+          }
+        }
+        parameter_element = parameter_element->next;
+      }
+
+      // If we got the expected response, continue with the next higher level
+      // of connection.
+      task->state_id = PLC4C_DRIVER_S7_CONNECT_SEND_S7_CONNECT_REQUEST;
+      break;
+    }
+    // Send a S7 connection request.
+    case PLC4C_DRIVER_S7_CONNECT_SEND_S7_CONNECT_REQUEST: {
+      plc4c_s7_read_write_tpkt_packet* s7_connect_request_packet;
+      plc4c_return_code return_code =
+          createS7ConnectionRequest(configuration, &s7_connect_request_packet);
+      if (return_code != OK) {
+        return return_code;
+      }
+
+      // Send the packet to the remote.
+      return_code = send_packet(connection, s7_connect_request_packet);
+      if (return_code != OK) {
+        return return_code;
+      }
+
+      task->state_id = PLC4C_DRIVER_S7_CONNECT_RECEIVE_S7_CONNECT_RESPONSE;
+      break;
+    }
+    // Receive a S7 connection response.
+    case PLC4C_DRIVER_S7_CONNECT_RECEIVE_S7_CONNECT_RESPONSE: {
+      // Read a response packet.
+      plc4c_s7_read_write_tpkt_packet* s7_connect_response_packet;
+      plc4c_return_code return_code =
+          receive_packet(connection, &s7_connect_response_packet);
+      // If we haven't read enough to process a full message, just try again
+      // next time.
+      if (return_code == UNFINISHED) {
+        return OK;
+      } else if (return_code != OK) {
+        return return_code;
+      }
+
+      // Check if the packet has the right type
+      if (s7_connect_response_packet->payload->_type !=
+          plc4c_s7_read_write_cotp_packet_type_plc4c_s7_read_write_cotp_packet_data) {
+        return INTERNAL_ERROR;
+      }
+      if (s7_connect_response_packet->payload->payload->_type !=
+          plc4c_s7_read_write_s7_message_type_plc4c_s7_read_write_s7_message_response) {
+        return INTERNAL_ERROR;
+      }
+      if (s7_connect_response_packet->payload->payload->parameter->_type !=
+          plc4c_s7_read_write_s7_parameter_type_plc4c_s7_read_write_s7_parameter_setup_communication) {
+        return INTERNAL_ERROR;
+      }
+
+      // Extract and save the information for:
+      // max-amq-caller, max-amq-callee, pdu-size.
+      configuration->pdu_size =
+          s7_connect_response_packet->payload->payload->parameter
+              ->s7_parameter_setup_communication_pdu_length;
+      configuration->max_amq_caller =
+          s7_connect_response_packet->payload->payload->parameter
+              ->s7_parameter_setup_communication_max_amq_caller;
+      configuration->max_amq_callee =
+          s7_connect_response_packet->payload->payload->parameter
+              ->s7_parameter_setup_communication_max_amq_callee;
+
+      // If no controller is explicitly selected, detect it.
+      if (configuration->controller_type !=
+          PLC4C_DRIVER_S7_CONTROLLER_TYPE_ANY) {
+        task->state_id = PLC4C_DRIVER_S7_CONNECT_SEND_S7_IDENTIFICATION_REQUEST;
+      }
+      // If a controller is explicitly selected, we're done connecting.
+      else {
+        task->state_id = PLC4C_DRIVER_S7_CONNECT_FINISHED;
+      }
+      break;
+    }
+    // Send a S7 identification request.
+    case PLC4C_DRIVER_S7_CONNECT_SEND_S7_IDENTIFICATION_REQUEST: {
+      plc4c_s7_read_write_tpkt_packet* s7_identify_remote_request_packet;
+      plc4c_return_code return_code =
+          createS7IdentifyRemoteRequest(&s7_identify_remote_request_packet);
+      if (return_code != OK) {
+        return return_code;
+      }
+
+      // Send the packet to the remote.
+      return_code = send_packet(connection, s7_identify_remote_request_packet);
+      if (return_code != OK) {
+        return return_code;
+      }
+
+      task->state_id =
+          PLC4C_DRIVER_S7_CONNECT_RECEIVE_S7_IDENTIFICATION_RESPONSE;
+      break;
+    }
+    // Receive a S7 identification response.
+    case PLC4C_DRIVER_S7_CONNECT_RECEIVE_S7_IDENTIFICATION_RESPONSE: {
+      // Read a response packet.
+      plc4c_s7_read_write_tpkt_packet* s7_identify_remote_response_packet;
+      plc4c_return_code return_code =
+          receive_packet(connection, &s7_identify_remote_response_packet);
+      // If we haven't read enough to process a full message, just try again
+      // next time.
+      if (return_code == UNFINISHED) {
+        return OK;
+      } else if (return_code != OK) {
+        return return_code;
+      }
+
+      // Check if the packet has the right type
+      if (s7_identify_remote_response_packet->payload->_type !=
+          plc4c_s7_read_write_cotp_packet_type_plc4c_s7_read_write_cotp_packet_data) {
+        return INTERNAL_ERROR;
+      }
+      if (s7_identify_remote_response_packet->payload->payload->_type !=
+          plc4c_s7_read_write_s7_message_type_plc4c_s7_read_write_s7_message_user_data) {
+        return INTERNAL_ERROR;
+      }
+      if (s7_identify_remote_response_packet->payload->payload->payload
+              ->_type !=
+          plc4c_s7_read_write_s7_payload_type_plc4c_s7_read_write_s7_payload_user_data) {
+        return INTERNAL_ERROR;
+      }
+
+      plc4c_list_element* cur_item =
+          s7_identify_remote_response_packet->payload->payload->payload
+              ->s7_payload_user_data_items->tail;
+      while (cur_item != NULL) {
+        plc4c_s7_read_write_s7_payload_user_data_item* item = cur_item->value;
+        if (item->_type ==
+            plc4c_s7_read_write_s7_payload_user_data_item_type_plc4c_s7_read_write_s7_payload_user_data_item_cpu_function_read_szl_response) {
+          plc4c_list_element* szl_item =
+              item->s7_payload_user_data_item_cpu_function_read_szl_response_items
+                  ->head;
+          while (szl_item != NULL) {
+            plc4c_s7_read_write_szl_data_tree_item* data_tree_item =
+                szl_item->value;
+            if (data_tree_item->item_index == 0x0001) {
+              char* article_number = list_to_string(data_tree_item->mlfb);
+              if (article_number != NULL) {
+                configuration->controller_type =
+                    decode_controller_type(article_number);
+                free(article_number);
+              } else {
+                configuration->controller_type =
+                    PLC4C_DRIVER_S7_CONTROLLER_TYPE_ANY;
+              }
+            }
+            szl_item = szl_item->next;
+          }
+        }
+
+        cur_item = cur_item->next;
+      }
+
+      task->state_id = PLC4C_DRIVER_S7_CONNECT_FINISHED;
+      break;
+    }
+    // Clean up some internal data-structures.
+    case PLC4C_DRIVER_S7_CONNECT_FINISHED: {
+      plc4c_connection_set_connected(connection, true);
+      task->completed = true;
+      break;
+    }
+    // If an unexpected state id was received, this is not really something
+    // we can recover from.
+    default: {
+      task->completed = true;
+      return INTERNAL_ERROR;
+    }
+  }
+  return OK;
+}
+
+plc4c_return_code plc4c_driver_s7_connect_function(plc4c_connection* connection,
+                                                   plc4c_system_task** task) {
+  plc4c_system_task* new_task = malloc(sizeof(plc4c_system_task));
+  // There's nothing to do here, so no need for a state-machine.
+  new_task->state_id = PLC4C_DRIVER_S7_CONNECT_INIT;
+  new_task->state_machine_function = &plc4c_driver_s7_connect_machine_function;
+  new_task->completed = false;
+  new_task->context = connection;
+  new_task->connection = connection;
+  *task = new_task;
+  return OK;
+}
diff --git a/sandbox/plc4c/drivers/s7/src/driver_s7_sm_disconnect.c b/sandbox/plc4c/drivers/s7/src/driver_s7_sm_disconnect.c
new file mode 100644
index 0000000..0669ab9
--- /dev/null
+++ b/sandbox/plc4c/drivers/s7/src/driver_s7_sm_disconnect.c
@@ -0,0 +1,81 @@
+/*
+  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 permiSchreib' missions and limitations
+  under the License.
+*/
+
+#include <ctype.h>
+#include <plc4c/plc4c.h>
+#include <plc4c/spi/types_private.h>
+#include <stdlib.h>
+#include <string.h>
+#include "plc4c/driver_s7.h"
+#include "plc4c/driver_s7_encode_decode.h"
+#include "plc4c/driver_s7_packets.h"
+#include "cotp_protocol_class.h"
+#include "tpkt_packet.h"
+
+enum plc4c_driver_s7_disconnect_states {
+  PLC4C_DRIVER_S7_DISCONNECT_INIT,
+  PLC4C_DRIVER_S7_DISCONNECT_WAIT_TASKS_FINISHED,
+  PLC4C_DRIVER_S7_DISCONNECT_FINISHED
+};
+
+plc4c_return_code plc4c_driver_s7_disconnect_machine_function(
+    plc4c_system_task* task) {
+  plc4c_connection* connection = task->context;
+  if (connection == NULL) {
+    return INTERNAL_ERROR;
+  }
+
+  switch (task->state_id) {
+    case PLC4C_DRIVER_S7_DISCONNECT_INIT: {
+      plc4c_connection_set_disconnect(connection, true);
+      task->state_id = PLC4C_DRIVER_S7_DISCONNECT_WAIT_TASKS_FINISHED;
+      break;
+    }
+    case PLC4C_DRIVER_S7_DISCONNECT_WAIT_TASKS_FINISHED: {
+      // The disconnect system-task also counts.
+      if (plc4c_connection_get_running_tasks_count(connection) == 1) {
+        plc4c_connection_set_connected(connection, false);
+        task->completed = true;
+        task->state_id = PLC4C_DRIVER_S7_DISCONNECT_FINISHED;
+      }
+      break;
+    }
+    case PLC4C_DRIVER_S7_DISCONNECT_FINISHED: {
+      // Do nothing
+      break;
+    }
+    default: {
+      return INTERNAL_ERROR;
+    }
+  }
+  return OK;
+}
+
+plc4c_return_code plc4c_driver_s7_disconnect_function(
+    plc4c_connection* connection, plc4c_system_task** task) {
+  plc4c_system_task* new_task = malloc(sizeof(plc4c_system_task));
+  new_task->state_id = PLC4C_DRIVER_S7_DISCONNECT_INIT;
+  new_task->state_machine_function =
+      &plc4c_driver_s7_disconnect_machine_function;
+  new_task->completed = false;
+  new_task->context = connection;
+  new_task->connection = connection;
+  *task = new_task;
+  return OK;
+}
diff --git a/sandbox/plc4c/drivers/s7/src/driver_s7_sm_read.c b/sandbox/plc4c/drivers/s7/src/driver_s7_sm_read.c
new file mode 100644
index 0000000..b855913
--- /dev/null
+++ b/sandbox/plc4c/drivers/s7/src/driver_s7_sm_read.c
@@ -0,0 +1,120 @@
+/*
+  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 permiSchreib' missions and limitations
+  under the License.
+*/
+
+#include <ctype.h>
+#include <plc4c/plc4c.h>
+#include <plc4c/spi/types_private.h>
+#include <stdlib.h>
+#include <string.h>
+#include "plc4c/driver_s7.h"
+#include "plc4c/driver_s7_encode_decode.h"
+#include "plc4c/driver_s7_packets.h"
+#include "cotp_protocol_class.h"
+#include "tpkt_packet.h"
+
+enum plc4c_driver_s7_read_states {
+  PLC4C_DRIVER_S7_READ_INIT,
+  PLC4C_DRIVER_S7_READ_FINISHED
+};
+
+plc4c_return_code plc4c_driver_s7_read_machine_function(
+    plc4c_system_task* task) {
+  plc4c_read_request_execution* read_request_execution = task->context;
+  if (read_request_execution == NULL) {
+    return INTERNAL_ERROR;
+  }
+  plc4c_read_request* read_request = read_request_execution->read_request;
+  if (read_request == NULL) {
+    return INTERNAL_ERROR;
+  }
+  plc4c_connection* connection = task->context;
+  if (connection == NULL) {
+    return INTERNAL_ERROR;
+  }
+
+  switch (task->state_id) {
+    case PLC4C_DRIVER_S7_READ_INIT: {
+      task->completed = true;
+
+      plc4c_s7_read_write_tpkt_packet* s7_read_request_packet;
+      plc4c_return_code return_code =
+          createS7ReadRequest(read_request, &s7_read_request_packet);
+      if (return_code != OK) {
+        return return_code;
+      }
+
+      // Send the packet to the remote.
+      return_code = send_packet(connection, s7_read_request_packet);
+      if (return_code != OK) {
+        return return_code;
+      }
+
+      task->state_id = PLC4C_DRIVER_S7_READ_FINISHED;
+      break;
+    }
+    case PLC4C_DRIVER_S7_READ_FINISHED: {
+      // Read a response packet.
+      plc4c_s7_read_write_tpkt_packet* s7_read_response_packet;
+      plc4c_return_code return_code =
+          receive_packet(connection, &s7_read_response_packet);
+      // If we haven't read enough to process a full message, just try again
+      // next time.
+      if (return_code == UNFINISHED) {
+        return OK;
+      } else if (return_code != OK) {
+        return return_code;
+      }
+
+      // TODO: Check the response ...
+      // TODO: Decode the items in the response ...
+      // TODO: Return the results to the API ...
+
+      task->completed = true;
+      break;
+    }
+  }
+  return OK;
+}
+
+plc4c_return_code plc4c_driver_s7_read_function(
+    plc4c_read_request_execution* read_request_execution,
+    plc4c_system_task** task) {
+  plc4c_system_task* new_task = malloc(sizeof(plc4c_system_task));
+  new_task->state_id = PLC4C_DRIVER_S7_READ_INIT;
+  new_task->state_machine_function = &plc4c_driver_s7_read_machine_function;
+  new_task->completed = false;
+  new_task->context = read_request_execution;
+  new_task->connection = read_request_execution->system_task->connection;
+  *task = new_task;
+  return OK;
+}
+
+void plc4c_driver_s7_free_read_response_item(
+    plc4c_list_element* read_item_element) {
+  plc4c_response_value_item* value_item =
+      (plc4c_response_value_item*)read_item_element->value;
+  plc4c_data_destroy(value_item->value);
+  value_item->value = NULL;
+}
+
+void plc4c_driver_s7_free_read_response(plc4c_read_response* response) {
+  // the request will be cleaned up elsewhere
+  plc4c_utils_list_delete_elements(response->items,
+                                   &plc4c_driver_s7_free_read_response_item);
+}
diff --git a/sandbox/plc4c/drivers/s7/src/driver_s7_sm_write.c b/sandbox/plc4c/drivers/s7/src/driver_s7_sm_write.c
new file mode 100644
index 0000000..ac1c48b
--- /dev/null
+++ b/sandbox/plc4c/drivers/s7/src/driver_s7_sm_write.c
@@ -0,0 +1,123 @@
+/*
+  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 permiSchreib' missions and limitations
+  under the License.
+*/
+
+#include <ctype.h>
+#include <plc4c/plc4c.h>
+#include <plc4c/spi/types_private.h>
+#include <stdlib.h>
+#include <string.h>
+#include "plc4c/driver_s7.h"
+#include "plc4c/driver_s7_encode_decode.h"
+#include "plc4c/driver_s7_packets.h"
+#include "cotp_protocol_class.h"
+#include "tpkt_packet.h"
+
+enum plc4c_driver_s7_write_states {
+  PLC4C_DRIVER_S7_WRITE_INIT,
+  PLC4C_DRIVER_S7_WRITE_FINISHED
+};
+
+plc4c_return_code plc4c_driver_s7_write_machine_function(
+    plc4c_system_task* task) {
+  plc4c_write_request_execution* write_request_execution = task->context;
+  if (write_request_execution == NULL) {
+    return INTERNAL_ERROR;
+  }
+  plc4c_write_request* write_request = write_request_execution->write_request;
+  if (write_request == NULL) {
+    return INTERNAL_ERROR;
+  }
+  plc4c_connection* connection = task->context;
+  if (connection == NULL) {
+    return INTERNAL_ERROR;
+  }
+
+  switch (task->state_id) {
+    case PLC4C_DRIVER_S7_WRITE_INIT: {
+      task->completed = true;
+
+      plc4c_s7_read_write_tpkt_packet* s7_write_request_packet;
+      plc4c_return_code return_code =
+          createS7WriteRequest(write_request, &s7_write_request_packet);
+      if (return_code != OK) {
+        return return_code;
+      }
+
+      // Send the packet to the remote.
+      return_code = send_packet(connection, s7_write_request_packet);
+      if (return_code != OK) {
+        return return_code;
+      }
+
+      task->state_id = PLC4C_DRIVER_S7_WRITE_FINISHED;
+      break;
+    }
+    case PLC4C_DRIVER_S7_WRITE_FINISHED: {
+      // Read a response packet.
+      plc4c_s7_read_write_tpkt_packet* s7_write_response_packet;
+      plc4c_return_code return_code =
+          receive_packet(connection, &s7_write_response_packet);
+      // If we haven't read enough to process a full message, just try again
+      // next time.
+      if (return_code == UNFINISHED) {
+        return OK;
+      } else if (return_code != OK) {
+        return return_code;
+      }
+
+      // TODO: Check the response ...
+      // TODO: Decode the return codes in the response ...
+      // TODO: Return the results to the API ...
+
+      task->completed = true;
+      break;
+    }
+  }
+  return OK;
+}
+
+plc4c_return_code plc4c_driver_s7_write_function(
+    plc4c_write_request_execution* write_request_execution,
+    plc4c_system_task** task) {
+  plc4c_system_task* new_task = malloc(sizeof(plc4c_system_task));
+  new_task->state_id = PLC4C_DRIVER_S7_WRITE_INIT;
+  new_task->state_machine_function = &plc4c_driver_s7_write_machine_function;
+  new_task->completed = false;
+  new_task->context = write_request_execution;
+  new_task->connection = write_request_execution->system_task->connection;
+  *task = new_task;
+  return OK;
+}
+
+void plc4c_driver_s7_free_write_response_item(
+    plc4c_list_element* write_item_element) {
+  plc4c_response_value_item* value_item =
+      (plc4c_response_value_item*)write_item_element->value;
+  // do not delete the plc4c_item
+  // we also, in THIS case don't delete the random value which isn't really
+  // a pointer
+  // free(value_item->value);
+  value_item->value = NULL;
+}
+
+void plc4c_driver_s7_free_write_response(plc4c_write_response* response) {
+  // the request will be cleaned up elsewhere
+  plc4c_utils_list_delete_elements(response->response_items,
+                                   &plc4c_driver_s7_free_write_response_item);
+}
diff --git a/sandbox/plc4c/spi/include/plc4c/spi/types_private.h b/sandbox/plc4c/spi/include/plc4c/spi/types_private.h
index 1ff8d39..af4a762 100644
--- a/sandbox/plc4c/spi/include/plc4c/spi/types_private.h
+++ b/sandbox/plc4c/spi/include/plc4c/spi/types_private.h
@@ -101,7 +101,7 @@ typedef plc4c_return_code (*plc4c_transport_send_message_function)(
 // bytes you get by making the negative value a positive and not returning any
 // read-buffer.
 typedef int16_t (*accept_message_function)(
-    uint8_t* data, uint8_t length);
+    uint8_t* data, uint16_t length);
 
 typedef plc4c_return_code (*plc4c_transport_select_message_function)(
     accept_message_function accept_message, plc4c_spi_read_buffer** message);