Merge pull request #39 from stv0g/sv-goose-bugfixes

Smaller bug fixes for SV & Goose
pull/143/head
Michael Zillgith 8 years ago committed by GitHub
commit bd92dc299e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -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}")
@ -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

@ -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)
@ -774,7 +794,7 @@ GooseReceiver_destroy(GooseReceiver self)
/***************************************
* Functions for non-threaded operation
***************************************/
void
EthernetSocket
GooseReceiver_startThreadless(GooseReceiver self)
{
if (self->interfaceId == NULL)
@ -788,6 +808,8 @@ GooseReceiver_startThreadless(GooseReceiver self)
}
else
self->running = false;
return self->ethSocket;
}
void
@ -811,10 +833,3 @@ GooseReceiver_tick(GooseReceiver self)
else
return false;
}
void
GooseReceiver_addHandleSet(GooseReceiver self, EthernetHandleSet handles)
{
return EthernetHandleSet_addSocket(handles, self->ethSocket);
}

@ -30,6 +30,7 @@ extern "C" {
#include <stdbool.h>
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

@ -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));
@ -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);
@ -410,7 +412,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);
}

@ -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.

@ -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)
{
@ -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,29 +231,26 @@ 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)
{
int bufPos = 0;
int svIdLength = 0;
int datSetLength = 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) {
@ -260,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;
@ -276,12 +280,21 @@ 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 */
if (DEBUG_SV_SUBSCRIBER) printf("SV_SUBSCRIBER: found unknown tag %02x\n", tag);
break;
}
@ -290,6 +303,25 @@ 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;
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)
@ -307,6 +339,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:
@ -314,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;
}
@ -330,6 +367,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;
@ -337,6 +378,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)
@ -358,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;
}
@ -585,6 +631,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)
@ -592,6 +655,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)
{
@ -606,6 +675,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)
{

@ -1,5 +1,5 @@
/*
* sv_subscriber_api.h
* sv_subscriber.h
*
* Copyright 2015 Michael Zillgith
*
@ -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
*/
@ -289,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
*
@ -297,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
*
@ -307,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
*

Loading…
Cancel
Save