pull/309/head
Michael Zillgith 5 years ago
commit 5f2e14f712

@ -2,7 +2,8 @@
* server_example_substitution.c * server_example_substitution.c
* *
* - How to use the IEC 61850 substitution service * - How to use the IEC 61850 substitution service
* - Two data objects can be substituted: * - How to use the blocking service
* - Two data objects can be substituted and/or blocked:
* -- GGIO1.AnIn1 * -- GGIO1.AnIn1
* -- GGIO1.Ind1 * -- GGIO1.Ind1
*/ */
@ -24,6 +25,8 @@ static IedServer iedServer = NULL;
static bool subsAnIn1 = false; static bool subsAnIn1 = false;
static bool subsInd1 = false; static bool subsInd1 = false;
static bool blkEnaAnIn1 = false;
static bool blkEnaInd1 = false;
static float an1 = 0.f; static float an1 = 0.f;
static uint64_t timestamp = 0; static uint64_t timestamp = 0;
@ -35,7 +38,6 @@ sigint_handler(int signalId)
running = 0; running = 0;
} }
static void static void
connectionHandler (IedServer self, ClientConnection connection, bool connected, void* parameter) connectionHandler (IedServer self, ClientConnection connection, bool connected, void* parameter)
{ {
@ -54,13 +56,13 @@ updateProcessValues()
Timestamp_setTimeInMilliseconds(&iecTimestamp, timestamp); Timestamp_setTimeInMilliseconds(&iecTimestamp, timestamp);
Timestamp_setLeapSecondKnown(&iecTimestamp, true); Timestamp_setLeapSecondKnown(&iecTimestamp, true);
if (subsAnIn1 == false) { if ((subsAnIn1 == false) && (blkEnaAnIn1 == false)) {
IedServer_updateTimestampAttributeValue(iedServer, IEDMODEL_LD1_GGIO1_AnIn1_t, &iecTimestamp); IedServer_updateTimestampAttributeValue(iedServer, IEDMODEL_LD1_GGIO1_AnIn1_t, &iecTimestamp);
IedServer_updateQuality(iedServer, IEDMODEL_LD1_GGIO1_AnIn1_q, QUALITY_VALIDITY_GOOD); IedServer_updateQuality(iedServer, IEDMODEL_LD1_GGIO1_AnIn1_q, QUALITY_VALIDITY_GOOD);
IedServer_updateFloatAttributeValue(iedServer, IEDMODEL_LD1_GGIO1_AnIn1_mag_f, an1); IedServer_updateFloatAttributeValue(iedServer, IEDMODEL_LD1_GGIO1_AnIn1_mag_f, an1);
} }
if (subsInd1 == false) { if ((subsInd1 == false) && (blkEnaInd1 == false)) {
IedServer_updateTimestampAttributeValue(iedServer, IEDMODEL_LD1_GGIO1_Ind1_t, &iecTimestamp); IedServer_updateTimestampAttributeValue(iedServer, IEDMODEL_LD1_GGIO1_Ind1_t, &iecTimestamp);
IedServer_updateQuality(iedServer, IEDMODEL_LD1_GGIO1_Ind1_q, QUALITY_VALIDITY_GOOD); IedServer_updateQuality(iedServer, IEDMODEL_LD1_GGIO1_Ind1_q, QUALITY_VALIDITY_GOOD);
IedServer_updateBooleanAttributeValue(iedServer, IEDMODEL_LD1_GGIO1_Ind1_stVal, ind1); IedServer_updateBooleanAttributeValue(iedServer, IEDMODEL_LD1_GGIO1_Ind1_stVal, ind1);
@ -116,6 +118,23 @@ writeAccessHandler (DataAttribute* dataAttribute, MmsValue* value, ClientConnect
} }
} }
else if (dataAttribute == IEDMODEL_LD1_GGIO1_AnIn1_blkEna) {
printf("Received GGIO1.AnIn1.blkEna: %i\n", MmsValue_getBoolean(value));
blkEnaAnIn1 = MmsValue_getBoolean(value);
/* Update quality flags */
Quality quality =
Quality_fromMmsValue(IedServer_getAttributeValue(iedServer, IEDMODEL_LD1_GGIO1_AnIn1_q));
if (blkEnaAnIn1)
Quality_setFlag(&quality, QUALITY_OPERATOR_BLOCKED);
else
Quality_unsetFlag(&quality, QUALITY_OPERATOR_BLOCKED);
IedServer_updateQuality(iedServer, IEDMODEL_LD1_GGIO1_AnIn1_q, quality);
}
else if (dataAttribute == IEDMODEL_LD1_GGIO1_Ind1_subEna) { else if (dataAttribute == IEDMODEL_LD1_GGIO1_Ind1_subEna) {
printf("Received GGIO1.Ind1.subEna: %i\n", MmsValue_getBoolean(value)); printf("Received GGIO1.Ind1.subEna: %i\n", MmsValue_getBoolean(value));
@ -160,6 +179,23 @@ writeAccessHandler (DataAttribute* dataAttribute, MmsValue* value, ClientConnect
} }
} }
else if (dataAttribute == IEDMODEL_LD1_GGIO1_Ind1_blkEna) {
printf("Received GGIO1.Ind1.blkEna: %i\n", MmsValue_getBoolean(value));
blkEnaInd1 = MmsValue_getBoolean(value);
/* Update quality flags */
Quality quality =
Quality_fromMmsValue(IedServer_getAttributeValue(iedServer, IEDMODEL_LD1_GGIO1_Ind1_q));
if (blkEnaAnIn1)
Quality_setFlag(&quality, QUALITY_OPERATOR_BLOCKED);
else
Quality_unsetFlag(&quality, QUALITY_OPERATOR_BLOCKED);
IedServer_updateQuality(iedServer, IEDMODEL_LD1_GGIO1_Ind1_q, quality);
}
return DATA_ACCESS_ERROR_SUCCESS; return DATA_ACCESS_ERROR_SUCCESS;
} }
@ -179,10 +215,12 @@ main(int argc, char** argv)
IedServer_handleWriteAccess(iedServer, IEDMODEL_LD1_GGIO1_AnIn1_subEna, writeAccessHandler, NULL); IedServer_handleWriteAccess(iedServer, IEDMODEL_LD1_GGIO1_AnIn1_subEna, writeAccessHandler, NULL);
IedServer_handleWriteAccess(iedServer, IEDMODEL_LD1_GGIO1_AnIn1_subMag_f, writeAccessHandler, NULL); IedServer_handleWriteAccess(iedServer, IEDMODEL_LD1_GGIO1_AnIn1_subMag_f, writeAccessHandler, NULL);
IedServer_handleWriteAccess(iedServer, IEDMODEL_LD1_GGIO1_AnIn1_subQ, writeAccessHandler, NULL); IedServer_handleWriteAccess(iedServer, IEDMODEL_LD1_GGIO1_AnIn1_subQ, writeAccessHandler, NULL);
IedServer_handleWriteAccess(iedServer, IEDMODEL_LD1_GGIO1_AnIn1_blkEna, writeAccessHandler, NULL);
IedServer_handleWriteAccess(iedServer, IEDMODEL_LD1_GGIO1_Ind1_subEna, writeAccessHandler, NULL); IedServer_handleWriteAccess(iedServer, IEDMODEL_LD1_GGIO1_Ind1_subEna, writeAccessHandler, NULL);
IedServer_handleWriteAccess(iedServer, IEDMODEL_LD1_GGIO1_Ind1_subVal, writeAccessHandler, NULL); IedServer_handleWriteAccess(iedServer, IEDMODEL_LD1_GGIO1_Ind1_subVal, writeAccessHandler, NULL);
IedServer_handleWriteAccess(iedServer, IEDMODEL_LD1_GGIO1_Ind1_subQ, writeAccessHandler, NULL); IedServer_handleWriteAccess(iedServer, IEDMODEL_LD1_GGIO1_Ind1_subQ, writeAccessHandler, NULL);
IedServer_handleWriteAccess(iedServer, IEDMODEL_LD1_GGIO1_Ind1_blkEna, writeAccessHandler, NULL);
/* MMS server will be instructed to start listening for client connections. */ /* MMS server will be instructed to start listening for client connections. */
IedServer_start(iedServer, 102); IedServer_start(iedServer, 102);
@ -225,6 +263,6 @@ main(int argc, char** argv)
/* Cleanup - free all resources */ /* Cleanup - free all resources */
IedServer_destroy(iedServer); IedServer_destroy(iedServer);
return 0;
return 0;
} /* main() */ } /* main() */

@ -1,7 +1,7 @@
/* /*
* static_model.c * static_model.c
* *
* automatically generated from substitution_example.icd * automatically generated from substitution_example.cid
*/ */
#include "static_model.h" #include "static_model.h"
@ -242,7 +242,7 @@ DataAttribute iedModel_LD1_LPHD1_Proxy_subID = {
DataAttributeModelType, DataAttributeModelType,
"subID", "subID",
(ModelNode*) &iedModel_LD1_LPHD1_Proxy, (ModelNode*) &iedModel_LD1_LPHD1_Proxy,
NULL, (ModelNode*) &iedModel_LD1_LPHD1_Proxy_blkEna,
NULL, NULL,
0, 0,
IEC61850_FC_SV, IEC61850_FC_SV,
@ -251,6 +251,19 @@ DataAttribute iedModel_LD1_LPHD1_Proxy_subID = {
NULL, NULL,
0}; 0};
DataAttribute iedModel_LD1_LPHD1_Proxy_blkEna = {
DataAttributeModelType,
"blkEna",
(ModelNode*) &iedModel_LD1_LPHD1_Proxy,
NULL,
NULL,
0,
IEC61850_FC_BL,
IEC61850_BOOLEAN,
0,
NULL,
0};
LogicalNode iedModel_LD1_MMDC1 = { LogicalNode iedModel_LD1_MMDC1 = {
LogicalNodeModelType, LogicalNodeModelType,
"MMDC1", "MMDC1",
@ -424,7 +437,7 @@ DataAttribute iedModel_LD1_MMDC1_Watt_subID = {
DataAttributeModelType, DataAttributeModelType,
"subID", "subID",
(ModelNode*) &iedModel_LD1_MMDC1_Watt, (ModelNode*) &iedModel_LD1_MMDC1_Watt,
NULL, (ModelNode*) &iedModel_LD1_MMDC1_Watt_blkEna,
NULL, NULL,
0, 0,
IEC61850_FC_SV, IEC61850_FC_SV,
@ -433,6 +446,19 @@ DataAttribute iedModel_LD1_MMDC1_Watt_subID = {
NULL, NULL,
0}; 0};
DataAttribute iedModel_LD1_MMDC1_Watt_blkEna = {
DataAttributeModelType,
"blkEna",
(ModelNode*) &iedModel_LD1_MMDC1_Watt,
NULL,
NULL,
0,
IEC61850_FC_BL,
IEC61850_BOOLEAN,
0,
NULL,
0};
DataObject iedModel_LD1_MMDC1_Amp = { DataObject iedModel_LD1_MMDC1_Amp = {
DataObjectModelType, DataObjectModelType,
"Amp", "Amp",
@ -550,7 +576,7 @@ DataAttribute iedModel_LD1_MMDC1_Amp_subID = {
DataAttributeModelType, DataAttributeModelType,
"subID", "subID",
(ModelNode*) &iedModel_LD1_MMDC1_Amp, (ModelNode*) &iedModel_LD1_MMDC1_Amp,
NULL, (ModelNode*) &iedModel_LD1_MMDC1_Amp_blkEna,
NULL, NULL,
0, 0,
IEC61850_FC_SV, IEC61850_FC_SV,
@ -559,6 +585,19 @@ DataAttribute iedModel_LD1_MMDC1_Amp_subID = {
NULL, NULL,
0}; 0};
DataAttribute iedModel_LD1_MMDC1_Amp_blkEna = {
DataAttributeModelType,
"blkEna",
(ModelNode*) &iedModel_LD1_MMDC1_Amp,
NULL,
NULL,
0,
IEC61850_FC_BL,
IEC61850_BOOLEAN,
0,
NULL,
0};
DataObject iedModel_LD1_MMDC1_Vol = { DataObject iedModel_LD1_MMDC1_Vol = {
DataObjectModelType, DataObjectModelType,
"Vol", "Vol",
@ -676,7 +715,7 @@ DataAttribute iedModel_LD1_MMDC1_Vol_subID = {
DataAttributeModelType, DataAttributeModelType,
"subID", "subID",
(ModelNode*) &iedModel_LD1_MMDC1_Vol, (ModelNode*) &iedModel_LD1_MMDC1_Vol,
NULL, (ModelNode*) &iedModel_LD1_MMDC1_Vol_blkEna,
NULL, NULL,
0, 0,
IEC61850_FC_SV, IEC61850_FC_SV,
@ -685,6 +724,19 @@ DataAttribute iedModel_LD1_MMDC1_Vol_subID = {
NULL, NULL,
0}; 0};
DataAttribute iedModel_LD1_MMDC1_Vol_blkEna = {
DataAttributeModelType,
"blkEna",
(ModelNode*) &iedModel_LD1_MMDC1_Vol,
NULL,
NULL,
0,
IEC61850_FC_BL,
IEC61850_BOOLEAN,
0,
NULL,
0};
LogicalNode iedModel_LD1_GGIO1 = { LogicalNode iedModel_LD1_GGIO1 = {
LogicalNodeModelType, LogicalNodeModelType,
"GGIO1", "GGIO1",
@ -832,7 +884,7 @@ DataAttribute iedModel_LD1_GGIO1_Ind1_subID = {
DataAttributeModelType, DataAttributeModelType,
"subID", "subID",
(ModelNode*) &iedModel_LD1_GGIO1_Ind1, (ModelNode*) &iedModel_LD1_GGIO1_Ind1,
NULL, (ModelNode*) &iedModel_LD1_GGIO1_Ind1_blkEna,
NULL, NULL,
0, 0,
IEC61850_FC_SV, IEC61850_FC_SV,
@ -841,6 +893,19 @@ DataAttribute iedModel_LD1_GGIO1_Ind1_subID = {
NULL, NULL,
0}; 0};
DataAttribute iedModel_LD1_GGIO1_Ind1_blkEna = {
DataAttributeModelType,
"blkEna",
(ModelNode*) &iedModel_LD1_GGIO1_Ind1,
NULL,
NULL,
0,
IEC61850_FC_BL,
IEC61850_BOOLEAN,
0,
NULL,
0};
DataObject iedModel_LD1_GGIO1_AnIn1 = { DataObject iedModel_LD1_GGIO1_AnIn1 = {
DataObjectModelType, DataObjectModelType,
"AnIn1", "AnIn1",
@ -958,7 +1023,7 @@ DataAttribute iedModel_LD1_GGIO1_AnIn1_subID = {
DataAttributeModelType, DataAttributeModelType,
"subID", "subID",
(ModelNode*) &iedModel_LD1_GGIO1_AnIn1, (ModelNode*) &iedModel_LD1_GGIO1_AnIn1,
NULL, (ModelNode*) &iedModel_LD1_GGIO1_AnIn1_blkEna,
NULL, NULL,
0, 0,
IEC61850_FC_SV, IEC61850_FC_SV,
@ -967,6 +1032,19 @@ DataAttribute iedModel_LD1_GGIO1_AnIn1_subID = {
NULL, NULL,
0}; 0};
DataAttribute iedModel_LD1_GGIO1_AnIn1_blkEna = {
DataAttributeModelType,
"blkEna",
(ModelNode*) &iedModel_LD1_GGIO1_AnIn1,
NULL,
NULL,
0,
IEC61850_FC_BL,
IEC61850_BOOLEAN,
0,
NULL,
0};
extern ReportControlBlock iedModel_LD1_LLN0_report0; extern ReportControlBlock iedModel_LD1_LLN0_report0;
extern ReportControlBlock iedModel_LD1_LLN0_report1; extern ReportControlBlock iedModel_LD1_LLN0_report1;

@ -1,7 +1,7 @@
/* /*
* static_model.h * static_model.h
* *
* automatically generated from substitution_example.icd * automatically generated from substitution_example.cid
*/ */
#ifndef STATIC_MODEL_H_ #ifndef STATIC_MODEL_H_
@ -32,6 +32,7 @@ extern DataAttribute iedModel_LD1_LPHD1_Proxy_subEna;
extern DataAttribute iedModel_LD1_LPHD1_Proxy_subVal; extern DataAttribute iedModel_LD1_LPHD1_Proxy_subVal;
extern DataAttribute iedModel_LD1_LPHD1_Proxy_subQ; extern DataAttribute iedModel_LD1_LPHD1_Proxy_subQ;
extern DataAttribute iedModel_LD1_LPHD1_Proxy_subID; extern DataAttribute iedModel_LD1_LPHD1_Proxy_subID;
extern DataAttribute iedModel_LD1_LPHD1_Proxy_blkEna;
extern LogicalNode iedModel_LD1_MMDC1; extern LogicalNode iedModel_LD1_MMDC1;
extern DataObject iedModel_LD1_MMDC1_Beh; extern DataObject iedModel_LD1_MMDC1_Beh;
extern DataAttribute iedModel_LD1_MMDC1_Beh_stVal; extern DataAttribute iedModel_LD1_MMDC1_Beh_stVal;
@ -47,6 +48,7 @@ extern DataAttribute iedModel_LD1_MMDC1_Watt_subMag;
extern DataAttribute iedModel_LD1_MMDC1_Watt_subMag_f; extern DataAttribute iedModel_LD1_MMDC1_Watt_subMag_f;
extern DataAttribute iedModel_LD1_MMDC1_Watt_subQ; extern DataAttribute iedModel_LD1_MMDC1_Watt_subQ;
extern DataAttribute iedModel_LD1_MMDC1_Watt_subID; extern DataAttribute iedModel_LD1_MMDC1_Watt_subID;
extern DataAttribute iedModel_LD1_MMDC1_Watt_blkEna;
extern DataObject iedModel_LD1_MMDC1_Amp; extern DataObject iedModel_LD1_MMDC1_Amp;
extern DataAttribute iedModel_LD1_MMDC1_Amp_mag; extern DataAttribute iedModel_LD1_MMDC1_Amp_mag;
extern DataAttribute iedModel_LD1_MMDC1_Amp_mag_f; extern DataAttribute iedModel_LD1_MMDC1_Amp_mag_f;
@ -57,6 +59,7 @@ extern DataAttribute iedModel_LD1_MMDC1_Amp_subMag;
extern DataAttribute iedModel_LD1_MMDC1_Amp_subMag_f; extern DataAttribute iedModel_LD1_MMDC1_Amp_subMag_f;
extern DataAttribute iedModel_LD1_MMDC1_Amp_subQ; extern DataAttribute iedModel_LD1_MMDC1_Amp_subQ;
extern DataAttribute iedModel_LD1_MMDC1_Amp_subID; extern DataAttribute iedModel_LD1_MMDC1_Amp_subID;
extern DataAttribute iedModel_LD1_MMDC1_Amp_blkEna;
extern DataObject iedModel_LD1_MMDC1_Vol; extern DataObject iedModel_LD1_MMDC1_Vol;
extern DataAttribute iedModel_LD1_MMDC1_Vol_mag; extern DataAttribute iedModel_LD1_MMDC1_Vol_mag;
extern DataAttribute iedModel_LD1_MMDC1_Vol_mag_f; extern DataAttribute iedModel_LD1_MMDC1_Vol_mag_f;
@ -67,6 +70,7 @@ extern DataAttribute iedModel_LD1_MMDC1_Vol_subMag;
extern DataAttribute iedModel_LD1_MMDC1_Vol_subMag_f; extern DataAttribute iedModel_LD1_MMDC1_Vol_subMag_f;
extern DataAttribute iedModel_LD1_MMDC1_Vol_subQ; extern DataAttribute iedModel_LD1_MMDC1_Vol_subQ;
extern DataAttribute iedModel_LD1_MMDC1_Vol_subID; extern DataAttribute iedModel_LD1_MMDC1_Vol_subID;
extern DataAttribute iedModel_LD1_MMDC1_Vol_blkEna;
extern LogicalNode iedModel_LD1_GGIO1; extern LogicalNode iedModel_LD1_GGIO1;
extern DataObject iedModel_LD1_GGIO1_Beh; extern DataObject iedModel_LD1_GGIO1_Beh;
extern DataAttribute iedModel_LD1_GGIO1_Beh_stVal; extern DataAttribute iedModel_LD1_GGIO1_Beh_stVal;
@ -80,6 +84,7 @@ extern DataAttribute iedModel_LD1_GGIO1_Ind1_subEna;
extern DataAttribute iedModel_LD1_GGIO1_Ind1_subVal; extern DataAttribute iedModel_LD1_GGIO1_Ind1_subVal;
extern DataAttribute iedModel_LD1_GGIO1_Ind1_subQ; extern DataAttribute iedModel_LD1_GGIO1_Ind1_subQ;
extern DataAttribute iedModel_LD1_GGIO1_Ind1_subID; extern DataAttribute iedModel_LD1_GGIO1_Ind1_subID;
extern DataAttribute iedModel_LD1_GGIO1_Ind1_blkEna;
extern DataObject iedModel_LD1_GGIO1_AnIn1; extern DataObject iedModel_LD1_GGIO1_AnIn1;
extern DataAttribute iedModel_LD1_GGIO1_AnIn1_mag; extern DataAttribute iedModel_LD1_GGIO1_AnIn1_mag;
extern DataAttribute iedModel_LD1_GGIO1_AnIn1_mag_f; extern DataAttribute iedModel_LD1_GGIO1_AnIn1_mag_f;
@ -90,6 +95,7 @@ extern DataAttribute iedModel_LD1_GGIO1_AnIn1_subMag;
extern DataAttribute iedModel_LD1_GGIO1_AnIn1_subMag_f; extern DataAttribute iedModel_LD1_GGIO1_AnIn1_subMag_f;
extern DataAttribute iedModel_LD1_GGIO1_AnIn1_subQ; extern DataAttribute iedModel_LD1_GGIO1_AnIn1_subQ;
extern DataAttribute iedModel_LD1_GGIO1_AnIn1_subID; extern DataAttribute iedModel_LD1_GGIO1_AnIn1_subID;
extern DataAttribute iedModel_LD1_GGIO1_AnIn1_blkEna;
@ -114,6 +120,7 @@ extern DataAttribute iedModel_LD1_GGIO1_AnIn1_subID;
#define IEDMODEL_LD1_LPHD1_Proxy_subVal (&iedModel_LD1_LPHD1_Proxy_subVal) #define IEDMODEL_LD1_LPHD1_Proxy_subVal (&iedModel_LD1_LPHD1_Proxy_subVal)
#define IEDMODEL_LD1_LPHD1_Proxy_subQ (&iedModel_LD1_LPHD1_Proxy_subQ) #define IEDMODEL_LD1_LPHD1_Proxy_subQ (&iedModel_LD1_LPHD1_Proxy_subQ)
#define IEDMODEL_LD1_LPHD1_Proxy_subID (&iedModel_LD1_LPHD1_Proxy_subID) #define IEDMODEL_LD1_LPHD1_Proxy_subID (&iedModel_LD1_LPHD1_Proxy_subID)
#define IEDMODEL_LD1_LPHD1_Proxy_blkEna (&iedModel_LD1_LPHD1_Proxy_blkEna)
#define IEDMODEL_LD1_MMDC1 (&iedModel_LD1_MMDC1) #define IEDMODEL_LD1_MMDC1 (&iedModel_LD1_MMDC1)
#define IEDMODEL_LD1_MMDC1_Beh (&iedModel_LD1_MMDC1_Beh) #define IEDMODEL_LD1_MMDC1_Beh (&iedModel_LD1_MMDC1_Beh)
#define IEDMODEL_LD1_MMDC1_Beh_stVal (&iedModel_LD1_MMDC1_Beh_stVal) #define IEDMODEL_LD1_MMDC1_Beh_stVal (&iedModel_LD1_MMDC1_Beh_stVal)
@ -129,6 +136,7 @@ extern DataAttribute iedModel_LD1_GGIO1_AnIn1_subID;
#define IEDMODEL_LD1_MMDC1_Watt_subMag_f (&iedModel_LD1_MMDC1_Watt_subMag_f) #define IEDMODEL_LD1_MMDC1_Watt_subMag_f (&iedModel_LD1_MMDC1_Watt_subMag_f)
#define IEDMODEL_LD1_MMDC1_Watt_subQ (&iedModel_LD1_MMDC1_Watt_subQ) #define IEDMODEL_LD1_MMDC1_Watt_subQ (&iedModel_LD1_MMDC1_Watt_subQ)
#define IEDMODEL_LD1_MMDC1_Watt_subID (&iedModel_LD1_MMDC1_Watt_subID) #define IEDMODEL_LD1_MMDC1_Watt_subID (&iedModel_LD1_MMDC1_Watt_subID)
#define IEDMODEL_LD1_MMDC1_Watt_blkEna (&iedModel_LD1_MMDC1_Watt_blkEna)
#define IEDMODEL_LD1_MMDC1_Amp (&iedModel_LD1_MMDC1_Amp) #define IEDMODEL_LD1_MMDC1_Amp (&iedModel_LD1_MMDC1_Amp)
#define IEDMODEL_LD1_MMDC1_Amp_mag (&iedModel_LD1_MMDC1_Amp_mag) #define IEDMODEL_LD1_MMDC1_Amp_mag (&iedModel_LD1_MMDC1_Amp_mag)
#define IEDMODEL_LD1_MMDC1_Amp_mag_f (&iedModel_LD1_MMDC1_Amp_mag_f) #define IEDMODEL_LD1_MMDC1_Amp_mag_f (&iedModel_LD1_MMDC1_Amp_mag_f)
@ -139,6 +147,7 @@ extern DataAttribute iedModel_LD1_GGIO1_AnIn1_subID;
#define IEDMODEL_LD1_MMDC1_Amp_subMag_f (&iedModel_LD1_MMDC1_Amp_subMag_f) #define IEDMODEL_LD1_MMDC1_Amp_subMag_f (&iedModel_LD1_MMDC1_Amp_subMag_f)
#define IEDMODEL_LD1_MMDC1_Amp_subQ (&iedModel_LD1_MMDC1_Amp_subQ) #define IEDMODEL_LD1_MMDC1_Amp_subQ (&iedModel_LD1_MMDC1_Amp_subQ)
#define IEDMODEL_LD1_MMDC1_Amp_subID (&iedModel_LD1_MMDC1_Amp_subID) #define IEDMODEL_LD1_MMDC1_Amp_subID (&iedModel_LD1_MMDC1_Amp_subID)
#define IEDMODEL_LD1_MMDC1_Amp_blkEna (&iedModel_LD1_MMDC1_Amp_blkEna)
#define IEDMODEL_LD1_MMDC1_Vol (&iedModel_LD1_MMDC1_Vol) #define IEDMODEL_LD1_MMDC1_Vol (&iedModel_LD1_MMDC1_Vol)
#define IEDMODEL_LD1_MMDC1_Vol_mag (&iedModel_LD1_MMDC1_Vol_mag) #define IEDMODEL_LD1_MMDC1_Vol_mag (&iedModel_LD1_MMDC1_Vol_mag)
#define IEDMODEL_LD1_MMDC1_Vol_mag_f (&iedModel_LD1_MMDC1_Vol_mag_f) #define IEDMODEL_LD1_MMDC1_Vol_mag_f (&iedModel_LD1_MMDC1_Vol_mag_f)
@ -149,6 +158,7 @@ extern DataAttribute iedModel_LD1_GGIO1_AnIn1_subID;
#define IEDMODEL_LD1_MMDC1_Vol_subMag_f (&iedModel_LD1_MMDC1_Vol_subMag_f) #define IEDMODEL_LD1_MMDC1_Vol_subMag_f (&iedModel_LD1_MMDC1_Vol_subMag_f)
#define IEDMODEL_LD1_MMDC1_Vol_subQ (&iedModel_LD1_MMDC1_Vol_subQ) #define IEDMODEL_LD1_MMDC1_Vol_subQ (&iedModel_LD1_MMDC1_Vol_subQ)
#define IEDMODEL_LD1_MMDC1_Vol_subID (&iedModel_LD1_MMDC1_Vol_subID) #define IEDMODEL_LD1_MMDC1_Vol_subID (&iedModel_LD1_MMDC1_Vol_subID)
#define IEDMODEL_LD1_MMDC1_Vol_blkEna (&iedModel_LD1_MMDC1_Vol_blkEna)
#define IEDMODEL_LD1_GGIO1 (&iedModel_LD1_GGIO1) #define IEDMODEL_LD1_GGIO1 (&iedModel_LD1_GGIO1)
#define IEDMODEL_LD1_GGIO1_Beh (&iedModel_LD1_GGIO1_Beh) #define IEDMODEL_LD1_GGIO1_Beh (&iedModel_LD1_GGIO1_Beh)
#define IEDMODEL_LD1_GGIO1_Beh_stVal (&iedModel_LD1_GGIO1_Beh_stVal) #define IEDMODEL_LD1_GGIO1_Beh_stVal (&iedModel_LD1_GGIO1_Beh_stVal)
@ -162,6 +172,7 @@ extern DataAttribute iedModel_LD1_GGIO1_AnIn1_subID;
#define IEDMODEL_LD1_GGIO1_Ind1_subVal (&iedModel_LD1_GGIO1_Ind1_subVal) #define IEDMODEL_LD1_GGIO1_Ind1_subVal (&iedModel_LD1_GGIO1_Ind1_subVal)
#define IEDMODEL_LD1_GGIO1_Ind1_subQ (&iedModel_LD1_GGIO1_Ind1_subQ) #define IEDMODEL_LD1_GGIO1_Ind1_subQ (&iedModel_LD1_GGIO1_Ind1_subQ)
#define IEDMODEL_LD1_GGIO1_Ind1_subID (&iedModel_LD1_GGIO1_Ind1_subID) #define IEDMODEL_LD1_GGIO1_Ind1_subID (&iedModel_LD1_GGIO1_Ind1_subID)
#define IEDMODEL_LD1_GGIO1_Ind1_blkEna (&iedModel_LD1_GGIO1_Ind1_blkEna)
#define IEDMODEL_LD1_GGIO1_AnIn1 (&iedModel_LD1_GGIO1_AnIn1) #define IEDMODEL_LD1_GGIO1_AnIn1 (&iedModel_LD1_GGIO1_AnIn1)
#define IEDMODEL_LD1_GGIO1_AnIn1_mag (&iedModel_LD1_GGIO1_AnIn1_mag) #define IEDMODEL_LD1_GGIO1_AnIn1_mag (&iedModel_LD1_GGIO1_AnIn1_mag)
#define IEDMODEL_LD1_GGIO1_AnIn1_mag_f (&iedModel_LD1_GGIO1_AnIn1_mag_f) #define IEDMODEL_LD1_GGIO1_AnIn1_mag_f (&iedModel_LD1_GGIO1_AnIn1_mag_f)
@ -172,6 +183,7 @@ extern DataAttribute iedModel_LD1_GGIO1_AnIn1_subID;
#define IEDMODEL_LD1_GGIO1_AnIn1_subMag_f (&iedModel_LD1_GGIO1_AnIn1_subMag_f) #define IEDMODEL_LD1_GGIO1_AnIn1_subMag_f (&iedModel_LD1_GGIO1_AnIn1_subMag_f)
#define IEDMODEL_LD1_GGIO1_AnIn1_subQ (&iedModel_LD1_GGIO1_AnIn1_subQ) #define IEDMODEL_LD1_GGIO1_AnIn1_subQ (&iedModel_LD1_GGIO1_AnIn1_subQ)
#define IEDMODEL_LD1_GGIO1_AnIn1_subID (&iedModel_LD1_GGIO1_AnIn1_subID) #define IEDMODEL_LD1_GGIO1_AnIn1_subID (&iedModel_LD1_GGIO1_AnIn1_subID)
#define IEDMODEL_LD1_GGIO1_AnIn1_blkEna (&iedModel_LD1_GGIO1_AnIn1_blkEna)
#endif /* STATIC_MODEL_H_ */ #endif /* STATIC_MODEL_H_ */

@ -99,6 +99,7 @@
<DA bType="BOOLEAN" fc="SV" name="subVal"/> <DA bType="BOOLEAN" fc="SV" name="subVal"/>
<DA bType="Quality" fc="SV" name="subQ"/> <DA bType="Quality" fc="SV" name="subQ"/>
<DA bType="VisString64" fc="SV" name="subID"/> <DA bType="VisString64" fc="SV" name="subID"/>
<DA bType="BOOLEAN" fc="BL" name="blkEna"/>
</DOType> </DOType>
<DOType cdc="MV" id="MV"> <DOType cdc="MV" id="MV">
<DA bType="Struct" dchg="true" dupd="false" fc="MX" name="mag" type="AnalogueValue"/> <DA bType="Struct" dchg="true" dupd="false" fc="MX" name="mag" type="AnalogueValue"/>
@ -108,6 +109,7 @@
<DA bType="Struct" fc="SV" name="subMag" type="AnalogueValue"/> <DA bType="Struct" fc="SV" name="subMag" type="AnalogueValue"/>
<DA bType="Quality" fc="SV" name="subQ"/> <DA bType="Quality" fc="SV" name="subQ"/>
<DA bType="VisString64" fc="SV" name="subID"/> <DA bType="VisString64" fc="SV" name="subID"/>
<DA bType="BOOLEAN" fc="BL" name="blkEna"/>
</DOType> </DOType>
<DAType id="AnalogueValue"> <DAType id="AnalogueValue">
<BDA bType="FLOAT32" name="f"/> <BDA bType="FLOAT32" name="f"/>

@ -151,8 +151,19 @@ UdpSocket_bind(UdpSocket self, const char* address, int port);
PAL_API bool PAL_API bool
UdpSocket_sendTo(UdpSocket self, const char* address, int port, uint8_t* msg, int msgSize); UdpSocket_sendTo(UdpSocket self, const char* address, int port, uint8_t* msg, int msgSize);
/**
* \brief Receive data from UDP socket (store data and (optionally) the IP address of the sender
*
* \param self UDP socket instance
* \param address (optional) buffer to store the IP address as string
* \param maxAddrSize (optional) size of the provided buffer to store the IP address
* \param msg buffer to store the UDP message data
* \param msgSize the maximum size of the message to receive
*
* \return number of received bytes or -1 in case of an error
*/
PAL_API int PAL_API int
UdpSocket_receiveFrom(UdpSocket self, char** address, int maxAddrSize, uint8_t* msg, int msgSize); UdpSocket_receiveFrom(UdpSocket self, char* address, int maxAddrSize, uint8_t* msg, int msgSize);
PAL_API void PAL_API void

@ -753,16 +753,43 @@ UdpSocket_sendTo(UdpSocket self, const char* address, int port, uint8_t* msg, in
} }
int int
UdpSocket_receiveFrom(UdpSocket self, char** address, int maxAddrSize, uint8_t* msg, int msgSize) UdpSocket_receiveFrom(UdpSocket self, char* address, int maxAddrSize, uint8_t* msg, int msgSize)
{ {
struct sockaddr_in remoteAddress; struct sockaddr_storage remoteAddress;
socklen_t structSize = sizeof(struct sockaddr_storage);
int result = recvfrom(self->fd, msg, msgSize, MSG_DONTWAIT, NULL, NULL); int result = recvfrom(self->fd, msg, msgSize, MSG_DONTWAIT, (struct sockaddr*)&remoteAddress, &structSize);
if (result == -1) { if (result == -1) {
if (DEBUG_SOCKET) if (DEBUG_SOCKET)
printf("SOCKET: failed to receive UDP message (errno=%i)\n", errno); printf("SOCKET: failed to receive UDP message (errno=%i)\n", errno);
} }
if (address) {
bool isIPv6;
char addrString[INET6_ADDRSTRLEN + 7];
int port;
if (remoteAddress.ss_family == AF_INET) {
struct sockaddr_in* ipv4Addr = (struct sockaddr_in*) &remoteAddress;
port = ntohs(ipv4Addr->sin_port);
inet_ntop(AF_INET, &(ipv4Addr->sin_addr), addrString, INET_ADDRSTRLEN);
isIPv6 = false;
}
else if (remoteAddress.ss_family == AF_INET6) {
struct sockaddr_in6* ipv6Addr = (struct sockaddr_in6*) &remoteAddress;
port = ntohs(ipv6Addr->sin6_port);
inet_ntop(AF_INET6, &(ipv6Addr->sin6_addr), addrString, INET6_ADDRSTRLEN);
isIPv6 = true;
}
else
return result ;
if (isIPv6)
snprintf(address, maxAddrSize, "[%s]:%i", addrString, port);
else
snprintf(address, maxAddrSize, "%s:%i", addrString, port);
}
return result; return result;
} }

@ -1,7 +1,7 @@
/* /*
* time.c * time.c
* *
* Copyright 2013, 2014 Michael Zillgith * Copyright 2013-2021 Michael Zillgith
* *
* This file is part of libIEC61850. * This file is part of libIEC61850.
* *

@ -523,14 +523,15 @@ ControlObjectClient_operate(ControlObjectClient self, MmsValue* ctlVal, uint64_t
MmsValue_update(self->ctlVal, ctlVal); MmsValue_update(self->ctlVal, ctlVal);
if (self->analogValue)
MmsValue_setElement(self->analogValue, 0, NULL);
self->opertime = operTime; self->opertime = operTime;
success = true; success = true;
exit_function: exit_function:
if (self->analogValue)
MmsValue_setElement(self->analogValue, 0, NULL);
return success; return success;
} }
@ -624,13 +625,14 @@ ControlObjectClient_operateAsync(ControlObjectClient self, IedClientError* err,
else { else {
MmsValue_update(self->ctlVal, ctlVal); MmsValue_update(self->ctlVal, ctlVal);
if (self->analogValue)
MmsValue_setElement(self->analogValue, 0, NULL);
self->opertime = operTime; self->opertime = operTime;
} }
exit_function: exit_function:
if (self->analogValue)
MmsValue_setElement(self->analogValue, 0, NULL);
return invokeId; return invokeId;
} }
@ -703,6 +705,8 @@ prepareSBOwParameters(ControlObjectClient self, MmsValue* ctlVal)
bool bool
ControlObjectClient_selectWithValue(ControlObjectClient self, MmsValue* ctlVal) ControlObjectClient_selectWithValue(ControlObjectClient self, MmsValue* ctlVal)
{ {
bool retVal = true;
resetLastApplError(self); resetLastApplError(self);
char domainId[65]; char domainId[65];
@ -741,22 +745,30 @@ ControlObjectClient_selectWithValue(ControlObjectClient self, MmsValue* ctlVal)
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");
return false;
retVal = false;
goto exit_function;
} }
else { else {
if (writeResult != DATA_ACCESS_ERROR_SUCCESS) { if (writeResult != DATA_ACCESS_ERROR_SUCCESS) {
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: select-with-value failed!\n"); printf("IED_CLIENT: select-with-value failed!\n");
return false;
retVal = false;
goto exit_function;
} }
} }
MmsValue_update(self->ctlVal, ctlVal); MmsValue_update(self->ctlVal, ctlVal);
exit_function:
if (self->analogValue) if (self->analogValue)
MmsValue_setElement(self->analogValue, 0, NULL); MmsValue_setElement(self->analogValue, 0, NULL);
return true; return retVal;
} }
static void static void
@ -857,12 +869,13 @@ ControlObjectClient_selectWithValueAsync(ControlObjectClient self, IedClientErro
} }
else { else {
MmsValue_update(self->ctlVal, ctlVal); MmsValue_update(self->ctlVal, ctlVal);
if (self->analogValue)
MmsValue_setElement(self->analogValue, 0, NULL);
} }
exit_function: exit_function:
if (self->analogValue)
MmsValue_setElement(self->analogValue, 0, NULL);
return invokeId; return invokeId;
} }

@ -473,8 +473,12 @@ handleLastApplErrorMessage(IedConnection self, MmsValue* lastApplError)
self->lastApplError.ctlNum = MmsValue_toUint32(ctlNum); self->lastApplError.ctlNum = MmsValue_toUint32(ctlNum);
self->lastApplError.addCause = (ControlAddCause) MmsValue_toInt32(addCause); self->lastApplError.addCause = (ControlAddCause) MmsValue_toInt32(addCause);
self->lastApplError.error = (ControlLastApplError) MmsValue_toInt32(error); self->lastApplError.error = (ControlLastApplError) MmsValue_toInt32(error);
Semaphore_wait(self->clientControlsLock);
LinkedList control = LinkedList_getNext(self->clientControls); LinkedList control = LinkedList_getNext(self->clientControls);
while (control != NULL) {
while (control) {
ControlObjectClient object = (ControlObjectClient) control->data; ControlObjectClient object = (ControlObjectClient) control->data;
const char* objectRef = ControlObjectClient_getObjectReference(object); const char* objectRef = ControlObjectClient_getObjectReference(object);
@ -485,6 +489,8 @@ handleLastApplErrorMessage(IedConnection self, MmsValue* lastApplError)
control = LinkedList_getNext(control); control = LinkedList_getNext(control);
} }
Semaphore_post(self->clientControlsLock);
} }
static void static void
@ -515,9 +521,11 @@ informationReportHandler(void* parameter, char* domainName,
if (DEBUG_IED_CLIENT) if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: RCVD CommandTermination for %s/%s\n", domainName, variableListName); printf("IED_CLIENT: RCVD CommandTermination for %s/%s\n", domainName, variableListName);
Semaphore_wait(self->clientControlsLock);
LinkedList control = LinkedList_getNext(self->clientControls); LinkedList control = LinkedList_getNext(self->clientControls);
while (control != NULL) { while (control) {
ControlObjectClient object = (ControlObjectClient) control->data; ControlObjectClient object = (ControlObjectClient) control->data;
const char* objectRef = ControlObjectClient_getObjectReference(object); const char* objectRef = ControlObjectClient_getObjectReference(object);
@ -527,6 +535,8 @@ informationReportHandler(void* parameter, char* domainName,
control = LinkedList_getNext(control); control = LinkedList_getNext(control);
} }
Semaphore_post(self->clientControlsLock);
} }
MmsValue_delete(value); MmsValue_delete(value);
@ -587,6 +597,7 @@ createNewConnectionObject(TLSConfiguration tlsConfig, bool useThreads)
if (self) { if (self) {
self->enabledReports = LinkedList_create(); self->enabledReports = LinkedList_create();
self->logicalDevices = NULL; self->logicalDevices = NULL;
self->clientControlsLock = Semaphore_create(1);
self->clientControls = LinkedList_create(); self->clientControls = LinkedList_create();
@ -812,6 +823,7 @@ IedConnection_destroy(IedConnection self)
LinkedList_destroyStatic(self->clientControls); LinkedList_destroyStatic(self->clientControls);
Semaphore_destroy(self->clientControlsLock);
Semaphore_destroy(self->outstandingCallsLock); Semaphore_destroy(self->outstandingCallsLock);
Semaphore_destroy(self->stateMutex); Semaphore_destroy(self->stateMutex);
Semaphore_destroy(self->reportHandlerMutex); Semaphore_destroy(self->reportHandlerMutex);
@ -3805,13 +3817,21 @@ IedConnection_getLastApplError(IedConnection self)
void void
iedConnection_addControlClient(IedConnection self, ControlObjectClient control) iedConnection_addControlClient(IedConnection self, ControlObjectClient control)
{ {
Semaphore_wait(self->clientControlsLock);
LinkedList_add(self->clientControls, control); LinkedList_add(self->clientControls, control);
Semaphore_post(self->clientControlsLock);
} }
void void
iedConnection_removeControlClient(IedConnection self, ControlObjectClient control) iedConnection_removeControlClient(IedConnection self, ControlObjectClient control)
{ {
Semaphore_wait(self->clientControlsLock);
LinkedList_remove(self->clientControls, control); LinkedList_remove(self->clientControls, control);
Semaphore_post(self->clientControlsLock);
} }
FileDirectoryEntry FileDirectoryEntry

@ -1957,14 +1957,32 @@ ControlObjectClient_createEx(const char* objectReference, IedConnection connecti
LIB61850_API void LIB61850_API void
ControlObjectClient_destroy(ControlObjectClient self); ControlObjectClient_destroy(ControlObjectClient self);
/**
* Cause of the \ref ControlObjectClient_ControlActionHandler invocation
*/
typedef enum typedef enum
{ {
CONTROL_ACTION_TYPE_SELECT = 0, CONTROL_ACTION_TYPE_SELECT = 0, /** < callback was invoked because of a select command */
CONTROL_ACTION_TYPE_OPERATE = 1, CONTROL_ACTION_TYPE_OPERATE = 1, /** < callback was invoked because of an operate command */
CONTROL_ACTION_TYPE_CANCEL = 2 CONTROL_ACTION_TYPE_CANCEL = 2 /** < callback was invoked because of a cancel command */
} ControlActionType; } ControlActionType;
/**
* \brief A callback handler that is invoked when a command termination message is received.
*
* This callback is invoked whenever a CommandTermination+ or CommandTermination- message is received.
* To distinguish between a CommandTermination+ and CommandTermination- please use the
* ControlObjectClient_getLastApplError function.
*
* NOTE: Do not call \ref ControlObjectClient_destroy inside of this callback! Doing so will cause a dead-lock.
*
* \param invokeId invoke ID of the command sent by the client
* \param parameter the user parameter that is passed to the callback function
* \param err the error code when an error occurred, or IED_ERROR_OK
* \param type control action type that caused the callback
* \param success true, when the command was successful, false otherwise
*
*/
typedef void typedef void
(*ControlObjectClient_ControlActionHandler) (uint32_t invokeId, void* parameter, IedClientError err, ControlActionType type, bool success); (*ControlObjectClient_ControlActionHandler) (uint32_t invokeId, void* parameter, IedClientError err, ControlActionType type, bool success);
@ -2196,7 +2214,7 @@ ControlObjectClient_setOrigin(ControlObjectClient self, const char* orIdent, int
* NOTE: Some non-standard compliant servers may require this to accept oper/cancel requests * NOTE: Some non-standard compliant servers may require this to accept oper/cancel requests
* *
* \param self the ControlObjectClient instance * \param self the ControlObjectClient instance
* \param useContantT enable this behaviour with true, disable with false * \param useContantT enable this behavior with true, disable with false
*/ */
LIB61850_API void LIB61850_API void
ControlObjectClient_useConstantT(ControlObjectClient self, bool useConstantT); ControlObjectClient_useConstantT(ControlObjectClient self, bool useConstantT);
@ -2233,13 +2251,15 @@ ControlObjectClient_setSynchroCheck(ControlObjectClient self, bool value);
/** /**
* \brief Private a callback handler that is invoked when a command termination message is received. * \brief A callback handler that is invoked when a command termination message is received.
* *
* This callback is invoked whenever a CommandTermination+ or CommandTermination- message is received. * This callback is invoked whenever a CommandTermination+ or CommandTermination- message is received.
* To distinguish between a CommandTermination+ and CommandTermination- please use the * To distinguish between a CommandTermination+ and CommandTermination- please use the
* ControlObjectClient_getLastApplError function. * ControlObjectClient_getLastApplError function.
* *
* \param parameter the user paramter that is passed to the callback function * NOTE: Do not call \ref ControlObjectClient_destroy inside of this callback! Doing so will cause a dead-lock.
*
* \param parameter the user parameter that is passed to the callback function
* \param controlClient the ControlObjectClient instance * \param controlClient the ControlObjectClient instance
*/ */
typedef void (*CommandTerminationHandler) (void* parameter, ControlObjectClient controlClient); typedef void (*CommandTerminationHandler) (void* parameter, ControlObjectClient controlClient);

@ -56,7 +56,10 @@ struct sIedConnection
IedConnectionState state; IedConnectionState state;
LinkedList enabledReports; LinkedList enabledReports;
LinkedList logicalDevices; LinkedList logicalDevices;
Semaphore clientControlsLock;
LinkedList clientControls; LinkedList clientControls;
LastApplError lastApplError; LastApplError lastApplError;
Semaphore stateMutex; Semaphore stateMutex;

@ -32,6 +32,7 @@
#define ALLOW_WRITE_ACCESS_SP 4 #define ALLOW_WRITE_ACCESS_SP 4
#define ALLOW_WRITE_ACCESS_SV 8 #define ALLOW_WRITE_ACCESS_SV 8
#define ALLOW_WRITE_ACCESS_SE 16 #define ALLOW_WRITE_ACCESS_SE 16
#define ALLOW_WRITE_ACCESS_BL 32
struct sIedServer struct sIedServer
{ {

@ -106,6 +106,8 @@ typedef struct {
ReportBuffer* reportBuffer; ReportBuffer* reportBuffer;
MmsValue* timeOfEntry; MmsValue* timeOfEntry;
ReportControlBlock* rcb;
IedServer server; IedServer server;
} ReportControl; } ReportControl;

@ -64,7 +64,7 @@ typedef struct
EditSettingGroupConfirmationHandler editSgConfirmedHandler; EditSettingGroupConfirmationHandler editSgConfirmedHandler;
void* editSgConfirmedHandlerParameter; void* editSgConfirmedHandlerParameter;
ClientConnection editingClient; MmsServerConnection editingClient;
uint64_t reservationTimeout; uint64_t reservationTimeout;
} SettingGroup; } SettingGroup;
@ -587,7 +587,7 @@ unselectAllSettingGroups(MmsMapping* self, MmsServerConnection serverCon)
while (settingGroupElement != NULL) { while (settingGroupElement != NULL) {
SettingGroup* settingGroup = (SettingGroup*) LinkedList_getData(settingGroupElement); SettingGroup* settingGroup = (SettingGroup*) LinkedList_getData(settingGroupElement);
if (settingGroup->editingClient == (ClientConnection) serverCon) if (settingGroup->editingClient == serverCon)
unselectEditSettingGroup(settingGroup); unselectEditSettingGroup(settingGroup);
settingGroupElement = LinkedList_getNext(settingGroupElement); settingGroupElement = LinkedList_getNext(settingGroupElement);
@ -2100,45 +2100,9 @@ isReportControlBlock(char* separator)
#endif /* (CONFIG_IEC61850_REPORT_SERVICE == 1) */ #endif /* (CONFIG_IEC61850_REPORT_SERVICE == 1) */
static bool static bool
isFunctionalConstraintCF(char* separator) isFunctionalConstraint(const char* fcStr, char* separator)
{ {
if (strncmp(separator + 1, "CF", 2) == 0) if (strncmp(separator + 1, fcStr, 2) == 0)
return true;
else
return false;
}
static bool
isFunctionalConstraintDC(char* separator)
{
if (strncmp(separator + 1, "DC", 2) == 0)
return true;
else
return false;
}
static bool
isFunctionalConstraintSP(char* separator)
{
if (strncmp(separator + 1, "SP", 2) == 0)
return true;
else
return false;
}
static bool
isFunctionalConstraintSV(char* separator)
{
if (strncmp(separator + 1, "SV", 2) == 0)
return true;
else
return false;
}
static bool
isFunctionalConstraintSE(char* separator)
{
if (strncmp(separator + 1, "SE", 2) == 0)
return true; return true;
else else
return false; return false;
@ -2445,16 +2409,18 @@ checkIfValueBelongsToModelNode(DataAttribute* dataAttribute, MmsValue* value, Mm
static FunctionalConstraint static FunctionalConstraint
getFunctionalConstraintForWritableNode(char* separator) getFunctionalConstraintForWritableNode(char* separator)
{ {
if (isFunctionalConstraintCF(separator)) if (isFunctionalConstraint("CF", separator))
return IEC61850_FC_CF; return IEC61850_FC_CF;
if (isFunctionalConstraintDC(separator)) if (isFunctionalConstraint("DC", separator))
return IEC61850_FC_DC; return IEC61850_FC_DC;
if (isFunctionalConstraintSP(separator)) if (isFunctionalConstraint("SP", separator))
return IEC61850_FC_SP; return IEC61850_FC_SP;
if (isFunctionalConstraintSV(separator)) if (isFunctionalConstraint("SV", separator))
return IEC61850_FC_SV; return IEC61850_FC_SV;
if (isFunctionalConstraintSE(separator)) if (isFunctionalConstraint("SE", separator))
return IEC61850_FC_SE; return IEC61850_FC_SE;
if (isFunctionalConstraint("BL", separator))
return IEC61850_FC_BL;
return IEC61850_FC_NONE; return IEC61850_FC_NONE;
} }
@ -2497,6 +2463,13 @@ getAccessPolicyForFC(MmsMapping* self, FunctionalConstraint fc)
return ACCESS_POLICY_DENY; return ACCESS_POLICY_DENY;
} }
if (fc == IEC61850_FC_BL) {
if (self->iedServer->writeAccessPolicies & ALLOW_WRITE_ACCESS_BL)
return ACCESS_POLICY_ALLOW;
else
return ACCESS_POLICY_DENY;
}
return ACCESS_POLICY_DENY; return ACCESS_POLICY_DENY;
} }
@ -2622,9 +2595,12 @@ mmsWriteHandler(void* parameter, MmsDomain* domain,
if ((val > 0) && (val <= sg->sgcb->numOfSGs)) { if ((val > 0) && (val <= sg->sgcb->numOfSGs)) {
if (val != sg->sgcb->actSG) { if (val != sg->sgcb->actSG) {
if (sg->actSgChangedHandler != NULL) { if (sg->actSgChangedHandler) {
ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, connection);
if (sg->actSgChangedHandler(sg->actSgChangedHandlerParameter, sg->sgcb, if (sg->actSgChangedHandler(sg->actSgChangedHandlerParameter, sg->sgcb,
(uint8_t) val, (ClientConnection) connection)) (uint8_t) val, clientConnection))
{ {
sg->sgcb->actSG = val; sg->sgcb->actSG = val;
@ -2634,7 +2610,6 @@ mmsWriteHandler(void* parameter, MmsDomain* domain,
MmsValue_setUint8(actSg, sg->sgcb->actSG); MmsValue_setUint8(actSg, sg->sgcb->actSG);
MmsValue_setUtcTimeMs(lActTm, Hal_getTimeInMs()); MmsValue_setUtcTimeMs(lActTm, Hal_getTimeInMs());
} }
else else
retVal = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED; retVal = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED;
} }
@ -2661,7 +2636,7 @@ mmsWriteHandler(void* parameter, MmsDomain* domain,
if (sg != NULL) { if (sg != NULL) {
uint32_t val = MmsValue_toUint32(value); uint32_t val = MmsValue_toUint32(value);
if ((sg->editingClient != NULL) && ( sg->editingClient != (ClientConnection) connection)) { if ((sg->editingClient != NULL) && ( sg->editingClient != connection)) {
/* Edit SG was set by other client */ /* Edit SG was set by other client */
retVal = DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE; retVal = DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE;
} }
@ -2674,13 +2649,15 @@ mmsWriteHandler(void* parameter, MmsDomain* domain,
if ((val > 0) && (val <= sg->sgcb->numOfSGs)) { if ((val > 0) && (val <= sg->sgcb->numOfSGs)) {
if (sg->editSgChangedHandler != NULL) { if (sg->editSgChangedHandler) {
ClientConnection clientConnection = private_IedServer_getClientConnectionByHandle(self->iedServer, connection);
if (sg->editSgChangedHandler(sg->editSgChangedHandlerParameter, sg->sgcb, if (sg->editSgChangedHandler(sg->editSgChangedHandlerParameter, sg->sgcb,
(uint8_t) val, (ClientConnection) connection)) (uint8_t) val, clientConnection))
{ {
sg->sgcb->editSG = val; sg->sgcb->editSG = val;
sg->editingClient = (ClientConnection) connection; sg->editingClient = connection;
sg->reservationTimeout = Hal_getTimeInMs() + (sg->sgcb->resvTms * 1000); sg->reservationTimeout = Hal_getTimeInMs() + (sg->sgcb->resvTms * 1000);
@ -2736,8 +2713,8 @@ mmsWriteHandler(void* parameter, MmsDomain* domain,
if (val == true) { if (val == true) {
if (sg->sgcb->editSG != 0) { if (sg->sgcb->editSG != 0) {
if (sg->editingClient == (ClientConnection) connection) { if (sg->editingClient == connection) {
if (sg->editSgConfirmedHandler != NULL) { if (sg->editSgConfirmedHandler) {
sg->editSgConfirmedHandler(sg->editSgConfirmedHandlerParameter, sg->sgcb, sg->editSgConfirmedHandler(sg->editSgConfirmedHandlerParameter, sg->sgcb,
sg->sgcb->editSG); sg->sgcb->editSG);
@ -2784,7 +2761,7 @@ mmsWriteHandler(void* parameter, MmsDomain* domain,
SettingGroup* sg = getSettingGroupByMmsDomain(self, domain); SettingGroup* sg = getSettingGroupByMmsDomain(self, domain);
if (sg != NULL) { if (sg != NULL) {
if (sg->editingClient != (ClientConnection) connection) if (sg->editingClient != connection)
return DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE; return DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE;
} }
else else
@ -2811,7 +2788,7 @@ mmsWriteHandler(void* parameter, MmsDomain* domain,
printf("IED_SERVER: write to %s policy:%i\n", variableId, nodeAccessPolicy); printf("IED_SERVER: write to %s policy:%i\n", variableId, nodeAccessPolicy);
#if (CONFIG_IEC61850_SETTING_GROUPS == 1) #if (CONFIG_IEC61850_SETTING_GROUPS == 1)
if (isFunctionalConstraintSE(separator)) { if (isFunctionalConstraint("SE", separator)) {
SettingGroup* sg = getSettingGroupByMmsDomain(self, domain); SettingGroup* sg = getSettingGroupByMmsDomain(self, domain);
if (sg != NULL) { if (sg != NULL) {
@ -3189,7 +3166,7 @@ mmsReadAccessHandler (void* parameter, MmsDomain* domain, char* variableId, MmsS
#if (CONFIG_IEC61850_SETTING_GROUPS == 1) #if (CONFIG_IEC61850_SETTING_GROUPS == 1)
if (separator) { if (separator) {
if (isFunctionalConstraintSE(separator)) { if (isFunctionalConstraint("SE", separator)) {
SettingGroup* sg = getSettingGroupByMmsDomain(self, domain); SettingGroup* sg = getSettingGroupByMmsDomain(self, domain);
if (sg != NULL) { if (sg != NULL) {

@ -40,7 +40,7 @@
#include <string.h> #include <string.h>
/* if not explicitly set by client "ResvTms" will be set to this value */ /* if not explicitly set by client "ResvTms" will be set to this value */
#define RESV_TMS_IMPLICIT_VALUE 30 #define RESV_TMS_IMPLICIT_VALUE 10
#ifndef DEBUG_IED_SERVER #ifndef DEBUG_IED_SERVER
#define DEBUG_IED_SERVER 0 #define DEBUG_IED_SERVER 0
@ -1345,6 +1345,8 @@ Reporting_createMmsBufferedRCBs(MmsMapping* self, MmsDomain* domain,
rc->name = StringUtils_createString(3, logicalNode->name, "$BR$", rc->name = StringUtils_createString(3, logicalNode->name, "$BR$",
reportControlBlock->name); reportControlBlock->name);
rc->rcb = reportControlBlock;
namedVariable->typeSpec.structure.elements[currentReport] = namedVariable->typeSpec.structure.elements[currentReport] =
createBufferedReportControlBlock(reportControlBlock, rc); createBufferedReportControlBlock(reportControlBlock, rc);
@ -1385,6 +1387,8 @@ Reporting_createMmsUnbufferedRCBs(MmsMapping* self, MmsDomain* domain,
rc->name = StringUtils_createString(3, logicalNode->name, "$RP$", rc->name = StringUtils_createString(3, logicalNode->name, "$RP$",
reportControlBlock->name); reportControlBlock->name);
rc->rcb = reportControlBlock;
namedVariable->typeSpec.structure.elements[currentReport] = namedVariable->typeSpec.structure.elements[currentReport] =
createUnbufferedReportControlBlock(reportControlBlock, rc); createUnbufferedReportControlBlock(reportControlBlock, rc);
@ -1472,8 +1476,19 @@ updateOwner(ReportControl* rc, MmsServerConnection connection)
} }
} }
else { else {
uint8_t emptyAddr[1]; if (rc->resvTms != -1) {
MmsValue_setOctetString(owner, emptyAddr, 0); uint8_t emptyAddr[1];
MmsValue_setOctetString(owner, emptyAddr, 0);
}
else {
/* Set to pre-configured owner */
if (rc->rcb->clientReservation[0] == 4) {
MmsValue_setOctetString(owner, rc->rcb->clientReservation + 1, 4);
}
else if (rc->rcb->clientReservation[0] == 6) {
MmsValue_setOctetString(owner, rc->rcb->clientReservation + 1, 16);
}
}
} }
} }
} }
@ -1539,9 +1554,14 @@ static void
checkReservationTimeout(MmsMapping* self, ReportControl* rc) checkReservationTimeout(MmsMapping* self, ReportControl* rc)
{ {
if (rc->enabled == false) { if (rc->enabled == false) {
if (rc->resvTms > 0) { if (rc->reservationTimeout > 0) {
if (Hal_getTimeInMs() > rc->reservationTimeout) { if (Hal_getTimeInMs() > rc->reservationTimeout) {
rc->resvTms = 0;
if (rc->resvTms != -1)
rc->resvTms = 0;
if (DEBUG_IED_SERVER)
printf("IED_SERVER: reservation timeout expired for %s.%s\n", rc->parentLN->name, rc->name);
#if (CONFIG_IEC61850_BRCB_WITH_RESVTMS == 1) #if (CONFIG_IEC61850_BRCB_WITH_RESVTMS == 1)
MmsValue* resvTmsVal = ReportControl_getRCBValue(rc, "ResvTms"); MmsValue* resvTmsVal = ReportControl_getRCBValue(rc, "ResvTms");
@ -1646,6 +1666,10 @@ Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* eleme
rc->reserved = true; rc->reserved = true;
rc->clientConnection = connection; rc->clientConnection = connection;
} }
else {
if (DEBUG_IED_SERVER)
printf("IED_SERVER: client IP not matching with pre-assigned owner\n");
}
#else #else
rc->reserved = true; rc->reserved = true;
rc->clientConnection = connection; rc->clientConnection = connection;
@ -1681,6 +1705,18 @@ Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* eleme
goto exit_function; goto exit_function;
} }
#if (CONFIG_IEC61850_RCB_ALLOW_ONLY_PRECONFIGURED_CLIENT == 1)
if (isIpAddressMatchingWithOwner(rc, MmsServerConnection_getClientAddress(connection)) == false) {
retVal = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED;
if (DEBUG_IED_SERVER)
printf("IED_SERVER: client IP not matching with pre-assigned owner --> write access denied!\n");
goto exit_function;
}
#endif
if (strcmp(elementName, "RptEna") == 0) { if (strcmp(elementName, "RptEna") == 0) {
if (value->value.boolean == true) { if (value->value.boolean == true) {
@ -1696,8 +1732,7 @@ Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* eleme
if (updateReportDataset(self, rc, NULL, connection)) { if (updateReportDataset(self, rc, NULL, connection)) {
if (rc->resvTms != -1) updateOwner(rc, connection);
updateOwner(rc, connection);
MmsValue* rptEna = ReportControl_getRCBValue(rc, "RptEna"); MmsValue* rptEna = ReportControl_getRCBValue(rc, "RptEna");
@ -1998,6 +2033,9 @@ exit_function:
reserveRcb(rc, connection); reserveRcb(rc, connection);
} }
else if (rc->resvTms == -1) {
reserveRcb(rc, connection);
}
} }
#if (CONFIG_IEC61850_SERVICE_TRACKING == 1) #if (CONFIG_IEC61850_SERVICE_TRACKING == 1)

@ -156,17 +156,30 @@ static void*
svReceiverLoop(void* threadParameter) svReceiverLoop(void* threadParameter)
{ {
SVReceiver self = (SVReceiver) threadParameter; SVReceiver self = (SVReceiver) threadParameter;
EthernetHandleSet handleSet = EthernetHandleSet_new();
EthernetHandleSet_addSocket(handleSet, self->ethSocket);
self->stopped = false; self->stopped = false;
while (self->running) { while (self->running) {
switch (EthernetHandleSet_waitReady(handleSet, 100))
{
case -1:
if (DEBUG_SV_SUBSCRIBER)
printf("SV_SUBSCRIBER: EhtnernetHandleSet_waitReady() failure\n");
break;
case 0:
break;
default:
SVReceiver_tick(self);
}
if (SVReceiver_tick(self) == false)
Thread_sleep(1);
} }
self->stopped = true; self->stopped = true;
EthernetHandleSet_destroy(handleSet);
return NULL; return NULL;
} }

Loading…
Cancel
Save