- IEC 61850 server: control model - implemented automatic handling of opRcvd, opOk, and tOpOk when present in data object

pull/179/head
Michael Zillgith 7 years ago
parent a3c2c4652e
commit d376370aaa

@ -7,7 +7,7 @@
<Text>Station bus</Text>
<ConnectedAP iedName="simpleIO" apName="accessPoint1">
<Address>
<P type="IP">192.168.2.223</P>
<P type="IP">0.0.0.0</P>
<P type="IP-SUBNET">255.255.255.0</P>
<P type="IP-GATEWAY">10.0.0.1</P>
<P type="OSI-TSEL">0001</P>
@ -35,6 +35,28 @@
<Authentication />
<LDevice inst="GenericIO">
<LN0 lnClass="LLN0" lnType="LLN01" inst="">
<DataSet name="ControlEvents" desc="control related events">
<FCDA ldInst="GenericIO" lnClass="GGIO" fc="ST" lnInst="1" doName="SPCSO1" daName="stVal" />
<FCDA ldInst="GenericIO" lnClass="GGIO" fc="ST" lnInst="1" doName="SPCSO2" daName="stVal" />
<FCDA ldInst="GenericIO" lnClass="GGIO" fc="ST" lnInst="1" doName="SPCSO3" daName="stVal" />
<FCDA ldInst="GenericIO" lnClass="GGIO" fc="ST" lnInst="1" doName="SPCSO4" daName="stVal" />
<FCDA ldInst="GenericIO" lnClass="GGIO" fc="ST" lnInst="1" doName="SPCSO5" daName="stVal" />
<FCDA ldInst="GenericIO" lnClass="GGIO" fc="ST" lnInst="1" doName="SPCSO6" daName="stVal" />
<FCDA ldInst="GenericIO" lnClass="GGIO" fc="ST" lnInst="1" doName="SPCSO7" daName="stVal" />
<FCDA ldInst="GenericIO" lnClass="GGIO" fc="ST" lnInst="1" doName="SPCSO8" daName="stVal" />
<FCDA ldInst="GenericIO" lnClass="GGIO" fc="ST" lnInst="1" doName="SPCSO9" daName="stVal" />
<FCDA ldInst="GenericIO" lnClass="GGIO" fc="ST" lnInst="1" doName="SPCSO2" daName="stSeld" />
<FCDA ldInst="GenericIO" lnClass="GGIO" fc="OR" lnInst="1" doName="SPCSO2" daName="opRcvd" />
<FCDA ldInst="GenericIO" lnClass="GGIO" fc="OR" lnInst="1" doName="SPCSO2" daName="opOk" />
</DataSet>
<ReportControl name="ControlEventsRCB" confRev="1" datSet="ControlEvents" rptID="ControlEvents" buffered="false" intgPd="1000" bufTime="0" indexed="true">
<TrgOps dchg="true" />
<OptFields seqNum="true" timeStamp="true" dataSet="true" reasonCode="true" entryID="true" configRef="true" />
<RptEnabled max="2" />
</ReportControl>
<DOI name="Mod">
<DAI name="ctlModel">
<Val>status-only</Val>
@ -57,6 +79,9 @@
<DAI name="ctlModel">
<Val>sbo-with-normal-security</Val>
</DAI>
<DAI name="sboTimeout">
<Val>2000</Val>
</DAI>
</DOI>
<DOI name="SPCSO3">
<DAI name="ctlModel">
@ -228,7 +253,12 @@
<DA name="stVal" bType="BOOLEAN" fc="ST" dchg="true" />
<DA name="q" bType="Quality" fc="ST" qchg="true" />
<DA name="t" bType="Timestamp" fc="ST" />
<DA bType="BOOLEAN" dchg="true" fc="ST" name="stSeld"/>
<DA name="opRcvd" bType="BOOLEAN" fc="OR" dchg="true" />
<DA name="opOk" bType="BOOLEAN" fc="OR" dchg="true" />
<DA name="tOpOk" bType="Timestamp" fc="OR" />
<DA name="ctlModel" type="CtlModels" bType="Enum" fc="CF" />
<DA bType="INT32U" fc="CF" name="sboTimeout" dchg="true" />
<DA name="sboClass" type="SboClasses" bType="Enum" fc="CF" />
</DOType>
<DOType id="SPC_1_SPCSO1" cdc="SPC">

@ -7,7 +7,149 @@
static void initializeValues();
extern DataSet iedModelds_GenericIO_LLN0_ControlEvents;
extern DataSetEntry iedModelds_GenericIO_LLN0_ControlEvents_fcda0;
extern DataSetEntry iedModelds_GenericIO_LLN0_ControlEvents_fcda1;
extern DataSetEntry iedModelds_GenericIO_LLN0_ControlEvents_fcda2;
extern DataSetEntry iedModelds_GenericIO_LLN0_ControlEvents_fcda3;
extern DataSetEntry iedModelds_GenericIO_LLN0_ControlEvents_fcda4;
extern DataSetEntry iedModelds_GenericIO_LLN0_ControlEvents_fcda5;
extern DataSetEntry iedModelds_GenericIO_LLN0_ControlEvents_fcda6;
extern DataSetEntry iedModelds_GenericIO_LLN0_ControlEvents_fcda7;
extern DataSetEntry iedModelds_GenericIO_LLN0_ControlEvents_fcda8;
extern DataSetEntry iedModelds_GenericIO_LLN0_ControlEvents_fcda9;
extern DataSetEntry iedModelds_GenericIO_LLN0_ControlEvents_fcda10;
extern DataSetEntry iedModelds_GenericIO_LLN0_ControlEvents_fcda11;
DataSetEntry iedModelds_GenericIO_LLN0_ControlEvents_fcda0 = {
"GenericIO",
false,
"GGIO1$ST$SPCSO1$stVal",
-1,
NULL,
NULL,
&iedModelds_GenericIO_LLN0_ControlEvents_fcda1
};
DataSetEntry iedModelds_GenericIO_LLN0_ControlEvents_fcda1 = {
"GenericIO",
false,
"GGIO1$ST$SPCSO2$stVal",
-1,
NULL,
NULL,
&iedModelds_GenericIO_LLN0_ControlEvents_fcda2
};
DataSetEntry iedModelds_GenericIO_LLN0_ControlEvents_fcda2 = {
"GenericIO",
false,
"GGIO1$ST$SPCSO3$stVal",
-1,
NULL,
NULL,
&iedModelds_GenericIO_LLN0_ControlEvents_fcda3
};
DataSetEntry iedModelds_GenericIO_LLN0_ControlEvents_fcda3 = {
"GenericIO",
false,
"GGIO1$ST$SPCSO4$stVal",
-1,
NULL,
NULL,
&iedModelds_GenericIO_LLN0_ControlEvents_fcda4
};
DataSetEntry iedModelds_GenericIO_LLN0_ControlEvents_fcda4 = {
"GenericIO",
false,
"GGIO1$ST$SPCSO5$stVal",
-1,
NULL,
NULL,
&iedModelds_GenericIO_LLN0_ControlEvents_fcda5
};
DataSetEntry iedModelds_GenericIO_LLN0_ControlEvents_fcda5 = {
"GenericIO",
false,
"GGIO1$ST$SPCSO6$stVal",
-1,
NULL,
NULL,
&iedModelds_GenericIO_LLN0_ControlEvents_fcda6
};
DataSetEntry iedModelds_GenericIO_LLN0_ControlEvents_fcda6 = {
"GenericIO",
false,
"GGIO1$ST$SPCSO7$stVal",
-1,
NULL,
NULL,
&iedModelds_GenericIO_LLN0_ControlEvents_fcda7
};
DataSetEntry iedModelds_GenericIO_LLN0_ControlEvents_fcda7 = {
"GenericIO",
false,
"GGIO1$ST$SPCSO8$stVal",
-1,
NULL,
NULL,
&iedModelds_GenericIO_LLN0_ControlEvents_fcda8
};
DataSetEntry iedModelds_GenericIO_LLN0_ControlEvents_fcda8 = {
"GenericIO",
false,
"GGIO1$ST$SPCSO9$stVal",
-1,
NULL,
NULL,
&iedModelds_GenericIO_LLN0_ControlEvents_fcda9
};
DataSetEntry iedModelds_GenericIO_LLN0_ControlEvents_fcda9 = {
"GenericIO",
false,
"GGIO1$ST$SPCSO2$stSeld",
-1,
NULL,
NULL,
&iedModelds_GenericIO_LLN0_ControlEvents_fcda10
};
DataSetEntry iedModelds_GenericIO_LLN0_ControlEvents_fcda10 = {
"GenericIO",
false,
"GGIO1$OR$SPCSO2$opRcvd",
-1,
NULL,
NULL,
&iedModelds_GenericIO_LLN0_ControlEvents_fcda11
};
DataSetEntry iedModelds_GenericIO_LLN0_ControlEvents_fcda11 = {
"GenericIO",
false,
"GGIO1$OR$SPCSO2$opOk",
-1,
NULL,
NULL,
NULL
};
DataSet iedModelds_GenericIO_LLN0_ControlEvents = {
"GenericIO",
"LLN0$ControlEvents",
12,
&iedModelds_GenericIO_LLN0_ControlEvents_fcda0,
NULL
};
LogicalDevice iedModel_GenericIO = {
LogicalDeviceModelType,
@ -1264,7 +1406,7 @@ DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_t = {
DataAttributeModelType,
"t",
(ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2,
(ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_ctlModel,
(ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_stSeld,
NULL,
0,
IEC61850_FC_ST,
@ -1273,11 +1415,63 @@ DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_t = {
NULL,
0};
DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_stSeld = {
DataAttributeModelType,
"stSeld",
(ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2,
(ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_opRcvd,
NULL,
0,
IEC61850_FC_ST,
IEC61850_BOOLEAN,
0 + TRG_OPT_DATA_CHANGED,
NULL,
0};
DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_opRcvd = {
DataAttributeModelType,
"opRcvd",
(ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2,
(ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_opOk,
NULL,
0,
IEC61850_FC_OR,
IEC61850_BOOLEAN,
0 + TRG_OPT_DATA_CHANGED,
NULL,
0};
DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_opOk = {
DataAttributeModelType,
"opOk",
(ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2,
(ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_tOpOk,
NULL,
0,
IEC61850_FC_OR,
IEC61850_BOOLEAN,
0 + TRG_OPT_DATA_CHANGED,
NULL,
0};
DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_tOpOk = {
DataAttributeModelType,
"tOpOk",
(ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2,
(ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_ctlModel,
NULL,
0,
IEC61850_FC_OR,
IEC61850_TIMESTAMP,
0,
NULL,
0};
DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_ctlModel = {
DataAttributeModelType,
"ctlModel",
(ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2,
(ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_sboClass,
(ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_sboTimeout,
NULL,
0,
IEC61850_FC_CF,
@ -1286,6 +1480,19 @@ DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_ctlModel = {
NULL,
0};
DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_sboTimeout = {
DataAttributeModelType,
"sboTimeout",
(ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2,
(ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_sboClass,
NULL,
0,
IEC61850_FC_CF,
IEC61850_INT32U,
0 + TRG_OPT_DATA_CHANGED,
NULL,
0};
DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_sboClass = {
DataAttributeModelType,
"sboClass",
@ -3868,7 +4075,11 @@ DataAttribute iedModel_GenericIO_GGIO1_Ind4_t = {
NULL,
0};
extern ReportControlBlock iedModel_GenericIO_LLN0_report0;
extern ReportControlBlock iedModel_GenericIO_LLN0_report1;
ReportControlBlock iedModel_GenericIO_LLN0_report0 = {&iedModel_GenericIO_LLN0, "ControlEventsRCB01", "ControlEvents", false, "ControlEvents", 1, 17, 239, 0, 1000, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, &iedModel_GenericIO_LLN0_report1};
ReportControlBlock iedModel_GenericIO_LLN0_report1 = {&iedModel_GenericIO_LLN0, "ControlEventsRCB02", "ControlEvents", false, "ControlEvents", 1, 17, 239, 0, 1000, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, NULL};
@ -3879,8 +4090,8 @@ DataAttribute iedModel_GenericIO_GGIO1_Ind4_t = {
IedModel iedModel = {
"simpleIO",
&iedModel_GenericIO,
NULL,
NULL,
&iedModelds_GenericIO_LLN0_ControlEvents,
&iedModel_GenericIO_LLN0_report0,
NULL,
NULL,
NULL,
@ -3901,6 +4112,8 @@ iedModel_GenericIO_GGIO1_SPCSO1_ctlModel.mmsValue = MmsValue_newIntegerFromInt32
iedModel_GenericIO_GGIO1_SPCSO2_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(2);
iedModel_GenericIO_GGIO1_SPCSO2_sboTimeout.mmsValue = MmsValue_newUnsignedFromUint32(2000);
iedModel_GenericIO_GGIO1_SPCSO3_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(3);
iedModel_GenericIO_GGIO1_SPCSO4_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(4);

@ -115,7 +115,12 @@ extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Cancel_Test;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_stVal;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_q;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_t;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_stSeld;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_opRcvd;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_opOk;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_tOpOk;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_ctlModel;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_sboTimeout;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_sboClass;
extern DataObject iedModel_GenericIO_GGIO1_SPCSO3;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper;
@ -425,7 +430,12 @@ extern DataAttribute iedModel_GenericIO_GGIO1_Ind4_t;
#define IEDMODEL_GenericIO_GGIO1_SPCSO2_stVal (&iedModel_GenericIO_GGIO1_SPCSO2_stVal)
#define IEDMODEL_GenericIO_GGIO1_SPCSO2_q (&iedModel_GenericIO_GGIO1_SPCSO2_q)
#define IEDMODEL_GenericIO_GGIO1_SPCSO2_t (&iedModel_GenericIO_GGIO1_SPCSO2_t)
#define IEDMODEL_GenericIO_GGIO1_SPCSO2_stSeld (&iedModel_GenericIO_GGIO1_SPCSO2_stSeld)
#define IEDMODEL_GenericIO_GGIO1_SPCSO2_opRcvd (&iedModel_GenericIO_GGIO1_SPCSO2_opRcvd)
#define IEDMODEL_GenericIO_GGIO1_SPCSO2_opOk (&iedModel_GenericIO_GGIO1_SPCSO2_opOk)
#define IEDMODEL_GenericIO_GGIO1_SPCSO2_tOpOk (&iedModel_GenericIO_GGIO1_SPCSO2_tOpOk)
#define IEDMODEL_GenericIO_GGIO1_SPCSO2_ctlModel (&iedModel_GenericIO_GGIO1_SPCSO2_ctlModel)
#define IEDMODEL_GenericIO_GGIO1_SPCSO2_sboTimeout (&iedModel_GenericIO_GGIO1_SPCSO2_sboTimeout)
#define IEDMODEL_GenericIO_GGIO1_SPCSO2_sboClass (&iedModel_GenericIO_GGIO1_SPCSO2_sboClass)
#define IEDMODEL_GenericIO_GGIO1_SPCSO3 (&iedModel_GenericIO_GGIO1_SPCSO3)
#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper (&iedModel_GenericIO_GGIO1_SPCSO3_Oper)

@ -1,7 +1,7 @@
/*
* control.h
*
* Copyright 2013-2018 Michael Zillgith
* Copyright 2013-2019 Michael Zillgith
*
* This file is part of libIEC61850.
*
@ -45,8 +45,11 @@ struct sControlObject
int state;
int pendingEvents:8;
#if (CONFIG_MMS_THREADLESS_STACK != 1)
Semaphore stateLock;
Semaphore pendingEventsLock;
#endif
MmsValue* mmsValue;
@ -65,8 +68,18 @@ struct sControlObject
MmsValue* ctlNumSt;
MmsValue* originSt;
/* for automatic update of stSeld attribute */
DataAttribute* stSeld;
/* for automatic update of opRcvd attribute */
DataAttribute* opRcvd;
/* for automatic update of opOk attribute */
DataAttribute* opOk;
/* for automatic update of tOpOk attribute */
DataAttribute* tOpOk;
char ctlObjectName[130];
/* for LastAppIError */

@ -46,6 +46,13 @@
#define STATE_WAIT_FOR_EXECUTION 4
#define STATE_OPERATE 5
#define PENDING_EVENT_SELECTED 1
#define PENDING_EVENT_UNSELECTED 2
#define PENDING_EVENT_OP_RCVD_TRUE 4
#define PENDING_EVENT_OP_RCVD_FALSE 8
#define PENDING_EVENT_OP_OK_TRUE 16
#define PENDING_EVENT_OP_OK_FALSE 32
void
ControlObject_sendLastApplError(ControlObject* self, MmsServerConnection connection, char* ctlVariable, int error,
ControlAddCause addCause, MmsValue* ctlNum, MmsValue* origin, bool handlerMode);
@ -95,6 +102,73 @@ getState(ControlObject* self)
return state;
}
static void
setStSeld(ControlObject* self, bool value)
{
if (self->stSeld) {
#if (CONFIG_MMS_THREADLESS_STACK != 1)
Semaphore_wait(self->pendingEventsLock);
#endif
if (value)
self->pendingEvents |= PENDING_EVENT_SELECTED;
else
self->pendingEvents |= PENDING_EVENT_UNSELECTED;
#if (CONFIG_MMS_THREADLESS_STACK != 1)
Semaphore_post(self->pendingEventsLock);
#endif
}
}
static void
setOpRcvd(ControlObject* self, bool value)
{
if (self->opRcvd) {
#if (CONFIG_MMS_THREADLESS_STACK != 1)
Semaphore_wait(self->pendingEventsLock);
#endif
if (value)
self->pendingEvents |= PENDING_EVENT_OP_RCVD_TRUE;
else
self->pendingEvents |= PENDING_EVENT_OP_RCVD_FALSE;
#if (CONFIG_MMS_THREADLESS_STACK != 1)
Semaphore_post(self->pendingEventsLock);
#endif
}
}
static void
setOpOk(ControlObject* self, bool value, uint64_t currentTimeInMs)
{
if (self->opOk) {
#if (CONFIG_MMS_THREADLESS_STACK != 1)
Semaphore_wait(self->pendingEventsLock);
#endif
if (value) {
if (self->tOpOk) {
MmsValue* timestamp = self->tOpOk->mmsValue;
MmsValue_setUtcTimeMs(timestamp, currentTimeInMs);
/* TODO update time quality */
}
self->pendingEvents |= PENDING_EVENT_OP_OK_TRUE;
}
else
self->pendingEvents |= PENDING_EVENT_OP_OK_FALSE;
#if (CONFIG_MMS_THREADLESS_STACK != 1)
Semaphore_post(self->pendingEventsLock);
#endif
}
}
static void
updateSboTimeoutValue(ControlObject* self)
{
@ -192,7 +266,7 @@ operateControl(ControlObject* self, MmsValue* value, uint64_t currentTime, bool
}
static void
executeControlTask(ControlObject* self)
executeControlTask(ControlObject* self, uint64_t currentTimeInMs)
{
int state;
@ -244,6 +318,8 @@ executeStateMachine:
setState(self, STATE_OPERATE);
setOpOk(self, true, currentTimeInMs);
goto executeStateMachine;
}
}
@ -275,6 +351,8 @@ executeStateMachine:
abortControlOperation(self);
exitControlTask(self);
setOpOk(self, false, currentTimeInMs);
}
}
break;
@ -295,8 +373,9 @@ ControlObject_create(IedServer iedServer, MmsDomain* domain, char* lnName, char*
#if (CONFIG_MMS_THREADLESS_STACK != 1)
self->stateLock = Semaphore_create(1);
self->pendingEventsLock = Semaphore_create(1);
if (self->stateLock == NULL) {
if ((self->stateLock == NULL) || (self->pendingEventsLock == NULL)) {
ControlObject_destroy(self);
self = NULL;
goto exit_function;
@ -404,6 +483,39 @@ ControlObject_initialize(ControlObject* self)
printf("IED_SERVER: ERROR - stSeld of wrong type!\n");
}
char* opRcvdName = StringUtils_createStringInBuffer(strBuf, 6, self->mmsDomain->domainName, "/", self->lnName, ".", self->name, ".opRcvd");
self->opRcvd = (DataAttribute*) IedModel_getModelNodeByObjectReference(self->iedServer->model, opRcvdName);
if ((self->opRcvd) && (self->opRcvd->type != IEC61850_BOOLEAN)) {
self->opRcvd = NULL;
if (DEBUG_IED_SERVER)
printf("IED_SERVER: ERROR - opRcvd of wrong type!\n");
}
char* opOkName = StringUtils_createStringInBuffer(strBuf, 6, self->mmsDomain->domainName, "/", self->lnName, ".", self->name, ".opOk");
self->opOk = (DataAttribute*) IedModel_getModelNodeByObjectReference(self->iedServer->model, opOkName);
if ((self->opOk) && (self->opOk->type != IEC61850_BOOLEAN)) {
self->opOk = NULL;
if (DEBUG_IED_SERVER)
printf("IED_SERVER: ERROR - opOk of wrong type!\n");
}
char* tOpOkName = StringUtils_createStringInBuffer(strBuf, 6, self->mmsDomain->domainName, "/", self->lnName, ".", self->name, ".tOpOk");
self->tOpOk = (DataAttribute*) IedModel_getModelNodeByObjectReference(self->iedServer->model, tOpOkName);
if ((self->tOpOk) && (self->tOpOk->type != IEC61850_TIMESTAMP)) {
self->tOpOk = NULL;
if (DEBUG_IED_SERVER)
printf("IED_SERVER: ERROR - tOpOk of wrong type!\n");
}
self->error = MmsValue_newIntegerFromInt32(0);
self->addCause = MmsValue_newIntegerFromInt32(0);
@ -422,36 +534,96 @@ ControlObject_initialize(ControlObject* self)
}
}
static void
ControlObject_handlePendingEvents(ControlObject* self)
{
#if (CONFIG_MMS_THREADLESS_STACK != 1)
Semaphore_wait(self->pendingEventsLock);
#endif
if (self->pendingEvents > 0) {
if (self->pendingEvents & PENDING_EVENT_SELECTED) {
if (self->stSeld)
IedServer_updateBooleanAttributeValue(self->iedServer, self->stSeld, true);
self->pendingEvents &= ~(PENDING_EVENT_SELECTED);
}
if (self->pendingEvents & PENDING_EVENT_UNSELECTED) {
if (self->stSeld)
IedServer_updateBooleanAttributeValue(self->iedServer, self->stSeld, false);
self->pendingEvents &= ~(PENDING_EVENT_UNSELECTED);
}
if (self->pendingEvents & PENDING_EVENT_OP_RCVD_TRUE) {
if (self->opRcvd)
IedServer_updateBooleanAttributeValue(self->iedServer, self->opRcvd, true);
self->pendingEvents &= ~(PENDING_EVENT_OP_RCVD_TRUE);
}
if (self->pendingEvents & PENDING_EVENT_OP_RCVD_FALSE) {
if (self->opRcvd)
IedServer_updateBooleanAttributeValue(self->iedServer, self->opRcvd, false);
self->pendingEvents &= ~(PENDING_EVENT_OP_RCVD_FALSE);
}
if (self->pendingEvents & PENDING_EVENT_OP_OK_TRUE) {
if (self->opOk)
IedServer_updateBooleanAttributeValue(self->iedServer, self->opOk, true);
self->pendingEvents &= ~(PENDING_EVENT_OP_OK_TRUE);
}
if (self->pendingEvents & PENDING_EVENT_OP_OK_FALSE) {
if (self->opOk)
IedServer_updateBooleanAttributeValue(self->iedServer, self->opOk, false);
self->pendingEvents &= ~(PENDING_EVENT_OP_OK_FALSE);
}
}
#if (CONFIG_MMS_THREADLESS_STACK != 1)
Semaphore_post(self->pendingEventsLock);
#endif
}
void
ControlObject_destroy(ControlObject* self)
{
if (self->mmsValue != NULL)
if (self->mmsValue)
MmsValue_delete(self->mmsValue);
if (self->emptyString != NULL)
if (self->emptyString)
MmsValue_delete(self->emptyString);
if (self->error != NULL)
if (self->error)
MmsValue_delete(self->error);
if (self->addCause != NULL)
if (self->addCause)
MmsValue_delete(self->addCause);
if (self->ctlVal != NULL)
if (self->ctlVal)
MmsValue_delete(self->ctlVal);
if (self->ctlNum != NULL)
if (self->ctlNum)
MmsValue_delete(self->ctlNum);
if (self->origin != NULL)
if (self->origin)
MmsValue_delete(self->origin);
if (self->name != NULL)
if (self->name)
GLOBAL_FREEMEM(self->name);
#if (CONFIG_MMS_THREADLESS_STACK != 1)
if (self->stateLock != NULL)
if (self->stateLock)
Semaphore_destroy(self->stateLock);
if (self->pendingEventsLock)
Semaphore_destroy(self->pendingEventsLock);
#endif
GLOBAL_FREEMEM(self);
@ -499,14 +671,6 @@ ControlObject_getMmsValue(ControlObject* self)
return self->mmsValue;
}
static void
setStSeld(ControlObject* self, bool value)
{
if (self->stSeld) {
IedServer_updateBooleanAttributeValue(self->iedServer, self->stSeld, value);
}
}
static void
selectObject(ControlObject* self, uint64_t selectTime, MmsServerConnection connection)
{
@ -613,8 +777,11 @@ Control_processControlActions(MmsMapping* self, uint64_t currentTimeInMs)
if (controlObject->operateTime <= currentTimeInMs) {
/* enter state Perform Test */
setOpRcvd(controlObject, true);
if (DEBUG_IED_SERVER)
printf("time activated operate: start operation\n");
printf("time activated operate: perform test\n");
controlObject->timeActivatedOperate = false;
@ -631,22 +798,37 @@ Control_processControlActions(MmsMapping* self, uint64_t currentTimeInMs)
}
if (checkResult == CONTROL_ACCEPTED) {
executeControlTask(controlObject);
if (DEBUG_IED_SERVER)
printf("time activated operate: command accepted\n");
/* leave state Perform Test */
setOpRcvd(controlObject, false);
executeControlTask(controlObject, currentTimeInMs);
}
else {
ControlObject_sendLastApplError(controlObject, controlObject->mmsConnection, "Oper",
CONTROL_ERROR_NO_ERROR, ADD_CAUSE_BLOCKED_BY_INTERLOCKING,
controlObject->ctlNum, controlObject->origin, false);
/* leave state Perform Test */
setOpRcvd(controlObject, false);
abortControlOperation(controlObject);
}
}
} /* if (controlObject->state == STATE_WAIT_FOR_ACTICATION_TIME) */
else if (!((controlObject->state == STATE_UNSELECTED) || (controlObject->state == STATE_READY))) {
executeControlTask(controlObject);
executeControlTask(controlObject, currentTimeInMs);
}
else if (controlObject->state == STATE_READY) {
checkSelectTimeout(controlObject, currentTimeInMs);
}
ControlObject_handlePendingEvents(controlObject);
element = LinkedList_getNext(element);
}
}
@ -1059,6 +1241,8 @@ Control_readAccessControlObject(MmsMapping* self, MmsDomain* domain, char* varia
if (getState(controlObject) == STATE_UNSELECTED) {
CheckHandlerResult checkResult = CONTROL_ACCEPTED;
/* opRcvd must not be set here! */
if (controlObject->checkHandler != NULL) { /* perform operative tests */
ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer,
@ -1252,6 +1436,8 @@ Control_writeAccessControlObject(MmsMapping* self, MmsDomain* domain, char* vari
CheckHandlerResult checkResult = CONTROL_ACCEPTED;
/* opRcvd must not be set here! */
bool interlockCheck = MmsValue_getBitStringBit(check, 1);
bool testCondition = MmsValue_getBoolean(test);
@ -1393,6 +1579,9 @@ Control_writeAccessControlObject(MmsMapping* self, MmsDomain* domain, char* vari
CheckHandlerResult checkResult = CONTROL_ACCEPTED;
/* enter state Perform Test */
setOpRcvd(controlObject, true);
if (controlObject->checkHandler != NULL) { /* perform operative tests */
ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer,
@ -1403,7 +1592,6 @@ Control_writeAccessControlObject(MmsMapping* self, MmsDomain* domain, char* vari
clientConnection);
}
if (checkResult == CONTROL_ACCEPTED) {
indication = DATA_ACCESS_ERROR_NO_RESPONSE;
@ -1413,11 +1601,17 @@ Control_writeAccessControlObject(MmsMapping* self, MmsDomain* domain, char* vari
setState(controlObject, STATE_WAIT_FOR_EXECUTION);
/* leave state Perform Test */
setOpRcvd(controlObject, false);
initiateControlTask(controlObject);
}
else {
indication = (MmsDataAccessError) checkResult;
/* leave state Perform Test */
setOpRcvd(controlObject, false);
abortControlOperation(controlObject);
}
}

Loading…
Cancel
Save