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/04/28 16:43:21 UTC

[plc4x] branch feature/c-api-read-support-no-promises updated: - Started implementing the core SPI logic - Implemented a connection string parser including testsuite - Implemented the functionality for searching for a matching driver

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

cdutz pushed a commit to branch feature/c-api-read-support-no-promises
in repository https://gitbox.apache.org/repos/asf/plc4x.git


The following commit(s) were added to refs/heads/feature/c-api-read-support-no-promises by this push:
     new d4dc98d  - Started implementing the core SPI logic - Implemented a connection string parser including testsuite - Implemented the functionality for searching for a matching driver
d4dc98d is described below

commit d4dc98d8311b452d931a157e5f8bd84ad32e3e02
Author: Christofer Dutz <ch...@c-ware.de>
AuthorDate: Tue Apr 28 18:43:12 2020 +0200

    - Started implementing the core SPI logic
    - Implemented a connection string parser including testsuite
    - Implemented the functionality for searching for a matching driver
---
 sandbox/plc4c/api/include/plc4c/system.h           | 102 ++++----
 sandbox/plc4c/api/include/plc4c/types.h            |   7 +-
 .../plc4c/drivers/simulated/src/driver_simulated.c |   1 +
 .../plc4c/examples/hello-world/src/hello_world.c   |  19 +-
 sandbox/plc4c/pom.xml                              |   3 +-
 sandbox/plc4c/spi/CMakeLists.txt                   |  12 +-
 .../plc4c/spi/include/plc4c/spi/system_private.h   |  28 +++
 .../plc4c/spi/include/plc4c/spi/types_private.h    |  60 +++--
 sandbox/plc4c/spi/src/connection.c                 |   2 +-
 sandbox/plc4c/spi/src/system.c                     | 262 +++++++++++++++++++--
 sandbox/plc4c/spi/test/system_test.c               |  78 ++++++
 11 files changed, 484 insertions(+), 90 deletions(-)

diff --git a/sandbox/plc4c/api/include/plc4c/system.h b/sandbox/plc4c/api/include/plc4c/system.h
index 4e9799e..24bec8a 100644
--- a/sandbox/plc4c/api/include/plc4c/system.h
+++ b/sandbox/plc4c/api/include/plc4c/system.h
@@ -31,57 +31,65 @@ extern "C" {
 
 /**
  * Function pointer for a callback called when a driver is loaded.
- * Set in plc4c_system @see plc4c_system_set_on_driver_loaded()
+ * Set in plc4c_system @see plc4c_system_set_on_driver_load_success_callback()
+ *
  * @param driver
  */
-typedef void (*plc4c_system_callback_on_driver_loaded)(plc4c_driver *driver);
+typedef void (*plc4c_system_on_driver_load_success_callback)(plc4c_driver *driver);
 
 /**
  * Function pointer for a callback called when loading a driver fails.
- * Set in plc4c_system @see plc4c_system_set_on_driver_load_error
+ * Set in plc4c_system @see plc4c_system_set_on_driver_load_failure_callback
  * NOTE: driver_name could be a pointer to the configuration for the driver instead....
+ *
  * @param driver_name
  * @param error_code
  */
-typedef void (*plc4c_system_callback_driver_load_error)(const char *driver_name, return_code error);
+typedef void (*plc4c_system_on_driver_load_failure_callback)(const char *driver_name, return_code error);
 
 /**
  * Function pointer for a callback called when is successfully made
- * Set in plc4c_system @see plc4c_system_set_on_connection()
+ * Set in plc4c_system @see plc4c_system_set_on_connect_success_callback().
+ *
  * @param connection
  */
-typedef void (*plc4c_system_callback_on_connection)(plc4c_connection *connection);
+typedef void (*plc4c_system_on_connect_success_callback)(plc4c_connection *connection);
 
 /**
  * Function pointer for a callback called when connecting fails.
- * Set in plc4c_system @see plc4c_system_set_on_connection_error
+ * Set in plc4c_system @see plc4c_system_set_on_connect_failure_callback.
+ *
  * @param connection_string
  * @param error_code
  */
-typedef void (*plc4c_system_callback_connection_error)(const char *connection_string, return_code error);
+typedef void (*plc4c_system_on_connect_failure_callback)(const char *connection_string, return_code error);
 
 /**
  * Function pointer for a callback called when is successfully made
- * Set in plc4c_system @see plc4c_system_set_on_connection()
+ * Set in plc4c_system @see plc4c_system_set_on_disconnect_success_callback().
+ *
  * @param connection
  */
-typedef void (*plc4c_system_callback_on_disconnection)(plc4c_connection *connection);
+typedef void (*plc4c_system_on_disconnect_success_callback)(plc4c_connection *connection);
 
 /**
  * Function pointer for a callback called when connecting fails.
- * Set in plc4c_system @see plc4c_system_set_on_connection_error
+ * Set in plc4c_system @see plc4c_system_set_on_disconnect_failure_callback.
+ *
  * @param connection
  * @param error_code
  */
-typedef void (*plc4c_system_callback_disconnection_error)(plc4c_connection *connection, return_code error);
+typedef void (*plc4c_system_on_disconnect_failure_callback)(plc4c_connection *connection, return_code error);
 
 /**
- * Function pointer for a callback called when a driver returns an error
+ * Function pointer for a callback called when a driver returns an error.
+ * Set in plc4c_system @see plc4c_system_set_on_loop_failure_callback.
+ *
  * @param driver
  * @param connection
  * @param error_code
  */
-typedef void(*plc4c_system_callback_loop_error)
+typedef void(*plc4c_system_on_loop_failure_callback)
         (plc4c_driver *driver, plc4c_connection *connection, return_code error);
 
 
@@ -95,84 +103,97 @@ typedef void(*plc4c_system_callback_loop_error)
  */
 
 /**
- * Function to create a plc4c_system
+ * Function to create a plc4c_system.
+ *
  * @param system
  * @return NO_MEMORY if failed to create system
  */
 return_code plc4c_system_create(plc4c_system **system);
 
 /**
- * Function to destroy a plc4c_system
- * This will also destroy all connections associated with the system
+ * Function to destroy a plc4c_system.
+ * This will also destroy all connections associated with the system.
+ *
  * @param system
  */
 void plc4c_system_destroy(plc4c_system *system);
 
 /**
- * Function to set the on_driver_loaded callback for the plc4c system
+ * Function to set the on_driver_loaded callback for the plc4c system.
+ *
  * @param system
  * @param callback plc4c_system_callback_on_driver
  */
-void plc4c_system_set_on_driver_loaded(plc4c_system *system,
-                                       plc4c_system_callback_on_driver_loaded callback);
+void plc4c_system_set_on_driver_load_success_callback(plc4c_system *system,
+                                                      plc4c_system_on_driver_load_success_callback callback);
 
 /**
- * Function to set the error callback for loading drivers for the plc4c system
+ * Function to set the error callback for loading drivers for the plc4c system.
+ *
  * @param system
  * @param callback plc4c_system_callback_driver_load_error
  */
-void plc4c_system_set_on_driver_load_error(plc4c_system *system,
-                                           plc4c_system_callback_driver_load_error callback);
+void plc4c_system_set_on_driver_load_failure_callback(plc4c_system *system,
+                                                      plc4c_system_on_driver_load_failure_callback callback);
 
 /**
- * Function to set the on_connection callback for the plc4c system
+ * Function to set the on_connection callback for the plc4c system.
+ *
  * @param system
  * @param callback plc4c_system_callback_on_connection
  */
-void plc4c_system_set_on_connection(plc4c_system *system,
-                                    plc4c_system_callback_on_connection callback);
+void plc4c_system_set_on_connect_success_callback(plc4c_system *system,
+                                                  plc4c_system_on_connect_success_callback callback);
 
 /**
- * Function to set the error callback for making connections for the plc4c system
+ * Function to set the error callback for making connections for the plc4c system.
+ *
  * @param system
- * @param callback plc4c_system_callback_connection_error
+ * @param callback plc4c_system_on_connect_failure_callback
  */
-void plc4c_system_set_on_connection_error(plc4c_system *system,
-                                          plc4c_system_callback_connection_error callback);
+void plc4c_system_set_on_connect_failure_callback(plc4c_system *system,
+                                                  plc4c_system_on_connect_failure_callback callback);
 
 /**
- * Function to set the on_disconnection callback for the plc4c system
+ * Function to set the on_disconnection callback for the plc4c system.
+ *
  * @param system
  * @param callback plc4c_system_callback_on_disconnection
  */
-void plc4c_system_set_on_disconnection(plc4c_system *system,
-                                       plc4c_system_callback_on_disconnection callback);
+void plc4c_system_set_on_disconnect_success_callback(plc4c_system *system,
+                                                     plc4c_system_on_disconnect_success_callback callback);
 
 /**
- * Function to set the error callback for shutting down connections for the plc4c system
+ * Function to set the error callback for shutting down connections for the plc4c system.
+ *
  * @param system
  * @param callback
  */
-void plc4c_system_set_on_disconnection_error(plc4c_system *system,
-                                             plc4c_system_callback_disconnection_error callback);
+void plc4c_system_set_on_disconnect_failure_callback(plc4c_system *system,
+                                                     plc4c_system_on_disconnect_failure_callback callback);
 
 /**
- * Function to set the error callback loops
+ * Function to set the error callback loops.
+ *
  * @param system
  * @param callback plc4c_system_callback_loop_error
  */
-void plc4c_system_set_on_loop_error(plc4c_system *system,
-                                    plc4c_system_callback_loop_error callback);
+void plc4c_system_set_on_loop_failure_callback(plc4c_system *system,
+                                               plc4c_system_on_loop_failure_callback callback);
 
 /**
  * Function to manually add a driver to the system.
+ *
+ * @param system the system the driver should be added to.
  * @param driver instance of the driver
  * @return return_code
  */
-return_code plc4c_system_add_driver(plc4c_driver *driver);
+return_code plc4c_system_add_driver(plc4c_system *system,
+                                    plc4c_driver *driver);
 
 /**
  * Function to initialize the PLC4C system (Initialize the driver manager and the list of enabled drivers)
+ *
  * @param system
  * @return return_code
  */
@@ -180,6 +201,7 @@ return_code plc4c_system_init(plc4c_system *system);
 
 /**
  * Function to clean up the PLC4C system (Free any still used resources, terminate live connections, ...)
+ *
  * @param system
  */
 void plc4c_system_shutdown(plc4c_system *system);
diff --git a/sandbox/plc4c/api/include/plc4c/types.h b/sandbox/plc4c/api/include/plc4c/types.h
index 2ef112b..eea69e5 100644
--- a/sandbox/plc4c/api/include/plc4c/types.h
+++ b/sandbox/plc4c/api/include/plc4c/types.h
@@ -31,11 +31,16 @@ extern "C" {
 typedef enum return_code {
     UNFINISHED,
     OK,
-    UNKNOWN_ERROR,
     NO_MEMORY,
     INVALID_CONNECTION_STRING,
     NOT_REACHABLE,
     PERMISSION_DENIED,
+
+    NO_DRIVER_AVAILABLE,
+    UNKNOWN_DRIVER,
+    UNSPECIFIED_TRANSPORT,
+
+    UNKNOWN_ERROR,
     INTERNAL_ERROR
 } return_code;
 
diff --git a/sandbox/plc4c/drivers/simulated/src/driver_simulated.c b/sandbox/plc4c/drivers/simulated/src/driver_simulated.c
index 11aab46..5af83fb 100644
--- a/sandbox/plc4c/drivers/simulated/src/driver_simulated.c
+++ b/sandbox/plc4c/drivers/simulated/src/driver_simulated.c
@@ -38,6 +38,7 @@ plc4c_driver *plc4c_driver_simulated_create() {
     plc4c_driver* driver = (plc4c_driver*) malloc(sizeof(plc4c_driver));
     driver->protocol_code = "simulated";
     driver->protocol_name = "Simulated PLC4X Datasource";
+    driver->default_transport_code = "dummy";
     driver->parse_address_function = &plc4c_driver_simulated_parse_address;
     return driver;
 }
diff --git a/sandbox/plc4c/examples/hello-world/src/hello_world.c b/sandbox/plc4c/examples/hello-world/src/hello_world.c
index f5aad2e..c372011 100644
--- a/sandbox/plc4c/examples/hello-world/src/hello_world.c
+++ b/sandbox/plc4c/examples/hello-world/src/hello_world.c
@@ -40,7 +40,7 @@ void onGlobalDisconnect(plc4c_connection *cur_connection) {
 }
 
 enum plc4c_connection_state_t {
-    PRE_CONNECTION,
+    CONNECTING,
     CONNECTED,
     READ_REQUEST_SENT,
     READ_RESPONSE_RECEIVED,
@@ -64,7 +64,7 @@ int main() {
 
     // Manually register the "simulated" driver with the system.
     plc4c_driver *simulatedDriver = plc4c_driver_simulated_create();
-    result = plc4c_system_add_driver(simulatedDriver);
+    result = plc4c_system_add_driver(system, simulatedDriver);
     if (result != OK) {
         return -1;
     }
@@ -76,24 +76,28 @@ int main() {
     }
 
     // Register the global callbacks.
-    plc4c_system_set_on_connection(system, &onGlobalConnect);
-    plc4c_system_set_on_disconnection(system, &onGlobalDisconnect);
+    plc4c_system_set_on_connect_success_callback(system, &onGlobalConnect);
+    plc4c_system_set_on_disconnect_success_callback(system, &onGlobalDisconnect);
 
     // Establish connections to remote devices
     // you may or may not care about the connection handle
-    result = plc4c_system_connect(system, "s7://192.168.42.20", &connection);
+    result = plc4c_system_connect(system, "simulated://foo", &connection);
     if (result != OK) {
         return -1;
     }
 
     // Central program loop ...
-    plc4c_connection_state state = PRE_CONNECTION;
+    plc4c_connection_state state = CONNECTING;
     while (loop) {
+        // Give plc4c a chance to do something.
+        // This is where all I/O is being done.
         if (plc4c_system_loop(system) != OK) {
             break;
         }
+
+        // Depending on the current state, implement some logic.
         switch (state) {
-            case PRE_CONNECTION: {
+            case CONNECTING: {
                 // Check if the connection is established:
                 if (plc4c_connection_is_connected(connection)) {
                     state = CONNECTED;
@@ -157,6 +161,7 @@ int main() {
             case DISCONNECTED: {
                 // End the loop.
                 loop = false;
+                break;
             }
         }
     }
diff --git a/sandbox/plc4c/pom.xml b/sandbox/plc4c/pom.xml
index 193166b..4af6c7b 100644
--- a/sandbox/plc4c/pom.xml
+++ b/sandbox/plc4c/pom.xml
@@ -281,7 +281,8 @@
             </configuration>
           </execution>
         </executions>
-      </plugin>    </plugins>
+      </plugin>
+    </plugins>
   </build>
 
   <!-- This dependency is just to ensure thrift is built first -->
diff --git a/sandbox/plc4c/spi/CMakeLists.txt b/sandbox/plc4c/spi/CMakeLists.txt
index d006973..542a924 100644
--- a/sandbox/plc4c/spi/CMakeLists.txt
+++ b/sandbox/plc4c/spi/CMakeLists.txt
@@ -21,4 +21,14 @@ include_directories("include" "../api/include")
 
 file(GLOB sources "src/*.c")
 
-add_library(plc4c-spi SHARED ${sources})
\ No newline at end of file
+add_library(plc4c-spi SHARED ${sources})
+
+if(BUILD_PHASE STREQUAL test-compile)
+    file(GLOB testSources "test/*.c")
+    add_executable(plc4c-spi-test ${testSources} test/system_test.c)
+    target_link_libraries (plc4c-spi-test
+            plc4c-spi
+            unity
+            )
+    add_test(NAME plc4c-spi-test COMMAND plc4c-spi-test)
+endif()
\ No newline at end of file
diff --git a/sandbox/plc4c/spi/include/plc4c/spi/system_private.h b/sandbox/plc4c/spi/include/plc4c/spi/system_private.h
new file mode 100644
index 0000000..71e675e
--- /dev/null
+++ b/sandbox/plc4c/spi/include/plc4c/spi/system_private.h
@@ -0,0 +1,28 @@
+/*
+ * 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_SPI_SYSTEM_PRIVATE_H_
+#define PLC4C_SPI_SYSTEM_PRIVATE_H_
+
+#include <plc4c/types.h>
+#include <plc4c/system.h>
+
+return_code plc4c_system_create_connection(const char *connection_string,
+                                           plc4c_connection **connection);
+
+#endif //PLC4C_SPI_SYSTEM_PRIVATE_H_
diff --git a/sandbox/plc4c/spi/include/plc4c/spi/types_private.h b/sandbox/plc4c/spi/include/plc4c/spi/types_private.h
index d353c53..8bb4cb6 100644
--- a/sandbox/plc4c/spi/include/plc4c/spi/types_private.h
+++ b/sandbox/plc4c/spi/include/plc4c/spi/types_private.h
@@ -20,51 +20,81 @@
 #define PLC4C_SPI_TYPES_PRIVATE_H_
 
 #include <plc4c/types.h>
+#include <plc4c/system.h>
+
+typedef struct plc4c_item_t plc4c_item;
+typedef struct plc4c_driver_list_item_t plc4c_driver_list_item;
+typedef struct plc4c_connection_list_item_t plc4c_connection_list_item;
+typedef struct plc4c_write_item_t plc4c_write_item;
+
+typedef plc4c_item *(*plc4c_connection_parse_address_item)(const char *address_string);
 
 struct plc4c_system_t {
-  /* drivers */
+    /* drivers */
+    plc4c_driver_list_item *driver_list_head;
 
-  /* connections */
+    /* connections */
+    plc4c_connection_list_item *connection_list_head;
 
-  /* callbacks */
+    /* callbacks */
+    plc4c_system_on_driver_load_success_callback on_driver_load_success_callback;
+    plc4c_system_on_driver_load_failure_callback on_driver_load_failure_callback;
+    plc4c_system_on_connect_success_callback on_connect_success_callback;
+    plc4c_system_on_connect_failure_callback on_connect_failure_callback;
+    plc4c_system_on_disconnect_success_callback on_disconnect_success_callback;
+    plc4c_system_on_disconnect_failure_callback on_disconnect_failure_callback;
+    plc4c_system_on_loop_failure_callback on_loop_failure_callback;
 };
 
 struct plc4c_item_t {
 };
-typedef struct plc4c_item_t plc4c_item;
-
-typedef plc4c_item* (*plc4c_connection_parse_address_item)(const char *address_string);
 
 struct plc4c_driver_t {
-    char* protocol_code;
-    char* protocol_name;
+    char *protocol_code;
+    char *protocol_name;
+    char *default_transport_code;
     plc4c_connection_parse_address_item parse_address_function;
 };
 
+struct plc4c_driver_list_item_t {
+    plc4c_driver *driver;
+    plc4c_driver_list_item *next;
+};
+
+
 struct plc4c_connection_t {
-    plc4c_driver driver;
-    char* connection_string;
+    const char *connection_string;
+    char *protocol_code;
+    char *transport_code;
+    char *transport_connect_information;
+    char *parameters;
+
+    plc4c_driver* driver;
     bool supports_reading;
     bool supports_writing;
     bool supports_subscriptions;
 };
 
+struct plc4c_connection_list_item_t {
+    plc4c_connection connection;
+    plc4c_connection_list_item *next;
+};
+
 struct plc4c_read_request_t {
-    plc4c_connection* connection;
+    plc4c_connection *connection;
     int num_items;
     plc4c_item items[];
 };
 
 struct plc4c_write_item_t {
     plc4c_item *item;
-    void* value;
+    void *value;
 };
-typedef struct plc4c_write_item_t plc4c_write_item;
 
 struct plc4c_write_request_t {
-    plc4c_connection* connection;
+    plc4c_connection *connection;
     int num_items;
-    plc4c_write_item* items;
+    plc4c_write_item *items;
 };
 
 #endif //PLC4C_SPI_TYPES_PRIVATE_H_
diff --git a/sandbox/plc4c/spi/src/connection.c b/sandbox/plc4c/spi/src/connection.c
index debf9f8..9ab61a3 100644
--- a/sandbox/plc4c/spi/src/connection.c
+++ b/sandbox/plc4c/spi/src/connection.c
@@ -59,7 +59,7 @@ return_code plc4c_connection_create_write_request(plc4c_connection *connection,
     new_write_request->items = malloc(num_items * sizeof(plc4c_write_item*));
     for(int i = 0; i < num_items; i++) {
         char* address = addresses[i];
-        plc4c_item* addressItem = connection->driver.parse_address_function(address);
+        plc4c_item* addressItem = connection->driver->parse_address_function(address);
 
         plc4c_write_item* write_item = malloc(sizeof(plc4c_write_item));
         write_item->item = addressItem;
diff --git a/sandbox/plc4c/spi/src/system.c b/sandbox/plc4c/spi/src/system.c
index aa8761d..bdf8b66 100644
--- a/sandbox/plc4c/spi/src/system.c
+++ b/sandbox/plc4c/spi/src/system.c
@@ -17,58 +17,96 @@
  * under the License.
  */
 
+#include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 #include <plc4c/system.h>
 #include "plc4c/spi/types_private.h"
+#include "plc4c/spi/system_private.h"
 
 return_code plc4c_system_create(plc4c_system **system) {
+    plc4c_system *new_system = malloc(sizeof(plc4c_system));
+    new_system->driver_list_head = NULL;
+    new_system->connection_list_head = NULL;
+    *system = new_system;
     return OK;
 }
 
 void plc4c_system_destroy(plc4c_system *system) {
-
+    // TODO: So some more cleaning up ...
+    free(system);
 }
 
-void plc4c_system_set_on_driver_loaded(plc4c_system *system,
-                                       plc4c_system_callback_on_driver_loaded callback) {
-
+void plc4c_system_set_on_driver_load_success_callback(plc4c_system *system,
+                                                      plc4c_system_on_driver_load_success_callback callback) {
+    system->on_driver_load_success_callback = callback;
 }
 
-void plc4c_system_set_on_driver_load_error(plc4c_system *system,
-                                           plc4c_system_callback_driver_load_error callback) {
-
+void plc4c_system_set_on_driver_load_failure_callback(plc4c_system *system,
+                                                      plc4c_system_on_driver_load_failure_callback callback) {
+    system->on_driver_load_failure_callback = callback;
 }
 
-void plc4c_system_set_on_connection(plc4c_system *system,
-                                    plc4c_system_callback_on_connection callback) {
-
+void plc4c_system_set_on_connect_success_callback(plc4c_system *system,
+                                                  plc4c_system_on_connect_success_callback callback) {
+    system->on_connect_success_callback = callback;
 }
 
-void plc4c_system_set_on_connection_error(plc4c_system *system,
-                                          plc4c_system_callback_connection_error callback) {
-
+void plc4c_system_set_on_connect_failure_callback(plc4c_system *system,
+                                                  plc4c_system_on_connect_failure_callback callback) {
+    system->on_connect_failure_callback = callback;
 }
 
-void plc4c_system_set_on_disconnection(plc4c_system *system,
-                                       plc4c_system_callback_on_disconnection callback) {
-
+void plc4c_system_set_on_disconnect_success_callback(plc4c_system *system,
+                                                     plc4c_system_on_disconnect_success_callback callback) {
+    system->on_disconnect_success_callback = callback;
 }
 
-void plc4c_system_set_on_disconnection_error(plc4c_system *system,
-                                             plc4c_system_callback_disconnection_error callback) {
+void plc4c_system_set_on_disconnection_failure_callback(plc4c_system *system,
+                                                        plc4c_system_on_disconnect_failure_callback callback) {
+    system->on_disconnect_failure_callback = callback;
+}
 
+void plc4c_system_set_on_loop_failure_callback(plc4c_system *system,
+                                               plc4c_system_on_loop_failure_callback callback) {
+    system->on_loop_failure_callback = callback;
 }
 
-void plc4c_system_set_on_loop_error(plc4c_system *system,
-                                    plc4c_system_callback_loop_error callback) {
+return_code plc4c_system_add_driver(plc4c_system *system,
+                                    plc4c_driver *driver) {
+    // If the system is not initialized, return an error.
+    // There is nothing we can do here.
+    if (system == NULL) {
+        return INTERNAL_ERROR;
+    }
 
-}
+    // Get the first element of the driver list.
+    plc4c_driver_list_item *cur_driver = system->driver_list_head;
 
-return_code plc4c_system_add_driver(plc4c_driver *driver) {
+    // If the driver list is empty. Start a new list of drivers.
+    if (cur_driver == NULL) {
+        system->driver_list_head = malloc(sizeof(plc4c_driver_list_item));
+        system->driver_list_head->driver = driver;
+        system->driver_list_head->next = NULL;
+    }
+        // Drivers are already listed, add the currentdriver to the end of the list.
+    else {
+        // Go to the last driver in the list.
+        while (cur_driver->next != NULL) {
+            cur_driver = cur_driver->next;
+        }
+
+        // Add a new driver item to the end of the list.
+        cur_driver->next = malloc(sizeof(plc4c_driver_list_item));
+        cur_driver->next->driver = driver;
+        cur_driver->next->next = NULL;
+    }
     return OK;
 }
 
 return_code plc4c_system_init(plc4c_system *system) {
+    // Nothing to really do at the moment.
+
     return OK;
 }
 
@@ -76,9 +114,185 @@ void plc4c_system_shutdown(plc4c_system *system) {
 
 }
 
+enum connection_string_parser_state {
+    PROTOCOL_CODE,
+    TRANSPORT_CODE,
+    TRANSPORT_CONNECTION_INFORMATION,
+    PARAMETERS,
+    FINISHED
+};
+
+return_code plc4c_system_create_connection(const char *connection_string, plc4c_connection** connection) {
+    // Count the number of colons and question-marks so we know which pattern to use for
+    // matching and how large the arrays for containing the different segments should be.
+    int num_colons = 0;
+    int num_question_marks = 0;
+    char* protocol_code = NULL;
+    char* transport_code = NULL;
+    char* transport_connect_information = NULL;
+    char* parameters = NULL;
+    int start_segment_index = 0;
+    const char* start_segment = connection_string;
+    // The connection string has two parts ... the first, where colons are the delimiters
+    // and the second where a question mark is the delimiter.
+    enum mode {
+        SEARCHING_FOR_COLONS,
+        SEARCHING_FOR_QUESTION_MARKS
+    } mode = SEARCHING_FOR_COLONS;
+    for(int i = 0; i <= strlen(connection_string); i++) {
+        // If we're in the first part of the connection string ... watch out for colons.
+        if(mode == SEARCHING_FOR_COLONS) {
+            // If we encounter a colon, depending on the number of colons already found, save the information in
+            // either the protocol code or transport code variable.
+            if (*(connection_string + i) == ':') {
+                num_colons++;
+                // The first colon delimits the protocol-code.
+                if (num_colons == 1) {
+                    // Allocate enough memory to hold the sub-string.
+                    protocol_code = malloc(sizeof(char) * ((i - start_segment_index) + 1));
+                    // Copy the sub-string to the freshly allocated memory area.
+                    strlcpy(protocol_code, start_segment, (i - start_segment_index) + 1);
+
+                    // Set the start of the next segment to directly after the colon.
+                    start_segment_index = i + 1;
+                    start_segment = connection_string + start_segment_index;
+
+                    // If the following character would be a slash, we're probably finished and no transport code is
+                    // provided. If this is the case, ensure it's actually a double-slash and if this is the case
+                    // switch to the question-mark searching mode.
+                    if(*start_segment == '/') {
+                        if(*(start_segment + 1) == '/') {
+                            mode = SEARCHING_FOR_QUESTION_MARKS;
+                            start_segment_index += 2;
+                            start_segment += 2;
+                        } else {
+                            return INVALID_CONNECTION_STRING;
+                        }
+                    }
+                }
+                // If we encountered a second colon, this is the transport code.
+                else if (num_colons == 2) {
+                    // Allocate enough memory to hold the sub-string.
+                    transport_code = malloc(sizeof(char) * ((i - start_segment_index) + 1));
+                    // Copy the sub-string to the freshly allocated memory area.
+                    strlcpy(transport_code, start_segment, (i - start_segment_index) + 1);
+
+                    // Set the start of the next segment to directly after the colon.
+                    start_segment_index = i + 1;
+                    start_segment = connection_string + start_segment_index;
+
+                    // The transport code is allways followed by "://". So check if this is the case.
+                    // If it is, switch to question-mark searching mode.
+                    if((*start_segment != '/') || (*(start_segment + 1) != '/')) {
+                        return INVALID_CONNECTION_STRING;
+                    }
+                    mode = SEARCHING_FOR_QUESTION_MARKS;
+
+                    // Bump the start of the segment to after the double slashes.
+                    start_segment_index += 2;
+                    start_segment += 2;
+                } else {
+                    return INVALID_CONNECTION_STRING;
+                }
+            }
+        }
+        // If we're in the second part, look for question marks.
+        else {
+            // The question-mark separates the transport connect information from the parameters.
+            if (*(connection_string + i) == '?') {
+                num_question_marks++;
+                // Only one question-mark is allowed in connection strings.
+                if (num_question_marks > 1) {
+                    return INVALID_CONNECTION_STRING;
+                }
+
+                // Allocate enough memory to hold the sub-string.
+                transport_connect_information = malloc(sizeof(char) * ((i - start_segment_index) + 1));
+                // Copy the sub-string to the freshly allocated memory area.
+                strlcpy(transport_connect_information, start_segment, (i - start_segment_index) + 1);
+
+                // Set the start of the next segment to directly after the question-mark.
+                start_segment_index = i + 1;
+                start_segment = connection_string + start_segment_index;
+            }
+            // This is the last character ... finish up the last loose end.
+            if (i == strlen(connection_string)) {
+                // If no question-mark has been encountered, this connection string doesn't have one and the
+                // remaining part is simply the transport connect information.
+                if (num_question_marks == 0) {
+                    transport_connect_information = malloc(sizeof(char) * ((i - start_segment_index) + 1));
+                    strlcpy(transport_connect_information, start_segment, (i - start_segment_index) + 1);
+                }
+                // I a question-mark was found, this is the paramters section.
+                else {
+                    parameters = malloc(sizeof(char) * (i - start_segment_index));
+                    strlcpy(parameters, start_segment, (i - start_segment_index) + 1);
+                }
+            }
+        }
+    }
+    if(num_colons == 0) {
+        return INVALID_CONNECTION_STRING;
+    }
+
+    // Initialize a new connection data-structure with the parsed information.
+    plc4c_connection* new_connection = malloc(sizeof(plc4c_connection));
+    new_connection->connection_string = connection_string;
+    new_connection->protocol_code = protocol_code;
+    new_connection->transport_code = transport_code;
+    new_connection->transport_connect_information = transport_connect_information;
+    new_connection->parameters = parameters;
+    *connection = new_connection;
+
+    return OK;
+}
+
 return_code plc4c_system_connect(plc4c_system *system,
-                                   const char *connectionString,
-                                   plc4c_connection **connection) {
+                                 const char *connection_string,
+                                 plc4c_connection **connection) {
+
+    // Parse the connection string and initialize some of the connection field variables from this.
+    plc4c_connection* new_connection = NULL;
+    return_code result = plc4c_system_create_connection(connection_string, &new_connection);
+    if(result != OK) {
+        return result;
+    }
+
+    // Find a matching driver from the driver-list
+    plc4c_driver_list_item* cur_driver_list_item = system->driver_list_head;
+    // If no driver is available at all this is devinitely a developer error,
+    // so we output a special error code for this case
+    if(cur_driver_list_item == NULL) {
+        return NO_DRIVER_AVAILABLE;
+    }
+    do {
+        if (strcmp(cur_driver_list_item->driver->protocol_code, new_connection->protocol_code) == 0) {
+            // Set the driver reference in the new connection.
+            new_connection->driver = cur_driver_list_item->driver;
+            // If no transport was selected, use the drivers default transport (if it exists).
+            if(new_connection->transport_code == NULL) {
+                if(cur_driver_list_item->driver->default_transport_code != NULL) {
+                    new_connection->transport_code = cur_driver_list_item->driver->default_transport_code;
+                }
+            }
+            break;
+        }
+        cur_driver_list_item = cur_driver_list_item->next;
+    } while (cur_driver_list_item != NULL);
+
+    // If the driver property is still NULL, the desired driver was not found.
+    if(new_connection->driver == NULL) {
+        return UNKNOWN_DRIVER;
+    }
+
+    // Return an error if the user didn't specify a transport and the driver doesn't have a default one.
+    if(new_connection->transport_code == NULL) {
+        return UNSPECIFIED_TRANSPORT;
+    }
+
+    // Pass the new connection back.
+    *connection = new_connection;
+
     return OK;
 }
 
diff --git a/sandbox/plc4c/spi/test/system_test.c b/sandbox/plc4c/spi/test/system_test.c
new file mode 100644
index 0000000..223eb83
--- /dev/null
+++ b/sandbox/plc4c/spi/test/system_test.c
@@ -0,0 +1,78 @@
+/*
+ * 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.
+ */
+#include <unity.h>
+#include <stdlib.h>
+#include <plc4c/spi/types_private.h>
+#include "plc4c/spi/system_private.h"
+
+void setUp(void) {
+}
+
+void tearDown(void) {
+}
+
+void test_system_plc4c_system_create_connection_args(const char *connection_string,
+                                                     return_code expected_return_code,
+                                                     const char *expected_connection_string,
+                                                     const char *expected_protocol_code,
+                                                     const char *expected_transport_code,
+                                                     const char *expected_transport_connect_information,
+                                                     const char *expected_parameters) {
+    plc4c_connection *connection = NULL;
+    return_code result = plc4c_system_create_connection(connection_string, &connection);
+    TEST_ASSERT_EQUAL(expected_return_code, result);
+    if(expected_return_code != OK) {
+        TEST_ASSERT_NULL(connection);
+    } else {
+        TEST_ASSERT_EQUAL_STRING(expected_connection_string, connection->connection_string);
+        TEST_ASSERT_EQUAL_STRING(expected_protocol_code, connection->protocol_code);
+        TEST_ASSERT_EQUAL_STRING(expected_transport_code, connection->transport_code);
+        TEST_ASSERT_EQUAL_STRING(expected_transport_connect_information, connection->transport_connect_information);
+        TEST_ASSERT_EQUAL_STRING(expected_parameters, connection->parameters);
+        free(connection);
+    }
+}
+
+void test_system_plc4c_system_create_connection(void) {
+    test_system_plc4c_system_create_connection_args("s7://1.2.3.4", OK, "s7://1.2.3.4", "s7", NULL, "1.2.3.4", NULL);
+    test_system_plc4c_system_create_connection_args("s7:tcp://1.2.3.4", OK, "s7:tcp://1.2.3.4", "s7", "tcp", "1.2.3.4", NULL);
+    test_system_plc4c_system_create_connection_args("s7://1.2.3.4?params", OK, "s7://1.2.3.4?params", "s7", NULL, "1.2.3.4", "params");
+    test_system_plc4c_system_create_connection_args("s7:tcp://1.2.3.4?params", OK, "s7:tcp://1.2.3.4?params", "s7", "tcp", "1.2.3.4", "params");
+
+    // A colon after the "://" shouldn't matter ...
+    test_system_plc4c_system_create_connection_args("s7://1.2.3.4:42", OK, "s7://1.2.3.4:42", "s7", NULL, "1.2.3.4:42", NULL);
+    test_system_plc4c_system_create_connection_args("s7://1.2.3.4?param=a:42", OK, "s7://1.2.3.4?param=a:42", "s7", NULL, "1.2.3.4", "param=a:42");
+
+    // Well obviously the parser shouldn't be able to find anything here ...
+    test_system_plc4c_system_create_connection_args("hurz", INVALID_CONNECTION_STRING, NULL, NULL, NULL, NULL, NULL);
+    // In these cases the parser expects a "//" after the second colon, which isn't there ...
+    test_system_plc4c_system_create_connection_args("a:b:c://d", INVALID_CONNECTION_STRING, NULL, NULL, NULL, NULL, NULL);
+    test_system_plc4c_system_create_connection_args("a:b:d", INVALID_CONNECTION_STRING, NULL, NULL, NULL, NULL, NULL);
+
+    // There should only be one question-mark ...
+    test_system_plc4c_system_create_connection_args("a://a?b?c", INVALID_CONNECTION_STRING, NULL, NULL, NULL, NULL, NULL);
+}
+
+int main(void) {
+    UNITY_BEGIN();
+
+    RUN_TEST(test_system_plc4c_system_create_connection);
+
+    return UNITY_END();
+}
\ No newline at end of file