diff --git a/examples/server_example_setting_groups/server_example_sg.c b/examples/server_example_setting_groups/server_example_sg.c index 6e16cd43..e319b26d 100644 --- a/examples/server_example_setting_groups/server_example_sg.c +++ b/examples/server_example_setting_groups/server_example_sg.c @@ -108,7 +108,14 @@ readAccessHandler(LogicalDevice* ld, LogicalNode* ln, DataObject* dataObject, Fu int main(int argc, char** argv) { - iedServer = IedServer_create(&iedModel); + IedServerConfig config = IedServerConfig_create(); + + //IedServerConfig_enableEditSG(config, false); + IedServerConfig_enableResvTmsForSGCB(config, false); + + iedServer = IedServer_createWithConfig(&iedModel, NULL, config); + + IedServerConfig_destroy(config); LogicalDevice* ld = IEDMODEL_PROT; diff --git a/src/iec61850/inc/iec61850_server.h b/src/iec61850/inc/iec61850_server.h index 2d80c811..0ba5d267 100644 --- a/src/iec61850/inc/iec61850_server.h +++ b/src/iec61850/inc/iec61850_server.h @@ -83,6 +83,12 @@ struct sIedServerConfig /** maximum number of MMS (TCP) connections */ int maxMmsConnections; + + /** enable EditSG service (default: true) */ + bool enableEditSG; + + /** enable visibility of SGCB.ResvTms (default: true) */ + bool enableResvTmsForSGCB; }; /** @@ -277,6 +283,27 @@ IedServerConfig_getMaxDatasSetEntries(IedServerConfig self); LIB61850_API void IedServerConfig_enableLogService(IedServerConfig self, bool enable); +/** + * \brief Enable/disable the EditSG service to allow clients to change setting groups (default is enabled) + * + * NOTE: When disabled SGCB.ResvTms is not available online and the setting of \ref IedServerConfig_enableResvTmsForSGCB + * is ignored. + * + * \param[in] enable set true to enable, otherwise false (default value it true) + */ +LIB61850_API void +IedServerConfig_enableEditSG(IedServerConfig self, bool enable); + +/** + * \brief Enable/disable the SGCB.ResvTms when EditSG is enabled + * + * NOTE: When EditSG is disabled (see \ref IedServerConfig_enableEditSG) then this setting is ignored. + * + * \param[in] enable set true to enable, otherwise false (default value it true) + */ +LIB61850_API void +IedServerConfig_enableResvTmsForSGCB(IedServerConfig self, bool enable); + /** * \brief Enable/disable using the integrated GOOSE publisher for configured GoCBs * diff --git a/src/iec61850/inc_private/ied_server_private.h b/src/iec61850/inc_private/ied_server_private.h index 0de69cb4..3d6aa3fd 100644 --- a/src/iec61850/inc_private/ied_server_private.h +++ b/src/iec61850/inc_private/ied_server_private.h @@ -67,6 +67,11 @@ struct sIedServer char* revision; #endif +#if (CONFIG_IEC61850_SETTING_GROUPS == 1) + bool enableEditSG; + bool hasSGCBResvTms; +#endif + uint8_t edition; bool running; diff --git a/src/iec61850/inc_private/mms_mapping_internal.h b/src/iec61850/inc_private/mms_mapping_internal.h index 126c47e3..b73618f6 100644 --- a/src/iec61850/inc_private/mms_mapping_internal.h +++ b/src/iec61850/inc_private/mms_mapping_internal.h @@ -294,6 +294,7 @@ struct sMmsMapping { #endif #if (CONFIG_IEC61850_SETTING_GROUPS == 1) + bool allowEditSg; LinkedList settingGroups; #endif diff --git a/src/iec61850/server/impl/ied_server.c b/src/iec61850/server/impl/ied_server.c index 1b83c516..ae95ab44 100644 --- a/src/iec61850/server/impl/ied_server.c +++ b/src/iec61850/server/impl/ied_server.c @@ -489,6 +489,17 @@ IedServer_createWithConfig(IedModel* dataModel, TLSConfiguration tlsConfiguratio } #endif +#if (CONFIG_IEC61850_SETTING_GROUPS == 1) + if (serverConfiguration) { + self->enableEditSG = serverConfiguration->enableEditSG; + self->hasSGCBResvTms = serverConfiguration->enableResvTmsForSGCB; + } + else { + self->enableEditSG = true; + self->hasSGCBResvTms = true; + } +#endif + self->mmsMapping = MmsMapping_create(dataModel, self); self->mmsDevice = MmsMapping_getMmsDeviceModel(self->mmsMapping); diff --git a/src/iec61850/server/impl/ied_server_config.c b/src/iec61850/server/impl/ied_server_config.c index 35db9b59..4f79819d 100644 --- a/src/iec61850/server/impl/ied_server_config.c +++ b/src/iec61850/server/impl/ied_server_config.c @@ -54,6 +54,7 @@ IedServerConfig_create() self->useIntegratedGoosePublisher = true; self->edition = IEC_61850_EDITION_2; self->maxMmsConnections = 5; + self->enableEditSG = true; } return self; @@ -186,6 +187,18 @@ IedServerConfig_enableLogService(IedServerConfig self, bool enable) self->enableLogService = enable; } +void +IedServerConfig_enableEditSG(IedServerConfig self, bool enable) +{ + self->enableEditSG = enable; +} + +void +IedServerConfig_enableResvTmsForSGCB(IedServerConfig self, bool enable) +{ + self->enableResvTmsForSGCB = enable; +} + void IedServerConfig_useIntegratedGoosePublisher(IedServerConfig self, bool enable) { diff --git a/src/iec61850/server/mms_mapping/mms_mapping.c b/src/iec61850/server/mms_mapping/mms_mapping.c index 4c9b65da..86497ccf 100644 --- a/src/iec61850/server/mms_mapping/mms_mapping.c +++ b/src/iec61850/server/mms_mapping/mms_mapping.c @@ -417,15 +417,20 @@ createFCNamedVariable(LogicalNode* logicalNode, FunctionalConstraint fc) #if (CONFIG_IEC61850_SETTING_GROUPS == 1) static MmsVariableSpecification* -createSGCB(void) +createSGCB(bool withResvTms) { + int numberOfElements = 5; + + if (withResvTms) + numberOfElements = 6; + MmsVariableSpecification* namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification)); namedVariable->name = StringUtils_copyString("SGCB"); namedVariable->type = MMS_STRUCTURE; - namedVariable->typeSpec.structure.elementCount = 6; - namedVariable->typeSpec.structure.elements = (MmsVariableSpecification**) GLOBAL_CALLOC(6, + namedVariable->typeSpec.structure.elementCount = numberOfElements; + namedVariable->typeSpec.structure.elements = (MmsVariableSpecification**) GLOBAL_CALLOC(numberOfElements, sizeof(MmsVariableSpecification*)); MmsVariableSpecification* element; @@ -458,18 +463,19 @@ createSGCB(void) element->type = MMS_UTC_TIME; namedVariable->typeSpec.structure.elements[4] = element; - element = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification)); - element->name = StringUtils_copyString("ResvTms"); - element->type = MMS_UNSIGNED; - element->typeSpec.integer = 16; - namedVariable->typeSpec.structure.elements[5] = element; + if (withResvTms) { + element = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification)); + element->name = StringUtils_copyString("ResvTms"); + element->type = MMS_UNSIGNED; + element->typeSpec.integer = 16; + namedVariable->typeSpec.structure.elements[5] = element; + } return namedVariable; } - static MmsVariableSpecification* -createFCNamedVariableSPWithSGCB(LogicalNode* logicalNode) +createFCNamedVariableSPWithSGCB(LogicalNode* logicalNode, bool withResvTms) { MmsVariableSpecification* namedVariable = (MmsVariableSpecification*) GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification)); @@ -493,7 +499,7 @@ createFCNamedVariableSPWithSGCB(LogicalNode* logicalNode) dataObjectCount = 1; - namedVariable->typeSpec.structure.elements[0] = createSGCB(); + namedVariable->typeSpec.structure.elements[0] = createSGCB(withResvTms); dataObject = (DataObject*) logicalNode->firstChild; @@ -563,10 +569,14 @@ unselectEditSettingGroup(SettingGroup* settingGroup) settingGroup->sgcb->editSG = 0; settingGroup->editingClient = NULL; + MmsValue* editSg = MmsValue_getElement(settingGroup->sgcbMmsValues, 2); - MmsValue_setUint8(editSg, 0U); + if (editSg) + MmsValue_setUint8(editSg, 0U); + MmsValue* resvTms = MmsValue_getElement(settingGroup->sgcbMmsValues, 5); - MmsValue_setUint16(resvTms, 0U); + if (resvTms) + MmsValue_setUint16(resvTms, 0U); } static void @@ -737,7 +747,9 @@ MmsMapping_configureSettingGroups(MmsMapping* self) MmsValue_setUint8(numOfSg, settingGroup->sgcb->numOfSGs); MmsValue_setUint8(actSg, settingGroup->sgcb->actSG); - MmsValue_setUint16(resvTms, 0U); + + if (resvTms) + MmsValue_setUint16(resvTms, 0U); settingGroup->sgcbMmsValues = values; } @@ -1626,8 +1638,15 @@ createNamedVariableFromLogicalNode(MmsMapping* self, MmsDomain* domain, #if (CONFIG_IEC61850_SETTING_GROUPS == 1) if (sgControlBlock != NULL) { + + bool withResvTms = false; + + if (self->iedServer->enableEditSG) { + withResvTms = self->iedServer->hasSGCBResvTms; + } + namedVariable->typeSpec.structure.elements[currentComponent] = - createFCNamedVariableSPWithSGCB(logicalNode); + createFCNamedVariableSPWithSGCB(logicalNode, withResvTms); currentComponent++; } else @@ -2027,6 +2046,7 @@ MmsMapping_destroy(MmsMapping* self) #if (CONFIG_IEC61850_SETTING_GROUPS == 1) LinkedList_destroy(self->settingGroups); + self->allowEditSg = true; #endif #if (CONFIG_IEC61850_LOG_SERVICE == 1) @@ -2632,55 +2652,67 @@ mmsWriteHandler(void* parameter, MmsDomain* domain, return retVal; } else if (strcmp(nameId, "EditSG") == 0) { + SettingGroup* sg = getSettingGroupByMmsDomain(self, domain); MmsDataAccessError retVal = DATA_ACCESS_ERROR_SUCCESS; - if (sg != NULL) { - uint32_t val = MmsValue_toUint32(value); + if (self->iedServer->enableEditSG) { - if ((sg->editingClient != NULL) && ( sg->editingClient != (ClientConnection) connection)) { - /* Edit SG was set by other client */ - retVal = DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE; - } - else { - if (val == 0) { - unselectEditSettingGroup(sg); - retVal = DATA_ACCESS_ERROR_SUCCESS; + if (sg != NULL) { + uint32_t val = MmsValue_toUint32(value); + + if ((sg->editingClient != NULL) && ( sg->editingClient != (ClientConnection) connection)) { + /* Edit SG was set by other client */ + retVal = DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE; } else { + if (val == 0) { + unselectEditSettingGroup(sg); + retVal = DATA_ACCESS_ERROR_SUCCESS; + } + else { - if ((val > 0) && (val <= sg->sgcb->numOfSGs)) { + if ((val > 0) && (val <= sg->sgcb->numOfSGs)) { - if (sg->editSgChangedHandler != NULL) { + if (sg->editSgChangedHandler != NULL) { - if (sg->editSgChangedHandler(sg->editSgChangedHandlerParameter, sg->sgcb, - (uint8_t) val, (ClientConnection) connection)) - { - sg->sgcb->editSG = val; - sg->editingClient = (ClientConnection) connection; + if (sg->editSgChangedHandler(sg->editSgChangedHandlerParameter, sg->sgcb, + (uint8_t) val, (ClientConnection) connection)) + { + sg->sgcb->editSG = val; + sg->editingClient = (ClientConnection) connection; - sg->reservationTimeout = Hal_getTimeInMs() + (sg->sgcb->resvTms * 1000); + sg->reservationTimeout = Hal_getTimeInMs() + (sg->sgcb->resvTms * 1000); - MmsValue* editSg = MmsValue_getElement(sg->sgcbMmsValues, 2); - MmsValue* resvTms = MmsValue_getElement(sg->sgcbMmsValues, 5); + MmsValue* editSg = MmsValue_getElement(sg->sgcbMmsValues, 2); - MmsValue_setUint16(resvTms, sg->sgcb->resvTms); - MmsValue_setUint8(editSg, sg->sgcb->editSG); + if (editSg) + MmsValue_setUint8(editSg, sg->sgcb->editSG); - retVal = DATA_ACCESS_ERROR_SUCCESS; + MmsValue* resvTms = MmsValue_getElement(sg->sgcbMmsValues, 5); + + if (resvTms) + MmsValue_setUint16(resvTms, sg->sgcb->resvTms); + + + retVal = DATA_ACCESS_ERROR_SUCCESS; + } + else + retVal = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; } else retVal = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; + } else - retVal = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; + retVal = DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID; } - else - retVal = DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID; - } } + else { + retVal = DATA_ACCESS_ERROR_OBJECT_ACCESS_UNSUPPORTED; + } } else { retVal = DATA_ACCESS_ERROR_OBJECT_ACCESS_UNSUPPORTED; @@ -2697,19 +2729,24 @@ mmsWriteHandler(void* parameter, MmsDomain* domain, SettingGroup* sg = getSettingGroupByMmsDomain(self, domain); MmsDataAccessError retVal = DATA_ACCESS_ERROR_SUCCESS; - if (sg != NULL) { - bool val = MmsValue_getBoolean(value); + if (self->iedServer->enableEditSG) { + + if (sg != NULL) { + bool val = MmsValue_getBoolean(value); - if (val == true) { - if (sg->sgcb->editSG != 0) { - if (sg->editingClient == (ClientConnection) connection) { - if (sg->editSgConfirmedHandler != NULL) { - sg->editSgConfirmedHandler(sg->editSgConfirmedHandlerParameter, sg->sgcb, - sg->sgcb->editSG); + if (val == true) { + if (sg->sgcb->editSG != 0) { + if (sg->editingClient == (ClientConnection) connection) { + if (sg->editSgConfirmedHandler != NULL) { + sg->editSgConfirmedHandler(sg->editSgConfirmedHandlerParameter, sg->sgcb, + sg->sgcb->editSG); - unselectEditSettingGroup(sg); + unselectEditSettingGroup(sg); - retVal = DATA_ACCESS_ERROR_SUCCESS; + retVal = DATA_ACCESS_ERROR_SUCCESS; + } + else + retVal = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; } else retVal = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; @@ -2718,10 +2755,11 @@ mmsWriteHandler(void* parameter, MmsDomain* domain, retVal = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; } else - retVal = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; + retVal = DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID; + } + else { + retVal = DATA_ACCESS_ERROR_OBJECT_ACCESS_UNSUPPORTED; } - else - retVal = DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID; } else { retVal = DATA_ACCESS_ERROR_OBJECT_ACCESS_UNSUPPORTED;