diff --git a/examples/server_example_substitution/server_example_substitution.c b/examples/server_example_substitution/server_example_substitution.c
index 0050f04f..2f41d892 100644
--- a/examples/server_example_substitution/server_example_substitution.c
+++ b/examples/server_example_substitution/server_example_substitution.c
@@ -2,7 +2,8 @@
* server_example_substitution.c
*
* - 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.Ind1
*/
@@ -24,6 +25,8 @@ static IedServer iedServer = NULL;
static bool subsAnIn1 = false;
static bool subsInd1 = false;
+static bool blkEnaAnIn1 = false;
+static bool blkEnaInd1 = false;
static float an1 = 0.f;
static uint64_t timestamp = 0;
@@ -35,7 +38,6 @@ sigint_handler(int signalId)
running = 0;
}
-
static void
connectionHandler (IedServer self, ClientConnection connection, bool connected, void* parameter)
{
@@ -54,13 +56,13 @@ updateProcessValues()
Timestamp_setTimeInMilliseconds(&iecTimestamp, timestamp);
Timestamp_setLeapSecondKnown(&iecTimestamp, true);
- if (subsAnIn1 == false) {
+ if ((subsAnIn1 == false) && (blkEnaAnIn1 == false)) {
IedServer_updateTimestampAttributeValue(iedServer, IEDMODEL_LD1_GGIO1_AnIn1_t, &iecTimestamp);
IedServer_updateQuality(iedServer, IEDMODEL_LD1_GGIO1_AnIn1_q, QUALITY_VALIDITY_GOOD);
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_updateQuality(iedServer, IEDMODEL_LD1_GGIO1_Ind1_q, QUALITY_VALIDITY_GOOD);
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) {
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;
}
@@ -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_subMag_f, 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_subVal, 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. */
IedServer_start(iedServer, 102);
@@ -225,6 +263,6 @@ main(int argc, char** argv)
/* Cleanup - free all resources */
IedServer_destroy(iedServer);
- return 0;
+ return 0;
} /* main() */
diff --git a/examples/server_example_substitution/static_model.c b/examples/server_example_substitution/static_model.c
index 0f8bff5d..c59ba0df 100644
--- a/examples/server_example_substitution/static_model.c
+++ b/examples/server_example_substitution/static_model.c
@@ -1,7 +1,7 @@
/*
* static_model.c
*
- * automatically generated from substitution_example.icd
+ * automatically generated from substitution_example.cid
*/
#include "static_model.h"
@@ -242,7 +242,7 @@ DataAttribute iedModel_LD1_LPHD1_Proxy_subID = {
DataAttributeModelType,
"subID",
(ModelNode*) &iedModel_LD1_LPHD1_Proxy,
- NULL,
+ (ModelNode*) &iedModel_LD1_LPHD1_Proxy_blkEna,
NULL,
0,
IEC61850_FC_SV,
@@ -251,6 +251,19 @@ DataAttribute iedModel_LD1_LPHD1_Proxy_subID = {
NULL,
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 = {
LogicalNodeModelType,
"MMDC1",
@@ -424,7 +437,7 @@ DataAttribute iedModel_LD1_MMDC1_Watt_subID = {
DataAttributeModelType,
"subID",
(ModelNode*) &iedModel_LD1_MMDC1_Watt,
- NULL,
+ (ModelNode*) &iedModel_LD1_MMDC1_Watt_blkEna,
NULL,
0,
IEC61850_FC_SV,
@@ -433,6 +446,19 @@ DataAttribute iedModel_LD1_MMDC1_Watt_subID = {
NULL,
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 = {
DataObjectModelType,
"Amp",
@@ -550,7 +576,7 @@ DataAttribute iedModel_LD1_MMDC1_Amp_subID = {
DataAttributeModelType,
"subID",
(ModelNode*) &iedModel_LD1_MMDC1_Amp,
- NULL,
+ (ModelNode*) &iedModel_LD1_MMDC1_Amp_blkEna,
NULL,
0,
IEC61850_FC_SV,
@@ -559,6 +585,19 @@ DataAttribute iedModel_LD1_MMDC1_Amp_subID = {
NULL,
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 = {
DataObjectModelType,
"Vol",
@@ -676,7 +715,7 @@ DataAttribute iedModel_LD1_MMDC1_Vol_subID = {
DataAttributeModelType,
"subID",
(ModelNode*) &iedModel_LD1_MMDC1_Vol,
- NULL,
+ (ModelNode*) &iedModel_LD1_MMDC1_Vol_blkEna,
NULL,
0,
IEC61850_FC_SV,
@@ -685,6 +724,19 @@ DataAttribute iedModel_LD1_MMDC1_Vol_subID = {
NULL,
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 = {
LogicalNodeModelType,
"GGIO1",
@@ -832,7 +884,7 @@ DataAttribute iedModel_LD1_GGIO1_Ind1_subID = {
DataAttributeModelType,
"subID",
(ModelNode*) &iedModel_LD1_GGIO1_Ind1,
- NULL,
+ (ModelNode*) &iedModel_LD1_GGIO1_Ind1_blkEna,
NULL,
0,
IEC61850_FC_SV,
@@ -841,6 +893,19 @@ DataAttribute iedModel_LD1_GGIO1_Ind1_subID = {
NULL,
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 = {
DataObjectModelType,
"AnIn1",
@@ -958,7 +1023,7 @@ DataAttribute iedModel_LD1_GGIO1_AnIn1_subID = {
DataAttributeModelType,
"subID",
(ModelNode*) &iedModel_LD1_GGIO1_AnIn1,
- NULL,
+ (ModelNode*) &iedModel_LD1_GGIO1_AnIn1_blkEna,
NULL,
0,
IEC61850_FC_SV,
@@ -967,6 +1032,19 @@ DataAttribute iedModel_LD1_GGIO1_AnIn1_subID = {
NULL,
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_report1;
diff --git a/examples/server_example_substitution/static_model.h b/examples/server_example_substitution/static_model.h
index 1ad6a5e4..55fc628a 100644
--- a/examples/server_example_substitution/static_model.h
+++ b/examples/server_example_substitution/static_model.h
@@ -1,7 +1,7 @@
/*
* static_model.h
*
- * automatically generated from substitution_example.icd
+ * automatically generated from substitution_example.cid
*/
#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_subQ;
extern DataAttribute iedModel_LD1_LPHD1_Proxy_subID;
+extern DataAttribute iedModel_LD1_LPHD1_Proxy_blkEna;
extern LogicalNode iedModel_LD1_MMDC1;
extern DataObject iedModel_LD1_MMDC1_Beh;
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_subQ;
extern DataAttribute iedModel_LD1_MMDC1_Watt_subID;
+extern DataAttribute iedModel_LD1_MMDC1_Watt_blkEna;
extern DataObject iedModel_LD1_MMDC1_Amp;
extern DataAttribute iedModel_LD1_MMDC1_Amp_mag;
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_subQ;
extern DataAttribute iedModel_LD1_MMDC1_Amp_subID;
+extern DataAttribute iedModel_LD1_MMDC1_Amp_blkEna;
extern DataObject iedModel_LD1_MMDC1_Vol;
extern DataAttribute iedModel_LD1_MMDC1_Vol_mag;
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_subQ;
extern DataAttribute iedModel_LD1_MMDC1_Vol_subID;
+extern DataAttribute iedModel_LD1_MMDC1_Vol_blkEna;
extern LogicalNode iedModel_LD1_GGIO1;
extern DataObject iedModel_LD1_GGIO1_Beh;
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_subQ;
extern DataAttribute iedModel_LD1_GGIO1_Ind1_subID;
+extern DataAttribute iedModel_LD1_GGIO1_Ind1_blkEna;
extern DataObject iedModel_LD1_GGIO1_AnIn1;
extern DataAttribute iedModel_LD1_GGIO1_AnIn1_mag;
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_subQ;
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_subQ (&iedModel_LD1_LPHD1_Proxy_subQ)
#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_Beh (&iedModel_LD1_MMDC1_Beh)
#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_subQ (&iedModel_LD1_MMDC1_Watt_subQ)
#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_mag (&iedModel_LD1_MMDC1_Amp_mag)
#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_subQ (&iedModel_LD1_MMDC1_Amp_subQ)
#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_mag (&iedModel_LD1_MMDC1_Vol_mag)
#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_subQ (&iedModel_LD1_MMDC1_Vol_subQ)
#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_Beh (&iedModel_LD1_GGIO1_Beh)
#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_subQ (&iedModel_LD1_GGIO1_Ind1_subQ)
#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_mag (&iedModel_LD1_GGIO1_AnIn1_mag)
#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_subQ (&iedModel_LD1_GGIO1_AnIn1_subQ)
#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_ */
diff --git a/examples/server_example_substitution/substitution_example.cid b/examples/server_example_substitution/substitution_example.cid
index 32d62c33..30ac3635 100644
--- a/examples/server_example_substitution/substitution_example.cid
+++ b/examples/server_example_substitution/substitution_example.cid
@@ -99,6 +99,7 @@
+
@@ -108,6 +109,7 @@
+
diff --git a/hal/inc/hal_socket.h b/hal/inc/hal_socket.h
index e52defb5..414a1a7e 100644
--- a/hal/inc/hal_socket.h
+++ b/hal/inc/hal_socket.h
@@ -151,8 +151,19 @@ UdpSocket_bind(UdpSocket self, const char* address, int port);
PAL_API bool
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
-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
diff --git a/hal/socket/linux/socket_linux.c b/hal/socket/linux/socket_linux.c
index dc9bbaeb..3c3b284c 100644
--- a/hal/socket/linux/socket_linux.c
+++ b/hal/socket/linux/socket_linux.c
@@ -753,16 +753,43 @@ UdpSocket_sendTo(UdpSocket self, const char* address, int port, uint8_t* msg, in
}
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 (DEBUG_SOCKET)
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;
}
diff --git a/hal/time/unix/time.c b/hal/time/unix/time.c
index 6565da33..5c1bffe7 100644
--- a/hal/time/unix/time.c
+++ b/hal/time/unix/time.c
@@ -1,7 +1,7 @@
/*
* time.c
*
- * Copyright 2013, 2014 Michael Zillgith
+ * Copyright 2013-2021 Michael Zillgith
*
* This file is part of libIEC61850.
*
diff --git a/src/iec61850/client/client_control.c b/src/iec61850/client/client_control.c
index 12b5669f..ad31648d 100644
--- a/src/iec61850/client/client_control.c
+++ b/src/iec61850/client/client_control.c
@@ -523,14 +523,15 @@ ControlObjectClient_operate(ControlObjectClient self, MmsValue* ctlVal, uint64_t
MmsValue_update(self->ctlVal, ctlVal);
- if (self->analogValue)
- MmsValue_setElement(self->analogValue, 0, NULL);
-
self->opertime = operTime;
success = true;
exit_function:
+
+ if (self->analogValue)
+ MmsValue_setElement(self->analogValue, 0, NULL);
+
return success;
}
@@ -624,13 +625,14 @@ ControlObjectClient_operateAsync(ControlObjectClient self, IedClientError* err,
else {
MmsValue_update(self->ctlVal, ctlVal);
- if (self->analogValue)
- MmsValue_setElement(self->analogValue, 0, NULL);
-
self->opertime = operTime;
}
exit_function:
+
+ if (self->analogValue)
+ MmsValue_setElement(self->analogValue, 0, NULL);
+
return invokeId;
}
@@ -703,6 +705,8 @@ prepareSBOwParameters(ControlObjectClient self, MmsValue* ctlVal)
bool
ControlObjectClient_selectWithValue(ControlObjectClient self, MmsValue* ctlVal)
{
+ bool retVal = true;
+
resetLastApplError(self);
char domainId[65];
@@ -741,22 +745,30 @@ ControlObjectClient_selectWithValue(ControlObjectClient self, MmsValue* ctlVal)
if (mmsError != MMS_ERROR_NONE) {
if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: select-with-value failed!\n");
- return false;
+
+ retVal = false;
+
+ goto exit_function;
}
else {
if (writeResult != DATA_ACCESS_ERROR_SUCCESS) {
if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: select-with-value failed!\n");
- return false;
+
+ retVal = false;
+
+ goto exit_function;
}
}
MmsValue_update(self->ctlVal, ctlVal);
+exit_function:
+
if (self->analogValue)
MmsValue_setElement(self->analogValue, 0, NULL);
- return true;
+ return retVal;
}
static void
@@ -857,12 +869,13 @@ ControlObjectClient_selectWithValueAsync(ControlObjectClient self, IedClientErro
}
else {
MmsValue_update(self->ctlVal, ctlVal);
-
- if (self->analogValue)
- MmsValue_setElement(self->analogValue, 0, NULL);
}
exit_function:
+
+ if (self->analogValue)
+ MmsValue_setElement(self->analogValue, 0, NULL);
+
return invokeId;
}
diff --git a/src/iec61850/client/ied_connection.c b/src/iec61850/client/ied_connection.c
index a055e7af..0e2da178 100644
--- a/src/iec61850/client/ied_connection.c
+++ b/src/iec61850/client/ied_connection.c
@@ -473,8 +473,12 @@ handleLastApplErrorMessage(IedConnection self, MmsValue* lastApplError)
self->lastApplError.ctlNum = MmsValue_toUint32(ctlNum);
self->lastApplError.addCause = (ControlAddCause) MmsValue_toInt32(addCause);
self->lastApplError.error = (ControlLastApplError) MmsValue_toInt32(error);
+
+ Semaphore_wait(self->clientControlsLock);
+
LinkedList control = LinkedList_getNext(self->clientControls);
- while (control != NULL) {
+
+ while (control) {
ControlObjectClient object = (ControlObjectClient) control->data;
const char* objectRef = ControlObjectClient_getObjectReference(object);
@@ -485,6 +489,8 @@ handleLastApplErrorMessage(IedConnection self, MmsValue* lastApplError)
control = LinkedList_getNext(control);
}
+
+ Semaphore_post(self->clientControlsLock);
}
static void
@@ -515,9 +521,11 @@ informationReportHandler(void* parameter, char* domainName,
if (DEBUG_IED_CLIENT)
printf("IED_CLIENT: RCVD CommandTermination for %s/%s\n", domainName, variableListName);
+ Semaphore_wait(self->clientControlsLock);
+
LinkedList control = LinkedList_getNext(self->clientControls);
- while (control != NULL) {
+ while (control) {
ControlObjectClient object = (ControlObjectClient) control->data;
const char* objectRef = ControlObjectClient_getObjectReference(object);
@@ -527,6 +535,8 @@ informationReportHandler(void* parameter, char* domainName,
control = LinkedList_getNext(control);
}
+
+ Semaphore_post(self->clientControlsLock);
}
MmsValue_delete(value);
@@ -587,6 +597,7 @@ createNewConnectionObject(TLSConfiguration tlsConfig, bool useThreads)
if (self) {
self->enabledReports = LinkedList_create();
self->logicalDevices = NULL;
+ self->clientControlsLock = Semaphore_create(1);
self->clientControls = LinkedList_create();
@@ -812,6 +823,7 @@ IedConnection_destroy(IedConnection self)
LinkedList_destroyStatic(self->clientControls);
+ Semaphore_destroy(self->clientControlsLock);
Semaphore_destroy(self->outstandingCallsLock);
Semaphore_destroy(self->stateMutex);
Semaphore_destroy(self->reportHandlerMutex);
@@ -3805,13 +3817,21 @@ IedConnection_getLastApplError(IedConnection self)
void
iedConnection_addControlClient(IedConnection self, ControlObjectClient control)
{
+ Semaphore_wait(self->clientControlsLock);
+
LinkedList_add(self->clientControls, control);
+
+ Semaphore_post(self->clientControlsLock);
}
void
iedConnection_removeControlClient(IedConnection self, ControlObjectClient control)
{
+ Semaphore_wait(self->clientControlsLock);
+
LinkedList_remove(self->clientControls, control);
+
+ Semaphore_post(self->clientControlsLock);
}
FileDirectoryEntry
diff --git a/src/iec61850/inc/iec61850_client.h b/src/iec61850/inc/iec61850_client.h
index bdc55a03..c5c51818 100644
--- a/src/iec61850/inc/iec61850_client.h
+++ b/src/iec61850/inc/iec61850_client.h
@@ -1957,14 +1957,32 @@ ControlObjectClient_createEx(const char* objectReference, IedConnection connecti
LIB61850_API void
ControlObjectClient_destroy(ControlObjectClient self);
+/**
+ * Cause of the \ref ControlObjectClient_ControlActionHandler invocation
+ */
typedef enum
{
- CONTROL_ACTION_TYPE_SELECT = 0,
- CONTROL_ACTION_TYPE_OPERATE = 1,
- CONTROL_ACTION_TYPE_CANCEL = 2
+ CONTROL_ACTION_TYPE_SELECT = 0, /** < callback was invoked because of a select command */
+ CONTROL_ACTION_TYPE_OPERATE = 1, /** < callback was invoked because of an operate command */
+ CONTROL_ACTION_TYPE_CANCEL = 2 /** < callback was invoked because of a cancel command */
} 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
(*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
*
* \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
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.
* To distinguish between a CommandTermination+ and CommandTermination- please use the
* 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
*/
typedef void (*CommandTerminationHandler) (void* parameter, ControlObjectClient controlClient);
diff --git a/src/iec61850/inc_private/ied_connection_private.h b/src/iec61850/inc_private/ied_connection_private.h
index 3b061b5b..5b7200ed 100644
--- a/src/iec61850/inc_private/ied_connection_private.h
+++ b/src/iec61850/inc_private/ied_connection_private.h
@@ -56,7 +56,10 @@ struct sIedConnection
IedConnectionState state;
LinkedList enabledReports;
LinkedList logicalDevices;
+
+ Semaphore clientControlsLock;
LinkedList clientControls;
+
LastApplError lastApplError;
Semaphore stateMutex;
diff --git a/src/iec61850/inc_private/ied_server_private.h b/src/iec61850/inc_private/ied_server_private.h
index 3d6aa3fd..6b1aad8a 100644
--- a/src/iec61850/inc_private/ied_server_private.h
+++ b/src/iec61850/inc_private/ied_server_private.h
@@ -32,6 +32,7 @@
#define ALLOW_WRITE_ACCESS_SP 4
#define ALLOW_WRITE_ACCESS_SV 8
#define ALLOW_WRITE_ACCESS_SE 16
+#define ALLOW_WRITE_ACCESS_BL 32
struct sIedServer
{
diff --git a/src/iec61850/inc_private/reporting.h b/src/iec61850/inc_private/reporting.h
index b6d0bb75..f57abdf1 100644
--- a/src/iec61850/inc_private/reporting.h
+++ b/src/iec61850/inc_private/reporting.h
@@ -106,6 +106,8 @@ typedef struct {
ReportBuffer* reportBuffer;
MmsValue* timeOfEntry;
+ ReportControlBlock* rcb;
+
IedServer server;
} ReportControl;
diff --git a/src/iec61850/server/mms_mapping/mms_mapping.c b/src/iec61850/server/mms_mapping/mms_mapping.c
index 86497ccf..7f74d3fc 100644
--- a/src/iec61850/server/mms_mapping/mms_mapping.c
+++ b/src/iec61850/server/mms_mapping/mms_mapping.c
@@ -64,7 +64,7 @@ typedef struct
EditSettingGroupConfirmationHandler editSgConfirmedHandler;
void* editSgConfirmedHandlerParameter;
- ClientConnection editingClient;
+ MmsServerConnection editingClient;
uint64_t reservationTimeout;
} SettingGroup;
@@ -587,7 +587,7 @@ unselectAllSettingGroups(MmsMapping* self, MmsServerConnection serverCon)
while (settingGroupElement != NULL) {
SettingGroup* settingGroup = (SettingGroup*) LinkedList_getData(settingGroupElement);
- if (settingGroup->editingClient == (ClientConnection) serverCon)
+ if (settingGroup->editingClient == serverCon)
unselectEditSettingGroup(settingGroup);
settingGroupElement = LinkedList_getNext(settingGroupElement);
@@ -2100,45 +2100,9 @@ isReportControlBlock(char* separator)
#endif /* (CONFIG_IEC61850_REPORT_SERVICE == 1) */
static bool
-isFunctionalConstraintCF(char* separator)
+isFunctionalConstraint(const char* fcStr, char* separator)
{
- if (strncmp(separator + 1, "CF", 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)
+ if (strncmp(separator + 1, fcStr, 2) == 0)
return true;
else
return false;
@@ -2445,16 +2409,18 @@ checkIfValueBelongsToModelNode(DataAttribute* dataAttribute, MmsValue* value, Mm
static FunctionalConstraint
getFunctionalConstraintForWritableNode(char* separator)
{
- if (isFunctionalConstraintCF(separator))
+ if (isFunctionalConstraint("CF", separator))
return IEC61850_FC_CF;
- if (isFunctionalConstraintDC(separator))
+ if (isFunctionalConstraint("DC", separator))
return IEC61850_FC_DC;
- if (isFunctionalConstraintSP(separator))
+ if (isFunctionalConstraint("SP", separator))
return IEC61850_FC_SP;
- if (isFunctionalConstraintSV(separator))
+ if (isFunctionalConstraint("SV", separator))
return IEC61850_FC_SV;
- if (isFunctionalConstraintSE(separator))
+ if (isFunctionalConstraint("SE", separator))
return IEC61850_FC_SE;
+ if (isFunctionalConstraint("BL", separator))
+ return IEC61850_FC_BL;
return IEC61850_FC_NONE;
}
@@ -2497,6 +2463,13 @@ getAccessPolicyForFC(MmsMapping* self, FunctionalConstraint fc)
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;
}
@@ -2622,9 +2595,12 @@ mmsWriteHandler(void* parameter, MmsDomain* domain,
if ((val > 0) && (val <= sg->sgcb->numOfSGs)) {
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,
- (uint8_t) val, (ClientConnection) connection))
+ (uint8_t) val, clientConnection))
{
sg->sgcb->actSG = val;
@@ -2634,7 +2610,6 @@ mmsWriteHandler(void* parameter, MmsDomain* domain,
MmsValue_setUint8(actSg, sg->sgcb->actSG);
MmsValue_setUtcTimeMs(lActTm, Hal_getTimeInMs());
}
-
else
retVal = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED;
}
@@ -2661,7 +2636,7 @@ mmsWriteHandler(void* parameter, MmsDomain* domain,
if (sg != NULL) {
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 */
retVal = DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE;
}
@@ -2674,13 +2649,15 @@ mmsWriteHandler(void* parameter, MmsDomain* domain,
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,
- (uint8_t) val, (ClientConnection) connection))
+ (uint8_t) val, clientConnection))
{
sg->sgcb->editSG = val;
- sg->editingClient = (ClientConnection) connection;
+ sg->editingClient = connection;
sg->reservationTimeout = Hal_getTimeInMs() + (sg->sgcb->resvTms * 1000);
@@ -2736,8 +2713,8 @@ mmsWriteHandler(void* parameter, MmsDomain* domain,
if (val == true) {
if (sg->sgcb->editSG != 0) {
- if (sg->editingClient == (ClientConnection) connection) {
- if (sg->editSgConfirmedHandler != NULL) {
+ if (sg->editingClient == connection) {
+ if (sg->editSgConfirmedHandler) {
sg->editSgConfirmedHandler(sg->editSgConfirmedHandlerParameter, sg->sgcb,
sg->sgcb->editSG);
@@ -2784,7 +2761,7 @@ mmsWriteHandler(void* parameter, MmsDomain* domain,
SettingGroup* sg = getSettingGroupByMmsDomain(self, domain);
if (sg != NULL) {
- if (sg->editingClient != (ClientConnection) connection)
+ if (sg->editingClient != connection)
return DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE;
}
else
@@ -2811,7 +2788,7 @@ mmsWriteHandler(void* parameter, MmsDomain* domain,
printf("IED_SERVER: write to %s policy:%i\n", variableId, nodeAccessPolicy);
#if (CONFIG_IEC61850_SETTING_GROUPS == 1)
- if (isFunctionalConstraintSE(separator)) {
+ if (isFunctionalConstraint("SE", separator)) {
SettingGroup* sg = getSettingGroupByMmsDomain(self, domain);
if (sg != NULL) {
@@ -3189,7 +3166,7 @@ mmsReadAccessHandler (void* parameter, MmsDomain* domain, char* variableId, MmsS
#if (CONFIG_IEC61850_SETTING_GROUPS == 1)
if (separator) {
- if (isFunctionalConstraintSE(separator)) {
+ if (isFunctionalConstraint("SE", separator)) {
SettingGroup* sg = getSettingGroupByMmsDomain(self, domain);
if (sg != NULL) {
diff --git a/src/iec61850/server/mms_mapping/reporting.c b/src/iec61850/server/mms_mapping/reporting.c
index 74398794..637f0503 100644
--- a/src/iec61850/server/mms_mapping/reporting.c
+++ b/src/iec61850/server/mms_mapping/reporting.c
@@ -40,7 +40,7 @@
#include
/* 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
#define DEBUG_IED_SERVER 0
@@ -1345,6 +1345,8 @@ Reporting_createMmsBufferedRCBs(MmsMapping* self, MmsDomain* domain,
rc->name = StringUtils_createString(3, logicalNode->name, "$BR$",
reportControlBlock->name);
+ rc->rcb = reportControlBlock;
+
namedVariable->typeSpec.structure.elements[currentReport] =
createBufferedReportControlBlock(reportControlBlock, rc);
@@ -1385,6 +1387,8 @@ Reporting_createMmsUnbufferedRCBs(MmsMapping* self, MmsDomain* domain,
rc->name = StringUtils_createString(3, logicalNode->name, "$RP$",
reportControlBlock->name);
+ rc->rcb = reportControlBlock;
+
namedVariable->typeSpec.structure.elements[currentReport] =
createUnbufferedReportControlBlock(reportControlBlock, rc);
@@ -1472,8 +1476,19 @@ updateOwner(ReportControl* rc, MmsServerConnection connection)
}
}
else {
- uint8_t emptyAddr[1];
- MmsValue_setOctetString(owner, emptyAddr, 0);
+ if (rc->resvTms != -1) {
+ 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)
{
if (rc->enabled == false) {
- if (rc->resvTms > 0) {
+ if (rc->reservationTimeout > 0) {
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)
MmsValue* resvTmsVal = ReportControl_getRCBValue(rc, "ResvTms");
@@ -1646,6 +1666,10 @@ Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* eleme
rc->reserved = true;
rc->clientConnection = connection;
}
+ else {
+ if (DEBUG_IED_SERVER)
+ printf("IED_SERVER: client IP not matching with pre-assigned owner\n");
+ }
#else
rc->reserved = true;
rc->clientConnection = connection;
@@ -1681,6 +1705,18 @@ Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* eleme
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 (value->value.boolean == true) {
@@ -1696,8 +1732,7 @@ Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* eleme
if (updateReportDataset(self, rc, NULL, connection)) {
- if (rc->resvTms != -1)
- updateOwner(rc, connection);
+ updateOwner(rc, connection);
MmsValue* rptEna = ReportControl_getRCBValue(rc, "RptEna");
@@ -1998,6 +2033,9 @@ exit_function:
reserveRcb(rc, connection);
}
+ else if (rc->resvTms == -1) {
+ reserveRcb(rc, connection);
+ }
}
#if (CONFIG_IEC61850_SERVICE_TRACKING == 1)
diff --git a/src/sampled_values/sv_subscriber.c b/src/sampled_values/sv_subscriber.c
index 950e803e..106430e0 100644
--- a/src/sampled_values/sv_subscriber.c
+++ b/src/sampled_values/sv_subscriber.c
@@ -156,17 +156,30 @@ static void*
svReceiverLoop(void* threadParameter)
{
SVReceiver self = (SVReceiver) threadParameter;
+ EthernetHandleSet handleSet = EthernetHandleSet_new();
+ EthernetHandleSet_addSocket(handleSet, self->ethSocket);
self->stopped = false;
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;
+ EthernetHandleSet_destroy(handleSet);
+
return NULL;
}