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/05/11 15:01:13 UTC

[plc4x] 01/01: - First draft of a subscription API

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

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

commit 470d751a548e599d85ce5d1434899a4bf9720f1d
Author: Christofer Dutz <ch...@c-ware.de>
AuthorDate: Mon May 11 16:58:14 2020 +0200

    - First draft of a subscription API
---
 sandbox/plc4c/api/include/plc4c/connection.h       |  50 ++--
 sandbox/plc4c/api/include/plc4c/read.h             |   6 +
 sandbox/plc4c/api/include/plc4c/subscribe.h        | 189 ++++++++++++++
 sandbox/plc4c/api/include/plc4c/types.h            |  38 +++
 sandbox/plc4c/api/include/plc4c/write.h            |   6 +
 .../plc4c/examples/hello-world/src/hello_world.c   |   4 +-
 .../plc4c/spi/include/plc4c/spi/types_private.h    |  65 ++++-
 sandbox/plc4c/spi/src/connection.c                 |  12 -
 sandbox/plc4c/spi/src/read.c                       |   8 +
 sandbox/plc4c/spi/src/subscribe.c                  | 274 +++++++++++++++++++++
 sandbox/plc4c/spi/src/write.c                      |   7 +
 11 files changed, 627 insertions(+), 32 deletions(-)

diff --git a/sandbox/plc4c/api/include/plc4c/connection.h b/sandbox/plc4c/api/include/plc4c/connection.h
index ace6d00..531d2ca 100644
--- a/sandbox/plc4c/api/include/plc4c/connection.h
+++ b/sandbox/plc4c/api/include/plc4c/connection.h
@@ -97,7 +97,7 @@ plc4c_transport *plc4c_connection_get_transport(plc4c_connection *connection);
  * @param transport plc4c_transport
  */
 void plc4c_connection_set_transport(plc4c_connection *connection,
-                                         plc4c_transport *transport);
+                                    plc4c_transport *transport);
 
 /**
  * Returns the transport connection information for a given connection
@@ -188,7 +188,7 @@ plc4c_driver *plc4c_connection_get_driver(plc4c_connection *connection);
  * @param connection plc4c_connection
  * @param plc4c_driver
  */
- void plc4c_connection_set_driver(plc4c_connection *connection,
+void plc4c_connection_set_driver(plc4c_connection *connection,
                                  plc4c_driver *driver);
 
 /**
@@ -229,12 +229,6 @@ plc4c_return_code plc4c_connection_create_read_request(
     plc4c_read_request **read_request);
 
 /**
- * Destroys a given read_response
- * @param read_response the read_response
- */
-void plc4c_connection_destroy_read_response(plc4c_read_response *read_response);
-
-/**
  * Check if the current connection supports write operations.
  *
  * @param connection reference to the connection
@@ -246,24 +240,16 @@ bool plc4c_connection_get_supports_writing(plc4c_connection *connection);
  * Initializes an empty write-request.
  *
  * @param connection connection that this write-request will be executed on.
- * @param num_items number of items we want to write.
  * @param addresses list of address strings.
  * @param values list of pointers to values.
  * @param write_request pointer to the write-request
- * @param plc4c_return_code
+ * @return plc4c_return_code
  */
 plc4c_return_code plc4c_connection_create_write_request(
     plc4c_connection *connection, plc4c_list *addresses, plc4c_list *values,
     plc4c_write_request **write_request);
 
 /**
- * Destroys a given write_response
- * @param write_response the write_response
- */
-void plc4c_connection_destroy_write_response(
-    plc4c_write_response *write_response);
-
-/**
  * Check if the current connection supports subscriptions.
  *
  * @param connection reference to the connection
@@ -272,6 +258,36 @@ void plc4c_connection_destroy_write_response(
 bool plc4c_connection_get_supports_subscriptions(plc4c_connection *connection);
 
 /**
+ * Initializes an empty subscription-request.
+ *
+ * @param connection connection that this subscription-request will be executed
+ * on.
+ * TODO: Somehow we need to provide the subscription type and depending on the
+ * type some additional parameters (Cycle-time).
+ * @param addresses list of address strings.
+ * @param subscription_request pointer to the subscription-request
+ * @return plc4c_return_code
+ */
+plc4c_return_code plc4c_connection_create_subscription_request(
+    plc4c_connection *connection, plc4c_list *addresses,
+    plc4c_subscription_request **subscription_request);
+
+/**
+ * Initializes an empty unsubscription-request.
+ *
+ * @param connection connection that this unsubscription-request will be
+ * executed on.
+ * TODO: Somehow we need to provide the unsubscription type and depending on the
+ * type some additional parameters (Cycle-time).
+ * @param addresses list of address strings.
+ * @param unsubscription_request pointer to the unsubscription-request
+ * @return plc4c_return_code
+ */
+plc4c_return_code plc4c_connection_create_unsubscription_request(
+    plc4c_connection *connection, plc4c_list *addresses,
+    plc4c_unsubscription_request **unsubscription_request);
+
+/**
  * Returns the current number of running tasks for this connection
  * @param connection plc4c_connection
  * @return the count of running tasks
diff --git a/sandbox/plc4c/api/include/plc4c/read.h b/sandbox/plc4c/api/include/plc4c/read.h
index e22882a..38d03b3 100644
--- a/sandbox/plc4c/api/include/plc4c/read.h
+++ b/sandbox/plc4c/api/include/plc4c/read.h
@@ -94,6 +94,12 @@ bool plc4c_read_request_execution_check_finished_with_error(
 plc4c_read_response *plc4c_read_request_execution_get_response(
     plc4c_read_request_execution *read_request_execution);
 
+/**
+ * Destroys a given read_response
+ * @param read_response the read_response
+ */
+void plc4c_read_destroy_read_response(plc4c_read_response *read_response);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/sandbox/plc4c/api/include/plc4c/subscribe.h b/sandbox/plc4c/api/include/plc4c/subscribe.h
new file mode 100644
index 0000000..b34ba60
--- /dev/null
+++ b/sandbox/plc4c/api/include/plc4c/subscribe.h
@@ -0,0 +1,189 @@
+/*
+ * 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_SUBSCRIBE_H_
+#define PLC4C_SUBSCRIBE_H_
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "plc4c/types.h"
+
+/*
+ *
+ * Subscriptions
+ *
+ */
+
+/**
+ * Destroys a given subscription-request.
+ *
+ * @param subscription_request the subscription-request.
+ */
+void plc4c_subscription_request_destroy(
+    plc4c_subscription_request *subscription_request);
+
+/**
+ * Returns the plc4c_connection for a give subscription request
+ * @param subscription_request plc4c_subscription_request
+ * @return plc4c_connection
+ */
+plc4c_connection *plc4c_subscription_request_get_connection(
+    plc4c_subscription_request *subscription_request);
+
+/**
+ * Sets the plc4c_connection for a given subscription request
+ * @param subscription_request plc4c_subscription_request
+ * @param connection plc4c_connection
+ */
+void plc4c_subscription_request_set_connection(
+    plc4c_subscription_request *subscription_request,
+    plc4c_connection *connection);
+
+/**
+ * Actually executes the subscription-request.
+ * @param connection connection this subscription-request will be executed on.
+ * @param subscription_request the subscription-request object.
+ * @param subscription_request_execution pointer to a data-structure handling
+ * one execution of the subscription-request.
+ * @return plc4c_return_code
+ */
+plc4c_return_code plc4c_subscription_request_execute(
+    plc4c_subscription_request *subscription_request,
+    plc4c_subscription_request_execution **subscription_request_execution);
+
+/**
+ * Destroys a given subscription-request execution.
+ *
+ * @param subscription_request_execution the subscription-request execution.
+ */
+void plc4c_subscription_request_execution_destroy(
+    plc4c_subscription_request_execution *subscription_request_execution);
+
+/**
+ * Check if the subscription-request is completed successfully.
+ *
+ * @param subscription_request_execution the subscription-request execution.
+ * @return true if the subscription-request is completed successfully.
+ */
+bool plc4c_subscription_request_execution_check_finished_successfully(
+    plc4c_subscription_request_execution *subscription_request_execution);
+
+/**
+ * Check if the subscription-request is completed unsuccessfully.
+ *
+ * @param subscription_request_execution the subscription-request execution.
+ * @return true if the subscription-request is completed with an error.
+ */
+bool plc4c_subscription_request_execution_check_finished_with_error(
+    plc4c_subscription_request_execution *subscription_request_execution);
+
+/**
+ * Retrieve the subscription-response from a given subscription-request
+ * execution.
+ *
+ * @param subscription_request_execution the subscription-request execution.
+ * @return the subscription-response.
+ */
+plc4c_subscription_response *plc4c_subscription_request_execution_get_response(
+    plc4c_subscription_request_execution *subscription_request_execution);
+
+/*
+ *
+ * Unsubscriptions
+ *
+ */
+
+/**
+ * Destroys a given unsubscription-request.
+ *
+ * @param unsubscription_request the unsubscription-request.
+ */
+void plc4c_unsubscription_request_destroy(
+    plc4c_unsubscription_request *unsubscription_request);
+
+/**
+ * Returns the plc4c_connection for a give unsubscription request
+ * @param unsubscription_request plc4c_unsubscription_request
+ * @return plc4c_connection
+ */
+plc4c_connection *plc4c_unsubscription_request_get_connection(
+    plc4c_unsubscription_request *unsubscription_request);
+
+/**
+ * Sets the plc4c_connection for a given unsubscription request
+ * @param unsubscription_request plc4c_unsubscription_request
+ * @param connection plc4c_connection
+ */
+void plc4c_unsubscription_request_set_connection(
+    plc4c_unsubscription_request *unsubscription_request,
+    plc4c_connection *connection);
+
+/**
+ * Actually executes the unsubscription-request.
+ * @param connection connection this unsubscription-request will be executed on.
+ * @param unsubscription_request the unsubscription-request object.
+ * @param unsubscription_request_execution pointer to a data-structure handling
+ * one execution of the unsubscription-request.
+ * @return plc4c_return_code
+ */
+plc4c_return_code plc4c_unsubscription_request_execute(
+    plc4c_unsubscription_request *unsubscription_request,
+    plc4c_unsubscription_request_execution **unsubscription_request_execution);
+
+/**
+ * Destroys a given unsubscription-request execution.
+ *
+ * @param unsubscription_request_execution the unsubscription-request execution.
+ */
+void plc4c_unsubscription_request_execution_destroy(
+    plc4c_unsubscription_request_execution *unsubscription_request_execution);
+
+/**
+ * Check if the unsubscription-request is completed successfully.
+ *
+ * @param unsubscription_request_execution the unsubscription-request execution.
+ * @return true if the unsubscription-request is completed successfully.
+ */
+bool plc4c_unsubscription_request_execution_check_finished_successfully(
+    plc4c_unsubscription_request_execution *unsubscription_request_execution);
+
+/**
+ * Check if the unsubscription-request is completed unsuccessfully.
+ *
+ * @param unsubscription_request_execution the unsubscription-request execution.
+ * @return true if the unsubscription-request is completed with an error.
+ */
+bool plc4c_unsubscription_request_execution_check_finished_with_error(
+    plc4c_unsubscription_request_execution *unsubscription_request_execution);
+
+/**
+ * Retrieve the unsubscription-response from a given unsubscription-request
+ * execution.
+ *
+ * @param unsubscription_request_execution the unsubscription-request execution.
+ * @return the unsubscription-response.
+ */
+plc4c_unsubscription_response *
+plc4c_unsubscription_request_execution_get_response(
+    plc4c_unsubscription_request_execution *unsubscription_request_execution);
+
+#ifdef __cplusplus
+}
+#endif
+#endif  // PLC4C_SUBSCRIBE_H_
\ No newline at end of file
diff --git a/sandbox/plc4c/api/include/plc4c/types.h b/sandbox/plc4c/api/include/plc4c/types.h
index 5040616..e20b52d 100644
--- a/sandbox/plc4c/api/include/plc4c/types.h
+++ b/sandbox/plc4c/api/include/plc4c/types.h
@@ -76,6 +76,12 @@ typedef enum plc4c_data_type {
   PLC4C_VOID_POINTER
 } plc4c_data_type;
 
+typedef enum plc4c_subscription_type {
+  PLC4C_SUBSCRIPTION_CYCLIC,
+  PLC4C_SUBSCRIPTION_CHANGE_OF_STATE,
+  PLC4C_SUBSCRIPTION_EVENT
+} plc4c_subscription_type;
+
 /**
  * Helper that translates from a return_code enum value to something a human can
  * work with.
@@ -152,6 +158,38 @@ typedef struct plc4c_write_request_execution_t plc4c_write_request_execution;
  */
 typedef struct plc4c_write_response_t plc4c_write_response;
 
+/**
+ * A plc4c subscription-request.
+ */
+typedef struct plc4c_subscription_request_t plc4c_subscription_request;
+
+/**
+ * A plc4c subscription-request-execution.
+ */
+typedef struct plc4c_subscription_request_execution_t
+    plc4c_subscription_request_execution;
+
+/**
+ * A plc4c subscription-response.
+ */
+typedef struct plc4c_unsubscription_response_t plc4c_subscription_response;
+
+/**
+ * A plc4c unsubscription-request.
+ */
+typedef struct plc4c_unsubscription_request_t plc4c_unsubscription_request;
+
+/**
+ * A plc4c unsubscription-request-execution.
+ */
+typedef struct plc4c_unsubscription_request_execution_t
+    plc4c_unsubscription_request_execution;
+
+/**
+ * A plc4c unsubscription-response.
+ */
+typedef struct plc4c_unsubscription_response_t plc4c_unsubscription_response;
+
 typedef struct plc4c_data_t plc4c_data;
 
 #ifdef __cplusplus
diff --git a/sandbox/plc4c/api/include/plc4c/write.h b/sandbox/plc4c/api/include/plc4c/write.h
index 05c388d..c7b62fe 100644
--- a/sandbox/plc4c/api/include/plc4c/write.h
+++ b/sandbox/plc4c/api/include/plc4c/write.h
@@ -94,6 +94,12 @@ bool plc4c_write_request_execution_check_completed_with_error(
 plc4c_write_response *plc4c_write_request_execution_get_response(
     plc4c_write_request_execution *write_request_execution);
 
+/**
+ * Destroys a given write_response
+ * @param write_response the write_response
+ */
+void plc4c_write_destroy_write_response(plc4c_write_response *write_response);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/sandbox/plc4c/examples/hello-world/src/hello_world.c b/sandbox/plc4c/examples/hello-world/src/hello_world.c
index 10ac7db..1a7fe0a 100644
--- a/sandbox/plc4c/examples/hello-world/src/hello_world.c
+++ b/sandbox/plc4c/examples/hello-world/src/hello_world.c
@@ -230,7 +230,7 @@ int main() {
         }
 
         // Clean up.
-        plc4c_connection_destroy_read_response(read_response);
+        plc4c_read_destroy_read_response(read_response);
         plc4c_read_request_execution_destroy(read_request_execution);
         plc4c_read_request_destroy(read_request);
 
@@ -302,7 +302,7 @@ int main() {
         }
 
         // Clean up.
-        plc4c_connection_destroy_write_response(write_response);
+        plc4c_write_destroy_write_response(write_response);
         plc4c_write_request_execution_destroy(write_request_execution);
 
         // Disconnect.
diff --git a/sandbox/plc4c/spi/include/plc4c/spi/types_private.h b/sandbox/plc4c/spi/include/plc4c/spi/types_private.h
index daa755b..bf0ce56 100644
--- a/sandbox/plc4c/spi/include/plc4c/spi/types_private.h
+++ b/sandbox/plc4c/spi/include/plc4c/spi/types_private.h
@@ -58,12 +58,26 @@ typedef plc4c_return_code (*plc4c_connection_write_function)(
     plc4c_write_request_execution *write_request_execution,
     plc4c_system_task **task);
 
+typedef plc4c_return_code (*plc4c_connection_subscribe_function)(
+    plc4c_subscription_request_execution *subscription_request_execution,
+    plc4c_system_task **task);
+
+typedef plc4c_return_code (*plc4c_connection_unsubscribe_function)(
+    plc4c_unsubscription_request_execution *unsubscription_request_execution,
+    plc4c_system_task **task);
+
 typedef void (*plc4c_connect_free_read_response_function)(
     plc4c_read_response *response);
 
 typedef void (*plc4c_connect_free_write_response_function)(
     plc4c_write_response *response);
 
+typedef void (*plc4c_connect_free_subscription_response_function)(
+    plc4c_subscription_response *response);
+
+typedef void (*plc4c_connect_free_unsubscription_response_function)(
+    plc4c_unsubscription_response *response);
+
 struct plc4c_system_t {
   /* drivers */
   plc4c_list *driver_list;
@@ -100,8 +114,12 @@ struct plc4c_driver_t {
   plc4c_connection_disconnect_function disconnect_function;
   plc4c_connection_read_function read_function;
   plc4c_connection_write_function write_function;
+  plc4c_connection_subscribe_function subscribe_function;
+  plc4c_connection_unsubscribe_function unsubscribe_function;
   plc4c_connect_free_read_response_function free_read_response_function;
   plc4c_connect_free_write_response_function free_write_response_function;
+  plc4c_connect_free_subscription_response_function free_subscription_response_function;
+  plc4c_connect_free_unsubscription_response_function free_unsubscription_response_function;
 };
 
 struct plc4c_driver_list_item_t {
@@ -178,7 +196,20 @@ struct plc4c_request_value_item_t {
 struct plc4c_response_value_item_t {
   plc4c_item *item;
   plc4c_response_code response_code;
-  void *value;
+  plc4c_data *value;
+};
+
+struct plc4c_response_subscription_item_t {
+  plc4c_item *item;
+  plc4c_response_code response_code;
+  // This is highly coupled to the protocol used.
+  void *subscription_handle;
+};
+
+struct plc4c_request_unsubscription_item_t {
+  plc4c_item *item;
+  // This is highly coupled to the protocol used.
+  void *subscription_handle;
 };
 
 struct plc4c_response_item_t {
@@ -196,6 +227,16 @@ struct plc4c_write_request_t {
   plc4c_list *items;
 };
 
+struct plc4c_subscription_request_t {
+  plc4c_connection *connection;
+  plc4c_list *items;
+};
+
+struct plc4c_unsubscription_request_t {
+  plc4c_connection *connection;
+  plc4c_list *items;
+};
+
 struct plc4c_read_request_execution_t {
   plc4c_read_request *read_request;
   plc4c_read_response *read_response;
@@ -208,6 +249,18 @@ struct plc4c_write_request_execution_t {
   plc4c_system_task *system_task;
 };
 
+struct plc4c_subscription_request_execution_t {
+  plc4c_subscription_request *subscription_request;
+  plc4c_subscription_response *subscription_response;
+  plc4c_system_task *system_task;
+};
+
+struct plc4c_unsubscription_request_execution_t {
+  plc4c_unsubscription_request *unsubscription_request;
+  plc4c_unsubscription_response *unsubscription_response;
+  plc4c_system_task *system_task;
+};
+
 struct plc4c_read_response_t {
   plc4c_read_request *read_request;
   plc4c_list *items;
@@ -218,6 +271,16 @@ struct plc4c_write_response_t {
   plc4c_list *response_items;
 };
 
+struct plc4c_subscription_response_t {
+  plc4c_subscription_request *subscription_request;
+  plc4c_list *response_items;
+};
+
+struct plc4c_unsubscription_response_t {
+  plc4c_unsubscription_request *unsubscription_request;
+  plc4c_list *response_items;
+};
+
 struct plc4c_system_task_t {
   int state_id;
   plc4c_system_task_state_machine_function state_machine_function;
diff --git a/sandbox/plc4c/spi/src/connection.c b/sandbox/plc4c/spi/src/connection.c
index 61ca280..04450ee 100644
--- a/sandbox/plc4c/spi/src/connection.c
+++ b/sandbox/plc4c/spi/src/connection.c
@@ -228,12 +228,6 @@ plc4c_return_code plc4c_connection_create_read_request(
   return OK;
 }
 
-void plc4c_connection_destroy_read_response(
-    plc4c_read_response *read_response) {
-  read_response->read_request->connection->driver->free_read_response_function(
-      read_response);
-}
-
 bool plc4c_connection_get_supports_writing(plc4c_connection *connection) {
   return connection->supports_writing;
 }
@@ -285,12 +279,6 @@ plc4c_return_code plc4c_connection_create_write_request(
   return OK;
 }
 
-void plc4c_connection_destroy_write_response(
-    plc4c_write_response *write_response) {
-  write_response->write_request->connection->driver
-      ->free_write_response_function(write_response);
-}
-
 int plc4c_connection_get_running_tasks_count(plc4c_connection *connection) {
   return connection->num_running_system_tasks;
 }
diff --git a/sandbox/plc4c/spi/src/read.c b/sandbox/plc4c/spi/src/read.c
index 7d90e63..3066d02 100644
--- a/sandbox/plc4c/spi/src/read.c
+++ b/sandbox/plc4c/spi/src/read.c
@@ -71,6 +71,7 @@ bool plc4c_read_request_execution_check_finished_successfully(
 
 bool plc4c_read_request_execution_check_finished_with_error(
     plc4c_read_request_execution *read_request_execution) {
+  // TODO: Implement this sensibly ...
   return false;
 }
 
@@ -90,3 +91,10 @@ void plc4c_read_request_execution_destroy(
     plc4c_read_request_execution *read_request_execution) {
   free(read_request_execution);
 }
+
+void plc4c_read_destroy_read_response(
+    plc4c_read_response *read_response) {
+  read_response->read_request->connection->driver->free_read_response_function(
+      read_response);
+}
+
diff --git a/sandbox/plc4c/spi/src/subscribe.c b/sandbox/plc4c/spi/src/subscribe.c
new file mode 100644
index 0000000..22b30f4
--- /dev/null
+++ b/sandbox/plc4c/spi/src/subscribe.c
@@ -0,0 +1,274 @@
+/*
+ * 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 <plc4c/plc4c.h>
+#include <plc4c/subscribe.h>
+#include <plc4c/spi/types_private.h>
+#include <stdlib.h>
+
+/*
+ *
+ * Subscriptions
+ *
+ */
+
+/**
+ * Destroys a given subscription-request.
+ *
+ * @param subscription_request the subscription-request.
+ */
+void plc4c_subscription_request_destroy(
+    plc4c_subscription_request *subscription_request) {
+  free(subscription_request);
+}
+
+/**
+ * Returns the plc4c_connection for a give subscription request
+ * @param subscription_request plc4c_subscription_request
+ * @return plc4c_connection
+ */
+plc4c_connection *plc4c_subscription_request_get_connection(
+    plc4c_subscription_request *subscription_request) {
+  return subscription_request->connection;
+}
+
+/**
+ * Sets the plc4c_connection for a given subscription request
+ * @param subscription_request plc4c_subscription_request
+ * @param connection plc4c_connection
+ */
+void plc4c_subscription_request_set_connection(
+    plc4c_subscription_request *subscription_request,
+    plc4c_connection *connection) {
+  subscription_request->connection = connection;
+}
+
+/**
+ * Actually executes the subscription-request.
+ * @param connection connection this subscription-request will be executed on.
+ * @param subscription_request the subscription-request object.
+ * @param subscription_request_execution pointer to a data-structure handling
+ * one execution of the subscription-request.
+ * @return plc4c_return_code
+ */
+plc4c_return_code plc4c_subscription_request_execute(
+    plc4c_subscription_request *subscription_request,
+    plc4c_subscription_request_execution **subscription_request_execution) {
+  // Inject the default subscription context into the system task.
+  plc4c_subscription_request_execution *new_subscription_request_execution =
+      malloc(sizeof(plc4c_subscription_request_execution));
+  new_subscription_request_execution->subscription_request = subscription_request;
+  new_subscription_request_execution->subscription_response = NULL;
+  new_subscription_request_execution->system_task = NULL;
+
+  plc4c_system_task *system_task;
+  plc4c_connection_get_driver(plc4c_subscription_request_get_connection(subscription_request))
+      ->subscribe_function(new_subscription_request_execution, &system_task);
+
+  // Increment the number of running tasks for this connection.
+  plc4c_connection_task_added(subscription_request->connection);
+  // Add the new task to the task-list.
+  plc4c_utils_list_insert_tail_value(
+      plc4c_system_get_task_list(plc4c_connection_get_system(
+          plc4c_subscription_request_get_connection(subscription_request))),
+      system_task);
+
+  *subscription_request_execution = new_subscription_request_execution;
+  return OK;
+}
+
+/**
+ * Destroys a given subscription-request execution.
+ *
+ * @param subscription_request_execution the subscription-request execution.
+ */
+void plc4c_subscription_request_execution_destroy(
+    plc4c_subscription_request_execution *subscription_request_execution) {
+  free(subscription_request_execution);
+}
+
+/**
+ * Check if the subscription-request is completed successfully.
+ *
+ * @param subscription_request_execution the subscription-request execution.
+ * @return true if the subscription-request is completed successfully.
+ */
+bool plc4c_subscription_request_execution_check_finished_successfully(
+    plc4c_subscription_request_execution *subscription_request_execution) {
+  if (subscription_request_execution == NULL) {
+    return true;
+  }
+  if (subscription_request_execution->system_task == NULL) {
+    return true;
+  }
+  return subscription_request_execution->system_task->completed;
+}
+
+/**
+ * Check if the subscription-request is completed unsuccessfully.
+ *
+ * @param subscription_request_execution the subscription-request execution.
+ * @return true if the subscription-request is completed with an error.
+ */
+bool plc4c_subscription_request_execution_check_finished_with_error(
+    plc4c_subscription_request_execution *subscription_request_execution) {
+  // TODO: Implement this sensibly ...
+  return false;
+}
+
+/**
+ * Retrieve the subscription-response from a given subscription-request
+ * execution.
+ *
+ * @param subscription_request_execution the subscription-request execution.
+ * @return the subscription-response.
+ */
+plc4c_subscription_response *plc4c_subscription_request_execution_get_response(
+    plc4c_subscription_request_execution *subscription_request_execution) {
+  if (subscription_request_execution == NULL) {
+    return NULL;
+  }
+  return subscription_request_execution->subscription_response;
+}
+
+/*
+ *
+ * Unsubscriptions
+ *
+ */
+
+/**
+ * Destroys a given unsubscription-request.
+ *
+ * @param unsubscription_request the unsubscription-request.
+ */
+void plc4c_unsubscription_request_destroy(
+    plc4c_unsubscription_request *unsubscription_request) {
+  free(unsubscription_request);
+}
+
+/**
+ * Returns the plc4c_connection for a give unsubscription request
+ * @param unsubscription_request plc4c_unsubscription_request
+ * @return plc4c_connection
+ */
+plc4c_connection *plc4c_unsubscription_request_get_connection(
+    plc4c_unsubscription_request *unsubscription_request) {
+  return unsubscription_request->connection;
+}
+
+/**
+ * Sets the plc4c_connection for a given unsubscription request
+ * @param unsubscription_request plc4c_unsubscription_request
+ * @param connection plc4c_connection
+ */
+void plc4c_unsubscription_request_set_connection(
+    plc4c_unsubscription_request *unsubscription_request,
+    plc4c_connection *connection) {
+  unsubscription_request->connection = connection;
+}
+
+/**
+ * Actually executes the unsubscription-request.
+ * @param connection connection this unsubscription-request will be executed on.
+ * @param unsubscription_request the unsubscription-request object.
+ * @param unsubscription_request_execution pointer to a data-structure handling
+ * one execution of the unsubscription-request.
+ * @return plc4c_return_code
+ */
+plc4c_return_code plc4c_unsubscription_request_execute(
+    plc4c_unsubscription_request *unsubscription_request,
+    plc4c_unsubscription_request_execution **unsubscription_request_execution) {
+  // Inject the default unsubscription context into the system task.
+  plc4c_unsubscription_request_execution *new_unsubscription_request_execution =
+      malloc(sizeof(plc4c_unsubscription_request_execution));
+  new_unsubscription_request_execution->unsubscription_request = unsubscription_request;
+  new_unsubscription_request_execution->unsubscription_response = NULL;
+  new_unsubscription_request_execution->system_task = NULL;
+
+  plc4c_system_task *system_task;
+  plc4c_connection_get_driver(plc4c_unsubscription_request_get_connection(unsubscription_request))
+      ->unsubscribe_function(new_unsubscription_request_execution, &system_task);
+
+  // Increment the number of running tasks for this connection.
+  plc4c_connection_task_added(unsubscription_request->connection);
+  // Add the new task to the task-list.
+  plc4c_utils_list_insert_tail_value(
+      plc4c_system_get_task_list(plc4c_connection_get_system(
+          plc4c_unsubscription_request_get_connection(unsubscription_request))),
+      system_task);
+
+  *unsubscription_request_execution = new_unsubscription_request_execution;
+  return OK;
+}
+
+/**
+ * Destroys a given unsubscription-request execution.
+ *
+ * @param unsubscription_request_execution the unsubscription-request execution.
+ */
+void plc4c_unsubscription_request_execution_destroy(
+    plc4c_unsubscription_request_execution *unsubscription_request_execution) {
+  free(unsubscription_request_execution);
+}
+
+/**
+ * Check if the unsubscription-request is completed successfully.
+ *
+ * @param unsubscription_request_execution the unsubscription-request execution.
+ * @return true if the unsubscription-request is completed successfully.
+ */
+bool plc4c_unsubscription_request_execution_check_finished_successfully(
+    plc4c_unsubscription_request_execution *unsubscription_request_execution) {
+  if (unsubscription_request_execution == NULL) {
+    return true;
+  }
+  if (unsubscription_request_execution->system_task == NULL) {
+    return true;
+  }
+  return unsubscription_request_execution->system_task->completed;
+}
+
+/**
+ * Check if the unsubscription-request is completed unsuccessfully.
+ *
+ * @param unsubscription_request_execution the unsubscription-request execution.
+ * @return true if the unsubscription-request is completed with an error.
+ */
+bool plc4c_unsubscription_request_execution_check_finished_with_error(
+    plc4c_unsubscription_request_execution *unsubscription_request_execution) {
+  // TODO: Implement this sensibly ...
+  return false;
+}
+
+/**
+ * Retrieve the unsubscription-response from a given unsubscription-request
+ * execution.
+ *
+ * @param unsubscription_request_execution the unsubscription-request execution.
+ * @return the unsubscription-response.
+ */
+plc4c_unsubscription_response *
+plc4c_unsubscription_request_execution_get_response(
+    plc4c_unsubscription_request_execution *unsubscription_request_execution) {
+  if (unsubscription_request_execution == NULL) {
+    return NULL;
+  }
+  return unsubscription_request_execution->unsubscription_response;
+}
diff --git a/sandbox/plc4c/spi/src/write.c b/sandbox/plc4c/spi/src/write.c
index d2ade49..ae65674 100644
--- a/sandbox/plc4c/spi/src/write.c
+++ b/sandbox/plc4c/spi/src/write.c
@@ -89,3 +89,10 @@ void plc4c_write_request_execution_destroy(
     plc4c_write_request_execution *write_request_execution) {
   free(write_request_execution);
 }
+
+void plc4c_write_destroy_write_response(
+    plc4c_write_response *write_response) {
+  write_response->write_request->connection->driver
+      ->free_write_response_function(write_response);
+}
+