From 9ad2b534f95b92c9185637569d9fd95f611fbfc2 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Wed, 6 Dec 2017 14:20:42 +0800 Subject: [PATCH 01/10] fix docs --- src/sampled_values/sv_subscriber.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sampled_values/sv_subscriber.h b/src/sampled_values/sv_subscriber.h index bc62bf94..6313aa9c 100644 --- a/src/sampled_values/sv_subscriber.h +++ b/src/sampled_values/sv_subscriber.h @@ -1,5 +1,5 @@ /* - * sv_subscriber_api.h + * sv_subscriber.h * * Copyright 2015 Michael Zillgith * From fa694f1b0dc1246b9b4e875c1fece156b79f3002 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Wed, 6 Dec 2017 14:24:51 +0800 Subject: [PATCH 02/10] sv/goose: remove {SVReceiver,GooseReceiver}_addHandleSet() function as it is unsafe to call before {SVReceiver,GooseReceiver}_startThreadless() The ethernet socket is now returned by {SVReceiver,GooseReceiver}_startThreadless() which allows us to call EthernetHandleSet_addSocket() afterwards. --- src/goose/goose_receiver.c | 11 +++-------- src/goose/goose_receiver.h | 17 ++--------------- src/sampled_values/sv_subscriber.c | 10 +++------- src/sampled_values/sv_subscriber.h | 18 +++--------------- 4 files changed, 11 insertions(+), 45 deletions(-) diff --git a/src/goose/goose_receiver.c b/src/goose/goose_receiver.c index c99e0426..2a59231a 100644 --- a/src/goose/goose_receiver.c +++ b/src/goose/goose_receiver.c @@ -774,7 +774,7 @@ GooseReceiver_destroy(GooseReceiver self) /*************************************** * Functions for non-threaded operation ***************************************/ -void +EthernetSocket GooseReceiver_startThreadless(GooseReceiver self) { if (self->interfaceId == NULL) @@ -788,6 +788,8 @@ GooseReceiver_startThreadless(GooseReceiver self) } else self->running = false; + + return self->ethSocket; } void @@ -811,10 +813,3 @@ GooseReceiver_tick(GooseReceiver self) else return false; } - -void -GooseReceiver_addHandleSet(GooseReceiver self, EthernetHandleSet handles) -{ - return EthernetHandleSet_addSocket(handles, self->ethSocket); -} - diff --git a/src/goose/goose_receiver.h b/src/goose/goose_receiver.h index 7d854ae0..4995daea 100644 --- a/src/goose/goose_receiver.h +++ b/src/goose/goose_receiver.h @@ -30,6 +30,7 @@ extern "C" { #include +typedef struct sEthernetSocket* EthernetSocket; /** * \addtogroup goose_api_group @@ -116,7 +117,7 @@ GooseReceiver_destroy(GooseReceiver self); /*************************************** * Functions for non-threaded operation ***************************************/ -void +EthernetSocket GooseReceiver_startThreadless(GooseReceiver self); void @@ -134,20 +135,6 @@ GooseReceiver_stopThreadless(GooseReceiver self); bool GooseReceiver_tick(GooseReceiver self); -/* Forward declaration */ -typedef struct sEthernetHandleSet* EthernetHandleSet; - -/** - * \brief Add the receiver to a handleset for multiplexed asynchronous IO. - * - * Note: This function must only be called after GooseReceiver_startThreadless(). - * - * \param[in] self The SVReceiver instance. - * \param[inout] handles The EthernetHandleSet to which the EthernetSocket of this receiver should be added. - */ -void -GooseReceiver_addHandleSet(GooseReceiver self, EthernetHandleSet handles); - /**@}*/ #ifdef __cplusplus diff --git a/src/sampled_values/sv_subscriber.c b/src/sampled_values/sv_subscriber.c index c17d05b8..061ca493 100644 --- a/src/sampled_values/sv_subscriber.c +++ b/src/sampled_values/sv_subscriber.c @@ -208,7 +208,7 @@ SVReceiver_destroy(SVReceiver self) GLOBAL_FREEMEM(self); } -void +EthernetSocket SVReceiver_startThreadless(SVReceiver self) { if (self->interfaceId == NULL) @@ -219,6 +219,8 @@ SVReceiver_startThreadless(SVReceiver self) Ethernet_setProtocolFilter(self->ethSocket, ETH_P_SV); self->running = true; + + return self->ethSocket; } void @@ -229,12 +231,6 @@ SVReceiver_stopThreadless(SVReceiver self) self->running = false; } -void -SVReceiver_addHandleSet(SVReceiver self, EthernetHandleSet handles) -{ - return EthernetHandleSet_addSocket(handles, self->ethSocket); -} - static void parseASDU(SVReceiver self, SVSubscriber subscriber, uint8_t* buffer, int length) { diff --git a/src/sampled_values/sv_subscriber.h b/src/sampled_values/sv_subscriber.h index 6313aa9c..fd4093e0 100644 --- a/src/sampled_values/sv_subscriber.h +++ b/src/sampled_values/sv_subscriber.h @@ -30,6 +30,8 @@ extern "C" { #endif +typedef struct sEthernetSocket* EthernetSocket; + /** * \defgroup sv_subscriber_api_group IEC 61850 Sampled Values (SV) subscriber API * @@ -204,7 +206,7 @@ SVReceiver_destroy(SVReceiver self); * Functions for non-threaded operation ***************************************/ -void +EthernetSocket SVReceiver_startThreadless(SVReceiver self); void @@ -222,20 +224,6 @@ SVReceiver_stopThreadless(SVReceiver self); bool SVReceiver_tick(SVReceiver self); -/* Forward declaration */ -typedef struct sEthernetHandleSet* EthernetHandleSet; - -/** - * \brief Add the receiver to a handleset for multiplexed asynchronous IO. - * - * Note: This function must only be called after SVReceiver_startThreadless(). - * - * \param[in] self The SVReceiver instance. - * \param[inout] handles The EthernetHandleSet to which the EthernetSocket of this receiver should be added. - */ -void -SVReceiver_addHandleSet(SVReceiver self, EthernetHandleSet handles); - /* * Subscriber */ From 9244412545af81671a9130ba04f0428b1286c9f9 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Wed, 6 Dec 2017 14:25:08 +0800 Subject: [PATCH 03/10] version bump --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7457fe4f..aca5ca5a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,7 +11,7 @@ project(libiec61850) ENABLE_TESTING() set(LIB_VERSION_MAJOR "1") -set(LIB_VERSION_MINOR "1") +set(LIB_VERSION_MINOR "2") set(LIB_VERSION_PATCH "0") set(LIB_VERSION "${LIB_VERSION_MAJOR}.${LIB_VERSION_MINOR}.${LIB_VERSION_PATCH}") From 9580c0add40b46a3a14abf3b2aca490abb510c14 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Wed, 6 Dec 2017 15:08:29 +0800 Subject: [PATCH 04/10] sv/goose: do not loop endless if invalid ASN.1 encoded payload has been received --- src/goose/goose_receiver.c | 20 ++++++++++++++++++++ src/sampled_values/sv_subscriber.c | 20 +++++++++++++++++--- 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/src/goose/goose_receiver.c b/src/goose/goose_receiver.c index 2a59231a..d18dccd8 100644 --- a/src/goose/goose_receiver.c +++ b/src/goose/goose_receiver.c @@ -129,6 +129,10 @@ parseAllData(uint8_t* buffer, int allDataLength, MmsValue* dataSetValues) MmsValue* value = MmsValue_getElement(dataSetValues, elementIndex); bufPos = BerDecoder_decodeLength(buffer, &elementLength, bufPos, allDataLength); + if (bufPos < 0) { + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Malformed message: failed to decode BER length tag!\n"); + return 0; + } if (bufPos + elementLength > allDataLength) { if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Malformed message: sub element is too large!\n"); @@ -277,6 +281,10 @@ parseAllDataUnknownValue(GooseSubscriber self, uint8_t* buffer, int allDataLengt uint8_t tag = buffer[bufPos++]; bufPos = BerDecoder_decodeLength(buffer, &elementLength, bufPos, allDataLength); + if (bufPos < 0) { + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Malformed message: failed to decode BER length tag!\n"); + return 0; + } if (bufPos + elementLength > allDataLength) { if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Malformed message: sub element is too large!\n"); @@ -331,6 +339,10 @@ parseAllDataUnknownValue(GooseSubscriber self, uint8_t* buffer, int allDataLengt uint8_t tag = buffer[bufPos++]; bufPos = BerDecoder_decodeLength(buffer, &elementLength, bufPos, allDataLength); + if (bufPos < 0) { + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Malformed message: failed to decode BER length tag!\n"); + return 0; + } if (bufPos + elementLength > allDataLength) { if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Malformed message: sub element is too large!\n"); @@ -461,6 +473,10 @@ parseGoosePayload(GooseReceiver self, uint8_t* buffer, int apduLength) if (buffer[bufPos++] == 0x61) { int gooseLength; bufPos = BerDecoder_decodeLength(buffer, &gooseLength, bufPos, apduLength); + if (bufPos < 0) { + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Malformed message: failed to decode BER length tag!\n"); + return 0; + } int gooseEnd = bufPos + gooseLength; @@ -469,6 +485,10 @@ parseGoosePayload(GooseReceiver self, uint8_t* buffer, int apduLength) uint8_t tag = buffer[bufPos++]; bufPos = BerDecoder_decodeLength(buffer, &elementLength, bufPos, apduLength); + if (bufPos < 0) { + if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Malformed message: failed to decode BER length tag!\n"); + return 0; + } if (bufPos + elementLength > apduLength) { if (DEBUG_GOOSE_SUBSCRIBER) diff --git a/src/sampled_values/sv_subscriber.c b/src/sampled_values/sv_subscriber.c index 061ca493..7c8be353 100644 --- a/src/sampled_values/sv_subscriber.c +++ b/src/sampled_values/sv_subscriber.c @@ -235,19 +235,21 @@ static void parseASDU(SVReceiver self, SVSubscriber subscriber, uint8_t* buffer, int length) { int bufPos = 0; + int svIdLength = 0; struct sSVSubscriber_ASDU asdu; memset(&asdu, 0, sizeof(struct sSVSubscriber_ASDU)); - int svIdLength = 0; - - while (bufPos < length) { int elementLength; uint8_t tag = buffer[bufPos++]; bufPos = BerDecoder_decodeLength(buffer, &elementLength, bufPos, length); + if (bufPos < 0) { + if (DEBUG_SV_SUBSCRIBER) printf("SV_SUBSCRIBER: Malformed message: failed to decode BER length tag!\n"); + return; + } switch (tag) { @@ -303,6 +305,10 @@ parseSequenceOfASDU(SVReceiver self, SVSubscriber subscriber, uint8_t* buffer, i uint8_t tag = buffer[bufPos++]; bufPos = BerDecoder_decodeLength(buffer, &elementLength, bufPos, length); + if (bufPos < 0) { + if (DEBUG_SV_SUBSCRIBER) printf("SV_SUBSCRIBER: Malformed message: failed to decode BER length tag!\n"); + return; + } switch (tag) { case 0x30: @@ -326,6 +332,10 @@ parseSVPayload(SVReceiver self, SVSubscriber subscriber, uint8_t* buffer, int ap int elementLength; bufPos = BerDecoder_decodeLength(buffer, &elementLength, bufPos, apduLength); + if (bufPos < 0) { + if (DEBUG_SV_SUBSCRIBER) printf("SV_SUBSCRIBER: Malformed message: failed to decode BER length tag!\n"); + return; + } int svEnd = bufPos + elementLength; @@ -333,6 +343,10 @@ parseSVPayload(SVReceiver self, SVSubscriber subscriber, uint8_t* buffer, int ap uint8_t tag = buffer[bufPos++]; bufPos = BerDecoder_decodeLength(buffer, &elementLength, bufPos, svEnd); + if (bufPos < 0) { + if (DEBUG_SV_SUBSCRIBER) printf("SV_SUBSCRIBER: Malformed message: failed to decode BER length tag!\n"); + return; + } if (bufPos + elementLength > apduLength) { if (DEBUG_SV_SUBSCRIBER) From e2601545df68684fa50d125bf44a40e6f75095af Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Wed, 6 Dec 2017 15:09:08 +0800 Subject: [PATCH 05/10] sv: fix invalid length ASN.1 BER length field for smpMod attribute --- src/sampled_values/sv_publisher.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sampled_values/sv_publisher.c b/src/sampled_values/sv_publisher.c index c6c178d5..4bb663e7 100644 --- a/src/sampled_values/sv_publisher.c +++ b/src/sampled_values/sv_publisher.c @@ -410,7 +410,7 @@ SVPublisher_ASDU_encodeToBuffer(SVPublisher_ASDU self, uint8_t* buffer, int bufP /* SmpMod */ if (self->hasSmpMod) { - bufPos = BerEncoder_encodeTL(0x88, 4, buffer, bufPos); + bufPos = BerEncoder_encodeTL(0x88, 2, buffer, bufPos); bufPos = encodeUInt16FixedSize(self->smpMod, buffer, bufPos); } From a4c002aa032983f31b6df2a83909314d679b50a2 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Wed, 6 Dec 2017 15:25:01 +0800 Subject: [PATCH 06/10] cmake: add missing debug options and enable all of them if DEBUG is set --- CMakeLists.txt | 39 +++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index aca5ca5a..d33aa4b4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,16 +46,35 @@ set(CONFIG_REPORTING_DEFAULT_REPORT_BUFFER_SIZE "8000" CACHE STRING "Default buf # advanced options option(DEBUG "Enable debugging mode (include assertions)" OFF) -option(DEBUG_SOCKET "Enable printf debugging for socket layer" OFF) -option(DEBUG_COTP "Enable COTP printf debugging" OFF) -option(DEBUG_ISO_SERVER "Enable ISO SERVER printf debugging" OFF) -option(DEBUG_ISO_CLIENT "Enable ISO CLIENT printf debugging" OFF) -option(DEBUG_IED_SERVER "Enable IED SERVER printf debugging" OFF) -option(DEBUG_IED_CLIENT "Enable IED CLIENT printf debugging" OFF) -option(DEBUG_MMS_SERVER "Enable MMS SERVER printf debugging" OFF) -option(DEBUG_MMS_CLIENT "Enable MMS CLIENT printf debugging" OFF) -#mark_as_advanced(DEBUG DEBUG_COTP DEBUG_ISO_SERVER DEBUG_ISO_CLIENT DEBUG_IED_SERVER -# DEBUG_IED_CLIENT DEBUG_MMS_SERVER DEBUG_MMS_CLIENT) +option(DEBUG_SOCKET "Enable printf debugging for socket layer" ${DEBUG}) +option(DEBUG_COTP "Enable COTP printf debugging" ${DEBUG}) +option(DEBUG_ISO_SERVER "Enable ISO SERVER printf debugging" ${DEBUG}) +option(DEBUG_ISO_CLIENT "Enable ISO CLIENT printf debugging" ${DEBUG}) +option(DEBUG_IED_SERVER "Enable IED SERVER printf debugging" ${DEBUG}) +option(DEBUG_IED_CLIENT "Enable IED CLIENT printf debugging" ${DEBUG}) +option(DEBUG_MMS_SERVER "Enable MMS SERVER printf debugging" ${DEBUG}) +option(DEBUG_MMS_CLIENT "Enable MMS CLIENT printf debugging" ${DEBUG}) +option(DEBUG_GOOSE_SUBSCRIBER "Enable GOOSE subscriber printf debugging" ${DEBUG}) +option(DEBUG_GOOSE_PUBLISHER "Enable GOOSE publisher printf debugging" ${DEBUG}) +option(DEBUG_SV_SUBSCRIBER "Enable Sampled Values subscriber debugging" ${DEBUG}) +option(DEBUG_SV_PUBLISHER "Enable Sampled Values publisher debugging" ${DEBUG}) +option(DEBUG_HAL_ETHERNET "Enable Ethernet HAL printf debugging" ${DEBUG}) + +#mark_as_advanced( +# DEBUG_SOCKET +# DEBUG_COTP +# DEBUG_ISO_SERVER +# DEBUG_ISO_CLIENT +# DEBUG_IED_SERVER +# DEBUG_IED_CLIENT +# DEBUG_MMS_SERVER +# DEBUG_MMS_CLIENT +# DEBUG_GOOSE_SUBSCRIBER +# DEBUG_GOOSE_PUBLISHER +# DEBUG_SV_SUBSCRIBER +# DEBUG_SV_PUBLISHER +# DEBUG_HAL_ETHERNET +#) include_directories( ${CMAKE_CURRENT_BINARY_DIR}/config From 10f0d843497b5e4fbd51e07e9dde9f9720d8542d Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Wed, 6 Dec 2017 15:42:23 +0800 Subject: [PATCH 07/10] sv: smpRate is an optional ASDU attribute. We shall only encode it if it was set before --- src/sampled_values/sv_publisher.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sampled_values/sv_publisher.c b/src/sampled_values/sv_publisher.c index 4bb663e7..ed2c904d 100644 --- a/src/sampled_values/sv_publisher.c +++ b/src/sampled_values/sv_publisher.c @@ -398,8 +398,10 @@ SVPublisher_ASDU_encodeToBuffer(SVPublisher_ASDU self, uint8_t* buffer, int bufP buffer[bufPos++] = self->smpSynch; /* SmpRate */ - bufPos = BerEncoder_encodeTL(0x86, 2, buffer, bufPos); - bufPos = encodeUInt16FixedSize(self->smpRate, buffer, bufPos); + if (self->hasSmpRate) { + bufPos = BerEncoder_encodeTL(0x86, 2, buffer, bufPos); + bufPos = encodeUInt16FixedSize(self->smpRate, buffer, bufPos); + } /* Sample */ bufPos = BerEncoder_encodeTL(0x87, self->dataSize, buffer, bufPos); From f407c6e6ca6cdfd8b2f2bcd6553405334a0b0c37 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Wed, 6 Dec 2017 16:06:37 +0800 Subject: [PATCH 08/10] sv: add support for decoding smpMod, smpRate and datSet attributes in ASDUs --- src/sampled_values/sv_subscriber.c | 67 ++++++++++++++++++++++++++++-- src/sampled_values/sv_subscriber.h | 54 ++++++++++++++++++++++++ 2 files changed, 118 insertions(+), 3 deletions(-) diff --git a/src/sampled_values/sv_subscriber.c b/src/sampled_values/sv_subscriber.c index 7c8be353..ca3ac081 100644 --- a/src/sampled_values/sv_subscriber.c +++ b/src/sampled_values/sv_subscriber.c @@ -70,20 +70,20 @@ struct sSVSubscriber { struct sSVSubscriber_ASDU { char* svId; + char* datSet; uint8_t* smpCnt; uint8_t* confRev; uint8_t* refrTm; uint8_t* smpSynch; - + uint8_t* smpMod; + uint8_t* smpRate; int dataBufferLength; uint8_t* dataBuffer; }; - - SVReceiver SVReceiver_create(void) { @@ -236,6 +236,7 @@ parseASDU(SVReceiver self, SVSubscriber subscriber, uint8_t* buffer, int length) { int bufPos = 0; int svIdLength = 0; + int datSetLength = 0; struct sSVSubscriber_ASDU asdu; memset(&asdu, 0, sizeof(struct sSVSubscriber_ASDU)); @@ -258,6 +259,11 @@ parseASDU(SVReceiver self, SVSubscriber subscriber, uint8_t* buffer, int length) svIdLength = elementLength; break; + case 0x81: + asdu.datSet = (char*) (buffer + bufPos); + datSetLength = elementLength; + break; + case 0x82: asdu.smpCnt = buffer + bufPos; break; @@ -274,11 +280,19 @@ parseASDU(SVReceiver self, SVSubscriber subscriber, uint8_t* buffer, int length) asdu.smpSynch = buffer + bufPos; break; + case 0x86: + asdu.smpRate = buffer + bufPos; + break; + case 0x87: asdu.dataBuffer = buffer + bufPos; asdu.dataBufferLength = elementLength; break; + case 0x88: + asdu.smpMod = buffer + bufPos; + break; + default: /* ignore unknown tag */ break; } @@ -288,6 +302,8 @@ parseASDU(SVReceiver self, SVSubscriber subscriber, uint8_t* buffer, int length) if (asdu.svId != NULL) asdu.svId[svIdLength] = 0; + if (asdu.datSet != NULL) + asdu.datSet[datSetLength] = 0; /* Call callback handler */ if (subscriber->listener != NULL) @@ -595,6 +611,23 @@ SVSubscriber_ASDU_hasRefrTm(SVSubscriber_ASDU self) return (self->refrTm != NULL); } +bool +SVSubscriber_ASDU_hasDatSet(SVSubscriber_ASDU self) +{ + return (self->datSet != NULL); +} + +bool +SVSubscriber_ASDU_hasSmpRate(SVSubscriber_ASDU self) +{ + return (self->smpRate != NULL); +} + +bool +SVSubscriber_ASDU_hasSmpMod(SVSubscriber_ASDU self) +{ + return (self->smpMod != NULL); +} const char* SVSubscriber_ASDU_getSvId(SVSubscriber_ASDU self) @@ -602,6 +635,12 @@ SVSubscriber_ASDU_getSvId(SVSubscriber_ASDU self) return self->svId; } +const char* +SVSubscriber_ASDU_getDatSet(SVSubscriber_ASDU self) +{ + return self->datSet; +} + uint32_t SVSubscriber_ASDU_getConfRev(SVSubscriber_ASDU self) { @@ -616,6 +655,28 @@ SVSubscriber_ASDU_getConfRev(SVSubscriber_ASDU self) return retVal; } +uint8_t +SVSubscriber_ASDU_getSmpMod(SVSubscriber_ASDU self) +{ + uint8_t retVal = *((uint8_t*) (self->smpMod)); + + return retVal; +} + +uint16_t +SVSubscriber_ASDU_getSmpRate(SVSubscriber_ASDU self) +{ + uint16_t retVal = *((uint16_t*) (self->smpRate)); + +#if (ORDER_LITTLE_ENDIAN == 1) + uint8_t* buf = (uint8_t*) (&retVal); + + BerEncoder_revertByteOrder(buf, 2); +#endif + + return retVal; +} + int8_t SVSubscriber_ASDU_getINT8(SVSubscriber_ASDU self, int index) { diff --git a/src/sampled_values/sv_subscriber.h b/src/sampled_values/sv_subscriber.h index fd4093e0..ef5ab875 100644 --- a/src/sampled_values/sv_subscriber.h +++ b/src/sampled_values/sv_subscriber.h @@ -277,6 +277,14 @@ SVSubscriber_ASDU_getSmpCnt(SVSubscriber_ASDU self); const char* SVSubscriber_ASDU_getSvId(SVSubscriber_ASDU self); +/** + * \brief return the DatSet value included in the SV ASDU + * + * \param self ASDU object instance + */ +const char* +SVSubscriber_ASDU_getDatSet(SVSubscriber_ASDU self); + /** * \brief return the ConfRev value included in the SV ASDU * @@ -285,6 +293,32 @@ SVSubscriber_ASDU_getSvId(SVSubscriber_ASDU self); uint32_t SVSubscriber_ASDU_getConfRev(SVSubscriber_ASDU self); +/** + * \brief return the SmpMod value included in the SV ASDU + * + * \param self ASDU object instance + */ +uint8_t +SVSubscriber_ASDU_getSmpMod(SVSubscriber_ASDU self); + +/** + * \brief return the SmpRate value included in the SV ASDU + * + * \param self ASDU object instance + */ +uint16_t +SVSubscriber_ASDU_getSmpRate(SVSubscriber_ASDU self); + +/** + * \brief Check if DatSet value is included in the SV ASDU + * + * \param self ASDU object instance + * + * \return true if DatSet value is present, false otherwise + */ +bool +SVSubscriber_ASDU_hasDatSet(SVSubscriber_ASDU self); + /** * \brief Check if RefrTm value is included in the SV ASDU * @@ -295,6 +329,26 @@ SVSubscriber_ASDU_getConfRev(SVSubscriber_ASDU self); bool SVSubscriber_ASDU_hasRefrTm(SVSubscriber_ASDU self); +/** + * \brief Check if SmpMod value is included in the SV ASDU + * + * \param self ASDU object instance + * + * \return true if SmpMod value is present, false otherwise + */ +bool +SVSubscriber_ASDU_hasSmpMod(SVSubscriber_ASDU self); + +/** + * \brief Check if SmpRate value is included in the SV ASDU + * + * \param self ASDU object instance + * + * \return true if SmpRate value is present, false otherwise + */ +bool +SVSubscriber_ASDU_hasSmpRate(SVSubscriber_ASDU self); + /** * \brief Get the RefrTim value included in SV ASDU as ms timestamp * From d85ce713661e210be1626dfc3d4c504dd3eeaf9b Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Wed, 6 Dec 2017 16:09:52 +0800 Subject: [PATCH 09/10] sv: improve debugging output in sampled values subscriber --- src/sampled_values/sv_subscriber.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/sampled_values/sv_subscriber.c b/src/sampled_values/sv_subscriber.c index ca3ac081..573fc39e 100644 --- a/src/sampled_values/sv_subscriber.c +++ b/src/sampled_values/sv_subscriber.c @@ -294,6 +294,7 @@ parseASDU(SVReceiver self, SVSubscriber subscriber, uint8_t* buffer, int length) break; default: /* ignore unknown tag */ + if (DEBUG_SV_SUBSCRIBER) printf("SV_SUBSCRIBER: found unknown tag %02x\n", tag); break; } @@ -304,6 +305,23 @@ parseASDU(SVReceiver self, SVSubscriber subscriber, uint8_t* buffer, int length) asdu.svId[svIdLength] = 0; if (asdu.datSet != NULL) asdu.datSet[datSetLength] = 0; + + if (DEBUG_SV_SUBSCRIBER) { + printf("SV_SUBSCRIBER: SV ASDU: ----------------\n"); + printf("SV_SUBSCRIBER: DataLength: %d\n", asdu.dataBufferLength); + printf("SV_SUBSCRIBER: SvId: %s\n", asdu.svId); + printf("SV_SUBSCRIBER: SmpCnt: %d\n", SVSubscriber_ASDU_getSmpCnt(&asdu)); + printf("SV_SUBSCRIBER: ConfRev: %d\n", SVSubscriber_ASDU_getConfRev(&asdu)); + + if (SVSubscriber_ASDU_hasDatSet(&asdu)) + printf("SV_SUBSCRIBER: DatSet: %s\n", asdu.datSet); + if (SVSubscriber_ASDU_hasRefrTm(&asdu)) + printf("SV_SUBSCRIBER: RefrTm: %lu\n", SVSubscriber_ASDU_getRefrTmAsMs(&asdu)); + if (SVSubscriber_ASDU_hasSmpMod(&asdu)) + printf("SV_SUBSCRIBER: SmpMod: %d\n", SVSubscriber_ASDU_getSmpMod(&asdu)); + if (SVSubscriber_ASDU_hasSmpRate(&asdu)) + printf("SV_SUBSCRIBER: SmpRate: %d\n", SVSubscriber_ASDU_getSmpRate(&asdu)); + } /* Call callback handler */ if (subscriber->listener != NULL) @@ -332,6 +350,7 @@ parseSequenceOfASDU(SVReceiver self, SVSubscriber subscriber, uint8_t* buffer, i break; default: /* ignore unknown tag */ + if (DEBUG_SV_SUBSCRIBER) printf("SV_SUBSCRIBER: found unknown tag %02x\n", tag); break; } @@ -384,6 +403,7 @@ parseSVPayload(SVReceiver self, SVSubscriber subscriber, uint8_t* buffer, int ap break; default: /* ignore unknown tag */ + if (DEBUG_SV_SUBSCRIBER) printf("SV_SUBSCRIBER: found unknown tag %02x\n", tag); break; } From f1c1ba527da70bbe0480bdd19768ba8d6f5eea34 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Wed, 6 Dec 2017 16:45:38 +0800 Subject: [PATCH 10/10] sv: use const for SvId and DatSet attributes as they are read-only --- src/sampled_values/sv_publisher.c | 6 +++--- src/sampled_values/sv_publisher.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sampled_values/sv_publisher.c b/src/sampled_values/sv_publisher.c index ed2c904d..578a1826 100644 --- a/src/sampled_values/sv_publisher.c +++ b/src/sampled_values/sv_publisher.c @@ -43,8 +43,8 @@ #define SV_MAX_MESSAGE_SIZE 1518 struct sSVPublisher_ASDU { - char* svID; - char* datset; + const char* svID; + const char* datset; int dataSize; bool hasRefrTm; @@ -296,7 +296,7 @@ SVPublisher_create(CommParameters* parameters, const char* interfaceId) } SVPublisher_ASDU -SVPublisher_addASDU(SVPublisher self, char* svID, char* datset, uint32_t confRev) +SVPublisher_addASDU(SVPublisher self, const char* svID, const char* datset, uint32_t confRev) { SVPublisher_ASDU newAsdu = (SVPublisher_ASDU) GLOBAL_CALLOC(1, sizeof(struct sSVPublisher_ASDU)); diff --git a/src/sampled_values/sv_publisher.h b/src/sampled_values/sv_publisher.h index 50a9ed6e..5ea8676b 100644 --- a/src/sampled_values/sv_publisher.h +++ b/src/sampled_values/sv_publisher.h @@ -85,7 +85,7 @@ SVPublisher_create(CommParameters* parameters, const char* interfaceId); * \return the new ASDU instance. */ SVPublisher_ASDU -SVPublisher_addASDU(SVPublisher self, char* svID, char* datset, uint32_t confRev); +SVPublisher_addASDU(SVPublisher self, const char* svID, const char* datset, uint32_t confRev); /** * \brief Prepare the publisher for publishing.