From 27965309bf84fe20e8116c126a92eeea698cef2e Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Sun, 19 Nov 2017 19:21:46 +0100 Subject: [PATCH 1/9] iec61850-9-2: added missing declarations to header --- include/villas/nodes/iec61850_sv.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/include/villas/nodes/iec61850_sv.h b/include/villas/nodes/iec61850_sv.h index 0b383c500..da0ba4bad 100644 --- a/include/villas/nodes/iec61850_sv.h +++ b/include/villas/nodes/iec61850_sv.h @@ -80,4 +80,24 @@ struct iec61850_sv { } publisher; }; +int iec61850_sv_init(struct super_node *sn); + +int iec61850_sv_deinit(); + +int iec61850_sv_parse(struct node *n, json_t *json); + +char * iec61850_sv_print(struct node *n); + +int iec61850_sv_start(struct node *n); + +int iec61850_sv_stop(struct node *n); + +int iec61850_sv_destroy(struct node *n); + +int iec61850_sv_read(struct node *n, struct sample *smps[], unsigned cnt); + +int iec61850_sv_write(struct node *n, struct sample *smps[], unsigned cnt); + +int iec61850_sv_fd(struct node *n); + /** @} */ From 39ffecae29c3e520daad6afbfe1af1fe346de724 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Sun, 19 Nov 2017 19:22:20 +0100 Subject: [PATCH 2/9] iec61850: improve package build time --- packaging/rpm/Makefile.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/rpm/Makefile.inc b/packaging/rpm/Makefile.inc index 03a33120f..c23211a85 100644 --- a/packaging/rpm/Makefile.inc +++ b/packaging/rpm/Makefile.inc @@ -47,7 +47,7 @@ rpm-nanomsg: $(BUILDDIR)/thirdparty/nanomsg/ | $(RPMDIR)/SOURCES/ rpmbuild -ba --define="_topdir $$(pwd)/$(RPMDIR)" $(SRCDIR)/packaging/rpm/nanomsg.spec rpm-libiec61850: $(BUILDDIR)/thirdparty/libiec61850/ | $(RPMDIR)/SOURCES/ - cmake -DCMAKE_INSTALL_PREFIX:PATH=$(PREFIX) -DCPACK_GENERATOR=TGZ \ + cmake -DCMAKE_INSTALL_PREFIX:PATH=$(PREFIX) -DCPACK_SOURCE_GENERATOR=TGZ \ -H$(SRCDIR)/thirdparty/libiec61850 \ -B$(BUILDDIR)/thirdparty/libiec61850 $(CMAKE_OPTS) make -C$(BUILDDIR)/thirdparty/libiec61850 package_source From 81e816621c8ca99af39ef8c9cc9547a6958e8520 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Sun, 19 Nov 2017 19:22:45 +0100 Subject: [PATCH 3/9] iec61850: add pkg-config file to RPM pacakge --- packaging/rpm/libiec61850.spec | 1 + 1 file changed, 1 insertion(+) diff --git a/packaging/rpm/libiec61850.spec b/packaging/rpm/libiec61850.spec index 86d139dc1..f13e6e892 100644 --- a/packaging/rpm/libiec61850.spec +++ b/packaging/rpm/libiec61850.spec @@ -59,6 +59,7 @@ rm -rf $RPM_BUILD_ROOT %{_prefix}/lib/libiec61850.so.1.1.0 %{_prefix}/lib/libiec61850.so %{_prefix}/lib/libiec61850.a +%{_prefix}/share/pkgconfig/libiec61850.pc %files devel %{_includedir}/libiec61850/* From ebdb4ba0269e9ba225c410706ba15efc217e7433 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Wed, 6 Dec 2017 14:09:26 +0800 Subject: [PATCH 4/9] iec61850: library now has a pkg-config in upstream repo --- lib/nodes/Makefile.inc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/nodes/Makefile.inc b/lib/nodes/Makefile.inc index c3ed7bb50..4549b52d9 100644 --- a/lib/nodes/Makefile.inc +++ b/lib/nodes/Makefile.inc @@ -90,10 +90,10 @@ endif # Enable IEC61850 node-types when libiec61850 is available ifeq ($(WITH_IEC61850),1) -ifneq ($(or $(wildcard /usr/include/libiec61850/*), $(wildcard /usr/local/include/libiec61850/*)),) - LIB_SRCS += $(wildcard lib/nodes/iec61850_*.c) - LIB_LDLIBS += -liec61850 +ifeq ($(shell $(PKGCONFIG) --atleast-version=1.2.0 libiec61850; echo $$?),0) + LIB_SRCS += lib/nodes/iec61850.c lib/nodes/iec61850_sv.c LIB_CFLAGS += -DWITH_IEC61850 + LIB_PKGS += libiec61850 endif endif From d8d8143c83601673b52ee384f5983c79978a4ddf Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Wed, 6 Dec 2017 14:25:46 +0800 Subject: [PATCH 5/9] iec61850: updated submodule to point to current upstream/development version --- thirdparty/libiec61850 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/thirdparty/libiec61850 b/thirdparty/libiec61850 index f7b04a02e..924441254 160000 --- a/thirdparty/libiec61850 +++ b/thirdparty/libiec61850 @@ -1 +1 @@ -Subproject commit f7b04a02ed21e2b12fe4ccdb0066e804f301e33f +Subproject commit 9244412545af81671a9130ba04f0428b1286c9f9 From 041f6be9822a3a25ad23933d9f993bb65ae863ea Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Wed, 6 Dec 2017 16:44:50 +0800 Subject: [PATCH 6/9] iec61850: rewrote iec61850-9-2 node-type in preperation for support of iec61850-8-1 node-type --- etc/example.conf | 1 - include/villas/nodes/iec61850.h | 76 ++--- include/villas/nodes/iec61850_sv.h | 6 - lib/nodes/iec61850.c | 274 ++++++++++++++++++ lib/nodes/iec61850_sv.c | 191 ++---------- .../integration/pipe-loopback-iec61850-9-2.sh | 1 - 6 files changed, 340 insertions(+), 209 deletions(-) create mode 100644 lib/nodes/iec61850.c diff --git a/etc/example.conf b/etc/example.conf index 3e370ec72..68c5a9f7d 100644 --- a/etc/example.conf +++ b/etc/example.conf @@ -291,7 +291,6 @@ nodes = { ], svid = "test1234", - datset = "test", smpmod = "samples_per_second", confrev = 55 }, diff --git a/include/villas/nodes/iec61850.h b/include/villas/nodes/iec61850.h index 30a23cdac..e587c4878 100644 --- a/include/villas/nodes/iec61850.h +++ b/include/villas/nodes/iec61850.h @@ -31,46 +31,13 @@ #include +#include +#include +#include + #include "node.h" #include "list.h" -/* libiec61850's API is ugly... */ -#define SVPublisher SampledValuesPublisher -#define SVPublisher_create SampledValuesPublisher_create -#define SVPublisher_destroy SampledValuesPublisher_destroy -#define SVPublisher_addASDU SampledValuesPublisher_addASDU -#define SVPublisher_setupComplete SampledValuesPublisher_setupComplete -#define SVPublisher_publish SampledValuesPublisher_publish - -#define SVPublisher_ASDU SV_ASDU -#define SVSubscriber_ASDU SVClientASDU - -#define SVPublisher_ASDU_setINT8 SV_ASDU_setINT8 -#define SVPublisher_ASDU_setINT32 SV_ASDU_setINT32 -#define SVPublisher_ASDU_setFLOAT32 SV_ASDU_setFLOAT -#define SVPublisher_ASDU_setFLOAT64 SV_ASDU_setFLOAT64 - -#define SVPublisher_ASDU_increaseSmpCnt SV_ASDU_increaseSmpCnt -#define SVPublisher_ASDU_setSmpCnt SV_ASDU_setSmpCnt -#define SVPublisher_ASDU_setRefrTm SV_ASDU_setRefrTm - -#define SVSubscriber_ASDU_getDataSize SVClientASDU_getDataSize -#define SVSubscriber_ASDU_getConfRev SVClientASDU_getConfRev -#define SVSubscriber_ASDU_getSvId SVClientASDU_getSvId -#define SVSubscriber_ASDU_getSmpCnt SVClientASDU_getSmpCnt -#define SVSubscriber_ASDU_getRefrTmAsMs SVClientASDU_getRefrTmAsMs -#define SVSubscriber_ASDU_hasRefrTm SVClientASDU_hasRefrTm - -#define SVSubscriber_ASDU_getINT8 SVClientASDU_getINT8 -#define SVSubscriber_ASDU_getINT16 SVClientASDU_getINT16 -#define SVSubscriber_ASDU_getINT32 SVClientASDU_getINT32 -#define SVSubscriber_ASDU_getINT8U SVClientASDU_getINT8U -#define SVSubscriber_ASDU_getINT16U SVClientASDU_getINT16U -#define SVSubscriber_ASDU_getINT32U SVClientASDU_getINT32U -#define SVSubscriber_ASDU_getFLOAT32 SVClientASDU_getFLOAT32 -#define SVSubscriber_ASDU_getFLOAT64 SVClientASDU_getFLOAT64 - - enum iec61850_type { /* According to IEC 61850-7-2 */ IEC61850_TYPE_BOOLEAN, @@ -99,10 +66,45 @@ enum iec61850_type { struct iec61850_type_descriptor { const char *name; + char format; enum iec61850_type type; unsigned size; bool publisher; bool subscriber; }; +struct iec61850_receiver { + char *interface; + + EthernetSocket socket; + + enum iec61850_receiver_type { + IEC61850_RECEIVER_GOOSE, + IEC61850_RECEIVER_SV + } type; + + union { + SVReceiver sv; + GooseReceiver goose; + }; +}; + +int iec61850_init(struct super_node *sn); + +int iec61850_deinit(); + +const struct iec61850_type_descriptor * iec61850_lookup_type(const char *name, char fmt); + +int iec61850_parse_mapping(json_t *json_mapping, struct list *mapping); + +struct iec61850_receiver * iec61850_receiver_lookup(enum iec61850_receiver_type t, const char *intf); + +struct iec61850_receiver * iec61850_receiver_create(enum iec61850_receiver_type t, const char *intf); + +int iec61850_receiver_start(struct iec61850_receiver *r); + +int iec61850_receiver_stop(struct iec61850_receiver *r); + +int iec61850_receiver_destroy(struct iec61850_receiver *r); + /** @} */ diff --git a/include/villas/nodes/iec61850_sv.h b/include/villas/nodes/iec61850_sv.h index da0ba4bad..4241f6a79 100644 --- a/include/villas/nodes/iec61850_sv.h +++ b/include/villas/nodes/iec61850_sv.h @@ -41,11 +41,6 @@ #include "nodes/iec61850.h" -struct iec61850_sv_receiver { - char *interface; - SVReceiver receiver; -}; - struct iec61850_sv { char *interface; int app_id; @@ -66,7 +61,6 @@ struct iec61850_sv { SVPublisher publisher; SVPublisher_ASDU asdu; - char *datset; char *svid; int vlan_priority; diff --git a/lib/nodes/iec61850.c b/lib/nodes/iec61850.c new file mode 100644 index 000000000..348df2f69 --- /dev/null +++ b/lib/nodes/iec61850.c @@ -0,0 +1,274 @@ +/** Node type: IEC 61850-9-2 (Sampled Values) + * + * @author Steffen Vogel + * @copyright 2017, 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 "nodes/iec61850_sv.h" +#include "plugin.h" + +#define CONFIG_SV_DEFAULT_APPID 0x4000 +#define CONFIG_SV_DEFAULT_DST_ADDRESS CONFIG_GOOSE_DEFAULT_DST_ADDRESS +#define CONFIG_SV_DEFAULT_PRIORITY 4 +#define CONFIG_SV_DEFAULT_VLAN_ID 0 + +const struct iec61850_type_descriptor type_descriptors[] = { + /* name, fmt, type, size, supported */ + { "boolean", 'b', IEC61850_TYPE_BOOLEAN, 1, false, false }, + { "int8", 'o', IEC61850_TYPE_INT8, 1, false, false }, + { "int16", 'w', IEC61850_TYPE_INT16, 2, false, false }, + { "int32", 'd', IEC61850_TYPE_INT32, 4, false, false }, + { "int64", 'g', IEC61850_TYPE_INT64, 8, false, false }, + { "int8u", 'O', IEC61850_TYPE_INT8U, 1, false, false }, + { "int16u", 'W', IEC61850_TYPE_INT16U, 2, false, false }, + { "int32u", 'D', IEC61850_TYPE_INT32U, 4, false, false }, + { "int64u", 'G', IEC61850_TYPE_INT64U, 8, false, false }, + { "float32", 'f', IEC61850_TYPE_FLOAT32, 4, false, false }, + { "float64", 'F', IEC61850_TYPE_FLOAT64, 8, false, false }, + { "enumerated", 'e', IEC61850_TYPE_ENUMERATED, 4, false, false }, + { "coded_enum", 'c', IEC61850_TYPE_CODED_ENUM, 4, false, false }, + { "octet_string", 's', IEC61850_TYPE_OCTET_STRING, 20, false, false }, + { "visible_string", 'S', IEC61850_TYPE_VISIBLE_STRING, 35, false, false }, + { "objectname", 'n', IEC61850_TYPE_OBJECTNAME, 20, false, false }, + { "objectreference", 'r', IEC61850_TYPE_OBJECTREFERENCE, 20, false, false }, + { "timestamp", 't', IEC61850_TYPE_TIMESTAMP, 8, false, false }, + { "entrytime", 'e', IEC61850_TYPE_ENTRYTIME, 6, false, false }, + { "bitstring", 'B', IEC61850_TYPE_BITSTRING, 4, false, false } +}; + +/** Each network interface needs a separate receiver */ +static struct list receivers = LIST_INIT(); +static pthread_t thread; +static EthernetHandleSet hset; +static int users = 0; + +static void * iec61850_thread(void *ctx) +{ + int ret; + + while (1) { + ret = EthernetHandleSet_waitReady(hset, 1000); + if (ret < 0) + continue; + + for (unsigned i = 0; i < list_length(&receivers); i++) { + struct iec61850_receiver *r = (struct iec61850_receiver *) list_at(&receivers, i); + + switch (r->type) { + case IEC61850_RECEIVER_GOOSE: GooseReceiver_tick(r->goose); break; + case IEC61850_RECEIVER_SV: SVReceiver_tick(r->sv); break; + } + } + } + + return NULL; +} + +const struct iec61850_type_descriptor * iec61850_lookup_type(const char *name, char fmt) +{ + /* Either name or fmt argument must be given */ + if ((fmt && name) || (!fmt && !name)) + return NULL; + + for (unsigned i = 0; i < ARRAY_LEN(type_descriptors); i++) { + if ((name && !strcmp(name, type_descriptors[i].name)) || + (fmt && fmt == type_descriptors[i].format)) + return &type_descriptors[i]; + } + + return NULL; +} + +int iec61850_parse_mapping(json_t *json_mapping, struct list *mapping) +{ + int total_size = 0; + + list_init(mapping); + + if (json_is_array(json_mapping)) { + json_t *json_field; + size_t index; + + json_array_foreach(json_mapping, index, json_field) { + const struct iec61850_type_descriptor *m; + const char *type = json_string_value(json_field); + + if (!json_is_string(json_field)) + return -1; + + m = iec61850_lookup_type(type, 0); + if (!m) + return -1; + + list_push(mapping, (void *) m); + + total_size += m->size; + } + } + else if (json_is_string(json_mapping)) { + const struct iec61850_type_descriptor *m; + const char *format_str = json_string_value(json_mapping); + + for (int i = 0; format_str[i]; i++) { + m = iec61850_lookup_type(NULL, format_str[i]); + if (!m) + return -1; + + list_push(mapping, (void *) m); + + total_size += m->size; + } + } + + return total_size; +} + +int iec61850_init(struct super_node *sn) +{ + int ret; + + /* Check if already initialized */ + if (users > 0) + return 0; + + hset = EthernetHandleSet_new(); + + ret = pthread_create(&thread, NULL, iec61850_thread, NULL); + if (ret) + return ret; + + return 0; +} + +int iec61850_deinit() +{ + int ret; + + if (--users > 0) + return 0; + + for (unsigned i = 0; i < list_length(&receivers); i++) { + struct iec61850_receiver *r = (struct iec61850_receiver *) list_at(&receivers, i); + + iec61850_receiver_stop(r); + } + + ret = pthread_cancel(thread); + if (ret) + return ret; + + ret = pthread_join(thread, NULL); + if (ret) + return ret; + + EthernetHandleSet_destroy(hset); + + list_destroy(&receivers, (dtor_cb_t) iec61850_receiver_destroy, true); + + return 0; +} + +int iec61850_receiver_start(struct iec61850_receiver *r) +{ + switch (r->type) { + case IEC61850_RECEIVER_GOOSE: r->socket = GooseReceiver_startThreadless(r->goose); break; + case IEC61850_RECEIVER_SV: r->socket = SVReceiver_startThreadless(r->sv); break; + } + + EthernetHandleSet_addSocket(hset, r->socket); + + return 0; +} + +int iec61850_receiver_stop(struct iec61850_receiver *r) +{ + EthernetHandleSet_removeSocket(hset, r->socket); + + switch (r->type) { + case IEC61850_RECEIVER_GOOSE: GooseReceiver_stopThreadless(r->goose); break; + case IEC61850_RECEIVER_SV: SVReceiver_stopThreadless(r->sv); break; + } + + return 0; +} + +int iec61850_receiver_destroy(struct iec61850_receiver *r) +{ + switch (r->type) { + case IEC61850_RECEIVER_GOOSE: GooseReceiver_destroy(r->goose); break; + case IEC61850_RECEIVER_SV: SVReceiver_destroy(r->sv); break; + } + + free(r->interface); + + return 0; +} + +struct iec61850_receiver * iec61850_receiver_lookup(enum iec61850_receiver_type t, const char *intf) +{ + for (unsigned i = 0; i < list_length(&receivers); i++) { + struct iec61850_receiver *r = (struct iec61850_receiver *) list_at(&receivers, i); + + if (r->type == t && strcmp(r->interface, intf) == 0) + return r; + } + + return NULL; +} + +struct iec61850_receiver * iec61850_receiver_create(enum iec61850_receiver_type t, const char *intf) +{ + struct iec61850_receiver *r; + + /* Check if there is already a SVReceiver for this interface */ + r = iec61850_receiver_lookup(t, intf); + if (!r) { + r = alloc(sizeof(struct iec61850_receiver)); + if (!r) + return NULL; + + r->interface = strdup(intf); + r->type = t; + + switch (r->type) { + case IEC61850_RECEIVER_GOOSE: + r->goose = GooseReceiver_create(); + GooseReceiver_setInterfaceId(r->goose, r->interface); + break; + + case IEC61850_RECEIVER_SV: + r->sv = SVReceiver_create(); + SVReceiver_setInterfaceId(r->sv, r->interface); + break; + } + + iec61850_receiver_start(r); + + list_push(&receivers, r); + } + + return r; +} diff --git a/lib/nodes/iec61850_sv.c b/lib/nodes/iec61850_sv.c index 009d674a1..dbb1d832e 100644 --- a/lib/nodes/iec61850_sv.c +++ b/lib/nodes/iec61850_sv.c @@ -37,49 +37,6 @@ #define CONFIG_SV_DEFAULT_PRIORITY 4 #define CONFIG_SV_DEFAULT_VLAN_ID 0 -struct iec61850_type_descriptor type_descriptors[] = { - /* name, type, size, supported */ - { "boolean", IEC61850_TYPE_BOOLEAN, 1, false, false }, - { "int8", IEC61850_TYPE_INT8, 1, false, false }, - { "int16", IEC61850_TYPE_INT16, 2, false, false }, - { "int32", IEC61850_TYPE_INT32, 4, false, false }, - { "int64", IEC61850_TYPE_INT64, 8, false, false }, - { "int8u", IEC61850_TYPE_INT8U, 1, false, false }, - { "int16u", IEC61850_TYPE_INT16U, 2, false, false }, - { "int32u", IEC61850_TYPE_INT32U, 4, false, false }, - { "int64u", IEC61850_TYPE_INT64U, 8, false, false }, - { "float32", IEC61850_TYPE_FLOAT32, 4, false, false }, - { "float64", IEC61850_TYPE_FLOAT64, 8, false, false }, - { "enumerated", IEC61850_TYPE_ENUMERATED, 4, false, false }, - { "coded_enum", IEC61850_TYPE_CODED_ENUM, 4, false, false }, - { "octet_string", IEC61850_TYPE_OCTET_STRING, 20, false, false }, - { "visible_string", IEC61850_TYPE_VISIBLE_STRING, 35, false, false }, - { "objectname", IEC61850_TYPE_OBJECTNAME, 20, false, false }, - { "objectreference", IEC61850_TYPE_OBJECTREFERENCE, 20, false, false }, - { "timestamp", IEC61850_TYPE_TIMESTAMP, 8, false, false }, - { "entrytime", IEC61850_TYPE_ENTRYTIME, 6, false, false }, - { "bitstring", IEC61850_TYPE_BITSTRING, 4, false, false } -}; - -/** Each network interface needs a separate receiver */ -static struct list receivers = LIST_INIT(); -static pthread_t thread; - -static void * iec61850_sv_thread(void *ctx) -{ - while (1) { - for (unsigned i = 0; i < list_length(&receivers); i++) { - struct iec61850_sv_receiver *r = (struct iec61850_sv_receiver *) list_at(&receivers, i); - - SVReceiver_tick(r->receiver); /* calls iec61850_sv_listener() */ - } - - usleep(1e3); - } - - return NULL; -} - static void iec61850_sv_listener(SVSubscriber subscriber, void *ctx, SVSubscriber_ASDU asdu) { struct node *n = (struct node *) ctx; @@ -90,7 +47,7 @@ static void iec61850_sv_listener(SVSubscriber subscriber, void *ctx, SVSubscribe int smpcnt = SVSubscriber_ASDU_getSmpCnt(asdu); int confrev = SVSubscriber_ASDU_getConfRev(asdu); - debug(5, "Received SV: svid=%s, smpcnt=%i, confrev=%u", svid, smpcnt, confrev); + info("Received SV: svid=%s, smpcnt=%i, confrev=%u", svid, smpcnt, confrev); if (SVSubscriber_ASDU_getDataSize(asdu) < i->subscriber.total_size) { warn("Received truncated ASDU: size=%d, expected=%d", SVSubscriber_ASDU_getDataSize(asdu), i->subscriber.total_size); @@ -167,91 +124,6 @@ static void iec61850_sv_listener(SVSubscriber subscriber, void *ctx, SVSubscribe queue_signalled_push(&i->subscriber.queue, smp); } -static struct iec61850_type_descriptor * iec61850_lookup_type(const char *name) -{ - for (unsigned i = 0; i < ARRAY_LEN(type_descriptors); i++) { - if (!strcmp(name, type_descriptors[i].name)) - return &type_descriptors[i]; - } - - return NULL; -} - -static int iec61850_sv_parse_mapping(json_t *json_mapping, struct list *mapping) -{ - json_t *json_field; - size_t index; - - if (!json_is_array(json_mapping)) - return -1; - - list_init(mapping); - - int total_size = 0; - json_array_foreach(json_mapping, index, json_field) { - struct iec61850_type_descriptor *m; - const char *type = json_string_value(json_field); - - if (!json_is_string(json_field)) - return -1; - - m = iec61850_lookup_type(type); - if (!m) - return -1; - - list_push(mapping, m); - - total_size += m->size; - } - - return total_size; -} - -int iec61850_sv_init(struct super_node *sn) -{ - int ret; - - /* Start all receivers */ - for (size_t i = 0; i < list_length(&receivers); i++) { - struct iec61850_sv_receiver *r = (struct iec61850_sv_receiver *) list_at(&receivers, i); - - SVReceiver_startThreadless(r->receiver); - } - - ret = pthread_create(&thread, NULL, iec61850_sv_thread, NULL); - if (ret) - return ret; - - return 0; -} - -int iec61850_sv_deinit() -{ - int ret; - - ret = pthread_cancel(thread); - if (ret) - return ret; - - ret = pthread_join(thread, NULL); - if (ret) - return ret; - - for (size_t i = 0; i < list_length(&receivers); i++) { - struct iec61850_sv_receiver *r = (struct iec61850_sv_receiver *) list_at(&receivers, i); - - /* Stop all receivers */ - SVReceiver_stopThreadless(r->receiver); - - /* Cleanup and free resources */ - SVReceiver_destroy(r->receiver); - } - - list_destroy(&receivers, NULL, false); - - return 0; -} - int iec61850_sv_parse(struct node *n, json_t *json) { int ret; @@ -260,7 +132,6 @@ int iec61850_sv_parse(struct node *n, json_t *json) const char *dst_address = NULL; const char *interface = NULL; const char *svid = NULL; - const char *datset = NULL; const char *smpmod = NULL; json_t *json_sub = NULL; @@ -297,10 +168,9 @@ int iec61850_sv_parse(struct node *n, json_t *json) ether_aton_r(dst_address, &i->dst_address); if (json_pub) { - ret = json_unpack_ex(json_pub, &err, 0, "{ s: o, s: s, s: s, s?: i, s?: s, s?: i, s?: i, s?: i }", + ret = json_unpack_ex(json_pub, &err, 0, "{ s: o, s: s, s?: i, s?: s, s?: i, s?: i, s?: i }", "fields", &json_mapping, "svid", &svid, - "datset", &datset, "confrev", &i->publisher.confrev, "smpmod", &smpmod, "smprate", &i->publisher.smprate, @@ -322,9 +192,8 @@ int iec61850_sv_parse(struct node *n, json_t *json) } i->publisher.svid = svid ? strdup(svid) : NULL; - i->publisher.datset = datset ? strdup(datset) : NULL; - ret = iec61850_sv_parse_mapping(json_mapping, &i->publisher.mapping); + ret = iec61850_parse_mapping(json_mapping, &i->publisher.mapping); if (ret <= 0) error("Failed to parse setting 'fields' of node %s", node_name(n)); @@ -338,29 +207,11 @@ int iec61850_sv_parse(struct node *n, json_t *json) if (ret) jerror(&err, "Failed to parse configuration of node %s", node_name(n)); - ret = iec61850_sv_parse_mapping(json_mapping, &i->subscriber.mapping); + ret = iec61850_parse_mapping(json_mapping, &i->subscriber.mapping); if (ret <= 0) error("Failed to parse setting 'fields' of node %s", node_name(n)); i->subscriber.total_size = ret; - - /* Check if there is already a SVReceiver for this interface */ - struct iec61850_sv_receiver *r = (struct iec61850_sv_receiver *) list_lookup(&receivers, interface); - - if (!r) { - r = alloc(sizeof(struct iec61850_sv_receiver)); - if (!r) - return -1; - - r->interface = strdup(interface); - r->receiver = SVReceiver_create(); - - SVReceiver_setInterfaceId(r->receiver, r->interface); - - list_push(&receivers, r); - } - - i->subscriber.receiver = r->receiver; } return 0; @@ -374,9 +225,8 @@ char * iec61850_sv_print(struct node *n) buf = strf("interface=%s, app_id=%#x, dst_address=%s", i->interface, i->app_id, ether_ntoa(&i->dst_address)); /* Publisher part */ - strcatf(&buf, ", pub.svid=%s, pub.datset=%s, pub.vlan_prio=%d, pub.vlan_id=%#x, pub.confrev=%d, pub.#fields=%zu", + strcatf(&buf, ", pub.svid=%s, pub.vlan_prio=%d, pub.vlan_id=%#x, pub.confrev=%d, pub.#fields=%zu", i->publisher.svid, - i->publisher.datset, i->publisher.vlan_priority, i->publisher.vlan_id, i->publisher.confrev, @@ -396,22 +246,22 @@ int iec61850_sv_start(struct node *n) /* Initialize publisher */ i->publisher.publisher = SVPublisher_create(NULL, i->interface); - i->publisher.asdu = SVPublisher_addASDU(i->publisher.publisher, i->publisher.svid, i->publisher.datset, i->publisher.confrev); + i->publisher.asdu = SVPublisher_addASDU(i->publisher.publisher, i->publisher.svid, node_name_short(n), i->publisher.confrev); for (unsigned k = 0; k < list_length(&i->publisher.mapping); k++) { struct iec61850_type_descriptor *m = (struct iec61850_type_descriptor *) list_at(&i->publisher.mapping, k); switch (m->type) { - case IEC61850_TYPE_INT8: SV_ASDU_addINT8(i->publisher.asdu); break; - case IEC61850_TYPE_INT32: SV_ASDU_addINT32(i->publisher.asdu); break; - case IEC61850_TYPE_FLOAT32: SV_ASDU_addFLOAT(i->publisher.asdu); break; - case IEC61850_TYPE_FLOAT64: SV_ASDU_addFLOAT64(i->publisher.asdu); break; + case IEC61850_TYPE_INT8: SVPublisher_ASDU_addINT8(i->publisher.asdu); break; + case IEC61850_TYPE_INT32: SVPublisher_ASDU_addINT32(i->publisher.asdu); break; + case IEC61850_TYPE_FLOAT32: SVPublisher_ASDU_addFLOAT(i->publisher.asdu); break; + case IEC61850_TYPE_FLOAT64: SVPublisher_ASDU_addFLOAT64(i->publisher.asdu); break; default: { } } } if (i->publisher.smpmod >= 0) - SV_ASDU_setSmpMod(i->publisher.asdu, i->publisher.smpmod); + SVPublisher_ASDU_setSmpMod(i->publisher.asdu, i->publisher.smpmod); // if (s->publisher.smprate >= 0) // SV_ASDU_setSmpRate(i->publisher.asdu, i->publisher.smprate); @@ -419,6 +269,9 @@ int iec61850_sv_start(struct node *n) SVPublisher_setupComplete(i->publisher.publisher); /* Initialize subscriber */ + struct iec61850_receiver *r = iec61850_receiver_create(IEC61850_RECEIVER_SV, i->interface); + + i->subscriber.receiver = r->sv; i->subscriber.subscriber = SVSubscriber_create(i->dst_address.ether_addr_octet, i->app_id); /* Install a callback handler for the subscriber */ @@ -439,6 +292,15 @@ int iec61850_sv_start(struct node *n) return 0; } +int iec61850_sv_stop(struct node *n) +{ + struct iec61850_sv *i = (struct iec61850_sv *) n->_vd; + + SVReceiver_removeSubscriber(i->subscriber.receiver, i->subscriber.subscriber); + + return 0; +} + int iec61850_sv_destroy(struct node *n) { int ret; @@ -502,7 +364,7 @@ int iec61850_sv_write(struct node *n, struct sample *smps[], unsigned cnt) switch (m->type) { case IEC61850_TYPE_INT8: SVPublisher_ASDU_setINT8(i->publisher.asdu, offset, ival); break; case IEC61850_TYPE_INT32: SVPublisher_ASDU_setINT32(i->publisher.asdu, offset, ival); break; - case IEC61850_TYPE_FLOAT32: SVPublisher_ASDU_setFLOAT32(i->publisher.asdu, offset, fval); break; + case IEC61850_TYPE_FLOAT32: SVPublisher_ASDU_setFLOAT(i->publisher.asdu, offset, fval); break; case IEC61850_TYPE_FLOAT64: SVPublisher_ASDU_setFLOAT64(i->publisher.asdu, offset, fval); break; default: { } } @@ -538,11 +400,12 @@ static struct plugin p = { .node = { .vectorize = 0, .size = sizeof(struct iec61850_sv), - .init = iec61850_sv_init, - .deinit = iec61850_sv_deinit, + .init = iec61850_init, + .deinit = iec61850_deinit, .parse = iec61850_sv_parse, .print = iec61850_sv_print, .start = iec61850_sv_start, + .stop = iec61850_sv_stop, .destroy = iec61850_sv_destroy, .read = iec61850_sv_read, .write = iec61850_sv_write, diff --git a/tests/integration/pipe-loopback-iec61850-9-2.sh b/tests/integration/pipe-loopback-iec61850-9-2.sh index 54605f631..19422b0ae 100755 --- a/tests/integration/pipe-loopback-iec61850-9-2.sh +++ b/tests/integration/pipe-loopback-iec61850-9-2.sh @@ -45,7 +45,6 @@ cat > ${CONFIG_FILE} << EOF "publish" : { "svid" : "1234", - "datset" : "abc", "fields" : [ "float32", "float32", "float32", "float32" ] }, "subscribe" : { From 9b39493d93ebb915e05d7cdcfd0e5bd4a3d3f29c Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Wed, 6 Dec 2017 16:55:22 +0800 Subject: [PATCH 7/9] iec61850: updated submodule --- thirdparty/libiec61850 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/thirdparty/libiec61850 b/thirdparty/libiec61850 index 924441254..f1c1ba527 160000 --- a/thirdparty/libiec61850 +++ b/thirdparty/libiec61850 @@ -1 +1 @@ -Subproject commit 9244412545af81671a9130ba04f0428b1286c9f9 +Subproject commit f1c1ba527da70bbe0480bdd19768ba8d6f5eea34 From 8af18ab227d968e6e82a1f4eb0996c1f14d68ba7 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Wed, 6 Dec 2017 16:57:02 +0800 Subject: [PATCH 8/9] pipe: fix bug in pool management which caused underruns --- src/pipe.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/pipe.c b/src/pipe.c index 3727fc725..9092baa65 100644 --- a/src/pipe.c +++ b/src/pipe.c @@ -188,12 +188,8 @@ static void * recv_loop(void *ctx) warn("Receive pool underrun"); recv = node_read(node, smps, ready); - if (recv < 0) { + if (recv < 0) warn("Failed to receive samples from node %s: reason=%d", node_name(node), recv); - continue; - } - else if (recv == 0) - continue; io_print(&io, smps, recv); From 617998df5b51205ee3acacac5083acbb2f3f3184 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Wed, 6 Dec 2017 16:57:23 +0800 Subject: [PATCH 9/9] iec61850: turn output into debug output --- lib/nodes/iec61850_sv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/nodes/iec61850_sv.c b/lib/nodes/iec61850_sv.c index dbb1d832e..d96a50a0b 100644 --- a/lib/nodes/iec61850_sv.c +++ b/lib/nodes/iec61850_sv.c @@ -47,7 +47,7 @@ static void iec61850_sv_listener(SVSubscriber subscriber, void *ctx, SVSubscribe int smpcnt = SVSubscriber_ASDU_getSmpCnt(asdu); int confrev = SVSubscriber_ASDU_getConfRev(asdu); - info("Received SV: svid=%s, smpcnt=%i, confrev=%u", svid, smpcnt, confrev); + debug(10, "Received SV: svid=%s, smpcnt=%i, confrev=%u", svid, smpcnt, confrev); if (SVSubscriber_ASDU_getDataSize(asdu) < i->subscriber.total_size) { warn("Received truncated ASDU: size=%d, expected=%d", SVSubscriber_ASDU_getDataSize(asdu), i->subscriber.total_size);