From b207bbf6739eb7b62a71ff84b418e51b65744b9a Mon Sep 17 00:00:00 2001
From: Steffen Vogel <post@steffenvogel.de>
Date: Sun, 6 Mar 2022 21:12:57 -0500
Subject: [PATCH] add C-API to libvillas

---
 include/villas/node.h |  92 ++++++++++++++++
 lib/CMakeLists.txt    |   1 +
 lib/node_capi.cpp     | 240 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 333 insertions(+)
 create mode 100644 include/villas/node.h
 create mode 100644 lib/node_capi.cpp

diff --git a/include/villas/node.h b/include/villas/node.h
new file mode 100644
index 000000000..7216201e0
--- /dev/null
+++ b/include/villas/node.h
@@ -0,0 +1,92 @@
+/** Node C-API
+ *
+ * @file
+ * @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
+ * @copyright 2014-2022, Institute for Automation of Complex Power Systems, EONERC
+ * @license GNU General Public License (version 3)
+ *
+ * VILLASnode
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *********************************************************************************/
+
+#pragma once
+
+#include <stdbool.h>
+
+#include <uuid/uuid.h>
+#include <jansson.h>
+
+typedef void *vnode;
+typedef void *vsample;
+
+vnode * node_new(const char *json_str, const char *sn_uuid_str);
+
+int node_prepare(vnode *n);
+
+int node_check(vnode *n);
+
+int node_start(vnode *n);
+
+int node_stop(vnode *n);
+
+int node_pause(vnode *n);
+
+int node_resume(vnode *n);
+
+int node_restart(vnode *n);
+
+int node_destroy(vnode *n);
+
+const char * node_name(vnode *n);
+
+const char * node_name_short(vnode *n);
+
+const char * node_name_full(vnode *n);
+
+const char * node_details(vnode *n);
+
+unsigned node_input_signals_max_cnt(vnode *n);
+
+unsigned node_output_signals_max_cnt(vnode *n);
+
+int node_reverse(vnode *n);
+
+int node_read(vnode *n, vsample **smps, unsigned cnt);
+
+int node_write(vnode *n, vsample **smps, unsigned cnt);
+
+int node_poll_fds(vnode *n, int fds[]);
+
+int node_netem_fds(vnode *n, int fds[]);
+
+bool node_is_valid_name(const char *name);
+
+bool node_is_enabled(const vnode *n);
+
+json_t * node_to_json(const vnode *n);
+
+const char * node_to_json_str(vnode *n);
+
+vsample * sample_alloc(unsigned len);
+
+unsigned sample_length(vsample *smp);
+
+void sample_decref(vsample *smp);
+
+vsample * sample_pack(unsigned seq, struct timespec *ts_origin, struct timespec *ts_received, unsigned len, double *values);
+
+void sample_unpack(vsample *s, unsigned *seq, struct timespec *ts_origin, struct timespec *ts_received, int *flags, unsigned *len, double *values);
+
+int memory_init(int hugepages);
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index 767371da5..54542a9b0 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -54,6 +54,7 @@ set(LIB_SRC
     memory/mmap.cpp
     node_direction.cpp
     node.cpp
+    node_capi.cpp
     node_compat.cpp
     node_list.cpp
     path_destination.cpp
diff --git a/lib/node_capi.cpp b/lib/node_capi.cpp
new file mode 100644
index 000000000..9ac9092c2
--- /dev/null
+++ b/lib/node_capi.cpp
@@ -0,0 +1,240 @@
+/** Node C-API
+ *
+ * @file
+ * @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
+ * @copyright 2014-2022, Institute for Automation of Complex Power Systems, EONERC
+ * @license GNU General Public License (version 3)
+ *
+ * VILLASnode
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <villas/node.hpp>
+
+extern "C" {
+	#include <villas/node.h>
+}
+
+using namespace villas;
+using namespace villas::node;
+
+vnode * node_new(const char *json_str, const char *sn_uuid_str)
+{
+	json_error_t err;
+	uuid_t sn_uuid;
+	uuid_parse(sn_uuid_str, sn_uuid);
+	auto *json = json_loads(json_str, 0, &err);
+	return (vnode *) NodeFactory::make(json, sn_uuid);
+}
+
+int node_prepare(vnode *n)
+{
+	auto *nc = (Node *) n;
+	return nc->prepare();
+}
+
+int node_check(vnode *n)
+{
+	auto *nc = (Node *) n;
+	return nc->check();
+}
+
+int node_start(vnode *n)
+{
+	auto *nc = (Node *) n;
+	return nc->start();
+}
+
+int node_stop(vnode *n)
+{
+	auto *nc = (Node *) n;
+	return nc->stop();
+}
+
+int node_pause(vnode *n)
+{
+	auto *nc = (Node *) n;
+	return nc->pause();
+}
+
+int node_resume(vnode *n)
+{
+	auto *nc = (Node *) n;
+	return nc->resume();
+}
+
+int node_restart(vnode *n)
+{
+	auto *nc = (Node *) n;
+	return nc->restart();
+}
+
+int node_destroy(vnode *n)
+{
+	auto *nc = (Node *) n;
+	nc->~Node();
+	return 0;
+}
+
+const char * node_name(vnode *n)
+{
+	auto *nc = (Node *) n;
+	return nc->getName().c_str();
+}
+
+const char * node_name_short(vnode *n)
+{
+	auto *nc = (Node *) n;
+	return nc->getNameShort().c_str();
+}
+
+const char * node_name_full(vnode *n)
+{
+	auto *nc = (Node *) n;
+	return nc->getNameFull().c_str();
+}
+
+const char * node_details(vnode *n)
+{
+	auto *nc = (Node *) n;
+	return nc->getDetails().c_str();
+}
+
+unsigned node_input_signals_max_cnt(vnode *n)
+{
+	auto *nc = (Node *) n;
+	return nc->getInputSignalsMaxCount();
+}
+
+unsigned node_output_signals_max_cnt(vnode *n)
+{
+	auto *nc = (Node *) n;
+	return nc->getOutputSignalsMaxCount();
+}
+
+int node_reverse(vnode *n)
+{
+	auto *nc = (Node *) n;
+	return nc->reverse();
+}
+
+int node_read(vnode *n, vsample **smps, unsigned cnt)
+{
+	auto *nc = (Node *) n;
+	return nc->read((villas::node::Sample**) smps, cnt);
+}
+
+int node_write(vnode *n, vsample **smps, unsigned cnt)
+{
+	auto *nc = (Node *) n;
+	return nc->write((villas::node::Sample**) smps, cnt);
+}
+
+int node_poll_fds(vnode *n, int fds[])
+{
+	auto *nc = (Node *) n;
+	auto l = nc->getPollFDs();
+
+	for (unsigned i = 0; i < l.size() && i < 16; i++)
+		fds[i] = l[i];
+
+	return l.size();
+}
+
+int node_netem_fds(vnode *n, int fds[])
+{
+	auto *nc = (Node *) n;
+	auto l = nc->getNetemFDs();
+
+	for (unsigned i = 0; i < l.size() && i < 16; i++)
+		fds[i] = l[i];
+
+	return l.size();
+}
+
+bool node_is_valid_name(const char *name)
+{
+	return Node::isValidName(name);
+}
+
+bool node_is_enabled(const vnode *n)
+{
+	auto *nc = (Node *) n;
+	return nc->isEnabled();
+}
+
+json_t * node_to_json(const vnode *n)
+{
+	auto *nc = (Node *) n;
+	return nc->toJson();
+}
+
+const char * node_to_json_str(vnode *n)
+{
+	auto json = node_to_json(n);
+	return json_dumps(json, 0);
+}
+
+vsample * sample_alloc(unsigned len)
+{
+	return (vsample *) sample_alloc_mem(len);
+}
+
+unsigned sample_length(vsample *s)
+{
+	auto *smp = (Sample *) s;
+	return smp->length;
+}
+
+
+vsample * sample_pack(unsigned seq, struct timespec *ts_origin, struct timespec *ts_received, unsigned len, double *values)
+{
+	auto *smp = sample_alloc_mem(len);
+
+	smp->sequence = seq;
+	smp->ts.origin = *ts_origin;
+	smp->ts.received = *ts_received;
+	smp->length = len;
+	smp->flags = (int) SampleFlags::HAS_SEQUENCE | (int) SampleFlags::HAS_DATA | (int) SampleFlags::HAS_TS_ORIGIN;
+
+	memcpy(smp->data, values, sizeof(double)*len);
+
+	return (vsample *) smp;
+}
+
+void sample_unpack(vsample *s, unsigned *seq, struct timespec *ts_origin, struct timespec *ts_received, int *flags, unsigned *len, double *values)
+{
+	auto *smp = (Sample *) s;
+
+	*seq = smp->sequence;
+
+	*ts_origin = smp->ts.origin;
+	*ts_received = smp->ts.received;
+
+	*flags =smp->flags;
+	*len = smp->length;
+
+	memcpy(values, smp->data, sizeof(double)* *len);
+}
+
+void sample_decref(vsample *smp)
+{
+	sample_decref((Sample *) smp);
+}
+
+int memory_init(int hugepages)
+{
+	return memory::init(hugepages);
+}