From 894ea2e726bb8b721239e45fe4ef3e1759a45580 Mon Sep 17 00:00:00 2001 From: Michael Zillgith Date: Fri, 6 Jul 2018 09:33:00 +0200 Subject: [PATCH] - SV: added function SVPublisher_ASDU_setSmpCntWrap - added quality flag "derived" - updated 9-2LE publisher example --- dotnet/IEC61850forCSharp/IEC61850CommonAPI.cs | 12 ++++++ .../iec61850_9_2_LE_example.c | 40 ++++++++++++++++++- src/iec61850/inc/iec61850_common.h | 2 + src/sampled_values/sv_publisher.c | 10 ++++- src/sampled_values/sv_publisher.h | 10 +++++ src/sampled_values/sv_subscriber.c | 8 ++-- src/vs/libiec61850.def | 2 +- 7 files changed, 78 insertions(+), 6 deletions(-) diff --git a/dotnet/IEC61850forCSharp/IEC61850CommonAPI.cs b/dotnet/IEC61850forCSharp/IEC61850CommonAPI.cs index cda16ae9..51692901 100644 --- a/dotnet/IEC61850forCSharp/IEC61850CommonAPI.cs +++ b/dotnet/IEC61850forCSharp/IEC61850CommonAPI.cs @@ -184,6 +184,7 @@ namespace IEC61850 private const UInt16 QUALITY_SOURCE_SUBSTITUTED = 1024; private const UInt16 QUALITY_TEST = 2048; private const UInt16 QUALITY_OPERATOR_BLOCKED = 4096; + private const UInt16 QUALITY_DERIVED = 8192; public override string ToString () { @@ -341,6 +342,17 @@ namespace IEC61850 this.value = (ushort) ((int) this.value & (~QUALITY_OPERATOR_BLOCKED)); } } + + public bool Derived + { + get { return ((this.value & QUALITY_DERIVED) != 0); } + set { + if (value) + this.value |= QUALITY_DERIVED; + else + this.value = (ushort) ((int) this.value & (~QUALITY_DERIVED)); + } + } } /// diff --git a/examples/iec61850_9_2_LE_example/iec61850_9_2_LE_example.c b/examples/iec61850_9_2_LE_example/iec61850_9_2_LE_example.c index c49347b1..d29a095d 100644 --- a/examples/iec61850_9_2_LE_example/iec61850_9_2_LE_example.c +++ b/examples/iec61850_9_2_LE_example/iec61850_9_2_LE_example.c @@ -48,11 +48,21 @@ static int amp2; static int amp3; static int amp4; +static int amp1q; +static int amp2q; +static int amp3q; +static int amp4q; + static int vol1; static int vol2; static int vol3; static int vol4; +static int vol1q; +static int vol2q; +static int vol3q; +static int vol4q; + static SVPublisher svPublisher; static SVPublisher_ASDU asdu; @@ -64,14 +74,24 @@ setupSVPublisher(const char* svInterface) asdu = SVPublisher_addASDU(svPublisher, "xxxxMUnn01", NULL, 1); amp1 = SVPublisher_ASDU_addINT32(asdu); + amp1q = SVPublisher_ASDU_addQuality(asdu); amp2 = SVPublisher_ASDU_addINT32(asdu); + amp2q = SVPublisher_ASDU_addQuality(asdu); amp3 = SVPublisher_ASDU_addINT32(asdu); + amp3q = SVPublisher_ASDU_addQuality(asdu); amp4 = SVPublisher_ASDU_addINT32(asdu); + amp4q = SVPublisher_ASDU_addQuality(asdu); vol1 = SVPublisher_ASDU_addINT32(asdu); + vol1q = SVPublisher_ASDU_addQuality(asdu); vol2 = SVPublisher_ASDU_addINT32(asdu); + vol2q = SVPublisher_ASDU_addQuality(asdu); vol3 = SVPublisher_ASDU_addINT32(asdu); + vol3q = SVPublisher_ASDU_addQuality(asdu); vol4 = SVPublisher_ASDU_addINT32(asdu); + vol4q = SVPublisher_ASDU_addQuality(asdu); + + SVPublisher_ASDU_setSmpCntWrap(asdu, 4000); SVPublisher_setupComplete(svPublisher); } @@ -123,6 +143,8 @@ main(int argc, char** argv) IedServer_setSVCBHandler(iedServer, svcb, sVCBEventHandler, NULL); + Quality q = QUALITY_VALIDITY_GOOD; + while (running) { uint64_t timeval = Hal_getTimeInMs(); @@ -130,28 +152,44 @@ main(int argc, char** argv) IedServer_lockDataModel(iedServer); IedServer_updateInt32AttributeValue(iedServer, IEDMODEL_MUnn_TCTR1_Amp_instMag_i, current); + IedServer_updateQuality(iedServer, IEDMODEL_MUnn_TCTR1_Amp_q, q); IedServer_updateInt32AttributeValue(iedServer, IEDMODEL_MUnn_TCTR2_Amp_instMag_i, current); + IedServer_updateQuality(iedServer, IEDMODEL_MUnn_TCTR2_Amp_q, q); IedServer_updateInt32AttributeValue(iedServer, IEDMODEL_MUnn_TCTR3_Amp_instMag_i, current); + IedServer_updateQuality(iedServer, IEDMODEL_MUnn_TCTR3_Amp_q, q); IedServer_updateInt32AttributeValue(iedServer, IEDMODEL_MUnn_TCTR3_Amp_instMag_i, current); + IedServer_updateQuality(iedServer, IEDMODEL_MUnn_TCTR4_Amp_q, q); IedServer_updateInt32AttributeValue(iedServer, IEDMODEL_MUnn_TVTR1_Vol_instMag_i, voltage); + IedServer_updateQuality(iedServer, IEDMODEL_MUnn_TVTR1_Vol_q, q); IedServer_updateInt32AttributeValue(iedServer, IEDMODEL_MUnn_TVTR2_Vol_instMag_i, voltage); + IedServer_updateQuality(iedServer, IEDMODEL_MUnn_TVTR2_Vol_q, q); IedServer_updateInt32AttributeValue(iedServer, IEDMODEL_MUnn_TVTR3_Vol_instMag_i, voltage); + IedServer_updateQuality(iedServer, IEDMODEL_MUnn_TVTR3_Vol_q, q); IedServer_updateInt32AttributeValue(iedServer, IEDMODEL_MUnn_TVTR4_Vol_instMag_i, voltage); + IedServer_updateQuality(iedServer, IEDMODEL_MUnn_TVTR4_Vol_q, q); IedServer_unlockDataModel(iedServer); if (svcbEnabled) { SVPublisher_ASDU_setINT32(asdu, amp1, current); + SVPublisher_ASDU_setQuality(asdu, amp1q, q); SVPublisher_ASDU_setINT32(asdu, amp2, current); + SVPublisher_ASDU_setQuality(asdu, amp2q, q); SVPublisher_ASDU_setINT32(asdu, amp3, current); + SVPublisher_ASDU_setQuality(asdu, amp3q, q); SVPublisher_ASDU_setINT32(asdu, amp4, current); + SVPublisher_ASDU_setQuality(asdu, amp4q, q); SVPublisher_ASDU_setINT32(asdu, vol1, voltage); + SVPublisher_ASDU_setQuality(asdu, vol1q, q); SVPublisher_ASDU_setINT32(asdu, vol2, voltage); + SVPublisher_ASDU_setQuality(asdu, vol2q, q); SVPublisher_ASDU_setINT32(asdu, vol3, voltage); + SVPublisher_ASDU_setQuality(asdu, vol3q, q); SVPublisher_ASDU_setINT32(asdu, vol4, voltage); + SVPublisher_ASDU_setQuality(asdu, vol4q, q); SVPublisher_ASDU_increaseSmpCnt(asdu); @@ -161,7 +199,7 @@ main(int argc, char** argv) voltage++; current++; - Thread_sleep(500); + Thread_sleep(1); } /* stop MMS server - close TCP server socket and all client sockets */ diff --git a/src/iec61850/inc/iec61850_common.h b/src/iec61850/inc/iec61850_common.h index d8de6a3e..f0a67246 100644 --- a/src/iec61850/inc/iec61850_common.h +++ b/src/iec61850/inc/iec61850_common.h @@ -286,6 +286,8 @@ typedef uint16_t Validity; #define QUALITY_OPERATOR_BLOCKED 4096 +#define QUALITY_DERIVED 8192 + Validity Quality_getValidity(Quality* self); diff --git a/src/sampled_values/sv_publisher.c b/src/sampled_values/sv_publisher.c index 91bdeb30..b703ad46 100644 --- a/src/sampled_values/sv_publisher.c +++ b/src/sampled_values/sv_publisher.c @@ -55,6 +55,7 @@ struct sSVPublisher_ASDU { uint8_t smpSynch; uint16_t smpCnt; + uint16_t smpCntLimit; uint32_t confRev; uint64_t refrTm; @@ -299,6 +300,7 @@ SVPublisher_addASDU(SVPublisher self, const char* svID, const char* datset, uint newAsdu->svID = svID; newAsdu->datset = datset; newAsdu->confRev = confRev; + newAsdu->smpCntLimit = UINT16_MAX; newAsdu->_next = NULL; @@ -652,10 +654,16 @@ SVPublisher_ASDU_setSmpCnt(SVPublisher_ASDU self, uint16_t value) encodeUInt16FixedSize(self->smpCnt, self->smpCntBuf, 0); } +void +SVPublisher_ASDU_setSmpCntWrap(SVPublisher_ASDU self, uint16_t value) +{ + self->smpCntLimit = value; +} + void SVPublisher_ASDU_increaseSmpCnt(SVPublisher_ASDU self) { - self->smpCnt++; + self->smpCnt = ((self->smpCnt + 1) % self->smpCntLimit); encodeUInt16FixedSize(self->smpCnt, self->smpCntBuf, 0); } diff --git a/src/sampled_values/sv_publisher.h b/src/sampled_values/sv_publisher.h index d75f5f5e..957e12a8 100644 --- a/src/sampled_values/sv_publisher.h +++ b/src/sampled_values/sv_publisher.h @@ -294,6 +294,16 @@ SVPublisher_ASDU_getSmpCnt(SVPublisher_ASDU self); void SVPublisher_ASDU_increaseSmpCnt(SVPublisher_ASDU self); +/** + * \brief Set the roll-over (wrap) limit for the sample counter. When reaching the limit the + * sample counter will be reset to 0 (default is no limit) + * + * \param[in] self the Sampled Values ASDU instance. + * \param[in] value the new sample counter limit + */ +void +SVPublisher_ASDU_setSmpCntWrap(SVPublisher_ASDU self, uint16_t value); + /** * \brief Set the refresh time attribute of the ASDU. * diff --git a/src/sampled_values/sv_subscriber.c b/src/sampled_values/sv_subscriber.c index 807e6208..9e03607c 100644 --- a/src/sampled_values/sv_subscriber.c +++ b/src/sampled_values/sv_subscriber.c @@ -1,7 +1,7 @@ /* * sv_receiver.c * - * Copyright 2015 Michael Zillgith + * Copyright 2015-2018 Michael Zillgith * * This file is part of libIEC61850. * @@ -337,8 +337,10 @@ parseASDU(SVReceiver self, SVSubscriber subscriber, uint8_t* buffer, int length) } /* Call callback handler */ - if (subscriber->listener != NULL) - subscriber->listener(subscriber, subscriber->listenerParameter, &asdu); + if (subscriber) { + if (subscriber->listener != NULL) + subscriber->listener(subscriber, subscriber->listenerParameter, &asdu); + } } static void diff --git a/src/vs/libiec61850.def b/src/vs/libiec61850.def index c19ac03c..7faa74db 100644 --- a/src/vs/libiec61850.def +++ b/src/vs/libiec61850.def @@ -731,4 +731,4 @@ EXPORTS ClientGooseControlBlock_getMaxTime ClientGooseControlBlock_getFixedOffs ControlObjectClient_getCtlValType - + SVPublisher_ASDU_setSmpCntWrap