From 5b1cda7a8990acad7a98bcf819afe2b65a0565ad Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Tue, 21 Jan 2020 19:34:23 +0100 Subject: [PATCH] can: inital code skeleton --- CMakeLists.txt | 1 + include/villas/nodes/can.hpp | 99 +++++++++++++ lib/nodes/CMakeLists.txt | 5 + lib/nodes/can.cpp | 263 +++++++++++++++++++++++++++++++++++ 4 files changed, 368 insertions(+) create mode 100644 include/villas/nodes/can.hpp create mode 100644 lib/nodes/can.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index b58e276e0..10b04d805 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -154,6 +154,7 @@ cmake_dependent_option(WITH_NODE_ULDAQ "Build with uldaq node-type" cmake_dependent_option(WITH_NODE_WEBSOCKET "Build with websocket node-type" ON "WITH_WEB; LIBWEBSOCKETS_FOUND" OFF) cmake_dependent_option(WITH_NODE_ZEROMQ "Build with zeromq node-type" ON "LIBZMQ_FOUND" OFF) cmake_dependent_option(WITH_NODE_ETHERCAT "Build with ethercat node-type" ON "ETHERLAB_FOUND" OFF) +cmake_dependent_option(WITH_NODE_CAN "Build with can node-type" ON "" OFF) cmake_dependent_option(WITH_NODE_EXAMPLE "Build with example node-type" ON "" OFF) cmake_dependent_option(WITH_NODE_FPGA "Build with fpga node-type" ON "WITH_FPGA" OFF) diff --git a/include/villas/nodes/can.hpp b/include/villas/nodes/can.hpp new file mode 100644 index 000000000..97536f02e --- /dev/null +++ b/include/villas/nodes/can.hpp @@ -0,0 +1,99 @@ +/** Node-type: CAN bus + * + * @file + * @author Steffen Vogel + * @copyright 2014-2020, 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 can CAN bus Node Type + * @ingroup node + * @{ + */ + +#pragma once + +#include +#include +#include +#include + +struct can { + /* Settings */ + int setting1; + + char *setting2; + + /* States */ + int state1; + struct timespec start_time; +}; + +/** @see node_vtable::type_start */ +int can_type_start(villas::node::SuperNode *sn); + +/** @see node_type::type_stop */ +int can_type_stop(); + +/** @see node_type::init */ +int can_init(struct node *n); + +/** @see node_type::destroy */ +int can_destroy(struct node *n); + +/** @see node_type::parse */ +int can_parse(struct node *n, json_t *cfg); + +/** @see node_type::print */ +char * can_print(struct node *n); + +/** @see node_type::check */ +int can_check(); + +/** @see node_type::prepare */ +int can_prepare(); + +/** @see node_type::start */ +int can_start(struct node *n); + +/** @see node_type::stop */ +int can_stop(struct node *n); + +/** @see node_type::pause */ +int can_pause(struct node *n); + +/** @see node_type::resume */ +int can_resume(struct node *n); + +/** @see node_type::write */ +int can_write(struct node *n, struct sample *smps[], unsigned cnt, unsigned *release); + +/** @see node_type::read */ +int can_read(struct node *n, struct sample *smps[], unsigned cnt, unsigned *release); + +/** @see node_type::reverse */ +int can_reverse(struct node *n); + +/** @see node_type::poll_fds */ +int can_poll_fds(struct node *n, int fds[]); + +/** @see node_type::netem_fds */ +int can_netem_fds(struct node *n, int fds[]); + +/** @} */ diff --git a/lib/nodes/CMakeLists.txt b/lib/nodes/CMakeLists.txt index 209a707e0..eca812f04 100644 --- a/lib/nodes/CMakeLists.txt +++ b/lib/nodes/CMakeLists.txt @@ -148,6 +148,11 @@ if(WITH_NODE_RTP) list(APPEND LIBRARIES PkgConfig::RE) endif() +# Enable CAN node type +if(WITH_NODE_CAN) + list(APPEND NODE_SRC can.cpp) +endif() + # Enable Example node type if(WITH_NODE_EXAMPLE) list(APPEND NODE_SRC example.cpp) diff --git a/lib/nodes/can.cpp b/lib/nodes/can.cpp new file mode 100644 index 000000000..93ac36ea6 --- /dev/null +++ b/lib/nodes/can.cpp @@ -0,0 +1,263 @@ +/** Node-type: CAN bus + * + * @author Steffen Vogel + * @copyright 2014-2020, 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 + +/* Forward declartions */ +static struct plugin p; + +using namespace villas::node; +using namespace villas::utils; + +int can_type_start(villas::node::SuperNode *sn) +{ + /* TODO: Add implementation here */ + + return 0; +} + +int can_type_stop() +{ + /* TODO: Add implementation here */ + + return 0; +} + +int can_init(struct node *n) +{ + struct can *c = (struct can *) n->_vd; + + /* TODO: Add implementation here. The following is just an can */ + + c->setting1 = 0; + c->setting2 = nullptr; + + return 0; +} + +int can_destroy(struct node *n) +{ + struct can *c = (struct can *) n->_vd; + + /* TODO: Add implementation here. The following is just an can */ + + if (c->setting2) + free(c->setting2); + + return 0; +} + +int can_parse(struct node *n, json_t *cfg) +{ + int ret; + struct can *c = (struct can *) n->_vd; + + json_error_t err; + + /* TODO: Add implementation here. The following is just an can */ + + ret = json_unpack_ex(cfg, &err, 0, "{ s?: i, s?: s }", + "setting1", &c->setting1, + "setting2", &c->setting2 + ); + if (ret) + jerror(&err, "Failed to parse configuration of node %s", node_name(n)); + + return 0; +} + +char * can_print(struct node *n) +{ + struct can *c = (struct can *) n->_vd; + + /* TODO: Add implementation here. The following is just an can */ + + return strf("setting1=%d, setting2=%s", c->setting1, c->setting2); +} + +int can_check(struct node *n) +{ + struct can *c = (struct can *) n->_vd; + + /* TODO: Add implementation here. The following is just an can */ + + if (c->setting1 > 100 || c->setting1 < 0) + return -1; + + if (!c->setting2 || strlen(c->setting2) > 10) + return -1; + + return 0; +} + +int can_prepare(struct node *n) +{ + struct can *c = (struct can *) n->_vd; + + /* TODO: Add implementation here. The following is just an can */ + + c->state1 = c->setting1; + + if (strcmp(c->setting2, "double") == 0) + c->state1 *= 2; + + return 0; +} + +int can_start(struct node *n) +{ + struct can *c = (struct can *) n->_vd; + + /* TODO: Add implementation here. The following is just an can */ + + c->start_time = time_now(); + + return 0; +} + +int can_stop(struct node *n) +{ + //struct can *c = (struct can *) n->_vd; + + /* TODO: Add implementation here. */ + + return 0; +} + +int can_pause(struct node *n) +{ + //struct can *c = (struct can *) n->_vd; + + /* TODO: Add implementation here. */ + + return 0; +} + +int can_resume(struct node *n) +{ + //struct can *c = (struct can *) n->_vd; + + /* TODO: Add implementation here. */ + + return 0; +} + +int can_read(struct node *n, struct sample *smps[], unsigned cnt, unsigned *release) +{ + int read; + struct can *c = (struct can *) n->_vd; + struct timespec now; + + /* TODO: Add implementation here. The following is just an can */ + + assert(cnt >= 1 && smps[0]->capacity >= 1); + + now = time_now(); + + smps[0]->data[0].f = time_delta(&now, &c->start_time); + + read = 1; /* The number of samples read */ + + return read; +} + +int can_write(struct node *n, struct sample *smps[], unsigned cnt, unsigned *release) +{ + int written; + //struct can *c = (struct can *) n->_vd; + + /* TODO: Add implementation here. */ + + written = 0; /* The number of samples written */ + + return written; +} + +int can_reverse(struct node *n) +{ + //struct can *c = (struct can *) n->_vd; + + /* TODO: Add implementation here. */ + + return 0; +} + +int can_poll_fds(struct node *n, int fds[]) +{ + //struct can *c = (struct can *) n->_vd; + + /* TODO: Add implementation here. */ + + return 0; /* The number of file descriptors which have been set in fds */ +} + +int can_netem_fds(struct node *n, int fds[]) +{ + //struct can *c = (struct can *) n->_vd; + + /* TODO: Add implementation here. */ + + return 0; /* The number of file descriptors which have been set in fds */ +} + +__attribute__((constructor(110))) +static void register_plugin() { + if (plugins.state == State::DESTROYED) + vlist_init(&plugins); + + p.name = "can"; + p.description = "CAN bus for Xilinx MPSoC boards"; + p.type = PluginType::NODE; + p.node.instances.state = State::DESTROYED; + p.node.vectorize = 0; + p.node.size = sizeof(struct can); + p.node.type.start = can_type_start; + p.node.type.stop = can_type_stop; + p.node.init = can_init; + p.node.destroy = can_destroy; + p.node.prepare = can_prepare; + p.node.parse = can_parse; + p.node.print = can_print; + p.node.check = can_check; + p.node.start = can_start; + p.node.stop = can_stop; + p.node.pause = can_pause; + p.node.resume = can_resume; + p.node.read = can_read; + p.node.write = can_write; + p.node.reverse = can_reverse; + p.node.poll_fds = can_poll_fds; + p.node.netem_fds = can_netem_fds; + + vlist_init(&p.node.instances); + vlist_push(&plugins, &p); +} + +__attribute__((destructor(110))) +static void deregister_plugin() { + if (plugins.state != State::DESTROYED) + vlist_remove_all(&plugins, &p); +}