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/19 11:07:06 UTC

[plc4x] branch feature/plc4c updated: - Continued implementing the S7 driver

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


The following commit(s) were added to refs/heads/feature/plc4c by this push:
     new 6aa844c  - Continued implementing the S7 driver
6aa844c is described below

commit 6aa844c3d2608f2ef3da725e73000075826b62dd
Author: Christofer Dutz <ch...@c-ware.de>
AuthorDate: Wed Aug 19 13:04:54 2020 +0200

    - Continued implementing the S7 driver
---
 .../resources/templates/c/enum-template-c.ftlh     |   4 +
 .../resources/templates/c/enum-template-h.ftlh     |   2 +
 sandbox/plc4c/drivers/s7/src/driver_s7.c           | 761 ++++++++++++---------
 .../s7/includes/cotp_protocol_class.h              |   2 +
 .../generated-sources/s7/includes/cotp_tpdu_size.h |   2 +
 .../s7/includes/data_transport_error_code.h        |   2 +
 .../s7/includes/data_transport_size.h              |   2 +
 .../generated-sources/s7/includes/device_group.h   |   2 +
 .../generated-sources/s7/includes/memory_area.h    |   2 +
 .../s7/includes/szl_module_type_class.h            |   2 +
 .../generated-sources/s7/includes/szl_sublist.h    |   2 +
 .../generated-sources/s7/includes/transport_size.h |   2 +
 .../generated-sources/s7/src/cotp_protocol_class.c |   4 +
 .../generated-sources/s7/src/cotp_tpdu_size.c      |   4 +
 .../s7/src/data_transport_error_code.c             |   4 +
 .../generated-sources/s7/src/data_transport_size.c |   4 +
 .../plc4c/generated-sources/s7/src/device_group.c  |   4 +
 .../plc4c/generated-sources/s7/src/memory_area.c   |   4 +
 .../s7/src/szl_module_type_class.c                 |   4 +
 .../plc4c/generated-sources/s7/src/szl_sublist.c   |   4 +
 .../generated-sources/s7/src/transport_size.c      |   4 +
 sandbox/plc4c/spi/src/utils/list.c                 |   1 +
 22 files changed, 483 insertions(+), 339 deletions(-)

diff --git a/build-utils/language-c/src/main/resources/templates/c/enum-template-c.ftlh b/build-utils/language-c/src/main/resources/templates/c/enum-template-c.ftlh
index 647a63d..6445cbd 100644
--- a/build-utils/language-c/src/main/resources/templates/c/enum-template-c.ftlh
+++ b/build-utils/language-c/src/main/resources/templates/c/enum-template-c.ftlh
@@ -54,6 +54,10 @@ ${helper.getCTypeName(type.name)} ${helper.getCTypeName(type.name)}_null() {
   return ${helper.getCTypeName(type.name)}_null_const;
 }
 
+int ${helper.getCTypeName(type.name)}_num_values() {
+  return ${type.enumValues?size};
+}
+
 <#--
     If this enum also defines constant values, output one function for each.
     Each of these functions consist of a simple switch statement using the enum as switch-value
diff --git a/build-utils/language-c/src/main/resources/templates/c/enum-template-h.ftlh b/build-utils/language-c/src/main/resources/templates/c/enum-template-h.ftlh
index 65e6b2e..a3fc892 100644
--- a/build-utils/language-c/src/main/resources/templates/c/enum-template-h.ftlh
+++ b/build-utils/language-c/src/main/resources/templates/c/enum-template-h.ftlh
@@ -68,6 +68,8 @@ typedef enum ${helper.getCTypeName(type.name)} ${helper.getCTypeName(type.name)}
 // Get an empty NULL-struct
 ${helper.getCTypeName(type.name)} ${helper.getCTypeName(type.name)}_null();
 
+int ${helper.getCTypeName(type.name)}_num_values();
+
 <#--
     If this enum also defines constant values, output one function for each.
     Each of these functions consist of a simple switch statement using the enum as switch-value
diff --git a/sandbox/plc4c/drivers/s7/src/driver_s7.c b/sandbox/plc4c/drivers/s7/src/driver_s7.c
index 80fad4a..622369b 100644
--- a/sandbox/plc4c/drivers/s7/src/driver_s7.c
+++ b/sandbox/plc4c/drivers/s7/src/driver_s7.c
@@ -17,13 +17,13 @@
   under the License.
 */
 
+#include <cotp_protocol_class.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>
-#include <cotp_protocol_class.h>
 
 // State definitions
 enum plc4c_driver_s7_connect_states {
@@ -53,18 +53,18 @@ enum plc4c_driver_s7_write_states {
   PLC4C_DRIVER_S7_WRITE_FINISHED
 };
 
-int16_t plc4c_driver_s7_select_message_function(
-    uint8_t* buffer_data, uint16_t buffer_length) {
+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) {
+  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++) {
+    if (*buffer_data != 0x03) {
+      for (int i = 1; i < (buffer_length - 1); i++) {
         buffer_data++;
-        if((*buffer_data == 0x03) && (*(buffer_data + 1) == 0x00)) {
+        if ((*buffer_data == 0x03) && (*(buffer_data + 1) == 0x00)) {
           // We've found a potential new packet start.
           return -(i - 1);
         }
@@ -76,19 +76,19 @@ int16_t plc4c_driver_s7_select_message_function(
     }
   }
   // The length information is located in bytes 3 and 4
-  if(buffer_length >= 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) {
+        (((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++) {
+    if (packet_length > 8192) {
+      for (int i = 1; i < (buffer_length - 1); i++) {
         buffer_data++;
-        if((*buffer_data == 0x03) && (*(buffer_data + 1) == 0x00)) {
+        if ((*buffer_data == 0x03) && (*(buffer_data + 1) == 0x00)) {
           // We've found a potential new packet start.
           return -(i - 1);
         }
@@ -102,20 +102,24 @@ int16_t plc4c_driver_s7_select_message_function(
 
 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);
+  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) {
-  // TODO: Implement ...
+  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) {
+  if (strncmp(prefix, article_number, strlen(prefix)) != 0) {
     return PLC4C_DRIVER_S7_CONTROLLER_TYPE_ANY;
   }
   char model = *(article_number + 5);
@@ -133,14 +137,69 @@ plc4c_driver_s7_controller_type decode_controller_type(char* article_number) {
   }
 }
 
+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);
+
 /**
  * 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;
+    plc4c_system_task* task) {
+  plc4c_connection* connection = task->context;
   if (connection == NULL) {
     return INTERNAL_ERROR;
   }
@@ -153,137 +212,68 @@ plc4c_return_code plc4c_driver_s7_connect_machine_function(
   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);
+          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);
+          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);
+          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: {
-      plc4c_s7_read_write_tpkt_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;
+      // 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;
       }
-      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;
-
-      // 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(
-          cotp_connect_request_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 INTERNAL_ERROR;
-      }
-      plc4c_s7_read_write_tpkt_packet_serialize(write_buffer, cotp_connect_request_packet);
 
-      // Now send this to the recipient.
-      return_code = connection->transport->send_message(write_buffer);
-      if (return_code != OK) {
-        return INTERNAL_ERROR;
+      // 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 tpkt connection response.
+    // Receive a COTP connection response.
     case PLC4C_DRIVER_S7_CONNECT_RECEIVE_COTP_CONNECT_RESPONSE: {
-      // 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) {
-        // If UNFINISHED was returned, the buffer hasn't received enough
-        // data for a full packet. Just return and come back later.
-        if(return_code == UNFINISHED) {
-          return OK;
-        }
-        return INTERNAL_ERROR;
-      }
-
-      // Parse the given data.
-      plc4c_s7_read_write_tpkt_packet* cotp_connect_response_packet = NULL;
-      return_code = plc4c_s7_read_write_tpkt_packet_parse(
-          read_buffer, &cotp_connect_response_packet);
-      if (return_code != OK) {
-        return INTERNAL_ERROR;
+      // 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 !=
+      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.
+      // 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;
+        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 =
@@ -313,61 +303,18 @@ plc4c_return_code plc4c_driver_s7_connect_machine_function(
     }
     // Send a S7 connection request.
     case PLC4C_DRIVER_S7_CONNECT_SEND_S7_CONNECT_REQUEST: {
-      plc4c_s7_read_write_tpkt_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;
+      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;
       }
-      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;
-
-      // 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(
-              s7_connect_request_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 INTERNAL_ERROR;
-      }
-      plc4c_s7_read_write_tpkt_packet_serialize(write_buffer, s7_connect_request_packet);
 
-      // Now send this to the recipient.
-      return_code = connection->transport->send_message(write_buffer);
-      if (return_code != OK) {
-        return INTERNAL_ERROR;
+      // 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;
@@ -375,37 +322,28 @@ plc4c_return_code plc4c_driver_s7_connect_machine_function(
     }
     // Receive a S7 connection response.
     case PLC4C_DRIVER_S7_CONNECT_RECEIVE_S7_CONNECT_RESPONSE: {
-      // 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) {
-        // If UNFINISHED was returned, the buffer hasn't received enough
-        // data for a full packet. Just return and come back later.
-        if(return_code == UNFINISHED) {
-          return OK;
-        }
-        return INTERNAL_ERROR;
-      }
-
-      // Parse the given data.
-      plc4c_s7_read_write_tpkt_packet* cotp_connect_response_packet = NULL;
-      return_code = plc4c_s7_read_write_tpkt_packet_parse(
-          read_buffer, &cotp_connect_response_packet);
-      if (return_code != OK) {
-        return INTERNAL_ERROR;
+      // 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(cotp_connect_response_packet->payload->_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(cotp_connect_response_packet->payload->payload->_type !=
+      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(cotp_connect_response_packet->payload->payload->parameter->_type !=
+      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;
       }
@@ -413,14 +351,18 @@ plc4c_return_code plc4c_driver_s7_connect_machine_function(
       // Extract and save the information for:
       // max-amq-caller, max-amq-callee, pdu-size.
       configuration->pdu_size =
-          cotp_connect_response_packet->payload->payload->parameter->s7_parameter_setup_communication_pdu_length;
+          s7_connect_response_packet->payload->payload->parameter
+              ->s7_parameter_setup_communication_pdu_length;
       configuration->max_amq_caller =
-          cotp_connect_response_packet->payload->payload->parameter->s7_parameter_setup_communication_max_amq_caller;
+          s7_connect_response_packet->payload->payload->parameter
+              ->s7_parameter_setup_communication_max_amq_caller;
       configuration->max_amq_callee =
-          cotp_connect_response_packet->payload->payload->parameter->s7_parameter_setup_communication_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) {
+      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.
@@ -431,137 +373,74 @@ plc4c_return_code plc4c_driver_s7_connect_machine_function(
     }
     // 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 =
-          malloc(sizeof(plc4c_s7_read_write_tpkt_packet));
-      if(s7_identify_remote_request_packet == NULL) {
-        return NO_MEMORY;
+      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;
       }
-      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;
-
-      // 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(
-              s7_identify_remote_request_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 INTERNAL_ERROR;
-      }
-      plc4c_s7_read_write_tpkt_packet_serialize(write_buffer, s7_identify_remote_request_packet);
 
-      // Now send this to the recipient.
-      return_code = connection->transport->send_message(write_buffer);
-      if (return_code != OK) {
-        return INTERNAL_ERROR;
+      // 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;
+      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: {
-      // 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) {
-        // If UNFINISHED was returned, the buffer hasn't received enough
-        // data for a full packet. Just return and come back later.
-        if(return_code == UNFINISHED) {
-          return OK;
-        }
-        return INTERNAL_ERROR;
-      }
-
-      // Parse the given data.
-      plc4c_s7_read_write_tpkt_packet* cotp_connect_response_packet = NULL;
-      return_code = plc4c_s7_read_write_tpkt_packet_parse(
-          read_buffer, &cotp_connect_response_packet);
-      if (return_code != OK) {
-        return INTERNAL_ERROR;
+      // 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(cotp_connect_response_packet->payload->_type !=
-         plc4c_s7_read_write_cotp_packet_type_plc4c_s7_read_write_cotp_packet_data) {
+      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(cotp_connect_response_packet->payload->payload->_type !=
+      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(cotp_connect_response_packet->payload->payload->payload->_type !=
+      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 = cotp_connect_response_packet->payload->payload->payload->s7_payload_user_data_items->tail;
-      while(cur_item != NULL) {
+      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) {
+        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);
+              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;
+                configuration->controller_type =
+                    PLC4C_DRIVER_S7_CONTROLLER_TYPE_ANY;
               }
             }
             szl_item = szl_item->next;
@@ -591,8 +470,8 @@ plc4c_return_code plc4c_driver_s7_connect_machine_function(
 }
 
 plc4c_return_code plc4c_driver_s7_disconnect_machine_function(
-    plc4c_system_task *task) {
-  plc4c_connection *connection = task->context;
+    plc4c_system_task* task) {
+  plc4c_connection* connection = task->context;
   if (connection == NULL) {
     return INTERNAL_ERROR;
   }
@@ -624,8 +503,8 @@ plc4c_return_code plc4c_driver_s7_disconnect_machine_function(
 }
 
 plc4c_return_code plc4c_driver_s7_read_machine_function(
-    plc4c_system_task *task) {
-  plc4c_read_request_execution *read_request_execution = task->context;
+    plc4c_system_task* task) {
+  plc4c_read_request_execution* read_request_execution = task->context;
   if (read_request_execution == NULL) {
     return INTERNAL_ERROR;
   }
@@ -648,8 +527,8 @@ plc4c_return_code plc4c_driver_s7_read_machine_function(
 }
 
 plc4c_return_code plc4c_driver_s7_write_machine_function(
-    plc4c_system_task *task) {
-  plc4c_write_request_execution *write_request_execution = task->context;
+    plc4c_system_task* task) {
+  plc4c_write_request_execution* write_request_execution = task->context;
   if (write_request_execution == NULL) {
     return INTERNAL_ERROR;
   }
@@ -671,9 +550,9 @@ plc4c_return_code plc4c_driver_s7_write_machine_function(
   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));
+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;
@@ -685,8 +564,8 @@ plc4c_return_code plc4c_driver_s7_connect_function(
 }
 
 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));
+    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;
@@ -698,9 +577,9 @@ plc4c_return_code plc4c_driver_s7_disconnect_function(
 }
 
 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));
+    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;
@@ -711,23 +590,23 @@ plc4c_return_code plc4c_driver_s7_read_function(
 }
 
 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_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) {
+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));
+    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;
@@ -738,9 +617,9 @@ plc4c_return_code plc4c_driver_s7_write_function(
 }
 
 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;
+    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
@@ -748,15 +627,14 @@ void plc4c_driver_s7_free_write_response_item(
   value_item->value = NULL;
 }
 
-void plc4c_driver_s7_free_write_response(
-    plc4c_write_response *response) {
+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);
 }
 
-plc4c_driver *plc4c_driver_s7_create() {
-  plc4c_driver *driver = (plc4c_driver *)malloc(sizeof(plc4c_driver));
+plc4c_driver* plc4c_driver_s7_create() {
+  plc4c_driver* driver = (plc4c_driver*)malloc(sizeof(plc4c_driver));
   driver->protocol_code = "s7";
   driver->protocol_name = "Siemens S7 (Basic)";
   driver->default_transport_code = "tcp";
@@ -773,3 +651,208 @@ 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;
+}
diff --git a/sandbox/plc4c/generated-sources/s7/includes/cotp_protocol_class.h b/sandbox/plc4c/generated-sources/s7/includes/cotp_protocol_class.h
index 2efcff7..33db7a7 100644
--- a/sandbox/plc4c/generated-sources/s7/includes/cotp_protocol_class.h
+++ b/sandbox/plc4c/generated-sources/s7/includes/cotp_protocol_class.h
@@ -39,6 +39,8 @@ typedef enum plc4c_s7_read_write_cotp_protocol_class plc4c_s7_read_write_cotp_pr
 // Get an empty NULL-struct
 plc4c_s7_read_write_cotp_protocol_class plc4c_s7_read_write_cotp_protocol_class_null();
 
+int plc4c_s7_read_write_cotp_protocol_class_num_values();
+
 
 #ifdef __cplusplus
 }
diff --git a/sandbox/plc4c/generated-sources/s7/includes/cotp_tpdu_size.h b/sandbox/plc4c/generated-sources/s7/includes/cotp_tpdu_size.h
index 38f156d..a5b9961 100644
--- a/sandbox/plc4c/generated-sources/s7/includes/cotp_tpdu_size.h
+++ b/sandbox/plc4c/generated-sources/s7/includes/cotp_tpdu_size.h
@@ -41,6 +41,8 @@ typedef enum plc4c_s7_read_write_cotp_tpdu_size plc4c_s7_read_write_cotp_tpdu_si
 // Get an empty NULL-struct
 plc4c_s7_read_write_cotp_tpdu_size plc4c_s7_read_write_cotp_tpdu_size_null();
 
+int plc4c_s7_read_write_cotp_tpdu_size_num_values();
+
 
 uint16_t plc4c_s7_read_write_cotp_tpdu_size_get_size_in_bytes(plc4c_s7_read_write_cotp_tpdu_size value);
 
diff --git a/sandbox/plc4c/generated-sources/s7/includes/data_transport_error_code.h b/sandbox/plc4c/generated-sources/s7/includes/data_transport_error_code.h
index 94bc081..c85e236 100644
--- a/sandbox/plc4c/generated-sources/s7/includes/data_transport_error_code.h
+++ b/sandbox/plc4c/generated-sources/s7/includes/data_transport_error_code.h
@@ -40,6 +40,8 @@ typedef enum plc4c_s7_read_write_data_transport_error_code plc4c_s7_read_write_d
 // Get an empty NULL-struct
 plc4c_s7_read_write_data_transport_error_code plc4c_s7_read_write_data_transport_error_code_null();
 
+int plc4c_s7_read_write_data_transport_error_code_num_values();
+
 
 #ifdef __cplusplus
 }
diff --git a/sandbox/plc4c/generated-sources/s7/includes/data_transport_size.h b/sandbox/plc4c/generated-sources/s7/includes/data_transport_size.h
index cbfc150..943a42d 100644
--- a/sandbox/plc4c/generated-sources/s7/includes/data_transport_size.h
+++ b/sandbox/plc4c/generated-sources/s7/includes/data_transport_size.h
@@ -41,6 +41,8 @@ typedef enum plc4c_s7_read_write_data_transport_size plc4c_s7_read_write_data_tr
 // Get an empty NULL-struct
 plc4c_s7_read_write_data_transport_size plc4c_s7_read_write_data_transport_size_null();
 
+int plc4c_s7_read_write_data_transport_size_num_values();
+
 
 bool plc4c_s7_read_write_data_transport_size_get_size_in_bits(plc4c_s7_read_write_data_transport_size value);
 
diff --git a/sandbox/plc4c/generated-sources/s7/includes/device_group.h b/sandbox/plc4c/generated-sources/s7/includes/device_group.h
index 9f8af73..2c0cb64 100644
--- a/sandbox/plc4c/generated-sources/s7/includes/device_group.h
+++ b/sandbox/plc4c/generated-sources/s7/includes/device_group.h
@@ -37,6 +37,8 @@ typedef enum plc4c_s7_read_write_device_group plc4c_s7_read_write_device_group;
 // Get an empty NULL-struct
 plc4c_s7_read_write_device_group plc4c_s7_read_write_device_group_null();
 
+int plc4c_s7_read_write_device_group_num_values();
+
 
 #ifdef __cplusplus
 }
diff --git a/sandbox/plc4c/generated-sources/s7/includes/memory_area.h b/sandbox/plc4c/generated-sources/s7/includes/memory_area.h
index d172543..311b43d 100644
--- a/sandbox/plc4c/generated-sources/s7/includes/memory_area.h
+++ b/sandbox/plc4c/generated-sources/s7/includes/memory_area.h
@@ -43,6 +43,8 @@ typedef enum plc4c_s7_read_write_memory_area plc4c_s7_read_write_memory_area;
 // Get an empty NULL-struct
 plc4c_s7_read_write_memory_area plc4c_s7_read_write_memory_area_null();
 
+int plc4c_s7_read_write_memory_area_num_values();
+
 
 char* plc4c_s7_read_write_memory_area_get_short_name(plc4c_s7_read_write_memory_area value);
 
diff --git a/sandbox/plc4c/generated-sources/s7/includes/szl_module_type_class.h b/sandbox/plc4c/generated-sources/s7/includes/szl_module_type_class.h
index 0af468c..be1fef7 100644
--- a/sandbox/plc4c/generated-sources/s7/includes/szl_module_type_class.h
+++ b/sandbox/plc4c/generated-sources/s7/includes/szl_module_type_class.h
@@ -38,6 +38,8 @@ typedef enum plc4c_s7_read_write_szl_module_type_class plc4c_s7_read_write_szl_m
 // Get an empty NULL-struct
 plc4c_s7_read_write_szl_module_type_class plc4c_s7_read_write_szl_module_type_class_null();
 
+int plc4c_s7_read_write_szl_module_type_class_num_values();
+
 
 #ifdef __cplusplus
 }
diff --git a/sandbox/plc4c/generated-sources/s7/includes/szl_sublist.h b/sandbox/plc4c/generated-sources/s7/includes/szl_sublist.h
index 4aa623e..626bfae 100644
--- a/sandbox/plc4c/generated-sources/s7/includes/szl_sublist.h
+++ b/sandbox/plc4c/generated-sources/s7/includes/szl_sublist.h
@@ -53,6 +53,8 @@ typedef enum plc4c_s7_read_write_szl_sublist plc4c_s7_read_write_szl_sublist;
 // Get an empty NULL-struct
 plc4c_s7_read_write_szl_sublist plc4c_s7_read_write_szl_sublist_null();
 
+int plc4c_s7_read_write_szl_sublist_num_values();
+
 
 #ifdef __cplusplus
 }
diff --git a/sandbox/plc4c/generated-sources/s7/includes/transport_size.h b/sandbox/plc4c/generated-sources/s7/includes/transport_size.h
index 9601b8c..a2c1f12 100644
--- a/sandbox/plc4c/generated-sources/s7/includes/transport_size.h
+++ b/sandbox/plc4c/generated-sources/s7/includes/transport_size.h
@@ -60,6 +60,8 @@ typedef enum plc4c_s7_read_write_transport_size plc4c_s7_read_write_transport_si
 // Get an empty NULL-struct
 plc4c_s7_read_write_transport_size plc4c_s7_read_write_transport_size_null();
 
+int plc4c_s7_read_write_transport_size_num_values();
+
 
 bool plc4c_s7_read_write_transport_size_get_supported__s7_300(plc4c_s7_read_write_transport_size value);
 
diff --git a/sandbox/plc4c/generated-sources/s7/src/cotp_protocol_class.c b/sandbox/plc4c/generated-sources/s7/src/cotp_protocol_class.c
index 4f46d34..8dfa8de 100644
--- a/sandbox/plc4c/generated-sources/s7/src/cotp_protocol_class.c
+++ b/sandbox/plc4c/generated-sources/s7/src/cotp_protocol_class.c
@@ -27,3 +27,7 @@ plc4c_s7_read_write_cotp_protocol_class plc4c_s7_read_write_cotp_protocol_class_
   return plc4c_s7_read_write_cotp_protocol_class_null_const;
 }
 
+int plc4c_s7_read_write_cotp_protocol_class_num_values() {
+  return 5;
+}
+
diff --git a/sandbox/plc4c/generated-sources/s7/src/cotp_tpdu_size.c b/sandbox/plc4c/generated-sources/s7/src/cotp_tpdu_size.c
index b6cfa78..3f02d05 100644
--- a/sandbox/plc4c/generated-sources/s7/src/cotp_tpdu_size.c
+++ b/sandbox/plc4c/generated-sources/s7/src/cotp_tpdu_size.c
@@ -27,6 +27,10 @@ plc4c_s7_read_write_cotp_tpdu_size plc4c_s7_read_write_cotp_tpdu_size_null() {
   return plc4c_s7_read_write_cotp_tpdu_size_null_const;
 }
 
+int plc4c_s7_read_write_cotp_tpdu_size_num_values() {
+  return 7;
+}
+
 
 uint16_t plc4c_s7_read_write_cotp_tpdu_size_get_size_in_bytes(plc4c_s7_read_write_cotp_tpdu_size value) {
   switch(value) {
diff --git a/sandbox/plc4c/generated-sources/s7/src/data_transport_error_code.c b/sandbox/plc4c/generated-sources/s7/src/data_transport_error_code.c
index 7baf834..9756535 100644
--- a/sandbox/plc4c/generated-sources/s7/src/data_transport_error_code.c
+++ b/sandbox/plc4c/generated-sources/s7/src/data_transport_error_code.c
@@ -27,3 +27,7 @@ plc4c_s7_read_write_data_transport_error_code plc4c_s7_read_write_data_transport
   return plc4c_s7_read_write_data_transport_error_code_null_const;
 }
 
+int plc4c_s7_read_write_data_transport_error_code_num_values() {
+  return 6;
+}
+
diff --git a/sandbox/plc4c/generated-sources/s7/src/data_transport_size.c b/sandbox/plc4c/generated-sources/s7/src/data_transport_size.c
index dcea90b..8e57457 100644
--- a/sandbox/plc4c/generated-sources/s7/src/data_transport_size.c
+++ b/sandbox/plc4c/generated-sources/s7/src/data_transport_size.c
@@ -27,6 +27,10 @@ plc4c_s7_read_write_data_transport_size plc4c_s7_read_write_data_transport_size_
   return plc4c_s7_read_write_data_transport_size_null_const;
 }
 
+int plc4c_s7_read_write_data_transport_size_num_values() {
+  return 7;
+}
+
 
 bool plc4c_s7_read_write_data_transport_size_get_size_in_bits(plc4c_s7_read_write_data_transport_size value) {
   switch(value) {
diff --git a/sandbox/plc4c/generated-sources/s7/src/device_group.c b/sandbox/plc4c/generated-sources/s7/src/device_group.c
index 91bca89..3a1cf5f 100644
--- a/sandbox/plc4c/generated-sources/s7/src/device_group.c
+++ b/sandbox/plc4c/generated-sources/s7/src/device_group.c
@@ -27,3 +27,7 @@ plc4c_s7_read_write_device_group plc4c_s7_read_write_device_group_null() {
   return plc4c_s7_read_write_device_group_null_const;
 }
 
+int plc4c_s7_read_write_device_group_num_values() {
+  return 3;
+}
+
diff --git a/sandbox/plc4c/generated-sources/s7/src/memory_area.c b/sandbox/plc4c/generated-sources/s7/src/memory_area.c
index 503ba73..e6574ad 100644
--- a/sandbox/plc4c/generated-sources/s7/src/memory_area.c
+++ b/sandbox/plc4c/generated-sources/s7/src/memory_area.c
@@ -27,6 +27,10 @@ plc4c_s7_read_write_memory_area plc4c_s7_read_write_memory_area_null() {
   return plc4c_s7_read_write_memory_area_null_const;
 }
 
+int plc4c_s7_read_write_memory_area_num_values() {
+  return 9;
+}
+
 
 char* plc4c_s7_read_write_memory_area_get_short_name(plc4c_s7_read_write_memory_area value) {
   switch(value) {
diff --git a/sandbox/plc4c/generated-sources/s7/src/szl_module_type_class.c b/sandbox/plc4c/generated-sources/s7/src/szl_module_type_class.c
index fe5ec8f..b042166 100644
--- a/sandbox/plc4c/generated-sources/s7/src/szl_module_type_class.c
+++ b/sandbox/plc4c/generated-sources/s7/src/szl_module_type_class.c
@@ -27,3 +27,7 @@ plc4c_s7_read_write_szl_module_type_class plc4c_s7_read_write_szl_module_type_cl
   return plc4c_s7_read_write_szl_module_type_class_null_const;
 }
 
+int plc4c_s7_read_write_szl_module_type_class_num_values() {
+  return 4;
+}
+
diff --git a/sandbox/plc4c/generated-sources/s7/src/szl_sublist.c b/sandbox/plc4c/generated-sources/s7/src/szl_sublist.c
index e33f462..3dcd087 100644
--- a/sandbox/plc4c/generated-sources/s7/src/szl_sublist.c
+++ b/sandbox/plc4c/generated-sources/s7/src/szl_sublist.c
@@ -27,3 +27,7 @@ plc4c_s7_read_write_szl_sublist plc4c_s7_read_write_szl_sublist_null() {
   return plc4c_s7_read_write_szl_sublist_null_const;
 }
 
+int plc4c_s7_read_write_szl_sublist_num_values() {
+  return 19;
+}
+
diff --git a/sandbox/plc4c/generated-sources/s7/src/transport_size.c b/sandbox/plc4c/generated-sources/s7/src/transport_size.c
index 026a73f..a772d87 100644
--- a/sandbox/plc4c/generated-sources/s7/src/transport_size.c
+++ b/sandbox/plc4c/generated-sources/s7/src/transport_size.c
@@ -29,6 +29,10 @@ plc4c_s7_read_write_transport_size plc4c_s7_read_write_transport_size_null() {
   return plc4c_s7_read_write_transport_size_null_const;
 }
 
+int plc4c_s7_read_write_transport_size_num_values() {
+  return 24;
+}
+
 
 bool plc4c_s7_read_write_transport_size_get_supported__s7_300(plc4c_s7_read_write_transport_size value) {
   switch(value) {
diff --git a/sandbox/plc4c/spi/src/utils/list.c b/sandbox/plc4c/spi/src/utils/list.c
index d570cc3..5d81dbb 100644
--- a/sandbox/plc4c/spi/src/utils/list.c
+++ b/sandbox/plc4c/spi/src/utils/list.c
@@ -20,6 +20,7 @@
 #include <plc4c/utils/list.h>
 
 void plc4c_utils_list_create(plc4c_list **list) {
+  // TODO: Add a NULL-Check ...
   plc4c_list *new_list = malloc(sizeof(plc4c_list));
   new_list->head = NULL;
   new_list->tail = NULL;