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

[plc4x] branch feature/c-api updated: - Continued working on the read support ... - Implemented connect and disconnect via system-task

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

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


The following commit(s) were added to refs/heads/feature/c-api by this push:
     new 7cd7ddf  - Continued working on the read support ... - Implemented connect and disconnect via system-task
7cd7ddf is described below

commit 7cd7ddf8c90fa56532e7c8aad4b81623892f872e
Author: Christofer Dutz <ch...@c-ware.de>
AuthorDate: Mon May 4 18:43:21 2020 +0200

    - Continued working on the read support ...
    - Implemented connect and disconnect via system-task
---
 .../plc4c/drivers/simulated/src/driver_simulated.c | 149 ++++++++++++++++++---
 .../plc4c/examples/hello-world/src/hello_world.c   |  33 +++++
 .../plc4c/spi/include/plc4c/spi/types_private.h    |  11 +-
 sandbox/plc4c/spi/src/connection.c                 |   8 +-
 sandbox/plc4c/spi/src/read.c                       |  17 ++-
 5 files changed, 193 insertions(+), 25 deletions(-)

diff --git a/sandbox/plc4c/drivers/simulated/src/driver_simulated.c b/sandbox/plc4c/drivers/simulated/src/driver_simulated.c
index 4c54be4..7a3d63f 100644
--- a/sandbox/plc4c/drivers/simulated/src/driver_simulated.c
+++ b/sandbox/plc4c/drivers/simulated/src/driver_simulated.c
@@ -18,12 +18,21 @@
 */
 
 #include <stdlib.h>
+#include <string.h>
 #include <plc4c/spi/types_private.h>
 #include <plc4c/driver_simulated.h>
 
+enum plc4c_driver_simulated_field_type_t {
+    RANDOM,
+    STATE,
+    STDOUT
+};
+typedef enum plc4c_driver_simulated_field_type_t plc4c_driver_simulated_field_type;
+
 // State definitions
 enum read_states {
-    READ_INIT
+    READ_INIT,
+    READ_FINISHED
 };
 
 enum write_states {
@@ -31,25 +40,64 @@ enum write_states {
 };
 
 struct plc4c_driver_simulated_item_t {
-    // Sort of senseless, but for keeping track of the fact that it's an plc4c_item.
-    plc4c_item super;
-
-    // Actual properties goes here ...
+    plc4c_driver_simulated_field_type type;
+    char *name;
+    char *data_type;
+    int num_elements;
 };
 typedef struct plc4c_driver_simulated_item_t plc4c_driver_simulated_item;
 
+return_code plc4c_driver_simulated_connect_machine_function(plc4c_system_task *task) {
+    plc4c_connection *connection = task->context;
+    if(connection == NULL) {
+        return INTERNAL_ERROR;
+    }
+    if(connection->connected) {
+        return INTERNAL_ERROR;
+    }
+    connection->connected = true;
+    task->completed = true;
+    return OK;
+}
+
+return_code plc4c_driver_simulated_disconnect_machine_function(plc4c_system_task *task) {
+    plc4c_connection *connection = task->context;
+    if(connection == NULL) {
+        return INTERNAL_ERROR;
+    }
+    if(!connection->connected) {
+        return INTERNAL_ERROR;
+    }
+    connection->connected = false;
+    task->completed = true;
+    return OK;
+}
+
 return_code plc4c_driver_simulated_read_machine_function(plc4c_system_task *task) {
-    if(task->context == NULL) {
+    if (task->context == NULL) {
         return INTERNAL_ERROR;
     }
 
     plc4c_read_request_execution *read_request_execution = task->context;
-    plc4c_system_task *system_task = read_request_execution->system_task;
-    switch (system_task->state_id) {
+    plc4c_read_request *read_request = read_request_execution->read_request;
+    switch (task->state_id) {
         case READ_INIT: {
+            // Process every field in the request.
+            plc4c_list_element *cur_element = plc4c_utils_list_head(read_request->items);
+            while (cur_element != NULL) {
+                plc4c_driver_simulated_item *cur_item = cur_element->value;
+                cur_element = cur_element->next;
+            }
+
+            // Create a response.
             plc4c_read_response *read_response = malloc(sizeof(plc4c_read_response));
             read_request_execution->read_response = read_response;
-            system_task->completed = true;
+            task->state_id = READ_FINISHED;
+            task->completed = true;
+            break;
+        }
+        case READ_FINISHED: {
+            // Do nothing
             break;
         }
         default: {
@@ -59,9 +107,65 @@ return_code plc4c_driver_simulated_read_machine_function(plc4c_system_task *task
     return OK;
 }
 
-plc4c_item *plc4c_driver_simulated_parse_address(const char *address_string) {
+plc4c_item *plc4c_driver_simulated_parse_address(char *address_string) {
+    plc4c_driver_simulated_field_type type = RANDOM;
+    char *name = NULL;
+    char *data_type = NULL;
+    int num_elements = 0;
+    int start_segment_index = 0;
+    char *start_segment = address_string;
+    for (int i = 0; i <= strlen(address_string); i++) {
+        // This marks the end of the type part.
+        if (*(address_string + i) == '/') {
+            char *type_str = malloc(sizeof(char) * (i + 1));
+            strlcpy(type_str, start_segment, i + 1);
+            if(strcmp(type_str, "RANDOM") == 0) {
+                type = RANDOM;
+            } else if(strcmp(type_str, "STATE") == 0) {
+                type = STATE;
+            } else if(strcmp(type_str, "STDOUT") == 0) {
+                type = STDOUT;
+            } else {
+                return NULL;
+            }
+            start_segment = address_string + i + 1;
+            start_segment_index = i + 1;
+        }
+        // This marks the end of the name part.
+        if (*(address_string + i) == ':') {
+            name = malloc(sizeof(char) * ((i - start_segment_index) + 1));
+            strlcpy(name, start_segment, (i - start_segment_index) + 1);
+            start_segment = address_string + i + 1;
+            start_segment_index = i + 1;
+        }
+        // This marks the end of the data-type part if there is a size coming in addition.
+        if ((i == strlen(address_string)) || (*(address_string + i) == '[')) {
+            data_type = malloc(sizeof(char) * ((i - start_segment_index) + 1));
+            strlcpy(data_type, start_segment, (i - start_segment_index) + 1);
+            start_segment = address_string + i + 1;
+            start_segment_index = i + 1;
+            if(i == strlen(address_string)) {
+                num_elements = 1;
+                break;
+            }
+        }
+        // This marks the end of the size part.
+        if (*(address_string + i) == ']') {
+            char *num_elements_str = malloc(sizeof(char) * ((i - start_segment_index) + 1));
+            strlcpy(num_elements_str, start_segment, (i - start_segment_index) + 1);
+            char *success = NULL;
+            num_elements = (int) strtol(num_elements_str, &success, 10);
+            break;
+        }
+    }
+
+    // Create a new driver specific item.
     plc4c_driver_simulated_item *item = (plc4c_driver_simulated_item *) malloc(sizeof(plc4c_driver_simulated_item));
-    // TODO: Actually to the parsing of the address ...
+    item->type = type;
+    item->name = name;
+    item->data_type = data_type;
+    item->num_elements = num_elements;
+
     return (plc4c_item *) item;
 }
 
@@ -71,28 +175,36 @@ return_code plc4c_driver_simulated_connect_function(plc4c_connection *connection
     new_task->context = connection;
     // There's nothing to do here, so no need for a state-machine.
     new_task->state_id = -1;
-    new_task->state_machine_function = NULL;
-    // We're setting this to true as there's nothing to do.
-    new_task->completed = true;
+    new_task->state_machine_function = &plc4c_driver_simulated_connect_machine_function;
     *task = new_task;
     return OK;
 }
 
-return_code plc4c_driver_simulated_read_function(plc4c_read_request *read_request, plc4c_system_task **task) {
+return_code plc4c_driver_simulated_disconnect_function(plc4c_connection *connection,
+                                                    plc4c_system_task **task) {
+    plc4c_system_task *new_task = malloc(sizeof(plc4c_system_task));
+    new_task->context = connection;
+    // There's nothing to do here, so no need for a state-machine.
+    new_task->state_id = -1;
+    new_task->state_machine_function = &plc4c_driver_simulated_disconnect_machine_function;
+    *task = new_task;
+    return OK;
+}
+
+return_code plc4c_driver_simulated_read_function(plc4c_system_task **task) {
     plc4c_system_task *new_task = malloc(sizeof(plc4c_system_task));
     new_task->state_id = READ_INIT;
     new_task->state_machine_function = &plc4c_driver_simulated_read_machine_function;
-    new_task->context = read_request;
     new_task->completed = false;
     *task = new_task;
     return OK;
 }
 
-return_code plc4c_driver_simulated_write_function(plc4c_write_request *write_request, plc4c_system_task **task) {
+return_code plc4c_driver_simulated_write_function(plc4c_system_task **task) {
     plc4c_system_task *new_task = malloc(sizeof(plc4c_system_task));
     new_task->state_id = WRITE_INIT;
     new_task->state_machine_function = NULL;
-    new_task->context = write_request;
+    new_task->completed = false;
     *task = new_task;
     return OK;
 }
@@ -104,6 +216,7 @@ plc4c_driver *plc4c_driver_simulated_create() {
     driver->default_transport_code = "dummy";
     driver->parse_address_function = &plc4c_driver_simulated_parse_address;
     driver->connect_function = &plc4c_driver_simulated_connect_function;
+    driver->disconnect_function = &plc4c_driver_simulated_disconnect_function;
     driver->read_function = &plc4c_driver_simulated_read_function;
     driver->write_function = &plc4c_driver_simulated_write_function;
     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 3ab0ef2..ed536c6 100644
--- a/sandbox/plc4c/examples/hello-world/src/hello_world.c
+++ b/sandbox/plc4c/examples/hello-world/src/hello_world.c
@@ -61,29 +61,41 @@ int main() {
     plc4c_read_request_execution *read_request_execution = NULL;
 
     // Create a new uninitialized plc4c_system
+    printf("Creating new PLC4C System (Initializing inner data-structures) ... ");
     return_code result = plc4c_system_create(&system);
     if (result != OK) {
+        printf("FAILED\n");
         return -1;
     }
+    printf("SUCCESS\n");
 
     // Manually register the "simulated" driver with the system.
+    printf("Registering driver for the 'simulated' protocol ... ");
     plc4c_driver *simulated_driver = plc4c_driver_simulated_create();
     result = plc4c_system_add_driver(system, simulated_driver);
     if (result != OK) {
+        printf("FAILED\n");
         return -1;
     }
+    printf("SUCCESS\n");
 
+    printf("Registering transport for the 'dummy' transport ... ");
     plc4c_transport *dummy_transport = plc4c_transport_dummy_create();
     result = plc4c_system_add_transport(system, dummy_transport);
     if (result != OK) {
+        printf("FAILED\n");
         return -1;
     }
+    printf("SUCCESS\n");
 
     // Initialize the plc4c_system (loading of drivers, setting up other stuff, ...)
+    printf("Initializing the PLC4C system (Loading of drivers and transports) ... ");
     result = plc4c_system_init(system);
     if (result != OK) {
+        printf("FAILED\n");
         return -1;
     }
+    printf("SUCCESS\n");
 
     // Register the global callbacks.
     plc4c_system_set_on_connect_success_callback(system, &onGlobalConnect);
@@ -91,17 +103,23 @@ int main() {
 
     // Establish connections to remote devices
     // you may or may not care about the connection handle
+    printf("Connecting to 'simulated://foo' ... ");
     result = plc4c_system_connect(system, "simulated://foo", &connection);
     if (result != OK) {
+        printf("FAILED\n");
         return -1;
     }
 
     // Central program loop ...
     plc4c_connection_state state = CONNECTING;
     while (loop) {
+
+        printf("* ");
+
         // Give plc4c a chance to do something.
         // This is where all I/O is being done.
         if (plc4c_system_loop(system) != OK) {
+            printf("ERROR in the system loop\n");
             break;
         }
 
@@ -110,23 +128,30 @@ int main() {
             case CONNECTING: {
                 // Check if the connection is established:
                 if (plc4c_connection_is_connected(connection)) {
+                    printf("SUCCESS\n");
                     state = CONNECTED;
                 } else if (plc4c_connection_has_error(connection)) {
+                    printf("FAILED\n");
                     return -1;
                 }
                 break;
             }
             case CONNECTED: {
                 // Create a new read-request.
+                printf("Preparing a read-request for 'RANDOM/foo:INTEGER' ... ");
                 char *addresses[] = {"RANDOM/foo:INTEGER"};
                 result = plc4c_connection_create_read_request(connection, 1, addresses, &read_request);
                 if(result != OK) {
+                    printf("FAILED\n");
                     return -1;
                 }
+                printf("SUCCESS\n");
 
                 // Execute the read-request.
+                printf("Executing a read-request ... ");
                 result = plc4c_read_request_execute(read_request, &read_request_execution);
                 if(result != OK) {
+                    printf("FAILED\n");
                     return -1;
                 } else {
                     state = READ_REQUEST_SENT;
@@ -136,8 +161,10 @@ int main() {
             // Wait until the read-request execution is finished.
             case READ_REQUEST_SENT: {
                 if(plc4c_read_request_finished_successfully(read_request_execution)) {
+                    printf("SUCCESS\n");
                     state = READ_RESPONSE_RECEIVED;
                 } else if(plc4c_read_request_has_error(read_request_execution)) {
+                    printf("FAILED\n");
                     return -1;
                 }
                 break;
@@ -153,8 +180,10 @@ int main() {
                 plc4c_read_request_destroy(read_request);
 
                 // Disconnect.
+                printf("Disconnecting ... ");
                 result = plc4c_connection_disconnect(connection);
                 if(result != OK) {
+                    printf("FAILED");
                     return -1;
                 }
                 state = DISCONNECTING;
@@ -163,8 +192,12 @@ int main() {
             // Wait until the connection is disconnected
             case DISCONNECTING: {
                 if(!plc4c_connection_is_connected(connection)) {
+                    printf("SUCCESS\n");
                     plc4c_connection_destroy(connection);
                     state = DISCONNECTED;
+
+                    // Terminate the main program loop.
+                    loop = false;
                 }
                 break;
             }
diff --git a/sandbox/plc4c/spi/include/plc4c/spi/types_private.h b/sandbox/plc4c/spi/include/plc4c/spi/types_private.h
index a02d499..14e53cb 100644
--- a/sandbox/plc4c/spi/include/plc4c/spi/types_private.h
+++ b/sandbox/plc4c/spi/include/plc4c/spi/types_private.h
@@ -30,7 +30,7 @@ typedef struct plc4c_transport_list_item_t plc4c_transport_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);
+typedef plc4c_item *(*plc4c_connection_parse_address_item)(char *address_string);
 
 typedef struct plc4c_system_task_t plc4c_system_task;
 
@@ -38,9 +38,11 @@ typedef return_code (*plc4c_system_task_state_machine_function)(plc4c_system_tas
 
 typedef return_code (*plc4c_connection_connect_function)(plc4c_connection *connection, plc4c_system_task **task);
 
-typedef return_code (*plc4c_connection_read_function)(plc4c_read_request *read_request, plc4c_system_task **task);
+typedef return_code (*plc4c_connection_disconnect_function)(plc4c_connection *connection, plc4c_system_task **task);
 
-typedef return_code (*plc4c_connection_write_function)(plc4c_write_request *write_request, plc4c_system_task **task);
+typedef return_code (*plc4c_connection_read_function)(plc4c_system_task **task);
+
+typedef return_code (*plc4c_connection_write_function)(plc4c_system_task **task);
 
 struct plc4c_system_t {
     /* drivers */
@@ -74,6 +76,7 @@ struct plc4c_driver_t {
     char *default_transport_code;
     plc4c_connection_parse_address_item parse_address_function;
     plc4c_connection_connect_function connect_function;
+    plc4c_connection_disconnect_function disconnect_function;
     plc4c_connection_read_function read_function;
     plc4c_connection_write_function write_function;
 };
@@ -103,6 +106,8 @@ struct plc4c_connection_t {
     char *transport_connect_information;
     char *parameters;
 
+    bool connected;
+
     plc4c_system *system;
     plc4c_driver *driver;
     plc4c_transport *transport;
diff --git a/sandbox/plc4c/spi/src/connection.c b/sandbox/plc4c/spi/src/connection.c
index 21280ac..edcb7fa 100644
--- a/sandbox/plc4c/spi/src/connection.c
+++ b/sandbox/plc4c/spi/src/connection.c
@@ -22,7 +22,7 @@
 #include <plc4c/spi/types_private.h>
 
 bool plc4c_connection_is_connected(plc4c_connection *connection) {
-    return true;
+    return connection->connected;
 }
 
 bool plc4c_connection_has_error(plc4c_connection *connection) {
@@ -30,6 +30,12 @@ bool plc4c_connection_has_error(plc4c_connection *connection) {
 }
 
 return_code plc4c_connection_disconnect(plc4c_connection *connection) {
+    plc4c_system_task *new_disconnection_task = NULL;
+    return_code result = connection->driver->disconnect_function(connection, &new_disconnection_task);
+    if(result != OK) {
+        return -1;
+    }
+    plc4c_utils_list_insert_tail_value(connection->system->task_list, new_disconnection_task);
     return OK;
 }
 
diff --git a/sandbox/plc4c/spi/src/read.c b/sandbox/plc4c/spi/src/read.c
index 0830a73..5c4648a 100644
--- a/sandbox/plc4c/spi/src/read.c
+++ b/sandbox/plc4c/spi/src/read.c
@@ -25,21 +25,29 @@
 return_code plc4c_read_request_execute(plc4c_read_request *read_request,
                                        plc4c_read_request_execution **read_request_execution) {
     plc4c_system_task *system_task;
-    read_request->connection->driver->read_function(read_request, &system_task);
+    read_request->connection->driver->read_function(&system_task);
     // Add the new task to the task-list.
     plc4c_utils_list_insert_tail_value(read_request->connection->system->task_list, system_task);
 
+    // Inject the default read context into the system task.
     plc4c_read_request_execution *new_read_request_execution = malloc(sizeof(plc4c_read_request_execution));
     new_read_request_execution->read_request = read_request;
     new_read_request_execution->read_response = NULL;
     new_read_request_execution->system_task = system_task;
+    new_read_request_execution->system_task->context = new_read_request_execution;
 
     *read_request_execution = new_read_request_execution;
     return OK;
 }
 
 bool plc4c_read_request_finished_successfully(plc4c_read_request_execution *read_request_execution) {
-    return true;
+    if(read_request_execution == NULL) {
+        return true;
+    }
+    if(read_request_execution->system_task == NULL) {
+        return true;
+    }
+    return read_request_execution->system_task->completed;
 }
 
 bool plc4c_read_request_has_error(plc4c_read_request_execution *read_request_execution) {
@@ -47,7 +55,10 @@ bool plc4c_read_request_has_error(plc4c_read_request_execution *read_request_exe
 }
 
 plc4c_read_response *plc4c_read_request_get_response(plc4c_read_request_execution *read_request_execution) {
-    return NULL;
+    if(read_request_execution == NULL) {
+        return NULL;
+    }
+    return read_request_execution->read_response;
 }
 
 void plc4c_read_request_destroy(plc4c_read_request *read_request) {