diff --git a/include/villas/nodes/ethercat.h b/include/villas/nodes/ethercat.h new file mode 100644 index 000000000..4556138a7 --- /dev/null +++ b/include/villas/nodes/ethercat.h @@ -0,0 +1,84 @@ +/** Node type: ethercat + * + * @file + * @author Niklas Eiling + * @author Steffen Vogel + * @copyright 2018, 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 . + *********************************************************************************/ + +/** + * @addtogroup ethercats WebSockets node type + * @ingroup node + * @{ + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define DEFAULT_ETHERCAT_QUEUE_LENGTH (DEFAULT_QUEUE_LENGTH * 64) +#define DEFAULT_ETHERCAT_SAMPLE_LENGTH DEFAULT_SAMPLE_LENGTH + +/* Forward declaration */ +struct lws; + +/** Internal data per ethercat node */ +struct ethercat { + struct pool pool; + struct queue_signalled queue; /**< For samples which are received from WebSockets */ +}; + +/* Internal datastructures */ + + +/** @see node_type::type_start */ +int ethercat_type_start(struct super_node *sn); + +/** @see node_type::type_stop */ +int ethercat_type_stop(); + +/** @see node_type::open */ +int ethercat_start(struct node *n); + +/** @see node_type::close */ +int ethercat_stop(struct node *n); + +/** @see node_type::close */ +int ethercat_destroy(struct node *n); + +/** @see node_type::read */ +int ethercat_read(struct node *n, struct sample *smps[], unsigned cnt, unsigned *release); + +/** @see node_type::write */ +int ethercat_write(struct node *n, struct sample *smps[], unsigned cnt, unsigned *release); + +/** @} */ + +#ifdef __cplusplus +} +#endif diff --git a/lib/nodes/CMakeLists.txt b/lib/nodes/CMakeLists.txt index 1f9e519c6..5dfd9355e 100644 --- a/lib/nodes/CMakeLists.txt +++ b/lib/nodes/CMakeLists.txt @@ -161,6 +161,9 @@ if(WITH_NODE_EXAMPLE) # list(APPEND LIBRARIES PkgConfig::EXAMPLELIB) endif() +# Enable ethercat support +# TODO + add_library(nodes STATIC ${NODE_SRC}) target_include_directories(nodes PUBLIC ${INCLUDE_DIRS}) target_link_libraries(nodes INTERFACE ${LIBRARIES} PUBLIC villas-common) diff --git a/lib/nodes/ethercat.c b/lib/nodes/ethercat.c new file mode 100644 index 000000000..5a8b2f763 --- /dev/null +++ b/lib/nodes/ethercat.c @@ -0,0 +1,191 @@ +/** Node type: Ethercat + * + * @author Niklas Eiling + * @author Steffen Vogel + * @copyright 2018, 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 . + *********************************************************************************/ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +/* Private static storage */ + +/* Forward declarations */ +static struct plugin p; + + +int ethercat_type_start(struct super_node *sn) +{ + /* TODO: type start ethercat */ + + return 0; +} + +int ethercat_start(struct node *n) +{ + int ret; + struct ethercat *w = (struct ethercat *) n->_vd; + + ret = pool_init(&w->pool, DEFAULT_ETHERCAT_QUEUE_LENGTH, SAMPLE_LENGTH(DEFAULT_ETHERCAT_SAMPLE_LENGTH), &memory_hugepage); + if (ret) + return ret; + + ret = queue_signalled_init(&w->queue, DEFAULT_ETHERCAT_QUEUE_LENGTH, &memory_hugepage, 0); + if (ret) + return ret; + + /* TODO: start ethercat connection */ + + return 0; +} + +int ethercat_stop(struct node *n) +{ + int ret; + struct ethercat *w = (struct ethercat *) n->_vd; + + /* TODO: stop ethercat connection */ + + ret = queue_signalled_destroy(&w->queue); + if (ret) + return ret; + + ret = pool_destroy(&w->pool); + if (ret) + return ret; + + return 0; +} + +int ethercat_destroy(struct node *n) +{ + struct websocket *w = (struct websocket *) n->_vd; + int ret; + + /* TODO: destroy ethercat connection */ + + if (ret) + return ret; + + return 0; +} + +int ethercat_read(struct node *n, struct sample *smps[], unsigned cnt, unsigned *release) +{ + int avail; + + struct ethercat *w = (struct ethercat *) n->_vd; + struct sample *cpys[cnt]; + + avail = queue_signalled_pull_many(&w->queue, (void **) cpys, cnt); + if (avail < 0) + return avail; + + sample_copy_many(smps, cpys, avail); + sample_decref_many(cpys, avail); + + return avail; +} + +int ethercat_write(struct node *n, struct sample *smps[], unsigned cnt, unsigned *release) +{ + int avail; + + struct ethercat *w = (struct ethercat *) n->_vd; + struct sample *cpys[cnt]; + + /* Make copies of all samples */ + avail = sample_alloc_many(&w->pool, cpys, cnt); + if (avail < cnt) + warn("Pool underrun for node %s: avail=%u", node_name(n), avail); + + sample_copy_many(cpys, smps, avail); + + /* TODO: write samples to ethercat driver */ + + sample_decref_many(cpys, avail); + + return cnt; +} + +int ethercat_parse(struct node *n, json_t *cfg) +{ + struct ethercat *w = (struct ethercat *) n->_vd; + int ret; + + size_t i; + json_t *json_dests = NULL; + json_t *json_dest; + json_error_t err; + + /* TODO: parse json */ + + return 0; +} + +char * ethercat_print(struct node *n) +{ + struct ethercat *w = (struct ethercat *) n->_vd; + + char *buf = NULL; + /* TODO: maybe use asprintf to build string? */ + + return buf; +} + +int ethercat_fd(struct node *n) +{ + struct ethercat *w = (struct ethercat *) n->_vd; + + return queue_signalled_fd(&w->queue); +} + +static struct plugin p = { + .name = "ethercat", + .description = "Send and receive samples of an ethercat connection", + .type = PLUGIN_TYPE_NODE, + .node = { + .vectorize = 0, /* unlimited */ + .size = sizeof(struct ethercat), + .type.start = ethercat_type_start, + .start = ethercat_start, + .stop = ethercat_stop, + .destroy = ethercat_destroy, + .read = ethercat_read, + .write = ethercat_write, + .print = ethercat_print, + .parse = ethercat_parse, + .fd = ethercat_fd + } +}; + +REGISTER_PLUGIN(&p) +LIST_INIT_STATIC(&p.node.instances)