diff --git a/src/iec61850/inc/iec61850_client.h b/src/iec61850/inc/iec61850_client.h index 4f3496f9..5e815ff2 100644 --- a/src/iec61850/inc/iec61850_client.h +++ b/src/iec61850/inc/iec61850_client.h @@ -64,7 +64,7 @@ typedef struct sIedConnection* IedConnection; typedef struct { int ctlNum; - int error; + ControlLastApplError error; ControlAddCause addCause; } LastApplError; diff --git a/src/iec61850/inc/iec61850_common.h b/src/iec61850/inc/iec61850_common.h index d934aff2..345d57e3 100644 --- a/src/iec61850/inc/iec61850_common.h +++ b/src/iec61850/inc/iec61850_common.h @@ -219,6 +219,21 @@ typedef enum { /** @} */ +/** + * @defgroup CONTROL_LAST_APPL_ERROR Definition for LastAppError error type - used in control models + * + * @{ + */ + +typedef enum { + CONTROL_ERROR_NO_ERROR = 0, + CONTROL_ERROR_UNKNOWN = 1, + CONTROL_ERROR_TIMEOUT_TEST = 2, + CONTROL_ERROR_OPERATOR_TEST = 3 +} ControlLastApplError; + +/** @} */ + /** * @defgroup FUNCTIONAL_CONSTRAINTS Definitions and functions related to functional constraints (FCs) * diff --git a/src/iec61850/inc/iec61850_server.h b/src/iec61850/inc/iec61850_server.h index 83a13cf6..d6e2cd27 100644 --- a/src/iec61850/inc/iec61850_server.h +++ b/src/iec61850/inc/iec61850_server.h @@ -1178,6 +1178,15 @@ typedef enum { typedef void* ControlAction; +/** + * \brief Sets the error code for the next command termination or application error message + * + * \param self the control action instance + * \param error the error code + */ +LIB61850_API void +ControlAction_setError(ControlAction self, ControlLastApplError error); + /** * \brief Sets the add cause for the next command termination or application error message * diff --git a/src/iec61850/inc_private/control.h b/src/iec61850/inc_private/control.h index c8192a69..8c8297a9 100644 --- a/src/iec61850/inc_private/control.h +++ b/src/iec61850/inc_private/control.h @@ -54,6 +54,7 @@ struct sControlObject unsigned operateOnce:1; unsigned isSelect:1; ControlAddCause addCauseValue:6; + unsigned errorValue:2; #if (CONFIG_MMS_THREADLESS_STACK != 1) Semaphore stateLock; diff --git a/src/iec61850/server/mms_mapping/control.c b/src/iec61850/server/mms_mapping/control.c index 32da5bf9..d1b2b582 100644 --- a/src/iec61850/server/mms_mapping/control.c +++ b/src/iec61850/server/mms_mapping/control.c @@ -34,11 +34,6 @@ #define DEBUG_IED_SERVER 0 #endif -#define CONTROL_ERROR_NO_ERROR 0 -#define CONTROL_ERROR_UNKOWN 1 -#define CONTROL_ERROR_TIMEOUT_TEST 2 -#define CONTROL_ERROR_OPERATOR_TEST 3 - #define STATE_UNSELECTED 0 #define STATE_READY 1 #define STATE_WAIT_FOR_ACTIVATION_TIME 2 @@ -303,6 +298,7 @@ operateControl(ControlObject* self, MmsValue* value, uint64_t currentTime, bool { self->selectTime = currentTime; + self->errorValue = CONTROL_ERROR_NO_ERROR; self->addCauseValue = ADD_CAUSE_UNKNOWN; if (self->operateHandler != NULL) @@ -399,6 +395,7 @@ executeStateMachine: if (state == STATE_WAIT_FOR_ACTIVATION_TIME) isTimeActivatedControl = true; + self->errorValue = CONTROL_ERROR_NO_ERROR; self->addCauseValue = ADD_CAUSE_BLOCKED_BY_SYNCHROCHECK; if (self->waitForExecutionHandler != NULL) { @@ -409,7 +406,7 @@ executeStateMachine: if (dynamicCheckResult == CONTROL_RESULT_FAILED) { if (isTimeActivatedControl) { ControlObject_sendLastApplError(self, self->mmsConnection, "Oper", - CONTROL_ERROR_NO_ERROR, self->addCauseValue, + self->errorValue, self->addCauseValue, self->ctlNum, self->origin, false); } else @@ -865,6 +862,7 @@ Control_processControlActions(MmsMapping* self, uint64_t currentTimeInMs) if (controlObject->checkHandler != NULL) { /* perform operative tests */ + controlObject->errorValue = CONTROL_ERROR_NO_ERROR; controlObject->addCauseValue = ADD_CAUSE_BLOCKED_BY_INTERLOCKING; checkResult = controlObject->checkHandler((ControlAction) self, @@ -885,7 +883,7 @@ Control_processControlActions(MmsMapping* self, uint64_t currentTimeInMs) else { ControlObject_sendLastApplError(controlObject, controlObject->mmsConnection, "Oper", - CONTROL_ERROR_NO_ERROR, controlObject->addCauseValue, + controlObject->errorValue, controlObject->addCauseValue, controlObject->ctlNum, controlObject->origin, false); /* leave state Perform Test */ @@ -1122,7 +1120,7 @@ ControlObject_sendCommandTerminationNegative(ControlObject* self) MmsValue_setElement(lastApplError, 0, ctlObjValue); - MmsValue_setInt32(self->error, CONTROL_ERROR_UNKOWN); + MmsValue_setInt32(self->error, self->errorValue); MmsValue_setInt32(self->addCause, self->addCauseValue); MmsValue_setElement(lastApplError, 1, self->error); @@ -1584,7 +1582,7 @@ Control_writeAccessControlObject(MmsMapping* self, MmsDomain* domain, char* vari else { indication = (MmsDataAccessError) checkResult; - ControlObject_sendLastApplError(controlObject, connection, "SBOw", 0, + ControlObject_sendLastApplError(controlObject, connection, "SBOw", controlObject->errorValue, controlObject->addCauseValue, ctlNum, origin, true); controlObject->mmsConnection = NULL; @@ -1833,6 +1831,14 @@ free_and_return: return indication; } +void +ControlAction_setError(ControlAction self, ControlLastApplError error) +{ + ControlObject* controlObject = (ControlObject*) self; + + controlObject->errorValue = error; +} + void ControlAction_setAddCause(ControlAction self, ControlAddCause addCause) {