- IED server: added ControlSelectStateChangedHandler callback for control model

pull/291/head
Michael Zillgith 5 years ago
parent fb5ed11001
commit 14f4f1ccf0

@ -1211,22 +1211,22 @@ IedServer_setEditSettingGroupConfirmationHandler(IedServer self, SettingGroupCon
* \brief result code for ControlPerformCheckHandler
*/
typedef enum {
CONTROL_ACCEPTED = -1, /** check passed */
CONTROL_WAITING_FOR_SELECT = 0, /** select operation in progress - handler will be called again later */
CONTROL_HARDWARE_FAULT = 1, /** check failed due to hardware fault */
CONTROL_TEMPORARILY_UNAVAILABLE = 2, /** control is already selected or operated */
CONTROL_OBJECT_ACCESS_DENIED = 3, /** check failed due to access control reason - access denied for this client or state */
CONTROL_OBJECT_UNDEFINED = 4, /** object not visible in this security context ??? */
CONTROL_VALUE_INVALID = 11 /** ctlVal out of range */
CONTROL_ACCEPTED = -1, /**< check passed */
CONTROL_WAITING_FOR_SELECT = 0, /**< select operation in progress - handler will be called again later */
CONTROL_HARDWARE_FAULT = 1, /**< check failed due to hardware fault */
CONTROL_TEMPORARILY_UNAVAILABLE = 2, /**< control is already selected or operated */
CONTROL_OBJECT_ACCESS_DENIED = 3, /**< check failed due to access control reason - access denied for this client or state */
CONTROL_OBJECT_UNDEFINED = 4, /**< object not visible in this security context ??? */
CONTROL_VALUE_INVALID = 11 /**< ctlVal out of range */
} CheckHandlerResult;
/**
* \brief result codes for control handler (ControlWaitForExecutionHandler and ControlHandler)
*/
typedef enum {
CONTROL_RESULT_FAILED = 0, /** check or operation failed */
CONTROL_RESULT_OK = 1, /** check or operation was successful */
CONTROL_RESULT_WAITING = 2 /** check or operation is in progress */
CONTROL_RESULT_FAILED = 0, /**< check or operation failed */
CONTROL_RESULT_OK = 1, /**< check or operation was successful */
CONTROL_RESULT_WAITING = 2 /**< check or operation is in progress */
} ControlHandlerResult;
typedef void* ControlAction;
@ -1387,6 +1387,30 @@ typedef ControlHandlerResult (*ControlWaitForExecutionHandler) (ControlAction ac
*/
typedef ControlHandlerResult (*ControlHandler) (ControlAction action, void* parameter, MmsValue* ctlVal, bool test);
/**
* \brief Reason why a select state of a control object changed
*/
typedef enum {
SELECT_STATE_REASON_SELECTED, /**< control has been selected */
SELECT_STATE_REASON_CANCELED, /**< cancel received for the control */
SELECT_STATE_REASON_TIMEOUT, /**< unselected due to timeout (sboTimeout) */
SELECT_STATE_REASON_OPERATED, /**< unselected due to successful operate */
SELECT_STATE_REASON_OPERATE_FAILED, /**< unselected due to failed operate */
SELECT_STATE_REASON_DISCONNECTED /**< unselected due to disconnection of selecting client */
} SelectStateChangedReason;
/**
* \brief Control model callback that is called when the select state of a control changes
*
* New in version 1.5
*
* \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 isSelected true when the control is selected, false otherwise
* \param reason reason why the select state changed
*/
typedef void (*ControlSelectStateChangedHandler) (ControlAction action, void* parameter, bool isSelected, SelectStateChangedReason reason);
/**
* \brief Set control handler for controllable data object
*
@ -1437,6 +1461,25 @@ IedServer_setPerformCheckHandler(IedServer self, DataObject* node, ControlPerfor
LIB61850_API void
IedServer_setWaitForExecutionHandler(IedServer self, DataObject* node, ControlWaitForExecutionHandler handler, void* parameter);
/**
* \brief Set a callback handler for a controllable data object to track select state changes
*
* The callback is called whenever the select state of a control changes. Reason for changes can be:
* - a successful select or select-with-value by a client
* - select timeout
* - operate or failed operate
* - cancel request by a client
* - the client that selected the control has been disconnected
*
* \param self the instance of IedServer to operate on.
* \param node the controllable data object handle
* \param handler a callback function of type ControlHandler
* \param parameter a user provided parameter that is passed to the control handler.
*/
LIB61850_API void
IedServer_setSelectStateChangedHandler(IedServer self, DataObject* node, ControlSelectStateChangedHandler handler, void* parameter);
/**
* \brief Update the control model for the specified controllable data object with the given value and
* update "ctlModel" attribute value.

@ -129,6 +129,9 @@ struct sControlObject
ControlWaitForExecutionHandler waitForExecutionHandler;
void* waitForExecutionHandlerParameter;
ControlSelectStateChangedHandler selectStateChangedHandler;
void* selectStateChangedHandlerParameter;
#if (CONFIG_IEC61850_SERVICE_TRACKING == 1)
/* Common data class (CDC) of control object */
ControlServiceCDC cdc;
@ -182,6 +185,10 @@ ControlObject_installCheckHandler(ControlObject* self, ControlPerformCheckHandle
LIB61850_INTERNAL void
ControlObject_installWaitForExecutionHandler(ControlObject* self, ControlWaitForExecutionHandler handler, void* parameter);
LIB61850_INTERNAL void
ControlObject_installSelectStateChangedHandler(ControlObject* self, ControlSelectStateChangedHandler handler,
void* parameter);
LIB61850_INTERNAL void
ControlObject_updateControlModel(ControlObject* self, ControlModel value, DataObject* ctlObject);

@ -853,7 +853,7 @@ IedServer_setControlHandler(
{
ControlObject* controlObject = lookupControlObject(self, node);
if (controlObject != NULL) {
if (controlObject) {
ControlObject_installListener(controlObject, listener, parameter);
if (DEBUG_IED_SERVER)
printf("IED_SERVER: Installed control handler for %s!\n", node->name);
@ -868,7 +868,7 @@ IedServer_setPerformCheckHandler(IedServer self, DataObject* node, ControlPerfor
{
ControlObject* controlObject = lookupControlObject(self, node);
if (controlObject != NULL)
if (controlObject)
ControlObject_installCheckHandler(controlObject, handler, parameter);
}
@ -878,10 +878,20 @@ IedServer_setWaitForExecutionHandler(IedServer self, DataObject* node, ControlWa
{
ControlObject* controlObject = lookupControlObject(self, node);
if (controlObject != NULL)
if (controlObject)
ControlObject_installWaitForExecutionHandler(controlObject, handler, parameter);
}
void
IedServer_setSelectStateChangedHandler(IedServer self, DataObject* node, ControlSelectStateChangedHandler handler,
void* parameter)
{
ControlObject* controlObject = lookupControlObject(self, node);
if (controlObject)
ControlObject_installSelectStateChangedHandler(controlObject, handler, parameter);
}
void
IedServer_updateCtlModel(IedServer self, DataObject* ctlObject, ControlModel value)
{

@ -408,7 +408,7 @@ updateGenericTrackingObjectValues(MmsMapping* self, ControlObject* controlObject
#endif /* (CONFIG_IEC61850_SERVICE_TRACKING == 1) */
static void
unselectObject(ControlObject* self);
unselectObject(ControlObject* self, SelectStateChangedReason reason);
static void
setState(ControlObject* self, int newState)
@ -488,17 +488,33 @@ selectObject(ControlObject* self, uint64_t selectTime, MmsServerConnection conne
self->mmsConnection = connection;
setStSeld(self, true);
setState(self, STATE_READY);
if (self->selectStateChangedHandler) {
self->selectStateChangedHandler((ControlAction) self,
self->selectStateChangedHandlerParameter,
true,
SELECT_STATE_REASON_SELECTED);
}
}
static void
unselectObject(ControlObject* self)
unselectObject(ControlObject* self, SelectStateChangedReason reason)
{
setState(self, STATE_UNSELECTED);
if (getState(self) != STATE_UNSELECTED) {
setState(self, STATE_UNSELECTED);
setStSeld(self, false);
setStSeld(self, false);
if (DEBUG_IED_SERVER)
printf("IED_SERVER: control %s/%s.%s unselected\n", MmsDomain_getName(self->mmsDomain), self->lnName, self->name);
if (self->selectStateChangedHandler) {
self->selectStateChangedHandler((ControlAction) self,
self->selectStateChangedHandlerParameter,
false,
reason);
}
if (DEBUG_IED_SERVER)
printf("IED_SERVER: control %s/%s.%s unselected\n", MmsDomain_getName(self->mmsDomain), self->lnName, self->name);
}
}
static void
@ -513,7 +529,7 @@ checkSelectTimeout(ControlObject* self, uint64_t currentTime)
printf("IED_SERVER: select-timeout (timeout-val = %i) for control %s/%s.%s\n",
self->selectTimeout, MmsDomain_getName(self->mmsDomain), self->lnName, self->name);
unselectObject(self);
unselectObject(self, SELECT_STATE_REASON_TIMEOUT);
}
}
}
@ -620,16 +636,16 @@ exitControlTask(ControlObject* self)
}
static void
abortControlOperation(ControlObject* self, bool unconditional)
abortControlOperation(ControlObject* self, bool unconditional, SelectStateChangedReason reason)
{
if ((self->ctlModel == 2) || (self->ctlModel == 4)) {
if (unconditional) {
unselectObject(self);
unselectObject(self, reason);
}
else {
if (isSboClassOperateOnce(self))
unselectObject(self);
unselectObject(self, reason);
else
setState(self, STATE_READY);
}
@ -804,7 +820,7 @@ executeStateMachine:
resetAddCause(controlObject);
abortControlOperation(controlObject, false);
abortControlOperation(controlObject, false, SELECT_STATE_REASON_OPERATE_FAILED);
exitControlTask(controlObject);
}
else if (dynamicCheckResult == CONTROL_RESULT_OK) {
@ -854,6 +870,8 @@ executeStateMachine:
updateGenericTrackingObjectValues(self, controlObject, IEC61850_SERVICE_TYPE_COMMAND_TERMINATION, IEC61850_SERVICE_ERROR_NO_ERROR);
#endif /* (CONFIG_IEC61850_SERVICE_TRACKING == 1) */
}
abortControlOperation(controlObject, false, SELECT_STATE_REASON_OPERATED);
}
else {
@ -867,9 +885,10 @@ executeStateMachine:
#if (CONFIG_IEC61850_SERVICE_TRACKING == 1)
updateGenericTrackingObjectValues(self, controlObject, IEC61850_SERVICE_TYPE_COMMAND_TERMINATION, IEC61850_SERVICE_ERROR_FAILED_DUE_TO_SERVER_CONSTRAINT);
#endif /* (CONFIG_IEC61850_SERVICE_TRACKING == 1) */
abortControlOperation(controlObject, false, SELECT_STATE_REASON_OPERATE_FAILED);
}
abortControlOperation(controlObject, false);
exitControlTask(controlObject);
setOpOk(controlObject, false, currentTimeInMs);
@ -1292,7 +1311,7 @@ bool
ControlObject_unselect(ControlObject* self, MmsServerConnection connection)
{
if (self->mmsConnection == connection) {
abortControlOperation(self, true);
abortControlOperation(self, true, SELECT_STATE_REASON_DISCONNECTED);
return true;
}
else
@ -1321,6 +1340,14 @@ ControlObject_installWaitForExecutionHandler(ControlObject* self, ControlWaitFor
self->waitForExecutionHandlerParameter = parameter;
}
void
ControlObject_installSelectStateChangedHandler(ControlObject* self, ControlSelectStateChangedHandler handler,
void* parameter)
{
self->selectStateChangedHandler = handler;
self->selectStateChangedHandlerParameter = parameter;
}
void
ControlObject_updateControlModel(ControlObject* self, ControlModel value, DataObject* ctlObject)
{
@ -1394,7 +1421,7 @@ Control_processControlActions(MmsMapping* self, uint64_t currentTimeInMs)
/* leave state Perform Test */
setOpRcvd(controlObject, false);
abortControlOperation(controlObject, false);
abortControlOperation(controlObject, false, SELECT_STATE_REASON_OPERATE_FAILED);
resetAddCause(controlObject);
}
@ -2056,7 +2083,7 @@ Control_writeAccessControlObject(MmsMapping* self, MmsDomain* domain, char* vari
CONTROL_ERROR_NO_ERROR, ADD_CAUSE_INCONSISTENT_PARAMETERS,
ctlNum, origin, true);
unselectObject(controlObject);
unselectObject(controlObject, SELECT_STATE_REASON_OPERATE_FAILED);
}
goto free_and_return;
@ -2112,7 +2139,7 @@ Control_writeAccessControlObject(MmsMapping* self, MmsDomain* domain, char* vari
CONTROL_ERROR_NO_ERROR, ADD_CAUSE_INCONSISTENT_PARAMETERS,
ctlNum, origin, true);
unselectObject(controlObject);
unselectObject(controlObject, SELECT_STATE_REASON_OPERATE_FAILED);
goto free_and_return;
}
@ -2197,10 +2224,7 @@ Control_writeAccessControlObject(MmsMapping* self, MmsDomain* domain, char* vari
/* leave state Perform Test */
setOpRcvd(controlObject, false);
abortControlOperation(controlObject, false);
if ((controlObject->ctlModel == 2) || (controlObject->ctlModel == 4))
unselectObject(controlObject);
abortControlOperation(controlObject, false, SELECT_STATE_REASON_OPERATE_FAILED);
}
}
@ -2254,7 +2278,7 @@ Control_writeAccessControlObject(MmsMapping* self, MmsDomain* domain, char* vari
if (state != STATE_UNSELECTED) {
if (controlObject->mmsConnection == connection) {
indication = DATA_ACCESS_ERROR_SUCCESS;
unselectObject(controlObject);
unselectObject(controlObject, SELECT_STATE_REASON_CANCELED);
goto free_and_return;
}
else {
@ -2271,7 +2295,7 @@ Control_writeAccessControlObject(MmsMapping* self, MmsDomain* domain, char* vari
if (controlObject->timeActivatedOperate) {
controlObject->timeActivatedOperate = false;
abortControlOperation(controlObject, false);
abortControlOperation(controlObject, false, SELECT_STATE_REASON_CANCELED);
indication = DATA_ACCESS_ERROR_SUCCESS;

Loading…
Cancel
Save