From 91c22b3193ff84346c857e9d43c0583f5da194a0 Mon Sep 17 00:00:00 2001 From: Michael Zillgith Date: Tue, 4 Dec 2018 21:32:35 +0100 Subject: [PATCH] - IEC 61850 server: added IedServer_updateCtlModel function to change control model at runtime --- src/iec61850/inc/iec61850_client.h | 30 ---------- src/iec61850/inc/iec61850_common.h | 34 +++++++++++ src/iec61850/inc/iec61850_server.h | 23 +++++++ src/iec61850/inc_private/control.h | 3 + src/iec61850/server/impl/ied_server.c | 30 +++++++++- src/iec61850/server/mms_mapping/control.c | 73 ++++++++++++++--------- 6 files changed, 131 insertions(+), 62 deletions(-) diff --git a/src/iec61850/inc/iec61850_client.h b/src/iec61850/inc/iec61850_client.h index 89d649f4..26e1f69e 100644 --- a/src/iec61850/inc/iec61850_client.h +++ b/src/iec61850/inc/iec61850_client.h @@ -1771,36 +1771,6 @@ ClientDataSet_getDataSetSize(ClientDataSet self); typedef struct sControlObjectClient* ControlObjectClient; -typedef enum { - /** - * No support for control functions. Control object only support status information. - */ - CONTROL_MODEL_STATUS_ONLY = 0, - - /** - * Direct control with normal security: Supports Operate, TimeActivatedOperate (optional), - * and Cancel (optional). - */ - CONTROL_MODEL_DIRECT_NORMAL = 1, - - /** - * Select before operate (SBO) with normal security: Supports Select, Operate, TimeActivatedOperate (optional), - * and Cancel (optional). - */ - CONTROL_MODEL_SBO_NORMAL = 2, - - /** - * Direct control with enhanced security (enhanced security includes the CommandTermination service) - */ - CONTROL_MODEL_DIRECT_ENHANCED = 3, - - /** - * Select before operate (SBO) with enhanced security (enhanced security includes the CommandTermination service) - */ - CONTROL_MODEL_SBO_ENHANCED = 4 -} ControlModel; - - /** * \brief Create a new client control object * diff --git a/src/iec61850/inc/iec61850_common.h b/src/iec61850/inc/iec61850_common.h index b03c9cba..075a8d91 100644 --- a/src/iec61850/inc/iec61850_common.h +++ b/src/iec61850/inc/iec61850_common.h @@ -54,6 +54,38 @@ typedef struct { uint8_t dstAddress[6]; } PhyComAddress; +/** + * \brief Control model (represented by "ctlModel" attribute) + */ +typedef enum { + /** + * No support for control functions. Control object only support status information. + */ + CONTROL_MODEL_STATUS_ONLY = 0, + + /** + * Direct control with normal security: Supports Operate, TimeActivatedOperate (optional), + * and Cancel (optional). + */ + CONTROL_MODEL_DIRECT_NORMAL = 1, + + /** + * Select before operate (SBO) with normal security: Supports Select, Operate, TimeActivatedOperate (optional), + * and Cancel (optional). + */ + CONTROL_MODEL_SBO_NORMAL = 2, + + /** + * Direct control with enhanced security (enhanced security includes the CommandTermination service) + */ + CONTROL_MODEL_DIRECT_ENHANCED = 3, + + /** + * Select before operate (SBO) with enhanced security (enhanced security includes the CommandTermination service) + */ + CONTROL_MODEL_SBO_ENHANCED = 4 +} ControlModel; + /** * @defgroup TRIGGER_OPTIONS Trigger options (bit values combinable) * @@ -76,6 +108,8 @@ typedef struct { #define TRG_OPT_GI 16 /** @} */ + + /** * @defgroup REPORT_OPTIONS Report options (bit values combinable) * diff --git a/src/iec61850/inc/iec61850_server.h b/src/iec61850/inc/iec61850_server.h index 9fe87c8e..8e7f9ba1 100644 --- a/src/iec61850/inc/iec61850_server.h +++ b/src/iec61850/inc/iec61850_server.h @@ -1195,6 +1195,29 @@ IedServer_setPerformCheckHandler(IedServer self, DataObject* node, ControlPerfor LIB61850_API void IedServer_setWaitForExecutionHandler(IedServer self, DataObject* node, ControlWaitForExecutionHandler handler, void* parameter); +/** + * \brief Update the control model for the specified controllable data object with the given value and + * update "ctlModel" attribute value. + * + * NOTE: The corresponding control structures for the control model have to be present in the data model! + * + * \param self the instance of IedServer to operate on. + * \param ctlObject the controllable data object handle + * \param value the new control model value + */ +LIB61850_API void +IedServer_updateCtlModel(IedServer self, DataObject* ctlObject, ControlModel value); + +/** + * \brief Refresh the control object parameters (ctlModel, sboClass, sboTimeout) from the current data + * attribute values in the online accessable data model. + * + * \param self the instance of IedServer to operate on. + * \param ctlObject the controllable data object handle + */ +LIB61850_API void +IedServer_refreshControlParameters(IedServer self, DataObject* ctlObject); + /**@}*/ /** diff --git a/src/iec61850/inc_private/control.h b/src/iec61850/inc_private/control.h index 879f945e..23a27e4b 100644 --- a/src/iec61850/inc_private/control.h +++ b/src/iec61850/inc_private/control.h @@ -148,4 +148,7 @@ ControlObject_installCheckHandler(ControlObject* self, ControlPerformCheckHandle LIB61850_INTERNAL void ControlObject_installWaitForExecutionHandler(ControlObject* self, ControlWaitForExecutionHandler handler, void* parameter); +LIB61850_INTERNAL void +ControlObject_updateControlModel(ControlObject* self, ControlModel value, DataObject* ctlObject); + #endif /* CONTROL_H_ */ diff --git a/src/iec61850/server/impl/ied_server.c b/src/iec61850/server/impl/ied_server.c index 035e3325..f14d54cb 100644 --- a/src/iec61850/server/impl/ied_server.c +++ b/src/iec61850/server/impl/ied_server.c @@ -62,8 +62,10 @@ createControlObjects(IedServer self, MmsDomain* domain, char* lnName, MmsVariabl bool hasCancel = false; int cancelIndex = 0; bool hasSBOw = false; + bool hasSBO = false; int sBOwIndex = 0; int operIndex = 0; + int sBOIndex = 0; MmsVariableSpecification* coSpec = typeSpec->typeSpec.structure.elements[i]; @@ -89,11 +91,14 @@ createControlObjects(IedServer self, MmsDomain* domain, char* lnName, MmsVariabl hasSBOw = true; sBOwIndex = j; } - else if (!(strcmp(coElementSpec->name, "SBO") == 0)) { + else if ((strcmp(coElementSpec->name, "SBO") == 0)) { + hasSBO = true; + sBOIndex = j; + } + else { if (DEBUG_IED_SERVER) - printf("IED_SERVER: createControlObjects: Unknown element in CO: %s! --> seems not to be a control object\n", coElementSpec->name); + printf("IED_SERVER: createControlObjects: Unknown element in CO: %s\n", coElementSpec->name); - break; } } @@ -128,6 +133,9 @@ createControlObjects(IedServer self, MmsDomain* domain, char* lnName, MmsVariabl if (hasSBOw) controlObject->sbow = MmsValue_getElement(structure, sBOwIndex); + if (hasSBO) + controlObject->sbo = MmsValue_getElement(structure, sBOIndex); + MmsMapping_addControlObject(mapping, controlObject); } else { @@ -775,6 +783,22 @@ IedServer_setWaitForExecutionHandler(IedServer self, DataObject* node, ControlWa if (controlObject != NULL) ControlObject_installWaitForExecutionHandler(controlObject, handler, parameter); } + +void +IedServer_updateCtlModel(IedServer self, DataObject* ctlObject, ControlModel value) +{ + ControlObject* controlObject = lookupControlObject(self, ctlObject); + + if (controlObject != NULL) + ControlObject_updateControlModel(controlObject, value, ctlObject); +} + +void +IedServer_refreshControlParameters(IedServer self, DataObject* ctlObject) +{ + +} + #endif /* (CONFIG_IEC61850_CONTROL_SERVICE == 1) */ #if (CONFIG_IEC61850_SAMPLED_VALUES_SUPPORT == 1) diff --git a/src/iec61850/server/mms_mapping/control.c b/src/iec61850/server/mms_mapping/control.c index 2febf484..c3f09611 100644 --- a/src/iec61850/server/mms_mapping/control.c +++ b/src/iec61850/server/mms_mapping/control.c @@ -291,7 +291,7 @@ ControlObject_create(IedServer iedServer, MmsDomain* domain, char* lnName, char* goto exit_function; if (DEBUG_IED_SERVER) - printf("create control object for LD: %s, LN: %s, name: %s\n", domain->domainName, lnName, name); + printf("IED_SERVER: create control object for LD: %s, LN: %s, name: %s\n", domain->domainName, lnName, name); #if (CONFIG_MMS_THREADLESS_STACK != 1) self->stateLock = Semaphore_create(1); @@ -339,14 +339,14 @@ ControlObject_initialize(ControlObject* self) char* ctlModelName = StringUtils_createStringInBuffer(strBuf, 4, self->lnName, "$CF$", self->name, "$ctlModel"); if (DEBUG_IED_SERVER) - printf("initialize control for %s\n", ctlModelName); + printf("IED_SERVER: initialize control for %s\n", ctlModelName); MmsValue* ctlModel = MmsServer_getValueFromCache(mmsServer, self->mmsDomain, ctlModelName); if (ctlModel == NULL) { if (DEBUG_IED_SERVER) - printf("No control model found for variable %s\n", ctlModelName); + printf("IED_SERVER: No control model found for variable %s\n", ctlModelName); } char* sboClassName = StringUtils_createStringInBuffer(strBuf, 4, self->lnName, "$CF$", self->name, "$sboClass"); @@ -364,6 +364,20 @@ ControlObject_initialize(ControlObject* self) self->originSt = MmsServer_getValueFromCache(mmsServer, self->mmsDomain, originName); + char* sboTimeoutName = StringUtils_createStringInBuffer(strBuf, 4, self->lnName, "$CF$", self->name, "$sboTimeout"); + + self->sboTimeout = MmsServer_getValueFromCache(mmsServer, + self->mmsDomain, sboTimeoutName); + + updateSboTimeoutValue(self); + + if (self->sbo) { + char* controlObjectReference = StringUtils_createStringInBuffer(strBuf, 6, self->mmsDomain->domainName, + "/", self->lnName, "$CO$", self->name, "$SBO"); + + MmsValue_setVisibleString(self->sbo, controlObjectReference); + } + self->error = MmsValue_newIntegerFromInt32(0); self->addCause = MmsValue_newIntegerFromInt32(0); @@ -373,33 +387,12 @@ ControlObject_initialize(ControlObject* self) self->ctlModel = ctlModelVal; if (DEBUG_IED_SERVER) - printf(" ctlModel: %i\n", ctlModelVal); - - if ((ctlModelVal == 2) || (ctlModelVal == 4)) { /* SBO */ - - - char* controlObjectReference = StringUtils_createStringInBuffer(strBuf, 6, self->mmsDomain->domainName, - "/", self->lnName, "$CO$", self->name, "$SBO"); - - self->sbo = MmsValue_newVisibleString(controlObjectReference); - - char* sboTimeoutName = StringUtils_createStringInBuffer(strBuf, 4, self->lnName, "$CF$", self->name, "$sboTimeout"); - - self->sboTimeout = MmsServer_getValueFromCache(mmsServer, - self->mmsDomain, sboTimeoutName); - - updateSboTimeoutValue(self); + printf("IED_SERVER: ctlModel: %i\n", ctlModelVal); + if ((ctlModelVal == 2) || (ctlModelVal == 4)) /* SBO */ setState(self, STATE_UNSELECTED); - - if (DEBUG_IED_SERVER) - printf("timeout for %s is %i\n", sboTimeoutName, self->selectTimeout); - } - else { - self->sbo = MmsValue_newVisibleString(NULL); - + else setState(self, STATE_READY); - } } } @@ -409,8 +402,8 @@ ControlObject_destroy(ControlObject* self) if (self->mmsValue != NULL) MmsValue_delete(self->mmsValue); - if (self->sbo != NULL) - MmsValue_delete(self->sbo); + // if (self->sbo != NULL) + // MmsValue_delete(self->sbo); if (self->emptyString != NULL) MmsValue_delete(self->emptyString); @@ -557,6 +550,23 @@ ControlObject_installWaitForExecutionHandler(ControlObject* self, ControlWaitFor self->waitForExecutionHandlerParameter = parameter; } +void +ControlObject_updateControlModel(ControlObject* self, ControlModel value, DataObject* ctlObject) +{ + self->ctlModel = (uint32_t) value; + + if ((self->ctlModel == 2) || (self->ctlModel == 4)) /* SBO */ + setState(self, STATE_UNSELECTED); + else + setState(self, STATE_READY); + + DataAttribute* ctlModel = (DataAttribute*) ModelNode_getChild((ModelNode*) ctlObject, "ctlModel"); + + if (ctlModel) { + IedServer_updateInt32AttributeValue(self->iedServer, ctlModel, (int32_t) value); + } +} + void Control_processControlActions(MmsMapping* self, uint64_t currentTimeInMs) { @@ -1163,6 +1173,11 @@ Control_writeAccessControlObject(MmsMapping* self, MmsDomain* domain, char* vari goto free_and_return; } + if (controlObject->ctlModel == CONTROL_MODEL_STATUS_ONLY) { + indication = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; + goto free_and_return; + } + if (strcmp(varName, "SBOw") == 0) { /* select with value */ if (controlObject->ctlModel == 4) {