- IEC 61850 server: refactored control model API (changed handler signatures, added ControlAction object to access origin and set addCause value, ...)

- IEC 61850 client: added ControlObjectClient_getLastError function
pull/179/head
Michael Zillgith 6 years ago
parent 5a3c3ba4b3
commit 6c14425ca8

@ -25,7 +25,7 @@ sigint_handler(int signalId)
} }
static CheckHandlerResult static CheckHandlerResult
checkHandler(void* parameter, MmsValue* ctlVal, bool test, bool interlockCheck, ClientConnection connection) checkHandler(ControlAction action, void* parameter, MmsValue* ctlVal, bool test, bool interlockCheck)
{ {
printf("check handler called!\n"); printf("check handler called!\n");
@ -51,7 +51,7 @@ checkHandler(void* parameter, MmsValue* ctlVal, bool test, bool interlockCheck,
} }
static ControlHandlerResult static ControlHandlerResult
controlHandlerForBinaryOutput(void* parameter, MmsValue* value, bool test) controlHandlerForBinaryOutput(ControlAction action, void* parameter, MmsValue* value, bool test)
{ {
uint64_t timestamp = Hal_getTimeInMs(); uint64_t timestamp = Hal_getTimeInMs();
@ -102,7 +102,6 @@ writeAccessHandler (DataAttribute* dataAttribute, MmsValue* value, ClientConnect
int int
main(int argc, char** argv) main(int argc, char** argv)
{ {
iedServer = IedServer_create(&iedModel); iedServer = IedServer_create(&iedModel);
IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO1, IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO1,

@ -56,6 +56,7 @@ struct sControlObjectClient
uint64_t constantT; /* timestamp of select/operate to be used when constant T option is selected */ uint64_t constantT; /* timestamp of select/operate to be used when constant T option is selected */
LastApplError lastApplError; LastApplError lastApplError;
MmsError lastMmsError;
CommandTerminationHandler commandTerminationHandler; CommandTerminationHandler commandTerminationHandler;
void* commandTerminaionHandlerParameter; void* commandTerminaionHandlerParameter;
@ -312,6 +313,12 @@ ControlObjectClient_getCtlValType(ControlObjectClient self)
return MmsValue_getType(self->ctlVal); return MmsValue_getType(self->ctlVal);
} }
IedClientError
ControlObjectClient_getLastError(ControlObjectClient self)
{
return iedConnection_mapMmsErrorToIedError(self->lastMmsError);
}
void void
ControlObjectClient_setOrigin(ControlObjectClient self, const char* orIdent, int orCat) ControlObjectClient_setOrigin(ControlObjectClient self, const char* orIdent, int orCat)
{ {
@ -500,6 +507,8 @@ ControlObjectClient_operate(ControlObjectClient self, MmsValue* ctlVal, uint64_t
MmsValue_setElement(operParameters, 0, NULL); MmsValue_setElement(operParameters, 0, NULL);
MmsValue_delete(operParameters); MmsValue_delete(operParameters);
self->lastMmsError = mmsError;
if (mmsError != MMS_ERROR_NONE) { if (mmsError != MMS_ERROR_NONE) {
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: operate failed!\n"); printf("IED_CLIENT: operate failed!\n");
@ -718,6 +727,8 @@ ControlObjectClient_selectWithValue(ControlObjectClient self, MmsValue* ctlVal)
MmsValue_setElement(selValParameters, 0, NULL); MmsValue_setElement(selValParameters, 0, NULL);
MmsValue_delete(selValParameters); MmsValue_delete(selValParameters);
self->lastMmsError = mmsError;
if (mmsError != MMS_ERROR_NONE) { if (mmsError != MMS_ERROR_NONE) {
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: select-with-value failed!\n"); printf("IED_CLIENT: select-with-value failed!\n");
@ -869,6 +880,8 @@ ControlObjectClient_select(ControlObjectClient self)
self->ctlNum++; self->ctlNum++;
self->lastMmsError = mmsError;
if (value == NULL) { if (value == NULL) {
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: select: read SBO failed!\n"); printf("IED_CLIENT: select: read SBO failed!\n");
@ -1068,6 +1081,8 @@ ControlObjectClient_cancel(ControlObjectClient self)
MmsDataAccessError writeResult = MmsConnection_writeVariable(IedConnection_getMmsConnection(self->connection), MmsDataAccessError writeResult = MmsConnection_writeVariable(IedConnection_getMmsConnection(self->connection),
&mmsError, domainId, itemId, cancelParameters); &mmsError, domainId, itemId, cancelParameters);
self->lastMmsError = mmsError;
MmsValue_setElement(cancelParameters, 0, NULL); MmsValue_setElement(cancelParameters, 0, NULL);
MmsValue_delete(cancelParameters); MmsValue_delete(cancelParameters);

@ -2001,6 +2001,16 @@ ControlObjectClient_changeServerControlModel(ControlObjectClient self, ControlMo
LIB61850_API MmsType LIB61850_API MmsType
ControlObjectClient_getCtlValType(ControlObjectClient self); ControlObjectClient_getCtlValType(ControlObjectClient self);
/**
* \brief Get the error code of the last synchronous control action (operate, select, select-with-value, cancel)
*
* \param self the control object instance to use
*
* \return the client error code
*/
LIB61850_API IedClientError
ControlObjectClient_getLastError(ControlObjectClient self);
/** /**
* \brief Send an operate command to the server * \brief Send an operate command to the server
* *

@ -3,7 +3,7 @@
* *
* IEC 61850 server API for libiec61850. * IEC 61850 server API for libiec61850.
* *
* Copyright 2013-2018 Michael Zillgith * Copyright 2013-2019 Michael Zillgith
* *
* This file is part of libIEC61850. * This file is part of libIEC61850.
* *
@ -1083,9 +1083,62 @@ typedef enum {
CONTROL_RESULT_WAITING = 2 /** check or operation is in progress */ CONTROL_RESULT_WAITING = 2 /** check or operation is in progress */
} ControlHandlerResult; } ControlHandlerResult;
typedef void* ControlAction;
/**
* \brief Set the add cause for the next command termination or application error message
*
* \param self the control action instance
* \param addCause the additional cause
*/
LIB61850_API void
ControlAction_setAddCause(ControlAction self, ControlAddCause addCause);
/**
* \brief Get the originator category provided by the client
*
* \param self the control action instance
*
* \return the originator category
*/
LIB61850_API int
ControlAction_getOrCat(ControlAction self);
/**
* \brief Get the originator identifier provided by the client
*
* \param self the control action instance
*
* \return the originator identifier
*/
LIB61850_API uint8_t*
ControlAction_getOrIdent(ControlAction self, int* orIdentSize);
/**
* \brief Get the client object associated with the client that caused the control action
*
* \param self the control action instance
*
* \return client connection instance
*/
LIB61850_API ClientConnection
ControlAction_getClientConnection(ControlAction self);
/**
* \brief Get the control object that is subject to this action
*
* \param self the control action instance
*
* \return the controllable data object instance
*/
LIB61850_API DataObject*
ControlAction_getControlObject(ControlAction self);
/** /**
* \brief Control model callback to perform the static tests (optional). * \brief Control model callback to perform the static tests (optional).
* *
* NOTE: Signature changed in version 1.4!
*
* User provided callback function for the control model. It will be invoked after * User provided callback function for the control model. It will be invoked after
* a control operation has been invoked by the client. This callback function is * a control operation has been invoked by the client. This callback function is
* intended to perform the static tests. It should check if the interlock conditions * intended to perform the static tests. It should check if the interlock conditions
@ -1093,20 +1146,21 @@ typedef enum {
* This handler can also be check if the client has the required permissions to execute the * This handler can also be check if the client has the required permissions to execute the
* operation and allow or deny the operation accordingly. * operation and allow or deny the operation accordingly.
* *
* \param action the control action parameter that provides access to additional context information
* \param parameter the parameter that was specified when setting the control handler * \param parameter the parameter that was specified when setting the control handler
* \param ctlVal the control value of the control operation. * \param ctlVal the control value of the control operation.
* \param test indicates if the operate request is a test operation * \param test indicates if the operate request is a test operation
* \param interlockCheck the interlockCheck parameter provided by the client * \param interlockCheck the interlockCheck parameter provided by the client
* \param connection the connection object of the client connection that invoked the control operation
* *
* \return CONTROL_ACCEPTED if the static tests had been successful, one of the error codes otherwise * \return CONTROL_ACCEPTED if the static tests had been successful, one of the error codes otherwise
*/ */
typedef CheckHandlerResult (*ControlPerformCheckHandler) (void* parameter, MmsValue* ctlVal, bool test, bool interlockCheck, typedef CheckHandlerResult (*ControlPerformCheckHandler) (ControlAction action, void* parameter, MmsValue* ctlVal, bool test, bool interlockCheck);
ClientConnection connection);
/** /**
* \brief Control model callback to perform the dynamic tests (optional). * \brief Control model callback to perform the dynamic tests (optional).
* *
* NOTE: Signature changed in version 1.4!
*
* User provided callback function for the control model. It will be invoked after * User provided callback function for the control model. It will be invoked after
* a control operation has been invoked by the client. This callback function is * a control operation has been invoked by the client. This callback function is
* intended to perform the dynamic tests. It should check if the synchronization conditions * intended to perform the dynamic tests. It should check if the synchronization conditions
@ -1115,6 +1169,7 @@ typedef CheckHandlerResult (*ControlPerformCheckHandler) (void* parameter, MmsVa
* cannot be performed immediately the function SHOULD return CONTROL_RESULT_WAITING and the * cannot be performed immediately the function SHOULD return CONTROL_RESULT_WAITING and the
* handler will be invoked again later. * handler will be invoked again later.
* *
* \param action the control action parameter that provides access to additional context information
* \param parameter the parameter that was specified when setting the control handler * \param parameter the parameter that was specified when setting the control handler
* \param ctlVal the control value of the control operation. * \param ctlVal the control value of the control operation.
* \param test indicates if the operate request is a test operation * \param test indicates if the operate request is a test operation
@ -1123,11 +1178,13 @@ typedef CheckHandlerResult (*ControlPerformCheckHandler) (void* parameter, MmsVa
* \return CONTROL_RESULT_OK if the dynamic tests had been successful, CONTROL_RESULT_FAILED otherwise, * \return CONTROL_RESULT_OK if the dynamic tests had been successful, CONTROL_RESULT_FAILED otherwise,
* CONTROL_RESULT_WAITING if the test is not yet finished * CONTROL_RESULT_WAITING if the test is not yet finished
*/ */
typedef ControlHandlerResult (*ControlWaitForExecutionHandler) (void* parameter, MmsValue* ctlVal, bool test, bool synchroCheck); typedef ControlHandlerResult (*ControlWaitForExecutionHandler) (ControlAction action, void* parameter, MmsValue* ctlVal, bool test, bool synchroCheck);
/** /**
* \brief Control model callback to actually perform the control operation. * \brief Control model callback to actually perform the control operation.
* *
* NOTE: Signature changed in version 1.4!
*
* User provided callback function for the control model. It will be invoked when * User provided callback function for the control model. It will be invoked when
* a control operation happens (Oper). Here the user should perform the control operation * a control operation happens (Oper). Here the user should perform the control operation
* (e.g. by setting an digital output or switching a relay). * (e.g. by setting an digital output or switching a relay).
@ -1135,6 +1192,7 @@ typedef ControlHandlerResult (*ControlWaitForExecutionHandler) (void* parameter,
* cannot be performed immediately the function SHOULD return CONTROL_RESULT_WAITING and the * cannot be performed immediately the function SHOULD return CONTROL_RESULT_WAITING and the
* handler will be invoked again later. * handler will be invoked again later.
* *
* \param action the control action parameter that provides access to additional context information
* \param parameter the parameter that was specified when setting the control handler * \param parameter the parameter that was specified when setting the control handler
* \param ctlVal the control value of the control operation. * \param ctlVal the control value of the control operation.
* \param test indicates if the operate request is a test operation * \param test indicates if the operate request is a test operation
@ -1142,7 +1200,7 @@ typedef ControlHandlerResult (*ControlWaitForExecutionHandler) (void* parameter,
* \return CONTROL_RESULT_OK if the control action bas been successful, CONTROL_RESULT_FAILED otherwise, * \return CONTROL_RESULT_OK if the control action bas been successful, CONTROL_RESULT_FAILED otherwise,
* CONTROL_RESULT_WAITING if the test is not yet finished * CONTROL_RESULT_WAITING if the test is not yet finished
*/ */
typedef ControlHandlerResult (*ControlHandler) (void* parameter, MmsValue* ctlVal, bool test); typedef ControlHandlerResult (*ControlHandler) (ControlAction action, void* parameter, MmsValue* ctlVal, bool test);
/** /**
* \brief Set control handler for controllable data object * \brief Set control handler for controllable data object

@ -51,6 +51,7 @@ struct sControlObject
int synchroCheck:1; int synchroCheck:1;
int timeActivatedOperate:1; int timeActivatedOperate:1;
int operateOnce:1; int operateOnce:1;
ControlAddCause addCauseValue:6;
#if (CONFIG_MMS_THREADLESS_STACK != 1) #if (CONFIG_MMS_THREADLESS_STACK != 1)
Semaphore stateLock; Semaphore stateLock;
@ -85,8 +86,6 @@ struct sControlObject
/* for automatic update of tOpOk attribute */ /* for automatic update of tOpOk attribute */
DataAttribute* tOpOk; DataAttribute* tOpOk;
// char ctlObjectName[130];
/* for LastAppIError */ /* for LastAppIError */
MmsValue* error; MmsValue* error;
MmsValue* addCause; MmsValue* addCause;
@ -110,6 +109,8 @@ struct sControlObject
ControlWaitForExecutionHandler waitForExecutionHandler; ControlWaitForExecutionHandler waitForExecutionHandler;
void* waitForExecutionHandlerParameter; void* waitForExecutionHandlerParameter;
DataObject* dataObject;
}; };
LIB61850_INTERNAL ControlObject* LIB61850_INTERNAL ControlObject*

@ -751,6 +751,9 @@ lookupControlObject(IedServer self, DataObject* node)
ControlObject* controlObject = MmsMapping_getControlObject(self->mmsMapping, domain, ControlObject* controlObject = MmsMapping_getControlObject(self->mmsMapping, domain,
lnName, objectName); lnName, objectName);
if (controlObject)
controlObject->dataObject = node;
return controlObject; return controlObject;
} }

@ -261,8 +261,10 @@ operateControl(ControlObject* self, MmsValue* value, uint64_t currentTime, bool
{ {
self->selectTime = currentTime; self->selectTime = currentTime;
self->addCauseValue = ADD_CAUSE_UNKNOWN;
if (self->operateHandler != NULL) if (self->operateHandler != NULL)
return self->operateHandler(self->operateHandlerParameter, value, testCondition); return self->operateHandler((ControlAction) self, self->operateHandlerParameter, value, testCondition);
return CONTROL_RESULT_OK; return CONTROL_RESULT_OK;
} }
@ -287,15 +289,17 @@ executeStateMachine:
if (state == STATE_WAIT_FOR_ACTIVATION_TIME) if (state == STATE_WAIT_FOR_ACTIVATION_TIME)
isTimeActivatedControl = true; isTimeActivatedControl = true;
self->addCauseValue = ADD_CAUSE_BLOCKED_BY_SYNCHROCHECK;
if (self->waitForExecutionHandler != NULL) { if (self->waitForExecutionHandler != NULL) {
dynamicCheckResult = self->waitForExecutionHandler(self->waitForExecutionHandlerParameter, self->ctlVal, dynamicCheckResult = self->waitForExecutionHandler((ControlAction) self, self->waitForExecutionHandlerParameter, self->ctlVal,
self->testMode, self->synchroCheck); self->testMode, self->synchroCheck);
} }
if (dynamicCheckResult == CONTROL_RESULT_FAILED) { if (dynamicCheckResult == CONTROL_RESULT_FAILED) {
if (isTimeActivatedControl) { if (isTimeActivatedControl) {
ControlObject_sendLastApplError(self, self->mmsConnection, "Oper", ControlObject_sendLastApplError(self, self->mmsConnection, "Oper",
CONTROL_ERROR_NO_ERROR, ADD_CAUSE_BLOCKED_BY_SYNCHROCHECK, CONTROL_ERROR_NO_ERROR, self->addCauseValue,
self->ctlNum, self->origin, false); self->ctlNum, self->origin, false);
} }
else else
@ -795,12 +799,11 @@ Control_processControlActions(MmsMapping* self, uint64_t currentTimeInMs)
if (controlObject->checkHandler != NULL) { /* perform operative tests */ if (controlObject->checkHandler != NULL) { /* perform operative tests */
ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, controlObject->addCauseValue = ADD_CAUSE_BLOCKED_BY_INTERLOCKING;
controlObject->mmsConnection);
checkResult = controlObject->checkHandler( checkResult = controlObject->checkHandler((ControlAction) self,
controlObject->checkHandlerParameter, controlObject->ctlVal, controlObject->testMode, controlObject->checkHandlerParameter, controlObject->ctlVal, controlObject->testMode,
controlObject->interlockCheck, clientConnection); controlObject->interlockCheck);
} }
if (checkResult == CONTROL_ACCEPTED) { if (checkResult == CONTROL_ACCEPTED) {
@ -814,9 +817,10 @@ Control_processControlActions(MmsMapping* self, uint64_t currentTimeInMs)
executeControlTask(controlObject, currentTimeInMs); executeControlTask(controlObject, currentTimeInMs);
} }
else { else {
ControlObject_sendLastApplError(controlObject, controlObject->mmsConnection, "Oper", ControlObject_sendLastApplError(controlObject, controlObject->mmsConnection, "Oper",
CONTROL_ERROR_NO_ERROR, ADD_CAUSE_BLOCKED_BY_INTERLOCKING, CONTROL_ERROR_NO_ERROR, controlObject->addCauseValue,
controlObject->ctlNum, controlObject->origin, false); controlObject->ctlNum, controlObject->origin, false);
/* leave state Perform Test */ /* leave state Perform Test */
setOpRcvd(controlObject, false); setOpRcvd(controlObject, false);
@ -1053,7 +1057,7 @@ ControlObject_sendCommandTerminationNegative(ControlObject* self)
MmsValue_setElement(lastApplError, 0, ctlObjValue); MmsValue_setElement(lastApplError, 0, ctlObjValue);
MmsValue_setInt32(self->error, CONTROL_ERROR_UNKOWN); MmsValue_setInt32(self->error, CONTROL_ERROR_UNKOWN);
MmsValue_setInt32(self->addCause, ADD_CAUSE_UNKNOWN); MmsValue_setInt32(self->addCause, self->addCauseValue);
MmsValue_setElement(lastApplError, 1, self->error); MmsValue_setElement(lastApplError, 1, self->error);
MmsValue_setElement(lastApplError, 2, self->origin); MmsValue_setElement(lastApplError, 2, self->origin);
@ -1262,14 +1266,12 @@ Control_readAccessControlObject(MmsMapping* self, MmsDomain* domain, char* varia
/* opRcvd must not be set here! */ /* opRcvd must not be set here! */
if (controlObject->checkHandler != NULL) { /* perform operative tests */ controlObject->addCauseValue = ADD_CAUSE_UNKNOWN;
ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, if (controlObject->checkHandler != NULL) { /* perform operative tests */
connection);
checkResult = controlObject->checkHandler( checkResult = controlObject->checkHandler((ControlAction) controlObject,
controlObject->checkHandlerParameter, NULL, false, false, controlObject->checkHandlerParameter, NULL, false, false);
clientConnection);
} }
if (checkResult == CONTROL_ACCEPTED) { if (checkResult == CONTROL_ACCEPTED) {
@ -1442,10 +1444,10 @@ Control_writeAccessControlObject(MmsMapping* self, MmsDomain* domain, char* vari
indication = DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE; indication = DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE;
if (connection != controlObject->mmsConnection) if (connection != controlObject->mmsConnection)
ControlObject_sendLastApplError(controlObject, connection, "SBOw", 0, ControlObject_sendLastApplError(controlObject, connection, "SBOw", CONTROL_ERROR_NO_ERROR,
ADD_CAUSE_LOCKED_BY_OTHER_CLIENT, ctlNum, origin, true); ADD_CAUSE_LOCKED_BY_OTHER_CLIENT, ctlNum, origin, true);
else else
ControlObject_sendLastApplError(controlObject, connection, "SBOw", 0, ControlObject_sendLastApplError(controlObject, connection, "SBOw", CONTROL_ERROR_NO_ERROR,
ADD_CAUSE_OBJECT_ALREADY_SELECTED, ctlNum, origin, true); ADD_CAUSE_OBJECT_ALREADY_SELECTED, ctlNum, origin, true);
if (DEBUG_IED_SERVER) if (DEBUG_IED_SERVER)
@ -1461,14 +1463,12 @@ Control_writeAccessControlObject(MmsMapping* self, MmsDomain* domain, char* vari
bool testCondition = MmsValue_getBoolean(test); bool testCondition = MmsValue_getBoolean(test);
if (controlObject->checkHandler != NULL) { /* perform operative tests */ controlObject->addCauseValue = ADD_CAUSE_SELECT_FAILED;
ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, if (controlObject->checkHandler != NULL) { /* perform operative tests */
connection);
checkResult = controlObject->checkHandler( checkResult = controlObject->checkHandler((ControlAction) controlObject,
controlObject->checkHandlerParameter, ctlVal, testCondition, interlockCheck, controlObject->checkHandlerParameter, ctlVal, testCondition, interlockCheck);
clientConnection);
} }
if (checkResult == CONTROL_ACCEPTED) { if (checkResult == CONTROL_ACCEPTED) {
@ -1485,7 +1485,7 @@ Control_writeAccessControlObject(MmsMapping* self, MmsDomain* domain, char* vari
indication = (MmsDataAccessError) checkResult; indication = (MmsDataAccessError) checkResult;
ControlObject_sendLastApplError(controlObject, connection, "SBOw", 0, ControlObject_sendLastApplError(controlObject, connection, "SBOw", 0,
ADD_CAUSE_SELECT_FAILED, ctlNum, origin, true); controlObject->addCauseValue, ctlNum, origin, true);
if (DEBUG_IED_SERVER) if (DEBUG_IED_SERVER)
printf("SBOw: select rejected by application!\n"); printf("SBOw: select rejected by application!\n");
@ -1601,14 +1601,12 @@ Control_writeAccessControlObject(MmsMapping* self, MmsDomain* domain, char* vari
/* enter state Perform Test */ /* enter state Perform Test */
setOpRcvd(controlObject, true); setOpRcvd(controlObject, true);
if (controlObject->checkHandler != NULL) { /* perform operative tests */ controlObject->addCauseValue = ADD_CAUSE_UNKNOWN;
ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, if (controlObject->checkHandler != NULL) { /* perform operative tests */
connection);
checkResult = controlObject->checkHandler( checkResult = controlObject->checkHandler((ControlAction) controlObject,
controlObject->checkHandlerParameter, ctlVal, testCondition, interlockCheck, controlObject->checkHandlerParameter, ctlVal, testCondition, interlockCheck);
clientConnection);
} }
if (checkResult == CONTROL_ACCEPTED) { if (checkResult == CONTROL_ACCEPTED) {
@ -1693,5 +1691,64 @@ free_and_return:
return indication; return indication;
} }
void
ControlAction_setAddCause(ControlAction self, ControlAddCause addCause)
{
ControlObject* controlObject = (ControlObject*) self;
controlObject->addCauseValue = addCause;
}
int
ControlAction_getOrCat(ControlAction self)
{
ControlObject* controlObject = (ControlObject*) self;
if (controlObject->origin) {
MmsValue* orCat = MmsValue_getElement(controlObject->origin, 0);
if (orCat) {
return MmsValue_toInt32(orCat);
}
}
return 0;
}
uint8_t*
ControlAction_getOrIdent(ControlAction self, int* orIdentSize)
{
ControlObject* controlObject = (ControlObject*) self;
if (controlObject->origin) {
MmsValue* orIdent = MmsValue_getElement(controlObject->origin, 1);
if (orIdent) {
if (MmsValue_getType(orIdent) == MMS_OCTET_STRING) {
*orIdentSize = MmsValue_getOctetStringSize(orIdent);
return MmsValue_getOctetStringBuffer(orIdent);
}
}
}
return NULL;
}
ClientConnection
ControlAction_getClientConnection(ControlAction self)
{
ControlObject* controlObject = (ControlObject*) self;
return private_IedServer_getClientConnectionByHandle(controlObject->iedServer, controlObject->mmsConnection);
}
DataObject*
ControlAction_getControlObject(ControlAction self)
{
ControlObject* controlObject = (ControlObject*) self;
return controlObject->dataObject;
}
#endif /* (CONFIG_IEC61850_CONTROL_SERVICE == 1) */ #endif /* (CONFIG_IEC61850_CONTROL_SERVICE == 1) */

Loading…
Cancel
Save