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/09/14 07:15:41 UTC

[plc4x] 02/02: - Working on the C 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

commit 7991d4a8cab84fead0e4902fe1ce8acd099a5b4c
Author: Christofer Dutz <ch...@c-ware.de>
AuthorDate: Mon Sep 14 09:15:30 2020 +0200

    - Working on the C S7 driver
---
 .../s7/readwrite/protocol/S7ProtocolLogic.java     |  13 ++-
 sandbox/plc4c/api/include/plc4c/connection.h       |  10 +-
 sandbox/plc4c/api/include/plc4c/types.h            |   1 +
 .../drivers/modbus/src/driver_modbus_packets.c     |   7 +-
 .../drivers/modbus/src/driver_modbus_sm_connect.c  |   1 +
 sandbox/plc4c/drivers/s7/include/plc4c/driver_s7.h |   4 +-
 sandbox/plc4c/drivers/s7/src/driver_s7.c           |  25 +++++
 .../plc4c/drivers/s7/src/driver_s7_encode_decode.c |   5 +-
 sandbox/plc4c/drivers/s7/src/driver_s7_packets.c   |  35 +++++--
 .../plc4c/drivers/s7/src/driver_s7_sm_connect.c    |  14 ++-
 .../s7/src/s7_payload_user_data_item.c             |   4 +-
 .../plc4c/spi/include/plc4c/spi/types_private.h    |  13 ++-
 sandbox/plc4c/spi/src/connection.c                 |   5 +
 sandbox/plc4c/spi/src/system.c                     |  17 +++-
 sandbox/plc4c/spi/src/utils/list.c                 |   2 +-
 .../plc4c/transports/serial/src/transport_serial.c |   3 +-
 .../transports/tcp/include/plc4c/transport_tcp.h   |   8 ++
 sandbox/plc4c/transports/tcp/src/transport_tcp.c   | 103 ++++++++++++++++++++-
 18 files changed, 240 insertions(+), 30 deletions(-)

diff --git a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/protocol/S7ProtocolLogic.java b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/protocol/S7ProtocolLogic.java
index e0d5b0d..0b6e4ec 100644
--- a/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/protocol/S7ProtocolLogic.java
+++ b/plc4j/drivers/s7/src/main/java/org/apache/plc4x/java/s7/readwrite/protocol/S7ProtocolLogic.java
@@ -297,11 +297,14 @@ public class S7ProtocolLogic extends Plc4xProtocolBase<TPKTPacket> {
     }
 
     private TPKTPacket createIdentifyRemoteMessage() {
-        S7MessageUserData identifyRemoteMessage = new S7MessageUserData(1, new S7ParameterUserData(new S7ParameterUserDataItem[]{
-            new S7ParameterUserDataItemCPUFunctions((short) 0x11, (byte) 0x4, (byte) 0x4, (short) 0x01, (short) 0x00, null, null, null)
-        }), new S7PayloadUserData(new S7PayloadUserDataItem[]{
-            new S7PayloadUserDataItemCpuFunctionReadSzlRequest(DataTransportErrorCode.OK, DataTransportSize.OCTET_STRING, new SzlId(SzlModuleTypeClass.CPU, (byte) 0x00, SzlSublist.MODULE_IDENTIFICATION), 0x0000)
-        }));
+        S7MessageUserData identifyRemoteMessage = new S7MessageUserData(1,
+            new S7ParameterUserData(new S7ParameterUserDataItem[]{
+                new S7ParameterUserDataItemCPUFunctions((short) 0x11, (byte) 0x4, (byte) 0x4, (short) 0x01, (short) 0x00, null, null, null)
+            }),
+            new S7PayloadUserData(new S7PayloadUserDataItem[]{
+                new S7PayloadUserDataItemCpuFunctionReadSzlRequest(DataTransportErrorCode.OK, DataTransportSize.OCTET_STRING, new SzlId(SzlModuleTypeClass.CPU, (byte) 0x00, SzlSublist.MODULE_IDENTIFICATION), 0x0000)
+            })
+        );
         COTPPacketData cotpPacketData = new COTPPacketData(null, identifyRemoteMessage, true, (short) 2);
         return new TPKTPacket(cotpPacketData);
     }
diff --git a/sandbox/plc4c/api/include/plc4c/connection.h b/sandbox/plc4c/api/include/plc4c/connection.h
index c1e8e47..2818add 100644
--- a/sandbox/plc4c/api/include/plc4c/connection.h
+++ b/sandbox/plc4c/api/include/plc4c/connection.h
@@ -186,12 +186,20 @@ plc4c_driver *plc4c_connection_get_driver(plc4c_connection *connection);
 /**
  * Sets a plc4c_driver for a given connection
  * @param connection plc4c_connection
- * @param plc4c_driver
+ * @param plc4c_driver driver
  */
 void plc4c_connection_set_driver(plc4c_connection *connection,
                                  plc4c_driver *driver);
 
 /**
+ * Sets the configuration for a given connection.
+ *
+ * @param connection plc4c connection
+ * @param configuration configuration
+ */
+void plc4c_connection_set_configuration(plc4c_connection *connection,
+                                        void *configuration);
+/**
  * Check if an error occurred while connecting.
  *
  * @param connection the connection.
diff --git a/sandbox/plc4c/api/include/plc4c/types.h b/sandbox/plc4c/api/include/plc4c/types.h
index e364753..cc2157f 100644
--- a/sandbox/plc4c/api/include/plc4c/types.h
+++ b/sandbox/plc4c/api/include/plc4c/types.h
@@ -54,6 +54,7 @@ typedef enum plc4c_return_code {
   PARSE_ERROR,
 
   UNKNOWN_ERROR,
+  CONNECTION_ERROR,
   INTERNAL_ERROR,
   NOT_IMPLEMENTED
 } plc4c_return_code;
diff --git a/sandbox/plc4c/drivers/modbus/src/driver_modbus_packets.c b/sandbox/plc4c/drivers/modbus/src/driver_modbus_packets.c
index 54ce4cc..af50cbe 100644
--- a/sandbox/plc4c/drivers/modbus/src/driver_modbus_packets.c
+++ b/sandbox/plc4c/drivers/modbus/src/driver_modbus_packets.c
@@ -68,7 +68,8 @@ plc4c_return_code plc4c_driver_modbus_send_packet(plc4c_connection* connection,
   plc4c_modbus_read_write_modbus_tcp_adu_serialize(write_buffer, packet);
 
   // Now send this to the recipient.
-  return_code = connection->transport->send_message(write_buffer);
+  return_code = connection->transport->send_message(
+      connection->transport_configuration, write_buffer);
   if (return_code != OK) {
     return return_code;
   }
@@ -82,7 +83,9 @@ plc4c_return_code plc4c_driver_modbus_receive_packet(plc4c_connection* connectio
   // If it is, get a read_buffer for reading it.
   plc4c_spi_read_buffer* read_buffer;
   plc4c_return_code return_code = connection->transport->select_message(
-      plc4c_driver_modbus_select_message_function, &read_buffer);
+      connection->transport_configuration,
+      6, plc4c_driver_modbus_select_message_function,
+      &read_buffer);
   // OK is only returned if a packet is available.
   if (return_code != OK) {
     return return_code;
diff --git a/sandbox/plc4c/drivers/modbus/src/driver_modbus_sm_connect.c b/sandbox/plc4c/drivers/modbus/src/driver_modbus_sm_connect.c
index 9ecbb66..a093567 100644
--- a/sandbox/plc4c/drivers/modbus/src/driver_modbus_sm_connect.c
+++ b/sandbox/plc4c/drivers/modbus/src/driver_modbus_sm_connect.c
@@ -37,6 +37,7 @@ plc4c_return_code plc4c_driver_modbus_connect_machine_function(
 
 plc4c_return_code plc4c_driver_modbus_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 = -1;
diff --git a/sandbox/plc4c/drivers/s7/include/plc4c/driver_s7.h b/sandbox/plc4c/drivers/s7/include/plc4c/driver_s7.h
index 78bd46d..a0cb706 100644
--- a/sandbox/plc4c/drivers/s7/include/plc4c/driver_s7.h
+++ b/sandbox/plc4c/drivers/s7/include/plc4c/driver_s7.h
@@ -25,6 +25,8 @@ extern "C" {
 #include <plc4c/types.h>
 #include <stdint.h>
 
+#include "../../../../generated-sources/s7/includes/cotp_tpdu_size.h"
+
 enum plc4c_driver_s7_controller_type {
   PLC4C_DRIVER_S7_CONTROLLER_TYPE_ANY = 0,
   PLC4C_DRIVER_S7_CONTROLLER_TYPE_S7_300 = 1,
@@ -49,7 +51,7 @@ struct plc4c_driver_s7_config {
   uint8_t remote_slot;
   uint16_t calling_tsap_id;
   uint16_t called_tsap_id;
-  uint16_t cotp_tpdu_size;
+  plc4c_s7_read_write_cotp_tpdu_size cotp_tpdu_size;
   uint16_t pdu_size;
   uint8_t max_amq_caller;
   uint8_t max_amq_callee;
diff --git a/sandbox/plc4c/drivers/s7/src/driver_s7.c b/sandbox/plc4c/drivers/s7/src/driver_s7.c
index d4f9862..2fe21e2 100644
--- a/sandbox/plc4c/drivers/s7/src/driver_s7.c
+++ b/sandbox/plc4c/drivers/s7/src/driver_s7.c
@@ -17,14 +17,39 @@
   under the License.
 */
 
+#include "plc4c/driver_s7.h"
 #include "plc4c/driver_s7_sm.h"
 
+plc4c_return_code plc4c_driver_s7_configure_function(
+    plc4c_list* parameters, void** configuration) {
+  plc4c_driver_s7_config* s7_config = malloc(sizeof(plc4c_driver_s7_config));
+  if(s7_config == NULL) {
+    return NO_MEMORY;
+  }
+
+  // Initialize the parts that the user can influence.
+  s7_config->local_rack = 1;
+  s7_config->local_slot = 1;
+  s7_config->remote_rack = 0;
+  s7_config->remote_slot = 0;
+  s7_config->pdu_size = 1024;
+  s7_config->max_amq_caller = 8;
+  s7_config->max_amq_callee = 8;
+  s7_config->controller_type = PLC4C_DRIVER_S7_CONTROLLER_TYPE_ANY;
+
+  // TODO: Apply the values from the parameters.
+
+  *configuration = s7_config;
+  return OK;
+}
+
 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";
   driver->parse_address_function = NULL;
+  driver->configure_function = &plc4c_driver_s7_configure_function;
   driver->connect_function = &plc4c_driver_s7_connect_function;
   driver->disconnect_function = &plc4c_driver_s7_disconnect_function;
   driver->read_function = &plc4c_driver_s7_read_function;
diff --git a/sandbox/plc4c/drivers/s7/src/driver_s7_encode_decode.c b/sandbox/plc4c/drivers/s7/src/driver_s7_encode_decode.c
index 95a4880..27972ea 100644
--- a/sandbox/plc4c/drivers/s7/src/driver_s7_encode_decode.c
+++ b/sandbox/plc4c/drivers/s7/src/driver_s7_encode_decode.c
@@ -35,9 +35,10 @@ uint16_t plc4c_driver_s7_encode_tsap_id(
 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);
+        plc4c_s7_read_write_cotp_tpdu_size_get_size_in_bytes(
+            plc4c_s7_read_write_cotp_tpdu_size_value_for_index(i));
     if (cur_value >= pdu_size) {
-      return cur_value;
+      return plc4c_s7_read_write_cotp_tpdu_size_value_for_index(i);
     }
   }
   return 0;
diff --git a/sandbox/plc4c/drivers/s7/src/driver_s7_packets.c b/sandbox/plc4c/drivers/s7/src/driver_s7_packets.c
index c79a053..2fb06c5 100644
--- a/sandbox/plc4c/drivers/s7/src/driver_s7_packets.c
+++ b/sandbox/plc4c/drivers/s7/src/driver_s7_packets.c
@@ -62,8 +62,8 @@ int16_t plc4c_driver_s7_select_message_function(uint8_t* buffer_data,
   // 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));
+        ((uint16_t) *(buffer_data + 2) << 8) |
+        ((uint16_t) *(buffer_data + 3));
     if (buffer_length >= packet_length) {
       return packet_length;
     }
@@ -79,6 +79,7 @@ int16_t plc4c_driver_s7_select_message_function(uint8_t* buffer_data,
       }
       return -(buffer_length - 1);
     }
+    return packet_length;
   }
   // In all other cases, we'll just have to wait for the next time.
   return 0;
@@ -97,10 +98,13 @@ plc4c_return_code plc4c_driver_s7_send_packet(plc4c_connection* connection,
   if (return_code != OK) {
     return return_code;
   }
-  plc4c_s7_read_write_tpkt_packet_serialize(write_buffer, packet);
+  return_code = plc4c_s7_read_write_tpkt_packet_serialize(write_buffer, packet);
+  if(return_code != OK) {
+    return return_code;
+  }
 
   // Now send this to the recipient.
-  return_code = connection->transport->send_message(write_buffer);
+  return_code = connection->transport->send_message(connection->transport_configuration, write_buffer);
   if (return_code != OK) {
     return return_code;
   }
@@ -114,7 +118,9 @@ plc4c_return_code plc4c_driver_s7_receive_packet(plc4c_connection* connection,
   // If it is, get a read_buffer for reading it.
   plc4c_spi_read_buffer* read_buffer;
   plc4c_return_code return_code = connection->transport->select_message(
-      plc4c_driver_s7_select_message_function, &read_buffer);
+      connection->transport_configuration,
+      4, plc4c_driver_s7_select_message_function,
+      &read_buffer);
   // OK is only returned if a packet is available.
   if (return_code != OK) {
     return return_code;
@@ -295,18 +301,19 @@ plc4c_return_code plc4c_driver_s7_create_s7_identify_remote_request(
   }
   (*s7_identify_remote_request_packet)->payload->payload->_type =
       plc4c_s7_read_write_s7_message_type_plc4c_s7_read_write_s7_message_user_data;
+
+  // Create a Parameter
   (*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) {
+  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));
+  // Create the Parameter Item
   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 =
@@ -331,9 +338,17 @@ plc4c_return_code plc4c_driver_s7_create_s7_identify_remote_request(
           ->payload->payload->parameter->s7_parameter_user_data_items,
       parameter_item);
 
+  // Create the Payload
+  (*s7_identify_remote_request_packet)->payload->payload->payload = malloc(sizeof(plc4c_s7_read_write_s7_payload));
+  if ((*s7_identify_remote_request_packet)->payload->payload->parameter == NULL) {
+    return NO_MEMORY;
+  }
+  (*s7_identify_remote_request_packet)->payload->payload->payload->_type =
+      plc4c_s7_read_write_s7_payload_type_plc4c_s7_read_write_s7_payload_user_data;
   plc4c_utils_list_create(
       &((*s7_identify_remote_request_packet)
             ->payload->payload->payload->s7_payload_user_data_items));
+  // Create the Payload Item
   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 =
@@ -351,6 +366,10 @@ plc4c_return_code plc4c_driver_s7_create_s7_identify_remote_request(
   payload_item->szl_id->sublist_extract = 0x00;
   payload_item->szl_id->sublist_list =
       plc4c_s7_read_write_szl_sublist_MODULE_IDENTIFICATION;
+  plc4c_utils_list_insert_head_value(
+      (*s7_identify_remote_request_packet)
+          ->payload->payload->payload->s7_payload_user_data_items,
+      payload_item);
 
   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
index eb53967..a54c6e8 100644
--- a/sandbox/plc4c/drivers/s7/src/driver_s7_sm_connect.c
+++ b/sandbox/plc4c/drivers/s7/src/driver_s7_sm_connect.c
@@ -30,6 +30,7 @@
 
 enum plc4c_driver_s7_connect_states {
   PLC4C_DRIVER_S7_CONNECT_INIT,
+  PLC4C_DRIVER_S7_CONNECT_TRANSPORT_CONNECT,
   PLC4C_DRIVER_S7_CONNECT_SEND_COTP_CONNECT_REQUEST,
   PLC4C_DRIVER_S7_CONNECT_RECEIVE_COTP_CONNECT_RESPONSE,
   PLC4C_DRIVER_S7_CONNECT_SEND_S7_CONNECT_REQUEST,
@@ -75,6 +76,15 @@ plc4c_return_code plc4c_driver_s7_connect_machine_function(
               configuration->pdu_size);
       configuration->pdu_size = configuration->cotp_tpdu_size - 16;
 
+      task->state_id = PLC4C_DRIVER_S7_CONNECT_TRANSPORT_CONNECT;
+      break;
+    }
+    case PLC4C_DRIVER_S7_CONNECT_TRANSPORT_CONNECT: {
+      plc4c_return_code return_code = connection->transport->open(connection->transport_configuration);
+      if(return_code != OK) {
+        return return_code;
+      }
+
       task->state_id = PLC4C_DRIVER_S7_CONNECT_SEND_COTP_CONNECT_REQUEST;
       break;
     }
@@ -192,7 +202,7 @@ plc4c_return_code plc4c_driver_s7_connect_machine_function(
         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) {
+          plc4c_s7_read_write_s7_message_type_plc4c_s7_read_write_s7_message_response_data) {
         return INTERNAL_ERROR;
       }
       if (s7_connect_response_packet->payload->payload->parameter->_type !=
@@ -213,7 +223,7 @@ plc4c_return_code plc4c_driver_s7_connect_machine_function(
               ->s7_parameter_setup_communication_max_amq_callee;
 
       // If no controller is explicitly selected, detect it.
-      if (configuration->controller_type !=
+      if (configuration->controller_type ==
           PLC4C_DRIVER_S7_CONTROLLER_TYPE_ANY) {
         task->state_id = PLC4C_DRIVER_S7_CONNECT_SEND_S7_IDENTIFICATION_REQUEST;
       }
diff --git a/sandbox/plc4c/generated-sources/s7/src/s7_payload_user_data_item.c b/sandbox/plc4c/generated-sources/s7/src/s7_payload_user_data_item.c
index ca75fb1..9ff710a 100644
--- a/sandbox/plc4c/generated-sources/s7/src/s7_payload_user_data_item.c
+++ b/sandbox/plc4c/generated-sources/s7/src/s7_payload_user_data_item.c
@@ -120,7 +120,7 @@ plc4c_return_code plc4c_s7_read_write_s7_payload_user_data_item_parse(plc4c_spi_
     }
 
 
-                    
+
     // Implicit Field (szlItemCount) (Used for parsing, but it's value is not stored as it's implicitly given by the objects content)
     uint16_t szlItemCount = 0;
     _res = plc4c_spi_read_unsigned_short(buf, 16, (uint16_t*) &szlItemCount);
@@ -141,7 +141,7 @@ plc4c_return_code plc4c_s7_read_write_s7_payload_user_data_item_parse(plc4c_spi_
       uint8_t itemCount = szlItemCount;
       for(int curItem = 0; curItem < itemCount; curItem++) {
         bool lastItem = curItem == (itemCount - 1);
-                          plc4c_list* _value = NULL;
+        plc4c_list* _value = NULL;
         _res = plc4c_s7_read_write_szl_data_tree_item_parse(buf, (void*) &_value);
         if(_res != OK) {
           return _res;
diff --git a/sandbox/plc4c/spi/include/plc4c/spi/types_private.h b/sandbox/plc4c/spi/include/plc4c/spi/types_private.h
index af4a762..b2cb006 100644
--- a/sandbox/plc4c/spi/include/plc4c/spi/types_private.h
+++ b/sandbox/plc4c/spi/include/plc4c/spi/types_private.h
@@ -38,6 +38,9 @@ typedef struct plc4c_response_item_t plc4c_response_item;
 typedef struct plc4c_response_subscription_item_t plc4c_response_subscription_item;
 typedef struct plc4c_response_unsubscription_item_t plc4c_response_unsubscription_item;
 
+typedef plc4c_return_code *(*plc4c_connection_configure_function)(
+    plc4c_list* parameters, void** configuration);
+
 typedef plc4c_item *(*plc4c_connection_parse_address_item)(
     char *address_string);
 
@@ -83,6 +86,9 @@ typedef void (*plc4c_connect_free_subscription_response_function)(
 typedef void (*plc4c_connect_free_unsubscription_response_function)(
     plc4c_unsubscription_response *response);
 
+typedef plc4c_return_code (*plc4c_transport_configure_function)(
+    plc4c_list* parameters, void** configuration);
+
 // TODO: Implement the argument.
 typedef plc4c_return_code (*plc4c_transport_open_function)(void* config);
 
@@ -90,7 +96,7 @@ typedef plc4c_return_code (*plc4c_transport_open_function)(void* config);
 typedef plc4c_return_code (*plc4c_transport_close_function)(void* config);
 
 typedef plc4c_return_code (*plc4c_transport_send_message_function)(
-    plc4c_spi_write_buffer* message);
+    void* transport_configuration, plc4c_spi_write_buffer* message);
 
 // Helper function that tells the transport what to do with the current input
 // on positive return value: a read-buffer with given number of bytes is
@@ -104,7 +110,7 @@ typedef int16_t (*accept_message_function)(
     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);
+    void* transport_configuration, uint8_t min_size, accept_message_function accept_message, plc4c_spi_read_buffer** message);
 
 struct plc4c_system_t {
   /* drivers */
@@ -137,6 +143,7 @@ struct plc4c_driver_t {
   char *protocol_code;
   char *protocol_name;
   char *default_transport_code;
+  plc4c_connection_configure_function configure_function;
   plc4c_connection_parse_address_item parse_address_function;
   plc4c_connection_connect_function connect_function;
   plc4c_connection_disconnect_function disconnect_function;
@@ -164,6 +171,7 @@ struct plc4c_transport_t {
   char *transport_code;
   char* transport_name;
 
+  plc4c_transport_configure_function configure;
   plc4c_transport_open_function open;
   plc4c_transport_close_function close;
   plc4c_transport_send_message_function send_message;
@@ -183,6 +191,7 @@ struct plc4c_connection_t {
   char *protocol_code;
   char *transport_code;
   char *transport_connect_information;
+  void *transport_configuration;
   char *parameters;
   void *configuration;
 
diff --git a/sandbox/plc4c/spi/src/connection.c b/sandbox/plc4c/spi/src/connection.c
index f3a1a53..370cefa 100644
--- a/sandbox/plc4c/spi/src/connection.c
+++ b/sandbox/plc4c/spi/src/connection.c
@@ -154,6 +154,11 @@ void plc4c_connection_set_driver(plc4c_connection *connection,
   connection->driver = driver;
 }
 
+void plc4c_connection_set_configuration(plc4c_connection *connection,
+                                        void *configuration) {
+  connection->configuration = configuration;
+}
+
 bool plc4c_connection_has_error(plc4c_connection *connection) { return false; }
 
 plc4c_return_code plc4c_connection_disconnect(plc4c_connection *connection) {
diff --git a/sandbox/plc4c/spi/src/system.c b/sandbox/plc4c/spi/src/system.c
index 3d8a147..c4744c4 100644
--- a/sandbox/plc4c/spi/src/system.c
+++ b/sandbox/plc4c/spi/src/system.c
@@ -435,9 +435,22 @@ plc4c_return_code plc4c_system_connect(plc4c_system *system,
   // Initialize a new connection task and schedule that.
   ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
+  plc4c_driver* driver = plc4c_connection_get_driver(new_connection);
+
+  // Configure the driver configuration first.
+  void* configuration = NULL;
+  // TODO: Pass in the configuration options ...
+  driver->configure_function(NULL, &configuration);
+  plc4c_connection_set_configuration(new_connection, configuration);
+
+  // TODO: Somehow let the driver inject default values which the transport can then pickup ...
+
+  // Prepare a configuration data structure for the current transport.
+  new_connection->transport->configure(NULL, &new_connection->transport_configuration);
+
+  // Create a new connection task.
   plc4c_system_task *new_connection_task = NULL;
-  result = plc4c_connection_get_driver(new_connection)
-               ->connect_function(new_connection, &new_connection_task);
+  result = driver->connect_function(new_connection, &new_connection_task);
   if (result != OK) {
     return -1;
   }
diff --git a/sandbox/plc4c/spi/src/utils/list.c b/sandbox/plc4c/spi/src/utils/list.c
index 5d81dbb..f6ceab7 100644
--- a/sandbox/plc4c/spi/src/utils/list.c
+++ b/sandbox/plc4c/spi/src/utils/list.c
@@ -28,7 +28,7 @@ void plc4c_utils_list_create(plc4c_list **list) {
 }
 
 size_t plc4c_utils_list_size(plc4c_list *list) {
-  if (list->tail == NULL) {
+  if ((list == NULL) || (list->tail == NULL)) {
     return 0;
   }
   plc4c_list_element *cur_element = list->tail;
diff --git a/sandbox/plc4c/transports/serial/src/transport_serial.c b/sandbox/plc4c/transports/serial/src/transport_serial.c
index 38222ef..2b1d073 100644
--- a/sandbox/plc4c/transports/serial/src/transport_serial.c
+++ b/sandbox/plc4c/transports/serial/src/transport_serial.c
@@ -35,7 +35,8 @@ plc4c_return_code plc4c_transport_serial_send_message_function(
 }
 
 plc4c_return_code plc4c_transport_serial_select_message_function(
-    accept_message_function accept_message, plc4c_spi_read_buffer** message) {
+    void* transport_configuration, accept_message_function accept_message,
+    plc4c_spi_read_buffer** message) {
   return OK;
 }
 
diff --git a/sandbox/plc4c/transports/tcp/include/plc4c/transport_tcp.h b/sandbox/plc4c/transports/tcp/include/plc4c/transport_tcp.h
index fb57734..18998b1 100644
--- a/sandbox/plc4c/transports/tcp/include/plc4c/transport_tcp.h
+++ b/sandbox/plc4c/transports/tcp/include/plc4c/transport_tcp.h
@@ -24,6 +24,14 @@ extern "C" {
 
 #include <plc4c/types.h>
 
+struct plc4c_transport_tcp_config {
+  char* address;
+  uint16_t port;
+
+  int sockfd;
+};
+typedef struct plc4c_transport_tcp_config plc4c_transport_tcp_config;
+
 plc4c_transport *plc4c_transport_tcp_create();
 
 #ifdef __cplusplus
diff --git a/sandbox/plc4c/transports/tcp/src/transport_tcp.c b/sandbox/plc4c/transports/tcp/src/transport_tcp.c
index 3d049cc..0bc0a79 100644
--- a/sandbox/plc4c/transports/tcp/src/transport_tcp.c
+++ b/sandbox/plc4c/transports/tcp/src/transport_tcp.c
@@ -20,22 +20,122 @@
 #include <plc4c/spi/types_private.h>
 #include <plc4c/transport_tcp.h>
 #include <stdlib.h>
+#include <stdio.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <errno.h>
+
+extern int errno;
+
+plc4c_return_code plc4c_transport_tcp_configure_function(
+    plc4c_list* parameters, void** configuration) {
+  plc4c_transport_tcp_config* tcp_configuration = malloc(sizeof(plc4c_transport_tcp_config));
+  if(tcp_configuration == NULL) {
+    return NO_MEMORY;
+  }
+  // TODO: Implement this ...
+  tcp_configuration->address = "192.168.23.30";
+  tcp_configuration->port = 102;
+
+  *configuration = tcp_configuration;
+  return OK;
+}
 
 plc4c_return_code plc4c_transport_tcp_open_function(void* config) {
+  int sockfd;
+  int connfd;
+  struct sockaddr_in servaddr;
+
+  plc4c_transport_tcp_config* tcp_config = config;
+
+  tcp_config->sockfd = socket(AF_INET, SOCK_STREAM, 0);
+  if (tcp_config->sockfd < 0) {
+    return CONNECTION_ERROR;
+  }
+
+  // Configure where to connect to.
+  bzero(&servaddr, sizeof(struct sockaddr_in));
+  servaddr.sin_family = AF_INET;
+  servaddr.sin_addr.s_addr = inet_addr(tcp_config->address);
+  servaddr.sin_port = htons(tcp_config->port);
+
+  int result = connect(tcp_config->sockfd, (struct sockaddr*) &servaddr,
+                       sizeof(servaddr));
+  if(result != 0) {
+    char* error_msg = strerror(errno);
+    printf(error_msg);
+    return CONNECTION_ERROR;
+  }
   return OK;
 }
 
 plc4c_return_code plc4c_transport_tcp_close_function(void* config) {
+  plc4c_transport_tcp_config* tcp_config = config;
+
+  // If the sockfd is zero we're not really connected.
+  if(tcp_config->sockfd == 0) {
+    return INTERNAL_ERROR;
+  }
+
+  // Stop receiving as well as sending.
+  shutdown(tcp_config->sockfd, 2);
   return OK;
 }
 
 plc4c_return_code plc4c_transport_tcp_send_message_function(
-    plc4c_spi_write_buffer* message) {
+    void* transport_configuration, plc4c_spi_write_buffer* message) {
+  plc4c_transport_tcp_config* tcp_config = transport_configuration;
+
+  ssize_t bytes_sent = send(tcp_config->sockfd, message->data, message->length, MSG_DONTWAIT);
+  if(bytes_sent < 0) {
+    return CONNECTION_ERROR;
+  }
+
   return OK;
 }
 
 plc4c_return_code plc4c_transport_tcp_select_message_function(
+    void* transport_configuration, uint8_t min_size,
     accept_message_function accept_message, plc4c_spi_read_buffer** message) {
+  plc4c_transport_tcp_config* tcp_config = transport_configuration;
+
+  // First try to read the minimum number of bytes the driver needs to know
+  // how big a packet is.
+  uint8_t* size_buffer = malloc(sizeof(uint8_t) * min_size);
+  if(size_buffer == NULL) {
+    return NO_MEMORY;
+  }
+  int received_bytes = recv(tcp_config->sockfd, size_buffer, min_size, 0);
+  // TODO: if the value is negative, it's more a "please remove this much of corrupt data" ...
+  if(received_bytes < 0) {
+    return CONNECTION_ERROR;
+  }
+
+  // Now that we have enough data to find out how many bytes we need, have
+  // the accept_message function find out how many
+  int16_t message_size = accept_message(size_buffer, min_size);
+  if(message_size < 0) {
+    return INTERNAL_ERROR;
+  }
+  uint8_t* message_buffer = malloc(sizeof(uint8_t) * message_size);
+  if(message_size < 0) {
+    return NO_MEMORY;
+  }
+
+  // Copy the size_buffer to the start of the new buffer.
+  memcpy(message_buffer, size_buffer, min_size);
+  free(size_buffer);
+
+  // Read the rest of the packet.
+  received_bytes = recv(tcp_config->sockfd, message_buffer + min_size, message_size - min_size, 0);
+  if(received_bytes != message_size - min_size) {
+    return CONNECTION_ERROR;
+  }
+
+  // Create a new read-buffer with the read message data.
+  plc4c_spi_read_buffer_create(message_buffer, message_size, message);
   return OK;
 }
 
@@ -44,6 +144,7 @@ plc4c_transport *plc4c_transport_tcp_create() {
       (plc4c_transport *)malloc(sizeof(plc4c_transport));
   transport->transport_code = "tcp";
   transport->transport_name = "TCP transport";
+  transport->configure = &plc4c_transport_tcp_configure_function;
   transport->open = &plc4c_transport_tcp_open_function;
   transport->close = &plc4c_transport_tcp_close_function;
   transport->send_message = &plc4c_transport_tcp_send_message_function;