- IED server: added GoCB event callback

- IED server: added configuration option to use GoCB block handling without the integrated GOOSE publisher (IedServerConfig_useIntegratedGoosePublisher)
pull/265/head
Michael Zillgith 5 years ago
parent e1ab323c1b
commit 7e1c2ef18f

@ -51,9 +51,20 @@ controlHandlerForBinaryOutput(ControlAction action, void* parameter, MmsValue* v
}
}
static void
goCbEventHandler(MmsGooseControlBlock goCb, int event, void* parameter)
{
printf("Access to GoCB: %s\n", MmsGooseControlBlock_getName(goCb));
printf(" GoEna: %i\n", MmsGooseControlBlock_getGoEna(goCb));
}
int main(int argc, char** argv) {
iedServer = IedServer_create(&iedModel);
IedServerConfig config = IedServerConfig_create();
iedServer = IedServer_createWithConfig(&iedModel, NULL, config);
IedServerConfig_destroy(config);
if (argc > 1) {
char* ethernetIfcID = argv[1];
@ -73,6 +84,7 @@ int main(int argc, char** argv) {
IedServer_setGooseInterfaceIdEx(iedServer, IEDMODEL_GenericIO_LLN0, "gcbAnalogValues", ethernetIfcID);
}
IedServer_setGoCBHandler(iedServer, goCbEventHandler, NULL);
/* MMS server will be instructed to start listening to client connections. */
IedServer_start(iedServer, 102);

@ -75,6 +75,9 @@ struct sIedServerConfig
/** when true (default) enable log service */
bool enableLogService;
/** when true (default) the integrated GOOSE publisher is used */
bool useIntegratedGoosePublisher;
/** IEC 61850 edition (0 = edition 1, 1 = edition 2, 2 = edition 2.1, ...) */
uint8_t edition;
@ -269,11 +272,21 @@ IedServerConfig_getMaxDatasSetEntries(IedServerConfig self);
/**
* \brief Enable/disable the log service for MMS
*
* \param[in] enable set true to enable dynamic data set service, otherwise false
* \param[in] enable set true to enable log service, otherwise false
*/
LIB61850_API void
IedServerConfig_enableLogService(IedServerConfig self, bool enable);
/**
* \brief Enable/disable using the integrated GOOSE publisher for configured GoCBs
*
* This is enabled by default. Disable it when you want to use a separate GOOSE publisher
*
* \param[in] enable set true to enable the integrated GOOSE publisher, otherwise false
*/
LIB61850_API void
IedServerConfig_useIntegratedGoosePublisher(IedServerConfig self, bool enable);
/**
* \brief Is the log service for MMS enabled or disabled
*
@ -1446,6 +1459,48 @@ IedServer_setSVCBHandler(IedServer self, SVControlBlock* svcb, SVCBEventHandler
/**@}*/
/**
* @defgroup IEC61850_SERVER_GOCB Server side GOOSE control block (GoCB) handling
*
* @{
*/
typedef struct sMmsGooseControlBlock* MmsGooseControlBlock;
/** Control block has been enabled by client */
#define IEC61850_GOCB_EVENT_ENABLE 1
/** Control block has been disabled by client */
#define IEC61850_GOCB_EVENT_DISABLE 0
typedef void (*GoCBEventHandler) (MmsGooseControlBlock goCb, int event, void* parameter);
LIB61850_API void
IedServer_setGoCBHandler(IedServer self, GoCBEventHandler handler, void* parameter);
LIB61850_API char*
MmsGooseControlBlock_getName(MmsGooseControlBlock self);
LIB61850_API LogicalNode*
MmsGooseControlBlock_getLogicalNode(MmsGooseControlBlock self);
LIB61850_API DataSet*
MmsGooseControlBlock_getDataSet(MmsGooseControlBlock self);
LIB61850_API bool
MmsGooseControlBlock_getGoEna(MmsGooseControlBlock self);
LIB61850_API int
MmsGooseControlBlock_getMinTime(MmsGooseControlBlock self);
LIB61850_API int
MmsGooseControlBlock_getMaxTime(MmsGooseControlBlock self);
LIB61850_API bool
MmsGooseControlBlock_getFixedOffs(MmsGooseControlBlock self);
/**@}*/
/**
* @defgroup IEC61850_SERVER_EXTERNAL_ACCESS Handle external access to data model and access control
*

@ -24,8 +24,6 @@
#ifndef MMS_GOOSE_H_
#define MMS_GOOSE_H_
typedef struct sMmsGooseControlBlock* MmsGooseControlBlock;
LIB61850_INTERNAL MmsGooseControlBlock
MmsGooseControlBlock_create(void);
@ -41,15 +39,9 @@ MmsGooseControlBlock_useGooseVlanTag(MmsGooseControlBlock self, bool useVlanTag)
LIB61850_INTERNAL void
MmsGooseControlBlock_setGooseInterfaceId(MmsGooseControlBlock self, const char* interfaceId);
LIB61850_INTERNAL LogicalNode*
MmsGooseControlBlock_getLogicalNode(MmsGooseControlBlock self);
LIB61850_INTERNAL char*
MmsGooseControlBlock_getLogicalNodeName(MmsGooseControlBlock self);
LIB61850_INTERNAL char*
MmsGooseControlBlock_getName(MmsGooseControlBlock self);
LIB61850_INTERNAL MmsValue*
MmsGooseControlBlock_getGCBValue(MmsGooseControlBlock self, char* elementName);
@ -59,9 +51,6 @@ MmsGooseControlBlock_getMmsValues(MmsGooseControlBlock self);
LIB61850_INTERNAL MmsVariableSpecification*
MmsGooseControlBlock_getVariableSpecification(MmsGooseControlBlock self);
LIB61850_INTERNAL DataSet*
MmsGooseControlBlock_getDataSet(MmsGooseControlBlock self);
LIB61850_INTERNAL bool
MmsGooseControlBlock_isEnabled(MmsGooseControlBlock self);
@ -75,10 +64,10 @@ LIB61850_INTERNAL void
MmsGooseControlBlock_publishNewState(MmsGooseControlBlock self);
LIB61850_INTERNAL void
MmsGooseControlBlock_enable(MmsGooseControlBlock self);
MmsGooseControlBlock_enable(MmsGooseControlBlock self, MmsMapping* mmsMapping);
LIB61850_INTERNAL void
MmsGooseControlBlock_disable(MmsGooseControlBlock self);
MmsGooseControlBlock_disable(MmsGooseControlBlock self, MmsMapping* mmsMapping);
LIB61850_INTERNAL void
GOOSE_sendPendingEvents(MmsMapping* self);

@ -106,6 +106,9 @@ MmsMapping_enableGoosePublishing(MmsMapping* self);
LIB61850_INTERNAL void
MmsMapping_disableGoosePublishing(MmsMapping* self);
LIB61850_INTERNAL void
MmsMapping_useIntegratedGoosePublisher(MmsMapping* self, bool enable);
LIB61850_INTERNAL void
MmsMapping_useGooseVlanTag(MmsMapping* self, LogicalNode* ln, const char* gcbName, bool useVlanTag);

@ -270,8 +270,13 @@ struct sMmsMapping {
#endif
#if (CONFIG_INCLUDE_GOOSE_SUPPORT == 1)
bool useIntegratedPublisher;
LinkedList gseControls;
const char* gooseInterfaceId;
GoCBEventHandler goCbHandler;
void* goCbHandlerParameter;
#endif
#if (CONFIG_IEC61850_SAMPLED_VALUES_SUPPORT == 1)

@ -533,6 +533,13 @@ IedServer_createWithConfig(IedModel* dataModel, TLSConfiguration tlsConfiguratio
#if (CONFIG_IEC61850_SETTING_GROUPS == 1)
MmsMapping_configureSettingGroups(self->mmsMapping);
#endif
#if (CONFIG_INCLUDE_GOOSE_SUPPORT)
if (serverConfiguration) {
MmsMapping_useIntegratedGoosePublisher(self->mmsMapping, serverConfiguration->useIntegratedGoosePublisher);
}
#endif
}
@ -885,6 +892,17 @@ IedServer_setSVCBHandler(IedServer self, SVControlBlock* svcb, SVCBEventHandler
#endif /* (CONFIG_IEC61850_SAMPLED_VALUES_SUPPORT == 1) */
#if (CONFIG_INCLUDE_GOOSE_SUPPORT == 1)
void
IedServer_setGoCBHandler(IedServer self, GoCBEventHandler handler, void* parameter)
{
self->mmsMapping->goCbHandler = handler;
self->mmsMapping->goCbHandlerParameter = parameter;
}
#endif /* (CONFIG_INCLUDE_GOOSE_SUPPORT == 1) */
MmsValue*
IedServer_getAttributeValue(IedServer self, DataAttribute* dataAttribute)
{

@ -51,6 +51,7 @@ IedServerConfig_create()
self->maxDomainSpecificDataSets = CONFIG_MMS_MAX_NUMBER_OF_DOMAIN_SPECIFIC_DATA_SETS;
self->maxDataSetEntries = CONFIG_MMS_MAX_NUMBER_OF_DATA_SET_MEMBERS;
self->enableLogService = true;
self->useIntegratedGoosePublisher = true;
self->edition = IEC_61850_EDITION_2;
self->maxMmsConnections = 5;
}
@ -185,6 +186,12 @@ IedServerConfig_enableLogService(IedServerConfig self, bool enable)
self->enableLogService = enable;
}
void
IedServerConfig_useIntegratedGoosePublisher(IedServerConfig self, bool enable)
{
self->useIntegratedGoosePublisher = enable;
}
bool
IedServerConfig_isLogServiceEnabled(IedServerConfig self)
{

@ -1,7 +1,7 @@
/*
* mms_goose.c
*
* Copyright 2013, 2014 Michael Zillgith
* Copyright 2013-2020 Michael Zillgith
*
* This file is part of libIEC61850.
*
@ -40,9 +40,9 @@
struct sMmsGooseControlBlock {
char* name;
int goEna:1;
int isDynamicDataSet:1;
int useVlanTag:1;
bool goEna;
unsigned int isDynamicDataSet:1;
unsigned int useVlanTag:1;
char* dstAddress;
@ -76,6 +76,71 @@ struct sMmsGooseControlBlock {
bool stateChangePending;
};
bool
MmsGooseControlBlock_getGoEna(MmsGooseControlBlock self)
{
bool retVal = false;
if (self->mmsValue) {
MmsValue* goEnaValue = MmsValue_getElement(self->mmsValue, 0);
if (goEnaValue) {
retVal = MmsValue_getBoolean(goEnaValue);
}
}
return retVal;
}
int
MmsGooseControlBlock_getMinTime(MmsGooseControlBlock self)
{
int retVal = -1;
if (self->mmsValue) {
MmsValue* minTimeValue = MmsValue_getElement(self->mmsValue, 6);
if (minTimeValue) {
retVal = MmsValue_toInt32(minTimeValue);
}
}
return retVal;
}
int
MmsGooseControlBlock_getMaxTime(MmsGooseControlBlock self)
{
int retVal = -1;
if (self->mmsValue) {
MmsValue* maxTimeValue = MmsValue_getElement(self->mmsValue, 7);
if (maxTimeValue) {
retVal = MmsValue_toInt32(maxTimeValue);
}
}
return retVal;
}
bool
MmsGooseControlBlock_getFixedOffs(MmsGooseControlBlock self)
{
bool retVal = false;
if (self->mmsValue) {
MmsValue* fixedOffsValue = MmsValue_getElement(self->mmsValue, 8);
if (fixedOffsValue) {
retVal = MmsValue_getBoolean(fixedOffsValue);
}
}
return retVal;
}
#if (CONFIG_IEC61850_SERVICE_TRACKING == 1)
static void
@ -264,7 +329,7 @@ MmsGooseControlBlock_isEnabled(MmsGooseControlBlock self)
}
void
MmsGooseControlBlock_enable(MmsGooseControlBlock self)
MmsGooseControlBlock_enable(MmsGooseControlBlock self, MmsMapping* mmsMapping)
{
#if (CONFIG_MMS_THREADLESS_STACK != 1)
Semaphore_wait(self->publisherMutex);
@ -326,58 +391,65 @@ MmsGooseControlBlock_enable(MmsGooseControlBlock self)
memcpy(commParameters.dstAddress, MmsValue_getOctetStringBuffer(macAddress), 6);
if (self->gooseInterfaceId)
self->publisher = GoosePublisher_createEx(&commParameters, self->gooseInterfaceId, self->useVlanTag);
else
self->publisher = GoosePublisher_createEx(&commParameters, self->mmsMapping->gooseInterfaceId, self->useVlanTag);
if (mmsMapping->useIntegratedPublisher) {
if (self->publisher) {
self->minTime = MmsValue_toUint32(MmsValue_getElement(self->mmsValue, 6));
self->maxTime = MmsValue_toUint32(MmsValue_getElement(self->mmsValue, 7));
if (self->gooseInterfaceId)
self->publisher = GoosePublisher_createEx(&commParameters, self->gooseInterfaceId, self->useVlanTag);
else
self->publisher = GoosePublisher_createEx(&commParameters, self->mmsMapping->gooseInterfaceId, self->useVlanTag);
GoosePublisher_setTimeAllowedToLive(self->publisher, self->maxTime * 3);
if (self->publisher) {
self->minTime = MmsValue_toUint32(MmsValue_getElement(self->mmsValue, 6));
self->maxTime = MmsValue_toUint32(MmsValue_getElement(self->mmsValue, 7));
GoosePublisher_setDataSetRef(self->publisher, self->dataSetRef);
GoosePublisher_setTimeAllowedToLive(self->publisher, self->maxTime * 3);
GoosePublisher_setGoCbRef(self->publisher, self->goCBRef);
GoosePublisher_setDataSetRef(self->publisher, self->dataSetRef);
uint32_t confRev = MmsValue_toUint32(MmsValue_getElement(self->mmsValue, 3));
GoosePublisher_setGoCbRef(self->publisher, self->goCBRef);
GoosePublisher_setConfRev(self->publisher, confRev);
uint32_t confRev = MmsValue_toUint32(MmsValue_getElement(self->mmsValue, 3));
bool needsCom = MmsValue_getBoolean(MmsValue_getElement(self->mmsValue, 4));
GoosePublisher_setConfRev(self->publisher, confRev);
GoosePublisher_setNeedsCommission(self->publisher, needsCom);
bool needsCom = MmsValue_getBoolean(MmsValue_getElement(self->mmsValue, 4));
if (self->goId != NULL)
GoosePublisher_setGoID(self->publisher, self->goId);
GoosePublisher_setNeedsCommission(self->publisher, needsCom);
/* prepare data set values */
self->dataSetValues = LinkedList_create();
if (self->goId != NULL)
GoosePublisher_setGoID(self->publisher, self->goId);
DataSetEntry* dataSetEntry = self->dataSet->fcdas;
/* prepare data set values */
self->dataSetValues = LinkedList_create();
while (dataSetEntry != NULL) {
LinkedList_add(self->dataSetValues, dataSetEntry->value);
dataSetEntry = dataSetEntry->sibling;
DataSetEntry* dataSetEntry = self->dataSet->fcdas;
while (dataSetEntry != NULL) {
LinkedList_add(self->dataSetValues, dataSetEntry->value);
dataSetEntry = dataSetEntry->sibling;
}
}
else {
if (DEBUG_IED_SERVER)
printf("IED_SERVER: Failed to create GOOSE publisher!\n");
}
}
self->goEna = true;
self->goEna = true;
#if (CONFIG_IEC61850_SERVICE_TRACKING == 1)
MmsDataAccessError retVal = DATA_ACCESS_ERROR_SUCCESS;
copyGCBValuesToTrackingObject(self);
updateGenericTrackingObjectValues(self, IEC61850_SERVICE_TYPE_SET_GOCB_VALUES, retVal);
MmsDataAccessError retVal = DATA_ACCESS_ERROR_SUCCESS;
copyGCBValuesToTrackingObject(self);
updateGenericTrackingObjectValues(self, IEC61850_SERVICE_TYPE_SET_GOCB_VALUES, retVal);
#endif /* (CONFIG_IEC61850_SERVICE_TRACKING == 1) */
}
else {
if (DEBUG_IED_SERVER)
printf("IED_SERVER: Failed to create GOOSE publisher!\n");
}
}
}
else {
printf("GoCB already enabled!\n");
}
#if (CONFIG_MMS_THREADLESS_STACK != 1)
Semaphore_post(self->publisherMutex);
@ -385,7 +457,7 @@ MmsGooseControlBlock_enable(MmsGooseControlBlock self)
}
void
MmsGooseControlBlock_disable(MmsGooseControlBlock self)
MmsGooseControlBlock_disable(MmsGooseControlBlock self, MmsMapping* mmsMapping)
{
if (MmsGooseControlBlock_isEnabled(self)) {
MmsValue* goEna = MmsValue_getElement(self->mmsValue, 0);
@ -398,11 +470,13 @@ MmsGooseControlBlock_disable(MmsGooseControlBlock self)
Semaphore_wait(self->publisherMutex);
#endif
if (self->publisher != NULL) {
GoosePublisher_destroy(self->publisher);
self->publisher = NULL;
LinkedList_destroyStatic(self->dataSetValues);
self->dataSetValues = NULL;
if (mmsMapping->useIntegratedPublisher) {
if (self->publisher != NULL) {
GoosePublisher_destroy(self->publisher);
self->publisher = NULL;
LinkedList_destroyStatic(self->dataSetValues);
self->dataSetValues = NULL;
}
}
#if (CONFIG_IEC61850_SERVICE_TRACKING == 1)
@ -602,13 +676,15 @@ createDataSetReference(char* domainName, char* lnName, char* dataSetName)
void
GOOSE_sendPendingEvents(MmsMapping* self)
{
LinkedList element = self->gseControls;
if (self->useIntegratedPublisher) {
LinkedList element = self->gseControls;
while ((element = LinkedList_getNext(element)) != NULL) {
MmsGooseControlBlock gcb = (MmsGooseControlBlock) element->data;
while ((element = LinkedList_getNext(element)) != NULL) {
MmsGooseControlBlock gcb = (MmsGooseControlBlock) element->data;
if (MmsGooseControlBlock_isEnabled(gcb)) {
MmsGooseControlBlock_publishNewState(gcb);
if (MmsGooseControlBlock_isEnabled(gcb)) {
MmsGooseControlBlock_publishNewState(gcb);
}
}
}
}

@ -715,7 +715,6 @@ MmsMapping_initializeControlObjects(MmsMapping* self)
void
MmsMapping_configureSettingGroups(MmsMapping* self)
{
LinkedList settingGroupElement = LinkedList_getNext(self->settingGroups);
while (settingGroupElement != NULL) {
@ -747,6 +746,12 @@ MmsMapping_configureSettingGroups(MmsMapping* self)
}
}
void
MmsMapping_useIntegratedGoosePublisher(MmsMapping* self, bool enable)
{
self->useIntegratedPublisher = enable;
}
void
MmsMapping_setSgChangedHandler(MmsMapping* self, SettingGroupControlBlock* sgcb,
ActiveSettingGroupChangedHandler handler, void* parameter)
@ -1958,8 +1963,13 @@ MmsMapping_create(IedModel* model, IedServer iedServer)
#endif
#if (CONFIG_INCLUDE_GOOSE_SUPPORT == 1)
self->useIntegratedPublisher = true;
self->gseControls = LinkedList_create();
self->gooseInterfaceId = NULL;
self->goCbHandler = NULL;
self->goCbHandlerParameter = NULL;
#endif
#if (CONFIG_IEC61850_SAMPLED_VALUES_SUPPORT == 1)
@ -2277,10 +2287,18 @@ writeAccessGooseControlBlock(MmsMapping* self, MmsDomain* domain, char* variable
if (MmsValue_getType(value) != MMS_BOOLEAN)
return DATA_ACCESS_ERROR_TYPE_INCONSISTENT;
if (MmsValue_getBoolean(value))
MmsGooseControlBlock_enable(mmsGCB);
else
MmsGooseControlBlock_disable(mmsGCB);
if (MmsValue_getBoolean(value)) {
MmsGooseControlBlock_enable(mmsGCB, self);
if (self->goCbHandler)
self->goCbHandler(mmsGCB, IEC61850_GOCB_EVENT_ENABLE, self->goCbHandlerParameter);
}
else {
MmsGooseControlBlock_disable(mmsGCB, self);
if (self->goCbHandler)
self->goCbHandler(mmsGCB, IEC61850_GOCB_EVENT_ENABLE, self->goCbHandlerParameter);
}
return DATA_ACCESS_ERROR_SUCCESS;
}
@ -3635,7 +3653,7 @@ MmsMapping_enableGoosePublishing(MmsMapping* self)
while ((element = LinkedList_getNext(element)) != NULL) {
MmsGooseControlBlock gcb = (MmsGooseControlBlock) element->data;
MmsGooseControlBlock_enable(gcb);
MmsGooseControlBlock_enable(gcb, self);
}
}
@ -3686,7 +3704,7 @@ MmsMapping_disableGoosePublishing(MmsMapping* self)
while ((element = LinkedList_getNext(element)) != NULL) {
MmsGooseControlBlock gcb = (MmsGooseControlBlock) element->data;
MmsGooseControlBlock_disable(gcb);
MmsGooseControlBlock_disable(gcb, self);
}
}
@ -3732,7 +3750,8 @@ processPeriodicTasks(MmsMapping* self)
uint64_t currentTimeInMs = Hal_getTimeInMs();
#if (CONFIG_INCLUDE_GOOSE_SUPPORT == 1)
GOOSE_processGooseEvents(self, currentTimeInMs);
if (self->useIntegratedPublisher)
GOOSE_processGooseEvents(self, currentTimeInMs);
#endif
#if (CONFIG_IEC61850_CONTROL_SERVICE == 1)

Loading…
Cancel
Save