diff --git a/config/stack_config.h b/config/stack_config.h
index a3c419df..5512c57f 100644
--- a/config/stack_config.h
+++ b/config/stack_config.h
@@ -147,7 +147,10 @@
#define CONFIG_IEC61850_REPORT_SERVICE 1
/* support buffered report control blocks with ResvTms field */
-#define CONFIG_IEC61850_BRCB_WITH_RESVTMS 0
+#define CONFIG_IEC61850_BRCB_WITH_RESVTMS 1
+
+/* allow only configured clients (when pre-configured by ClientLN) - note behavior in PIXIT Rp13 */
+#define CONFIG_IEC61850_RCB_ALLOW_ONLY_PRECONFIGURED_CLIENT 0
/* The default buffer size of buffered RCBs in bytes */
#define CONFIG_REPORTING_DEFAULT_REPORT_BUFFER_SIZE 65536
diff --git a/config/stack_config.h.cmake b/config/stack_config.h.cmake
index b3fcadf7..9365b492 100644
--- a/config/stack_config.h.cmake
+++ b/config/stack_config.h.cmake
@@ -137,7 +137,10 @@
#cmakedefine01 CONFIG_IEC61850_REPORT_SERVICE
/* support buffered report control blocks with ResvTms field */
-#define CONFIG_IEC61850_BRCB_WITH_RESVTMS 0
+#define CONFIG_IEC61850_BRCB_WITH_RESVTMS 1
+
+/* allow only configured clients (when pre-configured by ClientLN) - note behavior in PIXIT Rp13 */
+#define CONFIG_IEC61850_RCB_ALLOW_ONLY_PRECONFIGURED_CLIENT 0
/* The default buffer size of buffered RCBs in bytes */
#cmakedefine CONFIG_REPORTING_DEFAULT_REPORT_BUFFER_SIZE @CONFIG_REPORTING_DEFAULT_REPORT_BUFFER_SIZE@
diff --git a/examples/mms_utility/mms_utility.c b/examples/mms_utility/mms_utility.c
index cb21460c..56ca03bd 100644
--- a/examples/mms_utility/mms_utility.c
+++ b/examples/mms_utility/mms_utility.c
@@ -104,7 +104,7 @@ int main(int argc, char** argv) {
char* hostname = StringUtils_copyString("localhost");
int tcpPort = 102;
int maxPduSize = 65000;
- int arrayIndex = -1;
+ int arrayIndex = -1;
char* domainName = NULL;
char* variableName = NULL;
diff --git a/examples/server_example_basic_io/server_example_basic_io.c b/examples/server_example_basic_io/server_example_basic_io.c
index cc73e912..98bcf49a 100644
--- a/examples/server_example_basic_io/server_example_basic_io.c
+++ b/examples/server_example_basic_io/server_example_basic_io.c
@@ -99,7 +99,7 @@ main(int argc, char** argv)
/* disable MMS file service */
IedServerConfig_enableFileService(config, false);
- /* disable dynamic data set service */
+ /* enable dynamic data set service */
IedServerConfig_enableDynamicDataSetService(config, true);
/* disable log service */
diff --git a/examples/server_example_basic_io/simpleIO_direct_control.cid b/examples/server_example_basic_io/simpleIO_direct_control.cid
index 554ed708..1bc0fabc 100644
--- a/examples/server_example_basic_io/simpleIO_direct_control.cid
+++ b/examples/server_example_basic_io/simpleIO_direct_control.cid
@@ -5,7 +5,6 @@
Station bus
- 10
0.0.0.0
@@ -19,6 +18,19 @@
102
+
+
+ 192.168.2.9
+ 255.255.255.0
+ 192.168.2.1
+ 1,3,9999,33
+ 33
+ 00000001
+ 0001
+ 0001
+ 102
+
+
@@ -31,6 +43,7 @@
+
@@ -68,19 +81,35 @@
-
+
-
-
+
+
-
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -198,10 +227,10 @@
-
-
-
-
+
+
+
+
@@ -257,7 +286,7 @@
-
+
@@ -266,6 +295,14 @@
+
+
+
+
+
+
+
+
diff --git a/examples/server_example_basic_io/simpleIO_direct_control.icd b/examples/server_example_basic_io/simpleIO_direct_control.icd
index a32282b9..258e9ae6 100644
--- a/examples/server_example_basic_io/simpleIO_direct_control.icd
+++ b/examples/server_example_basic_io/simpleIO_direct_control.icd
@@ -2,25 +2,7 @@
-
-
- Station bus
- 10
-
-
- 0.0.0.0
- 255.255.255.0
- 192.168.2.1
- 1,3,9999,33
- 33
- 00000001
- 0001
- 0001
- 102
-
-
-
-
+
@@ -79,12 +61,6 @@
-
-
-
-
-
-
@@ -198,10 +174,10 @@
-
-
-
-
+
+
+
+
@@ -257,7 +233,7 @@
-
+
@@ -266,6 +242,14 @@
+
+
+
+
+
+
+
+
diff --git a/examples/server_example_basic_io/static_model.c b/examples/server_example_basic_io/static_model.c
index f1d43ff8..276d60da 100644
--- a/examples/server_example_basic_io/static_model.c
+++ b/examples/server_example_basic_io/static_model.c
@@ -1280,62 +1280,10 @@ DataObject iedModel_GenericIO_GGIO1_SPCSO2 = {
"SPCSO2",
(ModelNode*) &iedModel_GenericIO_GGIO1,
(ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3,
- (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_origin,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_stVal,
0
};
-DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_origin = {
- DataAttributeModelType,
- "origin",
- (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2,
- (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_ctlNum,
- (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_origin_orCat,
- 0,
- IEC61850_FC_ST,
- IEC61850_CONSTRUCTED,
- 0,
- NULL,
- 0};
-
-DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_origin_orCat = {
- DataAttributeModelType,
- "orCat",
- (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_origin,
- (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_origin_orIdent,
- NULL,
- 0,
- IEC61850_FC_ST,
- IEC61850_ENUMERATED,
- 0,
- NULL,
- 0};
-
-DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_origin_orIdent = {
- DataAttributeModelType,
- "orIdent",
- (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_origin,
- NULL,
- NULL,
- 0,
- IEC61850_FC_ST,
- IEC61850_OCTET_STRING_64,
- 0,
- NULL,
- 0};
-
-DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_ctlNum = {
- DataAttributeModelType,
- "ctlNum",
- (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2,
- (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_stVal,
- NULL,
- 0,
- IEC61850_FC_ST,
- IEC61850_INT8U,
- 0,
- NULL,
- 0};
-
DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_stVal = {
DataAttributeModelType,
"stVal",
@@ -1353,7 +1301,7 @@ DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_q = {
DataAttributeModelType,
"q",
(ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2,
- (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_t,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper,
NULL,
0,
IEC61850_FC_ST,
@@ -1362,37 +1310,11 @@ DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_q = {
NULL,
0};
-DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_t = {
- DataAttributeModelType,
- "t",
- (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2,
- (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_ctlModel,
- NULL,
- 0,
- IEC61850_FC_ST,
- IEC61850_TIMESTAMP,
- 0,
- NULL,
- 0};
-
-DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_ctlModel = {
- DataAttributeModelType,
- "ctlModel",
- (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2,
- (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper,
- NULL,
- 0,
- IEC61850_FC_CF,
- IEC61850_ENUMERATED,
- 0,
- NULL,
- 0};
-
DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper = {
DataAttributeModelType,
"Oper",
(ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2,
- NULL,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_ctlModel,
(ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlVal,
0,
IEC61850_FC_CO,
@@ -1505,66 +1427,40 @@ DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_Check = {
NULL,
0};
-DataObject iedModel_GenericIO_GGIO1_SPCSO3 = {
- DataObjectModelType,
- "SPCSO3",
- (ModelNode*) &iedModel_GenericIO_GGIO1,
- (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4,
- (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_origin,
- 0
-};
-
-DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_origin = {
- DataAttributeModelType,
- "origin",
- (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3,
- (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_ctlNum,
- (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_origin_orCat,
- 0,
- IEC61850_FC_ST,
- IEC61850_CONSTRUCTED,
- 0,
- NULL,
- 0};
-
-DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_origin_orCat = {
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_ctlModel = {
DataAttributeModelType,
- "orCat",
- (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_origin,
- (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_origin_orIdent,
+ "ctlModel",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_t,
NULL,
0,
- IEC61850_FC_ST,
+ IEC61850_FC_CF,
IEC61850_ENUMERATED,
0,
NULL,
0};
-DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_origin_orIdent = {
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_t = {
DataAttributeModelType,
- "orIdent",
- (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_origin,
+ "t",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2,
NULL,
NULL,
0,
IEC61850_FC_ST,
- IEC61850_OCTET_STRING_64,
+ IEC61850_TIMESTAMP,
0,
NULL,
0};
-DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_ctlNum = {
- DataAttributeModelType,
- "ctlNum",
- (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3,
+DataObject iedModel_GenericIO_GGIO1_SPCSO3 = {
+ DataObjectModelType,
+ "SPCSO3",
+ (ModelNode*) &iedModel_GenericIO_GGIO1,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4,
(ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_stVal,
- NULL,
- 0,
- IEC61850_FC_ST,
- IEC61850_INT8U,
- 0,
- NULL,
- 0};
+ 0
+};
DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_stVal = {
DataAttributeModelType,
@@ -1583,7 +1479,7 @@ DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_q = {
DataAttributeModelType,
"q",
(ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3,
- (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_t,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper,
NULL,
0,
IEC61850_FC_ST,
@@ -1592,37 +1488,11 @@ DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_q = {
NULL,
0};
-DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_t = {
- DataAttributeModelType,
- "t",
- (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3,
- (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_ctlModel,
- NULL,
- 0,
- IEC61850_FC_ST,
- IEC61850_TIMESTAMP,
- 0,
- NULL,
- 0};
-
-DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_ctlModel = {
- DataAttributeModelType,
- "ctlModel",
- (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3,
- (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper,
- NULL,
- 0,
- IEC61850_FC_CF,
- IEC61850_ENUMERATED,
- 0,
- NULL,
- 0};
-
DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper = {
DataAttributeModelType,
"Oper",
(ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3,
- NULL,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_ctlModel,
(ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlVal,
0,
IEC61850_FC_CO,
@@ -1735,66 +1605,40 @@ DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_Check = {
NULL,
0};
-DataObject iedModel_GenericIO_GGIO1_SPCSO4 = {
- DataObjectModelType,
- "SPCSO4",
- (ModelNode*) &iedModel_GenericIO_GGIO1,
- (ModelNode*) &iedModel_GenericIO_GGIO1_Ind1,
- (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_origin,
- 0
-};
-
-DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_origin = {
- DataAttributeModelType,
- "origin",
- (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4,
- (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_ctlNum,
- (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_origin_orCat,
- 0,
- IEC61850_FC_ST,
- IEC61850_CONSTRUCTED,
- 0,
- NULL,
- 0};
-
-DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_origin_orCat = {
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_ctlModel = {
DataAttributeModelType,
- "orCat",
- (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_origin,
- (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_origin_orIdent,
+ "ctlModel",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_t,
NULL,
0,
- IEC61850_FC_ST,
+ IEC61850_FC_CF,
IEC61850_ENUMERATED,
0,
NULL,
0};
-DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_origin_orIdent = {
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_t = {
DataAttributeModelType,
- "orIdent",
- (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_origin,
+ "t",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3,
NULL,
NULL,
0,
IEC61850_FC_ST,
- IEC61850_OCTET_STRING_64,
+ IEC61850_TIMESTAMP,
0,
NULL,
0};
-DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_ctlNum = {
- DataAttributeModelType,
- "ctlNum",
- (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4,
+DataObject iedModel_GenericIO_GGIO1_SPCSO4 = {
+ DataObjectModelType,
+ "SPCSO4",
+ (ModelNode*) &iedModel_GenericIO_GGIO1,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_Ind1,
(ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_stVal,
- NULL,
- 0,
- IEC61850_FC_ST,
- IEC61850_INT8U,
- 0,
- NULL,
- 0};
+ 0
+};
DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_stVal = {
DataAttributeModelType,
@@ -1813,7 +1657,7 @@ DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_q = {
DataAttributeModelType,
"q",
(ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4,
- (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_t,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper,
NULL,
0,
IEC61850_FC_ST,
@@ -1822,37 +1666,11 @@ DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_q = {
NULL,
0};
-DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_t = {
- DataAttributeModelType,
- "t",
- (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4,
- (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_ctlModel,
- NULL,
- 0,
- IEC61850_FC_ST,
- IEC61850_TIMESTAMP,
- 0,
- NULL,
- 0};
-
-DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_ctlModel = {
- DataAttributeModelType,
- "ctlModel",
- (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4,
- (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper,
- NULL,
- 0,
- IEC61850_FC_CF,
- IEC61850_ENUMERATED,
- 0,
- NULL,
- 0};
-
DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper = {
DataAttributeModelType,
"Oper",
(ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4,
- NULL,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_ctlModel,
(ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlVal,
0,
IEC61850_FC_CO,
@@ -1965,6 +1783,32 @@ DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_Check = {
NULL,
0};
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_ctlModel = {
+ DataAttributeModelType,
+ "ctlModel",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_t,
+ NULL,
+ 0,
+ IEC61850_FC_CF,
+ IEC61850_ENUMERATED,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_t = {
+ DataAttributeModelType,
+ "t",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4,
+ NULL,
+ NULL,
+ 0,
+ IEC61850_FC_ST,
+ IEC61850_TIMESTAMP,
+ 0,
+ NULL,
+ 0};
+
DataObject iedModel_GenericIO_GGIO1_Ind1 = {
DataObjectModelType,
"Ind1",
@@ -2168,16 +2012,16 @@ extern ReportControlBlock iedModel_GenericIO_LLN0_report7;
extern ReportControlBlock iedModel_GenericIO_LLN0_report8;
extern ReportControlBlock iedModel_GenericIO_LLN0_report9;
-ReportControlBlock iedModel_GenericIO_LLN0_report0 = {&iedModel_GenericIO_LLN0, "EventsRCB01", "Events1", false, "Events", 4294967295, 24, 175, 50, 1000, &iedModel_GenericIO_LLN0_report1};
-ReportControlBlock iedModel_GenericIO_LLN0_report1 = {&iedModel_GenericIO_LLN0, "EventsIndexed01", "Events2", false, "Events", 1, 24, 175, 50, 1000, &iedModel_GenericIO_LLN0_report2};
-ReportControlBlock iedModel_GenericIO_LLN0_report2 = {&iedModel_GenericIO_LLN0, "EventsIndexed02", "Events2", false, "Events", 1, 24, 175, 50, 1000, &iedModel_GenericIO_LLN0_report3};
-ReportControlBlock iedModel_GenericIO_LLN0_report3 = {&iedModel_GenericIO_LLN0, "EventsIndexed03", "Events2", false, "Events", 1, 24, 175, 50, 1000, &iedModel_GenericIO_LLN0_report4};
-ReportControlBlock iedModel_GenericIO_LLN0_report4 = {&iedModel_GenericIO_LLN0, "Events201", "Events2", false, "Events2", 1, 24, 175, 50, 1000, &iedModel_GenericIO_LLN0_report5};
-ReportControlBlock iedModel_GenericIO_LLN0_report5 = {&iedModel_GenericIO_LLN0, "Events202", "Events2", false, "Events2", 1, 24, 175, 50, 1000, &iedModel_GenericIO_LLN0_report6};
-ReportControlBlock iedModel_GenericIO_LLN0_report6 = {&iedModel_GenericIO_LLN0, "Events203", "Events2", false, "Events2", 1, 24, 175, 50, 1000, &iedModel_GenericIO_LLN0_report7};
-ReportControlBlock iedModel_GenericIO_LLN0_report7 = {&iedModel_GenericIO_LLN0, "Measurements01", "Measurements", true, "Measurements", 1, 16, 239, 50, 1000, &iedModel_GenericIO_LLN0_report8};
-ReportControlBlock iedModel_GenericIO_LLN0_report8 = {&iedModel_GenericIO_LLN0, "Measurements02", "Measurements", true, "Measurements", 1, 16, 239, 50, 1000, &iedModel_GenericIO_LLN0_report9};
-ReportControlBlock iedModel_GenericIO_LLN0_report9 = {&iedModel_GenericIO_LLN0, "Measurements03", "Measurements", true, "Measurements", 1, 16, 239, 50, 1000, NULL};
+ReportControlBlock iedModel_GenericIO_LLN0_report0 = {&iedModel_GenericIO_LLN0, "EventsRCB01", "Events1", false, "Events", 1, 24, 175, 50, 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, "EventsRCBPreConf01", "Events1", false, "Events", 1, 24, 175, 50, 1000, {0x4, 0xc0, 0xa8, 0x2, 0x9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, &iedModel_GenericIO_LLN0_report2};
+ReportControlBlock iedModel_GenericIO_LLN0_report2 = {&iedModel_GenericIO_LLN0, "EventsBRCB01", "Events2", true, "Events", 1, 24, 175, 50, 1000, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, &iedModel_GenericIO_LLN0_report3};
+ReportControlBlock iedModel_GenericIO_LLN0_report3 = {&iedModel_GenericIO_LLN0, "EventsBRCBPreConf01", "Events2", true, "Events", 1, 24, 175, 50, 1000, {0x4, 0xc0, 0xa8, 0x2, 0x9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, &iedModel_GenericIO_LLN0_report4};
+ReportControlBlock iedModel_GenericIO_LLN0_report4 = {&iedModel_GenericIO_LLN0, "EventsIndexed01", "Events2", false, "Events", 1, 24, 175, 50, 1000, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, &iedModel_GenericIO_LLN0_report5};
+ReportControlBlock iedModel_GenericIO_LLN0_report5 = {&iedModel_GenericIO_LLN0, "EventsIndexed02", "Events2", false, "Events", 1, 24, 175, 50, 1000, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, &iedModel_GenericIO_LLN0_report6};
+ReportControlBlock iedModel_GenericIO_LLN0_report6 = {&iedModel_GenericIO_LLN0, "EventsIndexed03", "Events2", false, "Events", 1, 24, 175, 50, 1000, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, &iedModel_GenericIO_LLN0_report7};
+ReportControlBlock iedModel_GenericIO_LLN0_report7 = {&iedModel_GenericIO_LLN0, "Measurements01", "Measurements", true, "Measurements", 1, 16, 239, 50, 1000, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, &iedModel_GenericIO_LLN0_report8};
+ReportControlBlock iedModel_GenericIO_LLN0_report8 = {&iedModel_GenericIO_LLN0, "Measurements02", "Measurements", true, "Measurements", 1, 16, 239, 50, 1000, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, &iedModel_GenericIO_LLN0_report9};
+ReportControlBlock iedModel_GenericIO_LLN0_report9 = {&iedModel_GenericIO_LLN0, "Measurements03", "Measurements", true, "Measurements", 1, 16, 239, 50, 1000, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, NULL};
diff --git a/examples/server_example_basic_io/static_model.h b/examples/server_example_basic_io/static_model.h
index c03ed491..b6030e51 100644
--- a/examples/server_example_basic_io/static_model.h
+++ b/examples/server_example_basic_io/static_model.h
@@ -100,14 +100,8 @@ extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_T;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_Test;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_Check;
extern DataObject iedModel_GenericIO_GGIO1_SPCSO2;
-extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_origin;
-extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_origin_orCat;
-extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_origin_orIdent;
-extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_ctlNum;
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_ctlModel;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlVal;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin;
@@ -117,15 +111,11 @@ extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlNum;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_T;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_Test;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_Check;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_ctlModel;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_t;
extern DataObject iedModel_GenericIO_GGIO1_SPCSO3;
-extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_origin;
-extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_origin_orCat;
-extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_origin_orIdent;
-extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_ctlNum;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_stVal;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_q;
-extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_t;
-extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_ctlModel;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlVal;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin;
@@ -135,15 +125,11 @@ extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlNum;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_T;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_Test;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_Check;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_ctlModel;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_t;
extern DataObject iedModel_GenericIO_GGIO1_SPCSO4;
-extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_origin;
-extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_origin_orCat;
-extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_origin_orIdent;
-extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_ctlNum;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_stVal;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_q;
-extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_t;
-extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_ctlModel;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlVal;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin;
@@ -153,6 +139,8 @@ extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlNum;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_T;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_Test;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_Check;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_ctlModel;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_t;
extern DataObject iedModel_GenericIO_GGIO1_Ind1;
extern DataAttribute iedModel_GenericIO_GGIO1_Ind1_stVal;
extern DataAttribute iedModel_GenericIO_GGIO1_Ind1_q;
@@ -261,14 +249,8 @@ extern DataAttribute iedModel_GenericIO_GGIO1_Ind4_t;
#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_Test (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_Test)
#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_Check (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_Check)
#define IEDMODEL_GenericIO_GGIO1_SPCSO2 (&iedModel_GenericIO_GGIO1_SPCSO2)
-#define IEDMODEL_GenericIO_GGIO1_SPCSO2_origin (&iedModel_GenericIO_GGIO1_SPCSO2_origin)
-#define IEDMODEL_GenericIO_GGIO1_SPCSO2_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO2_origin_orCat)
-#define IEDMODEL_GenericIO_GGIO1_SPCSO2_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO2_origin_orIdent)
-#define IEDMODEL_GenericIO_GGIO1_SPCSO2_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO2_ctlNum)
#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_ctlModel (&iedModel_GenericIO_GGIO1_SPCSO2_ctlModel)
#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper (&iedModel_GenericIO_GGIO1_SPCSO2_Oper)
#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_ctlVal (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlVal)
#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_origin (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin)
@@ -278,15 +260,11 @@ extern DataAttribute iedModel_GenericIO_GGIO1_Ind4_t;
#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_T (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_T)
#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_Test (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_Test)
#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_Check (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_Check)
+#define IEDMODEL_GenericIO_GGIO1_SPCSO2_ctlModel (&iedModel_GenericIO_GGIO1_SPCSO2_ctlModel)
+#define IEDMODEL_GenericIO_GGIO1_SPCSO2_t (&iedModel_GenericIO_GGIO1_SPCSO2_t)
#define IEDMODEL_GenericIO_GGIO1_SPCSO3 (&iedModel_GenericIO_GGIO1_SPCSO3)
-#define IEDMODEL_GenericIO_GGIO1_SPCSO3_origin (&iedModel_GenericIO_GGIO1_SPCSO3_origin)
-#define IEDMODEL_GenericIO_GGIO1_SPCSO3_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO3_origin_orCat)
-#define IEDMODEL_GenericIO_GGIO1_SPCSO3_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO3_origin_orIdent)
-#define IEDMODEL_GenericIO_GGIO1_SPCSO3_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO3_ctlNum)
#define IEDMODEL_GenericIO_GGIO1_SPCSO3_stVal (&iedModel_GenericIO_GGIO1_SPCSO3_stVal)
#define IEDMODEL_GenericIO_GGIO1_SPCSO3_q (&iedModel_GenericIO_GGIO1_SPCSO3_q)
-#define IEDMODEL_GenericIO_GGIO1_SPCSO3_t (&iedModel_GenericIO_GGIO1_SPCSO3_t)
-#define IEDMODEL_GenericIO_GGIO1_SPCSO3_ctlModel (&iedModel_GenericIO_GGIO1_SPCSO3_ctlModel)
#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper (&iedModel_GenericIO_GGIO1_SPCSO3_Oper)
#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_ctlVal (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlVal)
#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_origin (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin)
@@ -296,15 +274,11 @@ extern DataAttribute iedModel_GenericIO_GGIO1_Ind4_t;
#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_T (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_T)
#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_Test (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_Test)
#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_Check (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_Check)
+#define IEDMODEL_GenericIO_GGIO1_SPCSO3_ctlModel (&iedModel_GenericIO_GGIO1_SPCSO3_ctlModel)
+#define IEDMODEL_GenericIO_GGIO1_SPCSO3_t (&iedModel_GenericIO_GGIO1_SPCSO3_t)
#define IEDMODEL_GenericIO_GGIO1_SPCSO4 (&iedModel_GenericIO_GGIO1_SPCSO4)
-#define IEDMODEL_GenericIO_GGIO1_SPCSO4_origin (&iedModel_GenericIO_GGIO1_SPCSO4_origin)
-#define IEDMODEL_GenericIO_GGIO1_SPCSO4_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO4_origin_orCat)
-#define IEDMODEL_GenericIO_GGIO1_SPCSO4_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO4_origin_orIdent)
-#define IEDMODEL_GenericIO_GGIO1_SPCSO4_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO4_ctlNum)
#define IEDMODEL_GenericIO_GGIO1_SPCSO4_stVal (&iedModel_GenericIO_GGIO1_SPCSO4_stVal)
#define IEDMODEL_GenericIO_GGIO1_SPCSO4_q (&iedModel_GenericIO_GGIO1_SPCSO4_q)
-#define IEDMODEL_GenericIO_GGIO1_SPCSO4_t (&iedModel_GenericIO_GGIO1_SPCSO4_t)
-#define IEDMODEL_GenericIO_GGIO1_SPCSO4_ctlModel (&iedModel_GenericIO_GGIO1_SPCSO4_ctlModel)
#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper (&iedModel_GenericIO_GGIO1_SPCSO4_Oper)
#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_ctlVal (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlVal)
#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_origin (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin)
@@ -314,6 +288,8 @@ extern DataAttribute iedModel_GenericIO_GGIO1_Ind4_t;
#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_T (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_T)
#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_Test (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_Test)
#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_Check (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_Check)
+#define IEDMODEL_GenericIO_GGIO1_SPCSO4_ctlModel (&iedModel_GenericIO_GGIO1_SPCSO4_ctlModel)
+#define IEDMODEL_GenericIO_GGIO1_SPCSO4_t (&iedModel_GenericIO_GGIO1_SPCSO4_t)
#define IEDMODEL_GenericIO_GGIO1_Ind1 (&iedModel_GenericIO_GGIO1_Ind1)
#define IEDMODEL_GenericIO_GGIO1_Ind1_stVal (&iedModel_GenericIO_GGIO1_Ind1_stVal)
#define IEDMODEL_GenericIO_GGIO1_Ind1_q (&iedModel_GenericIO_GGIO1_Ind1_q)
diff --git a/examples/server_example_control/simpleIO_control_tests.icd b/examples/server_example_control/simpleIO_control_tests.icd
index 6bfd88cd..4ff831ec 100644
--- a/examples/server_example_control/simpleIO_control_tests.icd
+++ b/examples/server_example_control/simpleIO_control_tests.icd
@@ -1,15 +1,13 @@
-
-
+
Station bus
- 10
- 10.0.0.2
+ 192.168.2.223
255.255.255.0
10.0.0.1
0001
@@ -29,10 +27,7 @@
-
-
-
diff --git a/examples/server_example_files/static_model.c b/examples/server_example_files/static_model.c
index 05926022..aaa714d3 100644
--- a/examples/server_example_files/static_model.c
+++ b/examples/server_example_files/static_model.c
@@ -1944,13 +1944,13 @@ extern ReportControlBlock iedModel_GenericIO_LLN0_report4;
extern ReportControlBlock iedModel_GenericIO_LLN0_report5;
extern ReportControlBlock iedModel_GenericIO_LLN0_report6;
-ReportControlBlock iedModel_GenericIO_LLN0_report0 = {&iedModel_GenericIO_LLN0, "EventsRCB01", "Events1", false, "Events", 4294967295, 24, 239, 50, 1000, &iedModel_GenericIO_LLN0_report1};
-ReportControlBlock iedModel_GenericIO_LLN0_report1 = {&iedModel_GenericIO_LLN0, "EventsIndexed01", "Events2", false, "Events", 1, 24, 239, 50, 1000, &iedModel_GenericIO_LLN0_report2};
-ReportControlBlock iedModel_GenericIO_LLN0_report2 = {&iedModel_GenericIO_LLN0, "EventsIndexed02", "Events2", false, "Events", 1, 24, 239, 50, 1000, &iedModel_GenericIO_LLN0_report3};
-ReportControlBlock iedModel_GenericIO_LLN0_report3 = {&iedModel_GenericIO_LLN0, "EventsIndexed03", "Events2", false, "Events", 1, 24, 239, 50, 1000, &iedModel_GenericIO_LLN0_report4};
-ReportControlBlock iedModel_GenericIO_LLN0_report4 = {&iedModel_GenericIO_LLN0, "Measurements01", "Measurements", true, "Measurements", 1, 16, 239, 50, 1000, &iedModel_GenericIO_LLN0_report5};
-ReportControlBlock iedModel_GenericIO_LLN0_report5 = {&iedModel_GenericIO_LLN0, "Measurements02", "Measurements", true, "Measurements", 1, 16, 239, 50, 1000, &iedModel_GenericIO_LLN0_report6};
-ReportControlBlock iedModel_GenericIO_LLN0_report6 = {&iedModel_GenericIO_LLN0, "Measurements03", "Measurements", true, "Measurements", 1, 16, 239, 50, 1000, NULL};
+ReportControlBlock iedModel_GenericIO_LLN0_report0 = {&iedModel_GenericIO_LLN0, "EventsRCB01", "Events1", false, "Events", 4294967295, 24, 239, 50, 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, "EventsIndexed01", "Events2", false, "Events", 1, 24, 239, 50, 1000, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, &iedModel_GenericIO_LLN0_report2};
+ReportControlBlock iedModel_GenericIO_LLN0_report2 = {&iedModel_GenericIO_LLN0, "EventsIndexed02", "Events2", false, "Events", 1, 24, 239, 50, 1000, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, &iedModel_GenericIO_LLN0_report3};
+ReportControlBlock iedModel_GenericIO_LLN0_report3 = {&iedModel_GenericIO_LLN0, "EventsIndexed03", "Events2", false, "Events", 1, 24, 239, 50, 1000, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, &iedModel_GenericIO_LLN0_report4};
+ReportControlBlock iedModel_GenericIO_LLN0_report4 = {&iedModel_GenericIO_LLN0, "Measurements01", "Measurements", true, "Measurements", 1, 16, 239, 50, 1000, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, &iedModel_GenericIO_LLN0_report5};
+ReportControlBlock iedModel_GenericIO_LLN0_report5 = {&iedModel_GenericIO_LLN0, "Measurements02", "Measurements", true, "Measurements", 1, 16, 239, 50, 1000, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, &iedModel_GenericIO_LLN0_report6};
+ReportControlBlock iedModel_GenericIO_LLN0_report6 = {&iedModel_GenericIO_LLN0, "Measurements03", "Measurements", true, "Measurements", 1, 16, 239, 50, 1000, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, NULL};
diff --git a/examples/server_example_goose/static_model.c b/examples/server_example_goose/static_model.c
index 4c3d6c97..bcc77426 100644
--- a/examples/server_example_goose/static_model.c
+++ b/examples/server_example_goose/static_model.c
@@ -1882,8 +1882,8 @@ DataAttribute iedModel_GenericIO_GGIO1_Ind4_t = {
extern ReportControlBlock iedModel_GenericIO_LLN0_report0;
extern ReportControlBlock iedModel_GenericIO_LLN0_report1;
-ReportControlBlock iedModel_GenericIO_LLN0_report0 = {&iedModel_GenericIO_LLN0, "EventsRCB01", "Events", false, "Events", 1, 24, 111, 50, 1000, &iedModel_GenericIO_LLN0_report1};
-ReportControlBlock iedModel_GenericIO_LLN0_report1 = {&iedModel_GenericIO_LLN0, "AnalogValuesRCB01", "AnalogValues", false, "AnalogValues", 1, 24, 111, 50, 1000, NULL};
+ReportControlBlock iedModel_GenericIO_LLN0_report0 = {&iedModel_GenericIO_LLN0, "EventsRCB01", "Events", false, "Events", 1, 24, 239, 50, 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, "AnalogValuesRCB01", "AnalogValues", false, "AnalogValues", 1, 24, 239, 50, 1000, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, NULL};
extern GSEControlBlock iedModel_GenericIO_LLN0_gse0;
diff --git a/examples/server_example_logging/static_model.c b/examples/server_example_logging/static_model.c
index 07b5b4a4..aaa714d3 100644
--- a/examples/server_example_logging/static_model.c
+++ b/examples/server_example_logging/static_model.c
@@ -1944,13 +1944,13 @@ extern ReportControlBlock iedModel_GenericIO_LLN0_report4;
extern ReportControlBlock iedModel_GenericIO_LLN0_report5;
extern ReportControlBlock iedModel_GenericIO_LLN0_report6;
-ReportControlBlock iedModel_GenericIO_LLN0_report0 = {&iedModel_GenericIO_LLN0, "EventsRCB01", "Events1", false, "Events", 4294967295, 24, 111, 50, 1000, &iedModel_GenericIO_LLN0_report1};
-ReportControlBlock iedModel_GenericIO_LLN0_report1 = {&iedModel_GenericIO_LLN0, "EventsIndexed01", "Events2", false, "Events", 1, 24, 111, 50, 1000, &iedModel_GenericIO_LLN0_report2};
-ReportControlBlock iedModel_GenericIO_LLN0_report2 = {&iedModel_GenericIO_LLN0, "EventsIndexed02", "Events2", false, "Events", 1, 24, 111, 50, 1000, &iedModel_GenericIO_LLN0_report3};
-ReportControlBlock iedModel_GenericIO_LLN0_report3 = {&iedModel_GenericIO_LLN0, "EventsIndexed03", "Events2", false, "Events", 1, 24, 111, 50, 1000, &iedModel_GenericIO_LLN0_report4};
-ReportControlBlock iedModel_GenericIO_LLN0_report4 = {&iedModel_GenericIO_LLN0, "Measurements01", "Measurements", true, "Measurements", 1, 16, 111, 50, 1000, &iedModel_GenericIO_LLN0_report5};
-ReportControlBlock iedModel_GenericIO_LLN0_report5 = {&iedModel_GenericIO_LLN0, "Measurements02", "Measurements", true, "Measurements", 1, 16, 111, 50, 1000, &iedModel_GenericIO_LLN0_report6};
-ReportControlBlock iedModel_GenericIO_LLN0_report6 = {&iedModel_GenericIO_LLN0, "Measurements03", "Measurements", true, "Measurements", 1, 16, 111, 50, 1000, NULL};
+ReportControlBlock iedModel_GenericIO_LLN0_report0 = {&iedModel_GenericIO_LLN0, "EventsRCB01", "Events1", false, "Events", 4294967295, 24, 239, 50, 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, "EventsIndexed01", "Events2", false, "Events", 1, 24, 239, 50, 1000, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, &iedModel_GenericIO_LLN0_report2};
+ReportControlBlock iedModel_GenericIO_LLN0_report2 = {&iedModel_GenericIO_LLN0, "EventsIndexed02", "Events2", false, "Events", 1, 24, 239, 50, 1000, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, &iedModel_GenericIO_LLN0_report3};
+ReportControlBlock iedModel_GenericIO_LLN0_report3 = {&iedModel_GenericIO_LLN0, "EventsIndexed03", "Events2", false, "Events", 1, 24, 239, 50, 1000, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, &iedModel_GenericIO_LLN0_report4};
+ReportControlBlock iedModel_GenericIO_LLN0_report4 = {&iedModel_GenericIO_LLN0, "Measurements01", "Measurements", true, "Measurements", 1, 16, 239, 50, 1000, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, &iedModel_GenericIO_LLN0_report5};
+ReportControlBlock iedModel_GenericIO_LLN0_report5 = {&iedModel_GenericIO_LLN0, "Measurements02", "Measurements", true, "Measurements", 1, 16, 239, 50, 1000, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, &iedModel_GenericIO_LLN0_report6};
+ReportControlBlock iedModel_GenericIO_LLN0_report6 = {&iedModel_GenericIO_LLN0, "Measurements03", "Measurements", true, "Measurements", 1, 16, 239, 50, 1000, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, NULL};
diff --git a/examples/server_example_password_auth/static_model.c b/examples/server_example_password_auth/static_model.c
index 4cc943c7..2763f623 100644
--- a/examples/server_example_password_auth/static_model.c
+++ b/examples/server_example_password_auth/static_model.c
@@ -1795,7 +1795,7 @@ DataAttribute iedModel_GenericIO_GGIO1_Ind4_t = {
extern ReportControlBlock iedModel_GenericIO_LLN0_report0;
-ReportControlBlock iedModel_GenericIO_LLN0_report0 = {&iedModel_GenericIO_LLN0, "EventsRCB01", "Events", false, "Events", 1, 24, 239, 50, 1000, NULL};
+ReportControlBlock iedModel_GenericIO_LLN0_report0 = {&iedModel_GenericIO_LLN0, "EventsRCB01", "Events", false, "Events", 1, 24, 239, 50, 1000, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, NULL};
diff --git a/examples/server_example_simple/static_model.c b/examples/server_example_simple/static_model.c
index 922e1c25..9e91626d 100644
--- a/examples/server_example_simple/static_model.c
+++ b/examples/server_example_simple/static_model.c
@@ -3,7 +3,7 @@
*
* automatically generated from sampleModel_with_dataset.icd
*/
-#include "../server_example_simple/static_model.h"
+#include "static_model.h"
static void initializeValues();
@@ -1590,7 +1590,7 @@ DataAttribute iedModel_Device1_MMXU2_TotW_t = {
extern ReportControlBlock iedModel_Device1_LLN0_report0;
-ReportControlBlock iedModel_Device1_LLN0_report0 = {&iedModel_Device1_LLN0, "LLN0_Events_BuffRep01", "LLN0$RP$brcbEV1", true, "dataset1", 1, 25, 239, 50, 900000, NULL};
+ReportControlBlock iedModel_Device1_LLN0_report0 = {&iedModel_Device1_LLN0, "LLN0_Events_BuffRep01", "LLN0$RP$brcbEV1", true, "dataset1", 1, 25, 239, 50, 900000, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, NULL};
diff --git a/examples/server_example_substitution/static_model.c b/examples/server_example_substitution/static_model.c
index bf53c61a..0f8bff5d 100644
--- a/examples/server_example_substitution/static_model.c
+++ b/examples/server_example_substitution/static_model.c
@@ -970,8 +970,8 @@ DataAttribute iedModel_LD1_GGIO1_AnIn1_subID = {
extern ReportControlBlock iedModel_LD1_LLN0_report0;
extern ReportControlBlock iedModel_LD1_LLN0_report1;
-ReportControlBlock iedModel_LD1_LLN0_report0 = {&iedModel_LD1_LLN0, "urcb01", "13e08c78", false, "", 1, 23, 247, 3000, 5000, &iedModel_LD1_LLN0_report1};
-ReportControlBlock iedModel_LD1_LLN0_report1 = {&iedModel_LD1_LLN0, "urcb02", "13e08c78", false, "", 1, 23, 247, 3000, 5000, NULL};
+ReportControlBlock iedModel_LD1_LLN0_report0 = {&iedModel_LD1_LLN0, "urcb01", "13e08c78", false, "", 1, 23, 247, 3000, 5000, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, &iedModel_LD1_LLN0_report1};
+ReportControlBlock iedModel_LD1_LLN0_report1 = {&iedModel_LD1_LLN0, "urcb02", "13e08c78", false, "", 1, 23, 247, 3000, 5000, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, NULL};
diff --git a/examples/server_example_threadless/static_model.c b/examples/server_example_threadless/static_model.c
index 4f37bdea..ae71aa57 100644
--- a/examples/server_example_threadless/static_model.c
+++ b/examples/server_example_threadless/static_model.c
@@ -1843,10 +1843,10 @@ extern ReportControlBlock iedModel_GenericIO_LLN0_report1;
extern ReportControlBlock iedModel_GenericIO_LLN0_report2;
extern ReportControlBlock iedModel_GenericIO_LLN0_report3;
-ReportControlBlock iedModel_GenericIO_LLN0_report0 = {&iedModel_GenericIO_LLN0, "EventsRCB01", "Events1", false, "Events", 1, 24, 111, 50, 1000, &iedModel_GenericIO_LLN0_report1};
-ReportControlBlock iedModel_GenericIO_LLN0_report1 = {&iedModel_GenericIO_LLN0, "EventsIndexed01", "Events2", false, "Events", 1, 24, 111, 50, 1000, &iedModel_GenericIO_LLN0_report2};
-ReportControlBlock iedModel_GenericIO_LLN0_report2 = {&iedModel_GenericIO_LLN0, "EventsIndexed02", "Events2", false, "Events", 1, 24, 111, 50, 1000, &iedModel_GenericIO_LLN0_report3};
-ReportControlBlock iedModel_GenericIO_LLN0_report3 = {&iedModel_GenericIO_LLN0, "EventsIndexed03", "Events2", false, "Events", 1, 24, 111, 50, 1000, NULL};
+ReportControlBlock iedModel_GenericIO_LLN0_report0 = {&iedModel_GenericIO_LLN0, "EventsRCB01", "Events1", false, "Events", 1, 24, 239, 50, 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, "EventsIndexed01", "Events2", false, "Events", 1, 24, 239, 50, 1000, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, &iedModel_GenericIO_LLN0_report2};
+ReportControlBlock iedModel_GenericIO_LLN0_report2 = {&iedModel_GenericIO_LLN0, "EventsIndexed02", "Events2", false, "Events", 1, 24, 239, 50, 1000, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, &iedModel_GenericIO_LLN0_report3};
+ReportControlBlock iedModel_GenericIO_LLN0_report3 = {&iedModel_GenericIO_LLN0, "EventsIndexed03", "Events2", false, "Events", 1, 24, 239, 50, 1000, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, NULL};
diff --git a/examples/server_example_write_handler/static_model.c b/examples/server_example_write_handler/static_model.c
index c0dba265..0cf385e4 100644
--- a/examples/server_example_write_handler/static_model.c
+++ b/examples/server_example_write_handler/static_model.c
@@ -3,7 +3,7 @@
*
* automatically generated from complexModel.icd
*/
-#include "../server_example_write_handler/static_model.h"
+#include "static_model.h"
static void initializeValues();
@@ -3580,7 +3580,7 @@ DataAttribute iedModel_Physical_Measurements_LPHD1_Proxy_t = {
extern ReportControlBlock iedModel_Inverter_LLN0_report0;
-ReportControlBlock iedModel_Inverter_LLN0_report0 = {&iedModel_Inverter_LLN0, "rcb101", "ID", false, "dataset1", 0, 19, 32, 0, 0, NULL};
+ReportControlBlock iedModel_Inverter_LLN0_report0 = {&iedModel_Inverter_LLN0, "rcb101", "ID", false, "dataset1", 0, 19, 32, 0, 0, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, NULL};
diff --git a/examples/tls_server_example/static_model.c b/examples/tls_server_example/static_model.c
index ddc8dd64..276d60da 100644
--- a/examples/tls_server_example/static_model.c
+++ b/examples/tls_server_example/static_model.c
@@ -1,9 +1,9 @@
/*
* static_model.c
*
- * automatically generated from simpleIO_direct_control.icd
+ * automatically generated from simpleIO_direct_control.cid
*/
-#include "../server_example_basic_io/static_model.h"
+#include "static_model.h"
static void initializeValues();
@@ -248,7 +248,7 @@ DataAttribute iedModel_GenericIO_LLN0_Mod_stVal = {
NULL,
0,
IEC61850_FC_ST,
- IEC61850_INT32,
+ IEC61850_ENUMERATED,
0 + TRG_OPT_DATA_CHANGED,
NULL,
0};
@@ -309,7 +309,7 @@ DataAttribute iedModel_GenericIO_LLN0_Beh_stVal = {
NULL,
0,
IEC61850_FC_ST,
- IEC61850_INT32,
+ IEC61850_ENUMERATED,
0 + TRG_OPT_DATA_CHANGED,
NULL,
0};
@@ -357,7 +357,7 @@ DataAttribute iedModel_GenericIO_LLN0_Health_stVal = {
NULL,
0,
IEC61850_FC_ST,
- IEC61850_INT32,
+ IEC61850_ENUMERATED,
0 + TRG_OPT_DATA_CHANGED,
NULL,
0};
@@ -509,7 +509,7 @@ DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_stVal = {
NULL,
0,
IEC61850_FC_ST,
- IEC61850_INT32,
+ IEC61850_ENUMERATED,
0 + TRG_OPT_DATA_CHANGED,
NULL,
0};
@@ -601,10 +601,23 @@ DataObject iedModel_GenericIO_GGIO1_Mod = {
"Mod",
(ModelNode*) &iedModel_GenericIO_GGIO1,
(ModelNode*) &iedModel_GenericIO_GGIO1_Beh,
- (ModelNode*) &iedModel_GenericIO_GGIO1_Mod_q,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_Mod_stVal,
0
};
+DataAttribute iedModel_GenericIO_GGIO1_Mod_stVal = {
+ DataAttributeModelType,
+ "stVal",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_Mod,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_Mod_q,
+ NULL,
+ 0,
+ IEC61850_FC_ST,
+ IEC61850_ENUMERATED,
+ 0 + TRG_OPT_DATA_CHANGED,
+ NULL,
+ 0};
+
DataAttribute iedModel_GenericIO_GGIO1_Mod_q = {
DataAttributeModelType,
"q",
@@ -661,7 +674,7 @@ DataAttribute iedModel_GenericIO_GGIO1_Beh_stVal = {
NULL,
0,
IEC61850_FC_ST,
- IEC61850_INT32,
+ IEC61850_ENUMERATED,
0 + TRG_OPT_DATA_CHANGED,
NULL,
0};
@@ -709,7 +722,7 @@ DataAttribute iedModel_GenericIO_GGIO1_Health_stVal = {
NULL,
0,
IEC61850_FC_ST,
- IEC61850_INT32,
+ IEC61850_ENUMERATED,
0 + TRG_OPT_DATA_CHANGED,
NULL,
0};
@@ -1037,10 +1050,62 @@ DataObject iedModel_GenericIO_GGIO1_SPCSO1 = {
"SPCSO1",
(ModelNode*) &iedModel_GenericIO_GGIO1,
(ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2,
- (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_stVal,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_origin,
0
};
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_origin = {
+ DataAttributeModelType,
+ "origin",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_ctlNum,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_origin_orCat,
+ 0,
+ IEC61850_FC_ST,
+ IEC61850_CONSTRUCTED,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_origin_orCat = {
+ DataAttributeModelType,
+ "orCat",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_origin,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_origin_orIdent,
+ NULL,
+ 0,
+ IEC61850_FC_ST,
+ IEC61850_ENUMERATED,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_origin_orIdent = {
+ DataAttributeModelType,
+ "orIdent",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_origin,
+ NULL,
+ NULL,
+ 0,
+ IEC61850_FC_ST,
+ IEC61850_OCTET_STRING_64,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_ctlNum = {
+ DataAttributeModelType,
+ "ctlNum",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_stVal,
+ NULL,
+ 0,
+ IEC61850_FC_ST,
+ IEC61850_INT8U,
+ 0,
+ NULL,
+ 0};
+
DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_stVal = {
DataAttributeModelType,
"stVal",
@@ -1058,7 +1123,7 @@ DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_q = {
DataAttributeModelType,
"q",
(ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1,
- (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_t,
NULL,
0,
IEC61850_FC_ST,
@@ -1067,11 +1132,37 @@ DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_q = {
NULL,
0};
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_t = {
+ DataAttributeModelType,
+ "t",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_ctlModel,
+ NULL,
+ 0,
+ IEC61850_FC_ST,
+ IEC61850_TIMESTAMP,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_ctlModel = {
+ DataAttributeModelType,
+ "ctlModel",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper,
+ NULL,
+ 0,
+ IEC61850_FC_CF,
+ IEC61850_ENUMERATED,
+ 0,
+ NULL,
+ 0};
+
DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper = {
DataAttributeModelType,
"Oper",
(ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1,
- (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_ctlModel,
+ NULL,
(ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlVal,
0,
IEC61850_FC_CO,
@@ -1184,32 +1275,6 @@ DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_Check = {
NULL,
0};
-DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_ctlModel = {
- DataAttributeModelType,
- "ctlModel",
- (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1,
- (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_t,
- NULL,
- 0,
- IEC61850_FC_CF,
- IEC61850_ENUMERATED,
- 0,
- NULL,
- 0};
-
-DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_t = {
- DataAttributeModelType,
- "t",
- (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1,
- NULL,
- NULL,
- 0,
- IEC61850_FC_ST,
- IEC61850_TIMESTAMP,
- 0,
- NULL,
- 0};
-
DataObject iedModel_GenericIO_GGIO1_SPCSO2 = {
DataObjectModelType,
"SPCSO2",
@@ -1943,27 +2008,25 @@ extern ReportControlBlock iedModel_GenericIO_LLN0_report3;
extern ReportControlBlock iedModel_GenericIO_LLN0_report4;
extern ReportControlBlock iedModel_GenericIO_LLN0_report5;
extern ReportControlBlock iedModel_GenericIO_LLN0_report6;
+extern ReportControlBlock iedModel_GenericIO_LLN0_report7;
+extern ReportControlBlock iedModel_GenericIO_LLN0_report8;
+extern ReportControlBlock iedModel_GenericIO_LLN0_report9;
-ReportControlBlock iedModel_GenericIO_LLN0_report0 = {&iedModel_GenericIO_LLN0, "EventsRCB01", "Events1", false, "Events", 4294967295, 24, 239, 50, 1000, &iedModel_GenericIO_LLN0_report1};
-ReportControlBlock iedModel_GenericIO_LLN0_report1 = {&iedModel_GenericIO_LLN0, "EventsIndexed01", "Events2", false, "Events", 1, 24, 239, 50, 1000, &iedModel_GenericIO_LLN0_report2};
-ReportControlBlock iedModel_GenericIO_LLN0_report2 = {&iedModel_GenericIO_LLN0, "EventsIndexed02", "Events2", false, "Events", 1, 24, 239, 50, 1000, &iedModel_GenericIO_LLN0_report3};
-ReportControlBlock iedModel_GenericIO_LLN0_report3 = {&iedModel_GenericIO_LLN0, "EventsIndexed03", "Events2", false, "Events", 1, 24, 239, 50, 1000, &iedModel_GenericIO_LLN0_report4};
-ReportControlBlock iedModel_GenericIO_LLN0_report4 = {&iedModel_GenericIO_LLN0, "Measurements01", "Measurements", true, "Measurements", 1, 16, 239, 50, 1000, &iedModel_GenericIO_LLN0_report5};
-ReportControlBlock iedModel_GenericIO_LLN0_report5 = {&iedModel_GenericIO_LLN0, "Measurements02", "Measurements", true, "Measurements", 1, 16, 239, 50, 1000, &iedModel_GenericIO_LLN0_report6};
-ReportControlBlock iedModel_GenericIO_LLN0_report6 = {&iedModel_GenericIO_LLN0, "Measurements03", "Measurements", true, "Measurements", 1, 16, 239, 50, 1000, NULL};
+ReportControlBlock iedModel_GenericIO_LLN0_report0 = {&iedModel_GenericIO_LLN0, "EventsRCB01", "Events1", false, "Events", 1, 24, 175, 50, 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, "EventsRCBPreConf01", "Events1", false, "Events", 1, 24, 175, 50, 1000, {0x4, 0xc0, 0xa8, 0x2, 0x9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, &iedModel_GenericIO_LLN0_report2};
+ReportControlBlock iedModel_GenericIO_LLN0_report2 = {&iedModel_GenericIO_LLN0, "EventsBRCB01", "Events2", true, "Events", 1, 24, 175, 50, 1000, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, &iedModel_GenericIO_LLN0_report3};
+ReportControlBlock iedModel_GenericIO_LLN0_report3 = {&iedModel_GenericIO_LLN0, "EventsBRCBPreConf01", "Events2", true, "Events", 1, 24, 175, 50, 1000, {0x4, 0xc0, 0xa8, 0x2, 0x9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, &iedModel_GenericIO_LLN0_report4};
+ReportControlBlock iedModel_GenericIO_LLN0_report4 = {&iedModel_GenericIO_LLN0, "EventsIndexed01", "Events2", false, "Events", 1, 24, 175, 50, 1000, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, &iedModel_GenericIO_LLN0_report5};
+ReportControlBlock iedModel_GenericIO_LLN0_report5 = {&iedModel_GenericIO_LLN0, "EventsIndexed02", "Events2", false, "Events", 1, 24, 175, 50, 1000, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, &iedModel_GenericIO_LLN0_report6};
+ReportControlBlock iedModel_GenericIO_LLN0_report6 = {&iedModel_GenericIO_LLN0, "EventsIndexed03", "Events2", false, "Events", 1, 24, 175, 50, 1000, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, &iedModel_GenericIO_LLN0_report7};
+ReportControlBlock iedModel_GenericIO_LLN0_report7 = {&iedModel_GenericIO_LLN0, "Measurements01", "Measurements", true, "Measurements", 1, 16, 239, 50, 1000, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, &iedModel_GenericIO_LLN0_report8};
+ReportControlBlock iedModel_GenericIO_LLN0_report8 = {&iedModel_GenericIO_LLN0, "Measurements02", "Measurements", true, "Measurements", 1, 16, 239, 50, 1000, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, &iedModel_GenericIO_LLN0_report9};
+ReportControlBlock iedModel_GenericIO_LLN0_report9 = {&iedModel_GenericIO_LLN0, "Measurements03", "Measurements", true, "Measurements", 1, 16, 239, 50, 1000, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, NULL};
-extern LogControlBlock iedModel_GenericIO_LLN0_lcb0;
-extern LogControlBlock iedModel_GenericIO_LLN0_lcb1;
-LogControlBlock iedModel_GenericIO_LLN0_lcb0 = {&iedModel_GenericIO_LLN0, "EventLog", "Events", "GenericIO/LLN0$EventLog", 3, 0, true, true, &iedModel_GenericIO_LLN0_lcb1};
-LogControlBlock iedModel_GenericIO_LLN0_lcb1 = {&iedModel_GenericIO_LLN0, "GeneralLog", NULL, NULL, 3, 0, true, true, NULL};
-extern Log iedModel_GenericIO_LLN0_log0;
-extern Log iedModel_GenericIO_LLN0_log1;
-Log iedModel_GenericIO_LLN0_log0 = {&iedModel_GenericIO_LLN0, "GeneralLog", &iedModel_GenericIO_LLN0_log1};
-Log iedModel_GenericIO_LLN0_log1 = {&iedModel_GenericIO_LLN0, "EventLog", NULL};
IedModel iedModel = {
@@ -1974,8 +2037,8 @@ IedModel iedModel = {
NULL,
NULL,
NULL,
- &iedModel_GenericIO_LLN0_lcb0,
- &iedModel_GenericIO_LLN0_log0,
+ NULL,
+ NULL,
initializeValues
};
@@ -1983,16 +2046,30 @@ static void
initializeValues()
{
+iedModel_GenericIO_LLN0_Mod_stVal.mmsValue = MmsValue_newIntegerFromInt32(1);
+
iedModel_GenericIO_LLN0_Mod_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(0);
+iedModel_GenericIO_LLN0_Beh_stVal.mmsValue = MmsValue_newIntegerFromInt32(1);
+
+iedModel_GenericIO_LLN0_Health_stVal.mmsValue = MmsValue_newIntegerFromInt32(1);
+
iedModel_GenericIO_LLN0_NamPlt_vendor.mmsValue = MmsValue_newVisibleString("MZ Automation");
-iedModel_GenericIO_LLN0_NamPlt_swRev.mmsValue = MmsValue_newVisibleString("0.7.3");
+iedModel_GenericIO_LLN0_NamPlt_swRev.mmsValue = MmsValue_newVisibleString("1.3.0");
iedModel_GenericIO_LLN0_NamPlt_d.mmsValue = MmsValue_newVisibleString("libiec61850 server example");
+iedModel_GenericIO_LPHD1_PhyHealth_stVal.mmsValue = MmsValue_newIntegerFromInt32(1);
+
+iedModel_GenericIO_GGIO1_Mod_stVal.mmsValue = MmsValue_newIntegerFromInt32(1);
+
iedModel_GenericIO_GGIO1_Mod_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(0);
+iedModel_GenericIO_GGIO1_Beh_stVal.mmsValue = MmsValue_newIntegerFromInt32(1);
+
+iedModel_GenericIO_GGIO1_Health_stVal.mmsValue = MmsValue_newIntegerFromInt32(1);
+
iedModel_GenericIO_GGIO1_SPCSO1_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(1);
iedModel_GenericIO_GGIO1_SPCSO2_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(1);
diff --git a/examples/tls_server_example/static_model.h b/examples/tls_server_example/static_model.h
index b5670e9f..b6030e51 100644
--- a/examples/tls_server_example/static_model.h
+++ b/examples/tls_server_example/static_model.h
@@ -1,7 +1,7 @@
/*
* static_model.h
*
- * automatically generated from simpleIO_direct_control.icd
+ * automatically generated from simpleIO_direct_control.cid
*/
#ifndef STATIC_MODEL_H_
@@ -45,6 +45,7 @@ extern DataAttribute iedModel_GenericIO_LPHD1_Proxy_q;
extern DataAttribute iedModel_GenericIO_LPHD1_Proxy_t;
extern LogicalNode iedModel_GenericIO_GGIO1;
extern DataObject iedModel_GenericIO_GGIO1_Mod;
+extern DataAttribute iedModel_GenericIO_GGIO1_Mod_stVal;
extern DataAttribute iedModel_GenericIO_GGIO1_Mod_q;
extern DataAttribute iedModel_GenericIO_GGIO1_Mod_t;
extern DataAttribute iedModel_GenericIO_GGIO1_Mod_ctlModel;
@@ -81,8 +82,14 @@ extern DataAttribute iedModel_GenericIO_GGIO1_AnIn4_mag_f;
extern DataAttribute iedModel_GenericIO_GGIO1_AnIn4_q;
extern DataAttribute iedModel_GenericIO_GGIO1_AnIn4_t;
extern DataObject iedModel_GenericIO_GGIO1_SPCSO1;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_origin;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_origin_orCat;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_origin_orIdent;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_ctlNum;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_stVal;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_q;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_t;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_ctlModel;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlVal;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin;
@@ -92,8 +99,6 @@ extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlNum;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_T;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_Test;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_Check;
-extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_ctlModel;
-extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_t;
extern DataObject iedModel_GenericIO_GGIO1_SPCSO2;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_stVal;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_q;
@@ -189,6 +194,7 @@ extern DataAttribute iedModel_GenericIO_GGIO1_Ind4_t;
#define IEDMODEL_GenericIO_LPHD1_Proxy_t (&iedModel_GenericIO_LPHD1_Proxy_t)
#define IEDMODEL_GenericIO_GGIO1 (&iedModel_GenericIO_GGIO1)
#define IEDMODEL_GenericIO_GGIO1_Mod (&iedModel_GenericIO_GGIO1_Mod)
+#define IEDMODEL_GenericIO_GGIO1_Mod_stVal (&iedModel_GenericIO_GGIO1_Mod_stVal)
#define IEDMODEL_GenericIO_GGIO1_Mod_q (&iedModel_GenericIO_GGIO1_Mod_q)
#define IEDMODEL_GenericIO_GGIO1_Mod_t (&iedModel_GenericIO_GGIO1_Mod_t)
#define IEDMODEL_GenericIO_GGIO1_Mod_ctlModel (&iedModel_GenericIO_GGIO1_Mod_ctlModel)
@@ -225,8 +231,14 @@ extern DataAttribute iedModel_GenericIO_GGIO1_Ind4_t;
#define IEDMODEL_GenericIO_GGIO1_AnIn4_q (&iedModel_GenericIO_GGIO1_AnIn4_q)
#define IEDMODEL_GenericIO_GGIO1_AnIn4_t (&iedModel_GenericIO_GGIO1_AnIn4_t)
#define IEDMODEL_GenericIO_GGIO1_SPCSO1 (&iedModel_GenericIO_GGIO1_SPCSO1)
+#define IEDMODEL_GenericIO_GGIO1_SPCSO1_origin (&iedModel_GenericIO_GGIO1_SPCSO1_origin)
+#define IEDMODEL_GenericIO_GGIO1_SPCSO1_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO1_origin_orCat)
+#define IEDMODEL_GenericIO_GGIO1_SPCSO1_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO1_origin_orIdent)
+#define IEDMODEL_GenericIO_GGIO1_SPCSO1_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO1_ctlNum)
#define IEDMODEL_GenericIO_GGIO1_SPCSO1_stVal (&iedModel_GenericIO_GGIO1_SPCSO1_stVal)
#define IEDMODEL_GenericIO_GGIO1_SPCSO1_q (&iedModel_GenericIO_GGIO1_SPCSO1_q)
+#define IEDMODEL_GenericIO_GGIO1_SPCSO1_t (&iedModel_GenericIO_GGIO1_SPCSO1_t)
+#define IEDMODEL_GenericIO_GGIO1_SPCSO1_ctlModel (&iedModel_GenericIO_GGIO1_SPCSO1_ctlModel)
#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper (&iedModel_GenericIO_GGIO1_SPCSO1_Oper)
#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_ctlVal (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlVal)
#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_origin (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin)
@@ -236,8 +248,6 @@ extern DataAttribute iedModel_GenericIO_GGIO1_Ind4_t;
#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_T (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_T)
#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_Test (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_Test)
#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_Check (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_Check)
-#define IEDMODEL_GenericIO_GGIO1_SPCSO1_ctlModel (&iedModel_GenericIO_GGIO1_SPCSO1_ctlModel)
-#define IEDMODEL_GenericIO_GGIO1_SPCSO1_t (&iedModel_GenericIO_GGIO1_SPCSO1_t)
#define IEDMODEL_GenericIO_GGIO1_SPCSO2 (&iedModel_GenericIO_GGIO1_SPCSO2)
#define IEDMODEL_GenericIO_GGIO1_SPCSO2_stVal (&iedModel_GenericIO_GGIO1_SPCSO2_stVal)
#define IEDMODEL_GenericIO_GGIO1_SPCSO2_q (&iedModel_GenericIO_GGIO1_SPCSO2_q)
diff --git a/hal/socket/bsd/socket_bsd.c b/hal/socket/bsd/socket_bsd.c
index d53df7ac..c1dd339e 100644
--- a/hal/socket/bsd/socket_bsd.c
+++ b/hal/socket/bsd/socket_bsd.c
@@ -442,8 +442,12 @@ Socket_write(Socket self, uint8_t* buf, int size)
if (self->fd == -1)
return -1;
- // MSG_NOSIGNAL - prevent send to signal SIGPIPE when peer unexpectedly closed the socket
- return send(self->fd, buf, size, 0);
+ int retVal = send(self->fd, buf, size, 0);
+
+ if ((retVal == -1) && (errno == EAGAIN))
+ return 0;
+ else
+ return retVal;
}
void
diff --git a/hal/socket/linux/socket_linux.c b/hal/socket/linux/socket_linux.c
index 2a45294a..01c497cc 100644
--- a/hal/socket/linux/socket_linux.c
+++ b/hal/socket/linux/socket_linux.c
@@ -532,7 +532,12 @@ Socket_write(Socket self, uint8_t* buf, int size)
return -1;
/* MSG_NOSIGNAL - prevent send to signal SIGPIPE when peer unexpectedly closed the socket */
- return send(self->fd, buf, size, MSG_NOSIGNAL);
+ int retVal = send(self->fd, buf, size, MSG_NOSIGNAL);
+
+ if ((retVal == -1) && (errno == EAGAIN))
+ return 0;
+ else
+ return retVal;
}
void
diff --git a/hal/thread/bsd/thread_bsd.c b/hal/thread/bsd/thread_bsd.c
index 7d882d22..23ed9512 100644
--- a/hal/thread/bsd/thread_bsd.c
+++ b/hal/thread/bsd/thread_bsd.c
@@ -39,9 +39,9 @@ struct sThread {
Semaphore
Semaphore_create(int initialValue)
{
- char tmpname[] = {"/tmp/libiec61850.XXXXXX"};
- mktemp(tmpname);
- Semaphore self = sem_open(tmpname, O_CREAT, 0666, initialValue);
+ Semaphore self = GLOBAL_MALLOC(sizeof(sem_t));
+
+ sem_init((sem_t*) self, 0, initialValue);
return self;
}
diff --git a/src/common/inc/string_utilities.h b/src/common/inc/string_utilities.h
index 428a5bab..ed0ffe6c 100644
--- a/src/common/inc/string_utilities.h
+++ b/src/common/inc/string_utilities.h
@@ -122,7 +122,7 @@ StringUtils_sortList(LinkedList list);
*
* \return true when parsing has been successful, false otherwise
*/
-bool
+LIB61850_INTERNAL bool
StringUtils_convertIPv6AdddressStringToByteArray(const char* addressString, uint8_t ipV6Addr[]);
#ifdef __cplusplus
diff --git a/src/goose/goose_receiver.c b/src/goose/goose_receiver.c
index b833e04e..1985ee8c 100644
--- a/src/goose/goose_receiver.c
+++ b/src/goose/goose_receiver.c
@@ -48,7 +48,7 @@
struct sGooseReceiver
{
bool running;
- bool stopped;
+ bool stop;
char* interfaceId;
uint8_t* buffer;
EthernetSocket ethSocket;
@@ -65,6 +65,7 @@ GooseReceiver_create()
if (self != NULL) {
self->running = false;
+ self->stop = false;
self->interfaceId = NULL;
self->buffer = (uint8_t*) GLOBAL_MALLOC(ETH_BUFFER_LENGTH);
self->ethSocket = NULL;
@@ -772,9 +773,6 @@ gooseReceiverLoop(void* threadParameter)
{
GooseReceiver self = (GooseReceiver) threadParameter;
- self->running = true;
- self->stopped = false;
-
GooseReceiver_startThreadless(self);
if (self->running) {
@@ -783,12 +781,13 @@ gooseReceiverLoop(void* threadParameter)
if (GooseReceiver_tick(self) == false)
Thread_sleep(1);
+
+ if (self->stop)
+ break;
}
GooseReceiver_stopThreadless(self);
}
-
- self->stopped = true;
}
#endif
@@ -822,12 +821,11 @@ void
GooseReceiver_stop(GooseReceiver self)
{
#if (CONFIG_MMS_THREADLESS_STACK == 0)
+ self->stop = true;
self->running = false;
Thread_destroy(self->thread);
-
- while (self->stopped == false)
- Thread_sleep(1);
+ self->stop = false;
#endif
}
diff --git a/src/iec61850/inc/iec61850_dynamic_model.h b/src/iec61850/inc/iec61850_dynamic_model.h
index 72c69ba6..13599698 100644
--- a/src/iec61850/inc/iec61850_dynamic_model.h
+++ b/src/iec61850/inc/iec61850_dynamic_model.h
@@ -160,6 +160,18 @@ LIB61850_API ReportControlBlock*
ReportControlBlock_create(const char* name, LogicalNode* parent, char* rptId, bool isBuffered, char*
dataSetName, uint32_t confRef, uint8_t trgOps, uint8_t options, uint32_t bufTm, uint32_t intgPd);
+/**
+ * \brief Set a pre-configured client for the RCB
+ *
+ * If set only the pre configured client should use this RCB instance
+ *
+ * \param self the RCB instance
+ * \param clientType the type of the client (0 = no client, 4 = IPv4 client, 6 = IPv6 client)
+ * \param clientAddress buffer containing the client address (4 byte in case of an IPv4 address, 16 byte in case of an IPv6 address, NULL for no client)
+ */
+LIB61850_API void
+ReportControlBlock_setPreconfiguredClient(ReportControlBlock* self, uint8_t clientType, uint8_t* clientAddress);
+
/**
* \brief create a new log control block (LCB)
*
diff --git a/src/iec61850/inc/iec61850_model.h b/src/iec61850/inc/iec61850_model.h
index 6bcff86f..18de227c 100644
--- a/src/iec61850/inc/iec61850_model.h
+++ b/src/iec61850/inc/iec61850_model.h
@@ -264,6 +264,10 @@ struct sReportControlBlock {
uint32_t bufferTime; /* BufTm - time to buffer events until a report is generated */
uint32_t intPeriod; /* IntgPd - integrity period */
+ /* type (first byte) and address of the pre-configured client
+ type can be one of (0 - no reservation, 4 - IPv4 client, 6 - IPv6 client) */
+ uint8_t clientReservation[17];
+
ReportControlBlock* sibling; /* next control block in list or NULL if this is the last entry */
};
diff --git a/src/iec61850/inc_private/reporting.h b/src/iec61850/inc_private/reporting.h
index 125f6cde..1b471a81 100644
--- a/src/iec61850/inc_private/reporting.h
+++ b/src/iec61850/inc_private/reporting.h
@@ -1,7 +1,7 @@
/*
* reporting.h
*
- * Copyright 2013, 2014 Michael Zillgith
+ * Copyright 2013-2019 Michael Zillgith
*
* This file is part of libIEC61850.
*
@@ -28,9 +28,9 @@ typedef struct sReportBufferEntry ReportBufferEntry;
struct sReportBufferEntry {
uint8_t entryId[8];
- uint8_t flags; /* bit 0 (1 = isIntegrityReport), bit 1 (1 = isGiReport) */
uint64_t timeOfEntry;
- int entryLength;
+ int entryLength:30;
+ unsigned int flags:2; /* bit 0 (1 = isIntegrityReport), bit 1 (1 = isGiReport) */
ReportBufferEntry* next;
};
@@ -42,6 +42,8 @@ typedef struct {
ReportBufferEntry* lastEnqueuedReport;
ReportBufferEntry* nextToTransmit;
bool isOverflow; /* true if overflow condition is active */
+
+ Semaphore lock; /* protect access to report buffer */
} ReportBuffer;
typedef struct {
@@ -53,6 +55,7 @@ typedef struct {
MmsValue* rcbValues;
MmsValue* inclusionField;
MmsValue* confRev;
+
DataSet* dataSet;
bool isDynamicDataSet;
bool enabled;
@@ -76,6 +79,12 @@ typedef struct {
int triggerOps;
+ /* information for segmented reporting */
+ bool segmented; /* indicates that a segmented report is in process */
+ int startIndexForNextSegment; /* start data set index for the next report segment */
+ MmsValue* subSeqVal; /* sub sequence value for segmented reporting */
+ uint64_t segmentedReportTimestamp; /* time stamp used for all report segments */
+
#if (CONFIG_MMS_THREADLESS_STACK != 1)
Semaphore createNotificationsMutex; /* { covered by mutex } */
#endif
@@ -91,6 +100,7 @@ typedef struct {
bool isBuffering; /* true if buffered RCB is buffering (datSet is set to a valid value) */
bool isResync; /* true if buffered RCB is in resync state */
+ int resvTms; /* -1 for preconfigured client, 0 - not reserved, > 0 reserved by client */
ReportBuffer* reportBuffer;
MmsValue* timeOfEntry;
@@ -122,6 +132,9 @@ LIB61850_INTERNAL MmsDataAccessError
Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* elementName, MmsValue* value,
MmsServerConnection connection);
+LIB61850_INTERNAL void
+ReportControl_readAccess(ReportControl* rc, char* elementName);
+
LIB61850_INTERNAL void
Reporting_activateBufferedReports(MmsMapping* self);
diff --git a/src/iec61850/server/impl/ied_server.c b/src/iec61850/server/impl/ied_server.c
index b45248df..072733fb 100644
--- a/src/iec61850/server/impl/ied_server.c
+++ b/src/iec61850/server/impl/ied_server.c
@@ -99,6 +99,7 @@ createControlObjects(IedServer self, MmsDomain* domain, char* lnName, MmsVariabl
if (DEBUG_IED_SERVER)
printf("IED_SERVER: createControlObjects: Unknown element in CO: %s\n", coElementSpec->name);
+ break;
}
}
diff --git a/src/iec61850/server/mms_mapping/control.c b/src/iec61850/server/mms_mapping/control.c
index 9a4548ea..442cc8e5 100644
--- a/src/iec61850/server/mms_mapping/control.c
+++ b/src/iec61850/server/mms_mapping/control.c
@@ -417,6 +417,9 @@ ControlObject_destroy(ControlObject* self)
if (self->mmsValue != NULL)
MmsValue_delete(self->mmsValue);
+ if (self->sbo != NULL)
+ MmsValue_delete(self->sbo);
+
if (self->emptyString != NULL)
MmsValue_delete(self->emptyString);
diff --git a/src/iec61850/server/mms_mapping/reporting.c b/src/iec61850/server/mms_mapping/reporting.c
index 38bfd9bc..9c2b2a96 100644
--- a/src/iec61850/server/mms_mapping/reporting.c
+++ b/src/iec61850/server/mms_mapping/reporting.c
@@ -1,7 +1,7 @@
/*
* reporting.c
*
- * Copyright 2013-2018 Michael Zillgith
+ * Copyright 2013-2019 Michael Zillgith
*
* This file is part of libIEC61850.
*
@@ -29,14 +29,19 @@
#include "simple_allocator.h"
#include "mem_alloc_linked_list.h"
+#include "ber_encoder.h"
#include "mms_mapping_internal.h"
#include "mms_value_internal.h"
+#include "mms_server_internal.h"
#include "conversions.h"
#include "reporting.h"
#include "ied_server_private.h"
#include
+/* if not explicitly set by client "ResvTms" will be set to this value */
+#define RESV_TMS_IMPLICIT_VALUE 30
+
#ifndef DEBUG_IED_SERVER
#define DEBUG_IED_SERVER 0
#endif
@@ -66,6 +71,10 @@ ReportBuffer_create(int bufferSize)
GLOBAL_FREEMEM(self);
self = NULL;
}
+
+#if (CONFIG_MMS_THREADLESS_STACK != 1)
+ self->lock = Semaphore_create(1);
+#endif
}
return self;
@@ -75,6 +84,11 @@ static void
ReportBuffer_destroy(ReportBuffer* self)
{
GLOBAL_FREEMEM(self->memoryBlock);
+
+#if (CONFIG_MMS_THREADLESS_STACK != 1)
+ Semaphore_destroy(self->lock);
+#endif
+
GLOBAL_FREEMEM(self);
}
@@ -87,6 +101,9 @@ ReportControl_create(bool buffered, LogicalNode* parentLN, int reportBufferSize,
self->parentLN = parentLN;
self->rcbValues = NULL;
self->confRev = NULL;
+ self->subSeqVal = MmsValue_newUnsigned(16);
+ self->segmented = false;
+ self->startIndexForNextSegment = 0;
self->enabled = false;
self->reserved = false;
self->buffered = buffered;
@@ -113,6 +130,7 @@ ReportControl_create(bool buffered, LogicalNode* parentLN, int reportBufferSize,
self->bufferedDataSetValues = NULL;
self->valueReferences = NULL;
self->lastEntryId = 0;
+ self->resvTms = 0;
self->server = iedServer;
@@ -196,6 +214,8 @@ ReportControl_destroy(ReportControl* self)
if (self->buffered == false)
MmsValue_delete(self->timeOfEntry);
+ MmsValue_delete(self->subSeqVal);
+
deleteDataSetValuesShadowBuffer(self);
if (self->isDynamicDataSet) {
@@ -308,63 +328,238 @@ updateTimeOfEntry(ReportControl* self, uint64_t currentTime)
MmsValue_setBinaryTime(timeOfEntry, currentTime);
}
-static void
-sendReport(ReportControl* self, bool isIntegrity, bool isGI)
+static DataSetEntry*
+getDataSetEntryWithIndex(DataSetEntry* dataSet, int index)
+{
+ int i = 0;
+
+ while (dataSet) {
+ if (i == index)
+ return dataSet;
+
+ i++;
+
+ dataSet = dataSet->sibling;
+ }
+
+ return NULL;
+}
+
+static bool
+sendReportSegment(ReportControl* self, bool isIntegrity, bool isGI)
{
- updateTimeOfEntry(self, Hal_getTimeInMs());
+ if (self->clientConnection == NULL)
+ return false;
- LinkedList reportElements = LinkedList_create();
+ int maxMmsPduSize = MmsServerConnection_getMaxMmsPduSize(self->clientConnection);
+ int estimatedSegmentSize = 19; /* maximum size of header information (header can have 13-19 byte) */
+ estimatedSegmentSize += 8; /* reserve space for more-segments-follow (3 byte) and sub-seq-num (3-5 byte) */
- LinkedList deletableElements = LinkedList_create();
+ bool segmented = self->segmented;
+ bool moreFollows = false;
+
+ bool hasSeqNum = false;
+ bool hasReportTimestamp = false;
+ bool hasDataSetReference = false;
+ bool hasConfRev = false;
+
+ uint32_t accessResultSize = 0;
MmsValue* rptId = ReportControl_getRCBValue(self, "RptID");
MmsValue* optFlds = ReportControl_getRCBValue(self, "OptFlds");
MmsValue* datSet = ReportControl_getRCBValue(self, "DatSet");
- LinkedList_add(reportElements, rptId);
- LinkedList_add(reportElements, optFlds);
+ MmsValue timeOfEntry;
+ timeOfEntry.type = MMS_BINARY_TIME;
+ timeOfEntry.value.binaryTime.size = 6;
- /* delete option fields for unsupported options */
+ accessResultSize += MmsValue_encodeMmsData(rptId, NULL, 0, false);
+ accessResultSize += 5; /* size of OptFlds */
+
+ /* delete option fields for unrelated options (not present in unbuffered report) */
MmsValue_setBitStringBit(optFlds, 6, false); /* bufOvfl */
MmsValue_setBitStringBit(optFlds, 7, false); /* entryID */
- MmsValue_setBitStringBit(optFlds, 9, false); /* segmentation */
MmsValue* sqNum = ReportControl_getRCBValue(self, "SqNum");
- if (MmsValue_getBitStringBit(optFlds, 1)) /* sequence number */
- LinkedList_add(reportElements, sqNum);
+ if (MmsValue_getBitStringBit(optFlds, 1)) { /* sequence number */
+ hasSeqNum = true;
+ accessResultSize += MmsValue_encodeMmsData(sqNum, NULL, 0, false);
+ }
+
+ if (MmsValue_getBitStringBit(optFlds, 2)) { /* report time stamp */
+ hasReportTimestamp = true;
+ MmsValue_setBinaryTime(&timeOfEntry, self->segmentedReportTimestamp);
+ accessResultSize += MmsValue_encodeMmsData(&timeOfEntry, NULL, 0, false);
+ }
+
+ if (MmsValue_getBitStringBit(optFlds, 4)) { /* data set reference */
+ hasDataSetReference = true;
+ accessResultSize += MmsValue_encodeMmsData(datSet, NULL, 0, false);
+ }
- if (MmsValue_getBitStringBit(optFlds, 2)) /* report time stamp */
- LinkedList_add(reportElements, self->timeOfEntry);
+ if (MmsValue_getBitStringBit(optFlds, 8)) { /* configuration revision */
+ hasConfRev = true;
+ accessResultSize += MmsValue_encodeMmsData(self->confRev, NULL, 0, false);
+ }
- if (MmsValue_getBitStringBit(optFlds, 4)) /* data set reference */
- LinkedList_add(reportElements, datSet);
+ MmsValue_deleteAllBitStringBits(self->inclusionField);
+ accessResultSize += MmsValue_encodeMmsData(self->inclusionField, NULL, 0, false);
- if (MmsValue_getBitStringBit(optFlds, 8))
- LinkedList_add(reportElements, self->confRev);
+ /* here ends the base part that is equal for all sub reports and independent of the
+ * number of included data points
+ */
+ estimatedSegmentSize += accessResultSize;
- if (isGI || isIntegrity)
- MmsValue_setAllBitStringBits(self->inclusionField);
- else
- MmsValue_deleteAllBitStringBits(self->inclusionField);
+ int startElementIndex = self->startIndexForNextSegment; /* get value from segmented report control info */
- LinkedList_add(reportElements, self->inclusionField);
+ bool withDataReference = MmsValue_getBitStringBit(optFlds, 5);
+ bool withReasonCode = MmsValue_getBitStringBit(optFlds, 3);
- /* add data references if selected */
- if (MmsValue_getBitStringBit(optFlds, 5)) { /* data-reference */
- DataSetEntry* dataSetEntry = self->dataSet->fcdas;
+ LogicalDevice* ld = (LogicalDevice*) self->parentLN->parent;
+
+ IedModel* iedModel = (IedModel*) ld->parent;
+
+ int maxIndex = startElementIndex;
+
+ char* iedName = iedModel->name;
+ int iedNameLength = strlen(iedName);
+
+ int i;
+
+ MmsValue _moreFollows;
+ _moreFollows.type = MMS_BOOLEAN;
+ _moreFollows.value.boolean = false;
+
+ MmsValue* subSeqNum = self->subSeqVal;
+
+ for (i = startElementIndex; i < self->dataSet->elementCount; i++) {
+
+ DataSetEntry* dataSetEntry = getDataSetEntryWithIndex(self->dataSet->fcdas, i);
+
+ bool includeElementInReport = false;
+
+ if (isGI || isIntegrity)
+ includeElementInReport = true;
+ else if (self->inclusionFlags[i] != REPORT_CONTROL_NONE)
+ includeElementInReport = true;
+
+ if (includeElementInReport) {
+
+ int elementSize = 0;
+
+ if (withDataReference) {
+ int currentPos = 0;
+
+ currentPos += iedNameLength;
+ currentPos += (int) strlen(dataSetEntry->logicalDeviceName);
+ currentPos++;
+ currentPos += (int) strlen(dataSetEntry->variableName);
+
+ elementSize += (1 + BerEncoder_determineLengthSize(currentPos) + currentPos);
+ }
+
+ if (self->inclusionFlags[i] != REPORT_CONTROL_NONE) {
+ elementSize += MmsValue_encodeMmsData(self->bufferedDataSetValues[i], NULL, 0, false);
+ }
+ else {
+ elementSize += MmsValue_encodeMmsData(dataSetEntry->value, NULL, 0, false);
+ }
+
+ if (withReasonCode) {
+ elementSize += 4; /* reason code size is always 4 byte */
+ }
+
+ if ((estimatedSegmentSize + elementSize) > maxMmsPduSize) {
+
+ segmented = true;
+ moreFollows = true;
+ _moreFollows.value.boolean = true;
+
+ if (startElementIndex == 0)
+ MmsValue_setUint32(subSeqNum, 0);
+
+ if (DEBUG_IED_SERVER)
+ printf("IED_SERVER: element doesn't fit into MMS PDU --> another report segment is required!\n");
+ break;
+ }
+
+ MmsValue_setBitStringBit(self->inclusionField, i, true);
+
+ accessResultSize += elementSize;
+ estimatedSegmentSize += elementSize;
+ }
+
+ maxIndex++;
+ }
+
+ MmsValue_setBitStringBit(optFlds, 9, segmented); /* set segmentation flag */
+
+ /* now calculate the exact information report segment size */
+
+ if (segmented) {
+ int segmentedSize = MmsValue_encodeMmsData(&_moreFollows, NULL, 0, false) + MmsValue_encodeMmsData(subSeqNum, NULL, 0, false);
+ accessResultSize += segmentedSize;
+ }
+
+ uint32_t variableAccessSpecSize = 7; /* T L "RPT" */
+ uint32_t listOfAccessResultSize = accessResultSize + BerEncoder_determineLengthSize(accessResultSize) + 1;
+ uint32_t informationReportContentSize = variableAccessSpecSize + listOfAccessResultSize;
+ uint32_t informationReportSize = 1 + informationReportContentSize + BerEncoder_determineLengthSize(informationReportContentSize);
+ uint32_t completeMessageSize = 1 + informationReportSize + BerEncoder_determineLengthSize(informationReportSize);
+
+ if ((int) completeMessageSize > maxMmsPduSize) {
+ if (DEBUG_IED_SERVER)
+ printf("IED_SERVER: report message too large %i (max = %i) -> skip message!\n", completeMessageSize, maxMmsPduSize);
+
+ goto exit_function;
+ }
+
+ /* encode the report message */
+
+ ByteBuffer* reportBuffer = MmsServer_reserveTransmitBuffer(self->server->mmsServer);
+
+ uint8_t* buffer = reportBuffer->buffer;
+ int bufPos = 0;
+
+ /* encode header */
+ bufPos = BerEncoder_encodeTL(0xa3, informationReportSize, buffer, bufPos);
+ bufPos = BerEncoder_encodeTL(0xa0, informationReportContentSize, buffer, bufPos);
- LogicalDevice* ld = (LogicalDevice*) self->parentLN->parent;
+ bufPos = BerEncoder_encodeTL(0xa1, 5, buffer, bufPos);
+ bufPos = BerEncoder_encodeStringWithTag(0x80, "RPT", buffer, bufPos);
- IedModel* iedModel = (IedModel*) ld->parent;
+ bufPos = BerEncoder_encodeTL(0xa0, accessResultSize, buffer, bufPos);
- char* iedName = iedModel->name;
+ /* encode access-results */
- int iedNameLength = strlen(iedName);
+ bufPos = MmsValue_encodeMmsData(rptId, buffer, bufPos, true);
+ bufPos = MmsValue_encodeMmsData(optFlds, buffer, bufPos, true);
- int i = 0;
+ if (hasSeqNum)
+ bufPos = MmsValue_encodeMmsData(sqNum, buffer, bufPos, true);
- for (i = 0; i < self->dataSet->elementCount; i++) {
+ if (hasReportTimestamp)
+ bufPos = MmsValue_encodeMmsData(&timeOfEntry, buffer, bufPos, true);
+
+ if (hasDataSetReference)
+ bufPos = MmsValue_encodeMmsData(datSet, buffer, bufPos, true);
+
+ if (hasConfRev)
+ bufPos = MmsValue_encodeMmsData(self->confRev, buffer, bufPos, true);
+
+ if (segmented) {
+ bufPos = MmsValue_encodeMmsData(subSeqNum, buffer, bufPos, true);
+ bufPos = MmsValue_encodeMmsData(&_moreFollows, buffer, bufPos, true);
+ }
+
+ bufPos = MmsValue_encodeMmsData(self->inclusionField, buffer, bufPos, true);
+
+ /* encode data references if selected */
+ if (MmsValue_getBitStringBit(optFlds, 5)) { /* data-reference */
+ DataSetEntry* dataSetEntry = getDataSetEntryWithIndex(self->dataSet->fcdas, startElementIndex);
+
+ for (i = startElementIndex; i < maxIndex; i++) {
assert(dataSetEntry->value != NULL);
bool addReferenceForEntry = false;
@@ -400,33 +595,31 @@ sendReport(ReportControl* self, bool isIntegrity, bool isGI)
dataReference[currentPos] = 0;
- MmsValue* dataRef = MmsValue_newVisibleString(dataReference);
+ MmsValue _dataRef;
+ _dataRef.type = MMS_VISIBLE_STRING;
+ _dataRef.value.visibleString.buf = dataReference;
+ _dataRef.value.visibleString.size = currentPos;
- LinkedList_add(reportElements, dataRef);
- LinkedList_add(deletableElements, dataRef);
+ bufPos = MmsValue_encodeMmsData(&_dataRef, buffer, bufPos, true);
}
dataSetEntry = dataSetEntry->sibling;
-
}
}
- /* add data set value elements */
- DataSetEntry* dataSetEntry = self->dataSet->fcdas;
+ /* encode data set value elements */
+ DataSetEntry* dataSetEntry = getDataSetEntryWithIndex(self->dataSet->fcdas, startElementIndex);
- int i = 0;
- for (i = 0; i < self->dataSet->elementCount; i++) {
- assert(dataSetEntry->value != NULL);
+ for (i = startElementIndex; i < maxIndex; i++) {
if (isGI || isIntegrity) {
- LinkedList_add(reportElements, dataSetEntry->value);
+ /* encode value from data set */
+ bufPos = MmsValue_encodeMmsData(dataSetEntry->value, buffer, bufPos, true);
}
else {
if (self->inclusionFlags[i] != REPORT_CONTROL_NONE) {
- assert(self->bufferedDataSetValues[i] != NULL);
-
- LinkedList_add(reportElements, self->bufferedDataSetValues[i]);
- MmsValue_setBitStringBit(self->inclusionField, i, true);
+ /* encode value from the event buffer */
+ bufPos = MmsValue_encodeMmsData(self->bufferedDataSetValues[i], buffer, bufPos, true);
}
}
@@ -434,58 +627,90 @@ sendReport(ReportControl* self, bool isIntegrity, bool isGI)
}
/* add reason code to report if requested */
- if (MmsValue_getBitStringBit(optFlds, 3)) {
- for (i = 0; i < self->dataSet->elementCount; i++) {
+ if (withReasonCode) {
+
+ uint8_t bsBuf[1];
+
+ MmsValue _reason;
+ _reason.type = MMS_BIT_STRING;
+ _reason.value.bitString.size = 6;
+ _reason.value.bitString.buf = bsBuf;
+
+ for (i = startElementIndex; i < maxIndex; i++) {
if (isGI || isIntegrity) {
- MmsValue* reason = MmsValue_newBitString(6);
+ bsBuf[0] = 0; /* clear all bits */
if (isGI)
- MmsValue_setBitStringBit(reason, 5, true);
+ MmsValue_setBitStringBit(&_reason, 5, true);
if (isIntegrity)
- MmsValue_setBitStringBit(reason, 4, true);
+ MmsValue_setBitStringBit(&_reason, 4, true);
- LinkedList_add(reportElements, reason);
- LinkedList_add(deletableElements, reason);
+ bufPos = MmsValue_encodeMmsData(&_reason, buffer, bufPos, true);
}
else if (self->inclusionFlags[i] != REPORT_CONTROL_NONE) {
- MmsValue* reason = MmsValue_newBitString(6);
+ bsBuf[0] = 0; /* clear all bits */
if (self->inclusionFlags[i] == REPORT_CONTROL_QUALITY_CHANGED)
- MmsValue_setBitStringBit(reason, 2, true);
+ MmsValue_setBitStringBit(&_reason, 2, true);
else if (self->inclusionFlags[i] == REPORT_CONTROL_VALUE_CHANGED)
- MmsValue_setBitStringBit(reason, 1, true);
+ MmsValue_setBitStringBit(&_reason, 1, true);
else if (self->inclusionFlags[i] == REPORT_CONTROL_VALUE_UPDATE)
- MmsValue_setBitStringBit(reason, 3, true);
+ MmsValue_setBitStringBit(&_reason, 3, true);
- LinkedList_add(reportElements, reason);
- LinkedList_add(deletableElements, reason);
+ bufPos = MmsValue_encodeMmsData(&_reason, buffer, bufPos, true);
}
}
}
/* clear inclusion flags */
- for (i = 0; i < self->dataSet->elementCount; i++)
+ for (i = startElementIndex; i < maxIndex; i++)
self->inclusionFlags[i] = REPORT_CONTROL_NONE;
- ReportControl_unlockNotify(self);
+ reportBuffer->size = bufPos;
- MmsServerConnection_sendInformationReportVMDSpecific(self->clientConnection, "RPT", reportElements, false);
+ MmsServerConnection_sendMessage(self->clientConnection, reportBuffer, false);
- ReportControl_lockNotify(self);
+ MmsServer_releaseTransmitBuffer(self->server->mmsServer);
+
+ if (moreFollows == false) {
+ /* reset sub sequence number */
+ segmented = false;
+ self->startIndexForNextSegment = 0;
+ }
+ else {
+ /* increase sub sequence number */
+ uint32_t subSeqNumVal = MmsValue_toUint32(subSeqNum);
+ subSeqNumVal++;
+ MmsValue_setUint32(subSeqNum, subSeqNumVal);
+
+ self->startIndexForNextSegment = maxIndex;
+ }
+
+ if (segmented == false) {
+ /* Increase sequence number */
+ self->sqNum++;
- /* Increase sequence number */
- self->sqNum++;
+ /* Unbuffered reporting --> sqNum is 8 bit only!!! */
+ if (self->sqNum == 256)
+ self->sqNum = 0;
- /* Unbuffered reporting --> sqNum is 8 bit only!!! */
- if (self->sqNum == 256)
- self->sqNum = 0;
+ MmsValue_setUint16(sqNum, self->sqNum);
+ }
- MmsValue_setUint16(sqNum, self->sqNum);
+exit_function:
+ self->segmented = segmented;
+ return moreFollows;
+}
+
+static void
+sendReport(ReportControl* self, bool isIntegrity, bool isGI, uint64_t currentTime)
+{
+ updateTimeOfEntry(self, currentTime);
+ self->segmentedReportTimestamp = currentTime;
- LinkedList_destroyDeep(deletableElements, (LinkedListValueDeleteFunction) MmsValue_delete);
- LinkedList_destroyStatic(reportElements);
+ while (sendReportSegment(self, isIntegrity, isGI));
}
static void
@@ -936,7 +1161,17 @@ createUnbufferedReportControlBlock(ReportControlBlock* reportControlBlock,
namedVariable->type = MMS_OCTET_STRING;
namedVariable->typeSpec.octetString = -64;
rcb->typeSpec.structure.elements[11] = namedVariable;
- mmsValue->value.structure.components[11] = MmsValue_newOctetString(0, 128);
+ mmsValue->value.structure.components[11] = MmsValue_newOctetString(0, 16); /* size 16 is enough to store client IPv6 address */
+
+ /* initialize pre configured owner */
+ if (reportControlBlock->clientReservation[0] == 4) {
+ reportControl->resvTms = -1;
+ MmsValue_setOctetString(mmsValue->value.structure.components[11], reportControlBlock->clientReservation + 1, 4);
+ }
+ else if (reportControlBlock->clientReservation[0] == 6) {
+ reportControl->resvTms = -1;
+ MmsValue_setOctetString(mmsValue->value.structure.components[11], reportControlBlock->clientReservation + 1, 16);
+ }
}
reportControl->rcbValues = mmsValue;
@@ -1107,7 +1342,21 @@ createBufferedReportControlBlock(ReportControlBlock* reportControlBlock,
namedVariable->type = MMS_OCTET_STRING;
namedVariable->typeSpec.octetString = -64;
rcb->typeSpec.structure.elements[currentIndex] = namedVariable;
- mmsValue->value.structure.components[currentIndex] = MmsValue_newOctetString(0, 128); /* size 4 is enough to store client IPv4 address */
+ mmsValue->value.structure.components[currentIndex] = MmsValue_newOctetString(0, 16); /* size 16 is enough to store client IPv6 address */
+
+ /* initialize pre configured owner */
+ if (reportControlBlock->clientReservation[0] == 4) {
+ reportControl->resvTms = -1;
+ MmsValue_setOctetString(mmsValue->value.structure.components[currentIndex], reportControlBlock->clientReservation + 1, 4);
+ }
+ else if (reportControlBlock->clientReservation[0] == 6) {
+ reportControl->resvTms = -1;
+ MmsValue_setOctetString(mmsValue->value.structure.components[currentIndex], reportControlBlock->clientReservation + 1, 16);
+ }
+
+#if (CONFIG_IEC61850_BRCB_WITH_RESVTMS == 1)
+ MmsValue_setInt16(mmsValue->value.structure.components[13], reportControl->resvTms);
+#endif
}
reportControl->rcbValues = mmsValue;
@@ -1220,6 +1469,32 @@ Reporting_createMmsUnbufferedRCBs(MmsMapping* self, MmsDomain* domain,
return namedVariable;
}
+static bool
+convertIPv4AddressStringToByteArray(const char* clientAddressString, uint8_t ipV4Addr[])
+{
+ int addrElementCount = 0;
+
+ char* separator = (char*) clientAddressString;
+
+ while (separator != NULL && addrElementCount < 4) {
+ int intVal = atoi(separator);
+
+ ipV4Addr[addrElementCount] = intVal;
+
+ separator = strchr(separator, '.');
+
+ if (separator != NULL)
+ separator++; /* skip '.' character */
+
+ addrElementCount ++;
+ }
+
+ if (addrElementCount == 4)
+ return true;
+ else
+ return false;
+}
+
static void
updateOwner(ReportControl* rc, MmsServerConnection connection)
{
@@ -1238,28 +1513,13 @@ updateOwner(ReportControl* rc, MmsServerConnection connection)
if (strchr(clientAddressString, '.') != NULL) {
if (DEBUG_IED_SERVER)
- printf("IED_SERVER: reporting.c: client address is IPv4 address\n");
+ printf("IED_SERVER: reporting.c: client address is IPv4 address\n");
uint8_t ipV4Addr[4];
- int addrElementCount = 0;
-
- char* separator = clientAddressString;
-
- while (separator != NULL && addrElementCount < 4) {
- int intVal = atoi(separator);
-
- ipV4Addr[addrElementCount] = intVal;
-
- separator = strchr(separator, '.');
-
- if (separator != NULL)
- separator++; /* skip '.' character */
+ bool valid = convertIPv4AddressStringToByteArray(clientAddressString, ipV4Addr);
- addrElementCount ++;
- }
-
- if (addrElementCount == 4)
+ if (valid)
MmsValue_setOctetString(owner, ipV4Addr, 4);
else
MmsValue_setOctetString(owner, ipV4Addr, 0);
@@ -1267,8 +1527,21 @@ updateOwner(ReportControl* rc, MmsServerConnection connection)
}
else {
uint8_t ipV6Addr[16];
- MmsValue_setOctetString(owner, ipV6Addr, 0);
- if (DEBUG_IED_SERVER) printf("IED_SERVER: reporting.c: client address is IPv6 address or unknown\n");
+
+ bool valid = StringUtils_convertIPv6AdddressStringToByteArray(clientAddressString, ipV6Addr);
+
+ if (valid) {
+ if (DEBUG_IED_SERVER)
+ printf("IED_SERVER: reporting.c: client address is IPv6 address\n");
+
+ MmsValue_setOctetString(owner, ipV6Addr, 16);
+ }
+ else {
+ if (DEBUG_IED_SERVER)
+ printf("IED_SERVER: reporting.c: not a valid IPv6 address\n");
+
+ MmsValue_setOctetString(owner, ipV6Addr, 0);
+ }
}
}
else {
@@ -1276,11 +1549,9 @@ updateOwner(ReportControl* rc, MmsServerConnection connection)
MmsValue_setOctetString(owner, emptyAddr, 0);
}
}
-
}
}
-
static bool
checkForZeroEntryID(MmsValue* value)
{
@@ -1335,6 +1606,83 @@ increaseConfRev(ReportControl* self)
MmsValue_setUint32(self->confRev, confRev);
}
+static void
+checkReservationTimeout(ReportControl* rc)
+{
+ if (rc->enabled == false) {
+ if (rc->resvTms > 0) {
+ if (Hal_getTimeInMs() > rc->reservationTimeout) {
+ rc->resvTms = 0;
+
+#if (CONFIG_IEC61850_BRCB_WITH_RESVTMS == 1)
+ MmsValue* resvTmsVal = ReportControl_getRCBValue(rc, "ResvTms");
+ if (resvTmsVal)
+ MmsValue_setInt16(resvTmsVal, rc->resvTms);
+#endif
+
+ rc->reservationTimeout = 0;
+ updateOwner(rc, NULL);
+ rc->reserved = false;
+ }
+ }
+ }
+}
+
+void
+ReportControl_readAccess(ReportControl* rc, char* elementName)
+{
+ /* check reservation timeout */
+ if (rc->buffered) {
+ checkReservationTimeout(rc);
+ }
+}
+
+static bool
+isIpAddressMatchingWithOwner(ReportControl* rc, const char* ipAddress)
+{
+ MmsValue* owner = ReportControl_getRCBValue(rc, "Owner");
+
+ if (owner != NULL) {
+
+ if (strchr(ipAddress, '.') != NULL) {
+ uint8_t ipV4Addr[4];
+
+ if (convertIPv4AddressStringToByteArray(ipAddress, ipV4Addr)) {
+ if (memcmp(ipV4Addr, MmsValue_getOctetStringBuffer(owner), 4) == 0)
+ return true;
+ }
+ }
+ else {
+ uint8_t ipV6Addr[16];
+
+ if (StringUtils_convertIPv6AdddressStringToByteArray(ipAddress, ipV6Addr)) {
+ if (memcmp(ipV6Addr, MmsValue_getOctetStringBuffer(owner), 16) == 0)
+ return true;
+ }
+ else
+ return false;
+ }
+ }
+
+ return false;
+}
+
+static void
+reserveRcb(ReportControl* rc, MmsServerConnection connection)
+{
+ rc->reserved = true;
+ rc->clientConnection = connection;
+
+#if (CONFIG_IEC61850_BRCB_WITH_RESVTMS == 1)
+ MmsValue* resvTmsVal = ReportControl_getRCBValue(rc, "ResvTms");
+ if (resvTmsVal)
+ MmsValue_setInt16(resvTmsVal, rc->resvTms);
+#endif
+
+ rc->reservationTimeout = Hal_getTimeInMs() + (RESV_TMS_IMPLICIT_VALUE * 1000);
+ updateOwner(rc, connection);
+}
+
MmsDataAccessError
Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* elementName, MmsValue* value,
MmsServerConnection connection)
@@ -1343,6 +1691,53 @@ Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* eleme
ReportControl_lockNotify(rc);
+ bool resvTmsAccess = false;
+
+ /* check reservation timeout for buffered RCBs */
+ if (rc->buffered) {
+
+ checkReservationTimeout(rc);
+
+ if (rc->resvTms == 0) {
+ /* nothing to to */
+ }
+ else if (rc->resvTms == -1) {
+
+ if (rc->reserved == false) {
+
+#if (CONFIG_IEC61850_RCB_ALLOW_ONLY_PRECONFIGURED_CLIENT == 1)
+ if (isIpAddressMatchingWithOwner(rc, MmsServerConnection_getClientAddress(connection))) {
+ rc->reserved = true;
+ rc->clientConnection = connection;
+ }
+#else
+ rc->reserved = true;
+ rc->clientConnection = connection;
+#endif
+ }
+ }
+ else if (rc->resvTms > 0) {
+ if (rc->reserved == false) {
+
+ if (isIpAddressMatchingWithOwner(rc, MmsServerConnection_getClientAddress(connection))) {
+ rc->reserved = true;
+ rc->clientConnection = connection;
+ rc->reservationTimeout = Hal_getTimeInMs() + (rc->resvTms * 1000);
+ }
+ else {
+ if (DEBUG_IED_SERVER)
+ printf("IED_SERVER: client IP not matching with owner\n");
+ }
+
+ }
+ else {
+ if (rc->clientConnection == connection) {
+ rc->reservationTimeout = Hal_getTimeInMs() + (rc->resvTms * 1000);
+ }
+ }
+ }
+ }
+
if (strcmp(elementName, "RptEna") == 0) {
if (value->value.boolean == true) {
@@ -1358,7 +1753,8 @@ Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* eleme
if (updateReportDataset(self, rc, NULL, connection)) {
- updateOwner(rc, connection);
+ if (rc->resvTms != -1)
+ updateOwner(rc, connection);
MmsValue* rptEna = ReportControl_getRCBValue(rc, "RptEna");
@@ -1422,9 +1818,10 @@ Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* eleme
rc->triggered = false;
rc->reserved = false;
- }
- updateOwner(rc, NULL);
+ if (rc->resvTms != -1)
+ updateOwner(rc, NULL);
+ }
rc->enabled = false;
}
@@ -1581,6 +1978,44 @@ Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* eleme
goto exit_function;
}
+ else if (strcmp(elementName, "ResvTms") == 0) {
+ if (rc->buffered) {
+
+ resvTmsAccess = true;
+
+ if (rc->resvTms != -1) {
+
+ int resvTms = MmsValue_toInt32(value);
+
+ if (resvTms >= 0) {
+ rc->resvTms = resvTms;
+
+ if (rc->resvTms == 0) {
+ rc->reservationTimeout = 0;
+ rc->reserved = false;
+ updateOwner(rc, NULL);
+ }
+ else {
+ rc->reservationTimeout = Hal_getTimeInMs() + (rc->resvTms * 1000);
+
+ reserveRcb(rc, connection);
+ }
+
+ MmsValue* resvTmsVal = ReportControl_getRCBValue(rc, "ResvTms");
+
+ if (resvTmsVal != NULL)
+ MmsValue_update(resvTmsVal, value);
+ }
+ else
+ retVal = DATA_ACCESS_ERROR_OBJECT_VALUE_INVALID;
+ }
+ else {
+ retVal = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED;
+ }
+
+ goto exit_function;
+ }
+ }
else if (strcmp(elementName, "ConfRev") == 0) {
retVal = DATA_ACCESS_ERROR_OBJECT_ACCESS_DENIED;
goto exit_function;
@@ -1608,10 +2043,21 @@ Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* eleme
}
}
- else
+ else {
retVal = DATA_ACCESS_ERROR_TEMPORARILY_UNAVAILABLE;
+ }
exit_function:
+
+ /* every successful write access reserves the RCB */
+ if ((rc->buffered) && (retVal == DATA_ACCESS_ERROR_SUCCESS) && (resvTmsAccess == false)) {
+ if (rc->resvTms == 0) {
+ rc->resvTms = RESV_TMS_IMPLICIT_VALUE;
+
+ reserveRcb(rc, connection);
+ }
+ }
+
ReportControl_unlockNotify(rc);
return retVal;
@@ -1633,15 +2079,23 @@ Reporting_deactivateReportsForConnection(MmsMapping* self, MmsServerConnection c
MmsValue* rptEna = ReportControl_getRCBValue(rc, "RptEna");
MmsValue_setBoolean(rptEna, false);
+ rc->reserved = false;
+
if (rc->buffered == false) {
MmsValue* resv = ReportControl_getRCBValue(rc, "Resv");
MmsValue_setBoolean(resv, false);
- rc->reserved = false;
+ if (rc->resvTms != -1)
+ updateOwner(rc, NULL);
+ }
+ else {
+ if (rc->resvTms == 0)
+ updateOwner(rc, NULL);
+ else if (rc->resvTms > 0) {
+ rc->reservationTimeout = Hal_getTimeInMs() + (rc->resvTms * 1000);
+ }
}
-
- updateOwner(rc, NULL);
}
}
}
@@ -1713,7 +2167,6 @@ removeAllGIReportsFromReportBuffer(ReportBuffer* reportBuffer)
}
else {
lastReport->next = currentReport->next;
-
}
#if (DEBUG_IED_SERVER == 1)
@@ -1725,12 +2178,18 @@ removeAllGIReportsFromReportBuffer(ReportBuffer* reportBuffer)
if (reportBuffer->nextToTransmit == currentReport)
reportBuffer->nextToTransmit = currentReport->next;
- currentReport = currentReport->next;
+ if (reportBuffer->lastEnqueuedReport == currentReport) {
+ if (lastReport != NULL)
+ reportBuffer->lastEnqueuedReport = lastReport;
+ else
+ reportBuffer->lastEnqueuedReport = reportBuffer->oldestReport;
+ }
}
else {
lastReport = currentReport;
- currentReport = currentReport->next;
}
+
+ currentReport = currentReport->next;
}
if (reportBuffer->oldestReport == NULL)
@@ -1747,8 +2206,12 @@ enqueueReport(ReportControl* reportControl, bool isIntegrity, bool isGI, uint64_
updateTimeOfEntry(reportControl, Hal_getTimeInMs());
+ int inclusionBitStringSize = MmsValue_getBitStringSize(reportControl->inclusionField);
+
ReportBuffer* buffer = reportControl->reportBuffer;
+ Semaphore_wait(buffer->lock);
+
/* calculate size of complete buffer entry */
int bufferEntrySize = MemoryAllocator_getAlignedSize(sizeof(ReportBufferEntry));
@@ -1757,41 +2220,54 @@ enqueueReport(ReportControl* reportControl, bool isIntegrity, bool isGI, uint64_
MmsValue inclusionFieldStatic;
inclusionFieldStatic.type = MMS_BIT_STRING;
- inclusionFieldStatic.value.bitString.size = MmsValue_getBitStringSize(reportControl->inclusionField);
+ inclusionFieldStatic.value.bitString.size = inclusionBitStringSize;
MmsValue* inclusionField = &inclusionFieldStatic;
+ int dataBlockSize = 0;
+
if (isIntegrity || isGI) {
DataSetEntry* dataSetEntry = reportControl->dataSet->fcdas;
int i;
- for (i = 0; i < MmsValue_getBitStringSize(reportControl->inclusionField); i++) {
+ for (i = 0; i < inclusionBitStringSize; i++) {
assert(dataSetEntry != NULL);
- bufferEntrySize += MemoryAllocator_getAlignedSize(1); /* reason-for-inclusion */
+ /* don't need reason for inclusion in GI or integrity report */
- bufferEntrySize += MmsValue_getSizeInMemory(dataSetEntry->value);
+ int encodedSize = MmsValue_encodeMmsData(dataSetEntry->value, NULL, 0, false);
+
+ dataBlockSize += encodedSize;
dataSetEntry = dataSetEntry->sibling;
}
+
+ bufferEntrySize += MemoryAllocator_getAlignedSize(sizeof(int) + dataBlockSize); /* add aligned_size(LEN + DATA) */
}
else { /* other trigger reason */
bufferEntrySize += inclusionFieldSize;
+ int reasonForInclusionSize = 0;
+
int i;
- for (i = 0; i < MmsValue_getBitStringSize(reportControl->inclusionField); i++) {
+ for (i = 0; i < inclusionBitStringSize; i++) {
if (reportControl->inclusionFlags[i] != REPORT_CONTROL_NONE) {
- bufferEntrySize += MemoryAllocator_getAlignedSize(1); /* reason-for-inclusion */
+
+ reasonForInclusionSize++;
assert(reportControl->bufferedDataSetValues[i] != NULL);
- bufferEntrySize += MmsValue_getSizeInMemory(reportControl->bufferedDataSetValues[i]);
+ int encodedSize = MmsValue_encodeMmsData(reportControl->bufferedDataSetValues[i], NULL, 0, false);
+
+ dataBlockSize += encodedSize;
}
}
+
+ bufferEntrySize += MemoryAllocator_getAlignedSize(sizeof(int) + dataBlockSize + reasonForInclusionSize); /* add aligned_size (LEN + DATA + REASON) */
}
if (DEBUG_IED_SERVER)
@@ -2008,49 +2484,64 @@ enqueueReport(ReportControl* reportControl, bool isIntegrity, bool isGI, uint64_
else
entry->flags = 0;
- entry->entryLength = MemoryAllocator_getAlignedSize(bufferEntrySize);
+ entry->entryLength = bufferEntrySize;
entryBufPos += MemoryAllocator_getAlignedSize(sizeof(ReportBufferEntry));
if (isIntegrity || isGI) {
DataSetEntry* dataSetEntry = reportControl->dataSet->fcdas;
+ /* encode LEN */
+ memcpy(entryBufPos, (uint8_t*)(&dataBlockSize), sizeof(int));
+ entryBufPos += sizeof(int);
+
+ /* encode DATA */
int i;
- for (i = 0; i < MmsValue_getBitStringSize(reportControl->inclusionField); i++) {
+ for (i = 0; i < inclusionBitStringSize; i++) {
assert(dataSetEntry != NULL);
- *entryBufPos = (uint8_t) reportControl->inclusionFlags[i];
- entryBufPos += MemoryAllocator_getAlignedSize(1);
-
- entryBufPos = MmsValue_cloneToBuffer(dataSetEntry->value, entryBufPos);
+ entryBufPos += MmsValue_encodeMmsData(dataSetEntry->value, entryBufPos, 0, true);
dataSetEntry = dataSetEntry->sibling;
}
}
else {
+ /* encode inclusion bit string */
inclusionFieldStatic.value.bitString.buf = entryBufPos;
memset(entryBufPos, 0, inclusionFieldSize);
entryBufPos += inclusionFieldSize;
+ /* encode LEN */
+ memcpy(entryBufPos, (uint8_t*)(&dataBlockSize), sizeof(int));
+ entryBufPos += sizeof(int);
+
+ /* encode DATA */
int i;
- for (i = 0; i < MmsValue_getBitStringSize(reportControl->inclusionField); i++) {
+ for (i = 0; i < inclusionBitStringSize; i++) {
if (reportControl->inclusionFlags[i] != REPORT_CONTROL_NONE) {
+ /* update inclusion bit string for report entry */
+ MmsValue_setBitStringBit(inclusionField, i, true);
+
assert(reportControl->bufferedDataSetValues[i] != NULL);
- *entryBufPos = (uint8_t) reportControl->inclusionFlags[i];
- entryBufPos += MemoryAllocator_getAlignedSize(1);
+ entryBufPos += MmsValue_encodeMmsData(reportControl->bufferedDataSetValues[i], entryBufPos, 0, true);
+ }
- entryBufPos = MmsValue_cloneToBuffer(reportControl->bufferedDataSetValues[i], entryBufPos);
+ }
- MmsValue_setBitStringBit(inclusionField, i, true);
- }
+ /* encode REASON */
+ for (i = 0; i < inclusionBitStringSize; i++) {
+ if (reportControl->inclusionFlags[i] != REPORT_CONTROL_NONE) {
+ *entryBufPos = (uint8_t) reportControl->inclusionFlags[i];
+ entryBufPos ++;
+ }
}
}
@@ -2073,26 +2564,41 @@ enqueueReport(ReportControl* reportControl, bool isIntegrity, bool isGI, uint64_
reportControl->lastEntryId = entryId;
exit_function:
+
+ Semaphore_post(buffer->lock);
+
return;
} /* enqueuReport() */
-static void
-sendNextReportEntry(ReportControl* self)
+static bool
+sendNextReportEntrySegment(ReportControl* self)
{
-#define LOCAL_STORAGE_MEMORY_SIZE 65536
+ if (self->clientConnection == NULL)
+ return false;
- if (self->reportBuffer->nextToTransmit == NULL)
- return;
+ int maxMmsPduSize = MmsServerConnection_getMaxMmsPduSize(self->clientConnection);
- char* localStorage = (char*) GLOBAL_MALLOC(LOCAL_STORAGE_MEMORY_SIZE); /* reserve 64k for dynamic memory allocation -
- this can be optimized - maybe there is a good guess for the
- required memory size */
+ Semaphore_wait(self->reportBuffer->lock);
- if (localStorage == NULL) /* out-of-memory */
- goto return_out_of_memory;
+ if (self->reportBuffer->nextToTransmit == NULL) {
+ Semaphore_post(self->reportBuffer->lock);
+ return false;
+ }
+
+ int estimatedSegmentSize = 19; /* maximum size of header information (header can have 13-19 byte) */
+ estimatedSegmentSize += 8; /* reserve space for more-segments-follow (3 byte) and sub-seq-num (3-5 byte) */
+
+ bool segmented = self->segmented;
+ bool moreFollows = false;
+
+ bool hasSeqNum = false;
+ bool hasReportTimestamp = false;
+ bool hasDataSetReference = false;
+ bool hasBufOvfl = false;
+ bool hasEntryId = false;
+ bool hasConfRev = false;
- MemoryAllocator ma;
- MemoryAllocator_init(&ma, localStorage, LOCAL_STORAGE_MEMORY_SIZE);
+ uint32_t accessResultSize = 0;
ReportBufferEntry* report = self->reportBuffer->nextToTransmit;
@@ -2105,329 +2611,473 @@ sendNextReportEntry(ReportControl* self)
MmsValue* entryIdValue = MmsValue_getElement(self->rcbValues, 11);
MmsValue_setOctetString(entryIdValue, (uint8_t*) report->entryId, 8);
- MemAllocLinkedList reportElements = MemAllocLinkedList_create(&ma);
-
- assert(reportElements != NULL);
-
- if (reportElements == NULL)
- goto return_out_of_memory;
-
MmsValue* rptId = ReportControl_getRCBValue(self, "RptID");
MmsValue* optFlds = ReportControl_getRCBValue(self, "OptFlds");
- if (MemAllocLinkedList_add(reportElements, rptId) == NULL)
- goto return_out_of_memory;
-
- if (MemAllocLinkedList_add(reportElements, optFlds) == NULL)
- goto return_out_of_memory;
+ accessResultSize += MmsValue_encodeMmsData(rptId, NULL, 0, false);
+ accessResultSize += 5; /* add size of OptFlds */
MmsValue inclusionFieldStack;
- inclusionFieldStack.type = MMS_BIT_STRING;
- inclusionFieldStack.value.bitString.size = MmsValue_getBitStringSize(self->inclusionField);
-
uint8_t* currentReportBufferPos = (uint8_t*) report + sizeof(ReportBufferEntry);
- inclusionFieldStack.value.bitString.buf = currentReportBufferPos;
+ MmsValue* inclusionField = NULL;
- MmsValue* inclusionField = &inclusionFieldStack;
+ if (report->flags == 0) {
- if (report->flags == 0)
- currentReportBufferPos += MemoryAllocator_getAlignedSize(MmsValue_getBitStringByteSize(inclusionField));
- else {
- inclusionFieldStack.value.bitString.buf =
- (uint8_t*) MemoryAllocator_allocate(&ma, MmsValue_getBitStringByteSize(inclusionField));
+ inclusionField = &inclusionFieldStack;
- if (inclusionFieldStack.value.bitString.buf == NULL)
- goto return_out_of_memory;
+ inclusionFieldStack.type = MMS_BIT_STRING;
+ inclusionFieldStack.value.bitString.size = MmsValue_getBitStringSize(self->inclusionField);
+ inclusionFieldStack.value.bitString.buf = currentReportBufferPos;
+
+ currentReportBufferPos += MemoryAllocator_getAlignedSize(MmsValue_getBitStringByteSize(inclusionField));
}
+ MmsValue_deleteAllBitStringBits(self->inclusionField);
+
+ int dataLen;
+
+ /* get LEN (length of encoded data) from report buffer */
+ memcpy((uint8_t*)(&dataLen), currentReportBufferPos, sizeof(int));
+ currentReportBufferPos += sizeof(int);
+
uint8_t* valuesInReportBuffer = currentReportBufferPos;
MmsValue_setBitStringBit(optFlds, 9, false); /* segmentation */
MmsValue* sqNum = ReportControl_getRCBValue(self, "SqNum");
- if (MmsValue_getBitStringBit(optFlds, 1)) /* sequence number */
- if (MemAllocLinkedList_add(reportElements, sqNum) == NULL)
- goto return_out_of_memory;
-
- if (MmsValue_getBitStringBit(optFlds, 2)) { /* report time stamp */
- MmsValue* timeOfEntry = (MmsValue*) MemoryAllocator_allocate(&ma, sizeof(MmsValue));
+ if (MmsValue_getBitStringBit(optFlds, 1)) { /* sequence number */
+ hasSeqNum = true;
+ accessResultSize += MmsValue_encodeMmsData(sqNum, NULL, 0, false);
+ }
- if (timeOfEntry == NULL) goto return_out_of_memory;
+ MmsValue _timeOfEntry;
+ MmsValue* timeOfEntry = NULL;
- timeOfEntry->deleteValue = 0;
- timeOfEntry->type = MMS_BINARY_TIME;
- timeOfEntry->value.binaryTime.size = 6;
+ if (MmsValue_getBitStringBit(optFlds, 2)) { /* report time stamp */
+ hasReportTimestamp = true;
+ _timeOfEntry.type = MMS_BINARY_TIME;
+ _timeOfEntry.value.binaryTime.size = 6;
+ timeOfEntry = &_timeOfEntry;
MmsValue_setBinaryTime(timeOfEntry, report->timeOfEntry);
- if (MemAllocLinkedList_add(reportElements, timeOfEntry) == NULL)
- goto return_out_of_memory;
+ accessResultSize += MmsValue_encodeMmsData(timeOfEntry, NULL, 0, false);
}
+ MmsValue* datSet = ReportControl_getRCBValue(self, "DatSet");
+
if (MmsValue_getBitStringBit(optFlds, 4)) {/* data set reference */
- MmsValue* datSet = ReportControl_getRCBValue(self, "DatSet");
- if (MemAllocLinkedList_add(reportElements, datSet) == NULL)
- goto return_out_of_memory;
+ hasDataSetReference = true;
+ accessResultSize += MmsValue_encodeMmsData(datSet, NULL, 0, false);
}
- if (MmsValue_getBitStringBit(optFlds, 6)) { /* bufOvfl */
+ MmsValue _bufOvfl;
+ MmsValue* bufOvfl = NULL;
- MmsValue* bufOvfl = (MmsValue*) MemoryAllocator_allocate(&ma, sizeof(MmsValue));
+ if (MmsValue_getBitStringBit(optFlds, 6)) { /* bufOvfl */
+ hasBufOvfl = true;
- if (bufOvfl == NULL) goto return_out_of_memory;
+ bufOvfl = &_bufOvfl;
- bufOvfl->deleteValue = 0;
- bufOvfl->type = MMS_BOOLEAN;
- bufOvfl->value.boolean = self->reportBuffer->isOverflow;
+ _bufOvfl.type = MMS_BOOLEAN;
+ _bufOvfl.value.boolean = self->reportBuffer->isOverflow;
- if (self->reportBuffer->isOverflow)
- self->reportBuffer->isOverflow = false;
-
- if (MemAllocLinkedList_add(reportElements, bufOvfl) == NULL)
- goto return_out_of_memory;
+ accessResultSize += MmsValue_encodeMmsData(bufOvfl, NULL, 0, false);
}
- if (MmsValue_getBitStringBit(optFlds, 7)) { /* entryID */
- MmsValue* entryId = (MmsValue*) MemoryAllocator_allocate(&ma, sizeof(MmsValue));
+ MmsValue _entryId;
+ MmsValue* entryId = NULL;
- if (entryId == NULL) goto return_out_of_memory;
+ if (MmsValue_getBitStringBit(optFlds, 7)) { /* entryID */
+ hasEntryId = true;
+ entryId = &_entryId;
- entryId->deleteValue = 0;
entryId->type = MMS_OCTET_STRING;
entryId->value.octetString.buf = report->entryId;
entryId->value.octetString.size = 8;
entryId->value.octetString.maxSize = 8;
- if (MemAllocLinkedList_add(reportElements, entryId) == NULL)
- goto return_out_of_memory;
+ accessResultSize += MmsValue_encodeMmsData(entryId, NULL, 0, false);
+ }
+
+ if (MmsValue_getBitStringBit(optFlds, 8)) {
+ hasConfRev = true;
+ accessResultSize += MmsValue_encodeMmsData(self->confRev, NULL, 0, false);
}
- if (MmsValue_getBitStringBit(optFlds, 8))
- if (MemAllocLinkedList_add(reportElements, self->confRev) == NULL)
- goto return_out_of_memory;
+ accessResultSize += MmsValue_encodeMmsData(self->inclusionField, NULL, 0, false);
- if (report->flags > 0)
- MmsValue_setAllBitStringBits(inclusionField);
+ /* here ends the base part that is equal for all sub reports and independent of the
+ * number of included data points
+ */
- if (MemAllocLinkedList_add(reportElements, inclusionField) == NULL)
- goto return_out_of_memory;
+ estimatedSegmentSize += accessResultSize;
+ int startElementIndex = self->startIndexForNextSegment; /* get value from segmented report control info */
- /* add data references if selected */
- if (MmsValue_getBitStringBit(optFlds, 5)) { /* data-reference */
- DataSetEntry* dataSetEntry = self->dataSet->fcdas;
+ bool withDataReference = MmsValue_getBitStringBit(optFlds, 5);
+ bool withReasonCode = MmsValue_getBitStringBit(optFlds, 3);
+
+ LogicalDevice* ld = (LogicalDevice*) self->parentLN->parent;
+
+ IedModel* iedModel = (IedModel*) ld->parent;
+
+ int maxIndex = startElementIndex;
- LogicalDevice* ld = (LogicalDevice*) self->parentLN->parent;
+ char* iedName = iedModel->name;
+ int iedNameLength = strlen(iedName);
- IedModel* iedModel = (IedModel*) ld->parent;
+ int i;
+
+ MmsValue _moreFollows;
+ _moreFollows.type = MMS_BOOLEAN;
+ _moreFollows.value.boolean = false;
- char* iedName = iedModel->name;
+ MmsValue* subSeqNum = self->subSeqVal;
- int iedNameLength = strlen(iedName);
+ for (i = startElementIndex; i < self->dataSet->elementCount; i++) {
- int i = 0;
+ DataSetEntry* dataSetEntry = getDataSetEntryWithIndex(self->dataSet->fcdas, i);
- for (i = 0; i < self->dataSet->elementCount; i++) {
- assert(dataSetEntry->value != NULL);
+ if ((report->flags > 0) || MmsValue_getBitStringBit(inclusionField, i)) {
- bool addReferenceForEntry = false;
+ int elementSize = 0;
- if (report->flags > 0)
- addReferenceForEntry = true;
- else
- if (MmsValue_getBitStringBit(inclusionField, i))
- addReferenceForEntry = true;
+ if (withDataReference) {
- if (addReferenceForEntry) {
+ char dataReference[130];
+ int currentPos = 0;
- int ldNameLength = strlen(dataSetEntry->logicalDeviceName);
- int variableNameLength = strlen(dataSetEntry->variableName);
+ int j;
+
+ for (j = 0; j < iedNameLength; j++) {
+ dataReference[currentPos++] = iedName[j];
+ }
- int refLen = iedNameLength
- + ldNameLength
- + variableNameLength + 1;
+ int ldNameLength = strlen(dataSetEntry->logicalDeviceName);
+ for (j = 0; j < ldNameLength; j++) {
+ dataReference[currentPos] = dataSetEntry->logicalDeviceName[j];
+ currentPos++;
+ }
- char* dataReference = (char*) MemoryAllocator_allocate(&ma, refLen + 1);
+ dataReference[currentPos++] = '/';
- if (dataReference == NULL) goto return_out_of_memory;
+ for (j = 0; j < (int) strlen(dataSetEntry->variableName); j++) {
+ dataReference[currentPos++] = dataSetEntry->variableName[j];
+ }
- int currentPos = 0;
+ dataReference[currentPos] = 0;
- int j;
+ MmsValue _dataRef;
+ _dataRef.type = MMS_VISIBLE_STRING;
+ _dataRef.value.visibleString.buf = dataReference;
+ _dataRef.value.visibleString.size = currentPos;
- for (j = 0; j < iedNameLength; j++) {
- dataReference[currentPos++] = iedName[j];
- }
+ elementSize += MmsValue_encodeMmsData(&_dataRef, NULL, 0, false);
+ }
- for (j = 0; j < ldNameLength; j++) {
- dataReference[currentPos] = dataSetEntry->logicalDeviceName[j];
- currentPos++;
- }
+ /* get size of data */
+ if ((report->flags > 0) || MmsValue_getBitStringBit(inclusionField, i)) {
+ int length;
- dataReference[currentPos++] = '/';
+ int lenSize = BerDecoder_decodeLength(currentReportBufferPos + 1, &length, 0, report->entryLength);
- for (j = 0; j < variableNameLength; j++) {
- dataReference[currentPos++] = dataSetEntry->variableName[j];
- }
+ int dataElementSize = 1 + lenSize + length;
- dataReference[currentPos] = 0;
+ elementSize += dataElementSize;
+ currentReportBufferPos += dataElementSize;
+ }
- MmsValue* dataRef = (MmsValue*) MemoryAllocator_allocate(&ma, sizeof(MmsValue));
+ if (withReasonCode) {
+ elementSize += 4; /* reason code size is always 4 byte */
+ }
- if (dataRef == NULL) goto return_out_of_memory;
- dataRef->deleteValue = 0;
- dataRef->type = MMS_VISIBLE_STRING;
- dataRef->value.visibleString.buf = dataReference;
- dataRef->value.visibleString.size = refLen;
+ if ((estimatedSegmentSize + elementSize) > maxMmsPduSize) {
+ segmented = true;
+ moreFollows = true;
+ _moreFollows.value.boolean = true;
- if (MemAllocLinkedList_add(reportElements, dataRef) == NULL)
- goto return_out_of_memory;
+ if (startElementIndex == 0)
+ MmsValue_setUint32(subSeqNum, 0);
- }
+ break;
+ }
- dataSetEntry = dataSetEntry->sibling;
+ MmsValue_setBitStringBit(self->inclusionField, i, true);
+ accessResultSize += elementSize;
+ estimatedSegmentSize += elementSize;
}
+
+ maxIndex++;
}
- /* add data set value elements */
- int i = 0;
- for (i = 0; i < self->dataSet->elementCount; i++) {
+ MmsValue_setBitStringBit(optFlds, 9, segmented); /* set segmentation flag */
- if (report->flags > 0) {
- currentReportBufferPos += MemoryAllocator_getAlignedSize(1);;
- if (MemAllocLinkedList_add(reportElements, currentReportBufferPos) == NULL)
- goto return_out_of_memory;
+ /* now calculate the exact information report segment size */
- currentReportBufferPos += MmsValue_getSizeInMemory((MmsValue*) currentReportBufferPos);
- }
- else {
- if (MmsValue_getBitStringBit(inclusionField, i)) {
- currentReportBufferPos += MemoryAllocator_getAlignedSize(1);;
- if (MemAllocLinkedList_add(reportElements, currentReportBufferPos) == NULL)
- goto return_out_of_memory;
- currentReportBufferPos += MmsValue_getSizeInMemory((MmsValue*) currentReportBufferPos);
+ if (segmented) {
+ int segmentedSize = MmsValue_encodeMmsData(&_moreFollows, NULL, 0, false) + MmsValue_encodeMmsData(subSeqNum, NULL, 0, false);
+ accessResultSize += segmentedSize;
+ }
+
+ uint32_t variableAccessSpecSize = 7; /* T L "RPT" */
+ uint32_t listOfAccessResultSize = accessResultSize + BerEncoder_determineLengthSize(accessResultSize) + 1;
+ uint32_t informationReportContentSize = variableAccessSpecSize + listOfAccessResultSize;
+ uint32_t informationReportSize = 1 + informationReportContentSize + BerEncoder_determineLengthSize(informationReportContentSize);
+ uint32_t completeMessageSize = 1 + informationReportSize + BerEncoder_determineLengthSize(informationReportSize);
+
+ if ((int) completeMessageSize > maxMmsPduSize) {
+ if (DEBUG_IED_SERVER)
+ printf("IED_SERVER: report message too large %i (max = %i) -> skip message!\n", completeMessageSize, maxMmsPduSize);
+
+ goto exit_function;
+ }
+
+ /* encode the report message */
+
+ ReportControl_unlockNotify(self);
+
+ ByteBuffer* reportBuffer = MmsServer_reserveTransmitBuffer(self->server->mmsServer);
+
+ uint8_t* buffer = reportBuffer->buffer;
+ int bufPos = 0;
+
+ /* encode header */
+ bufPos = BerEncoder_encodeTL(0xa3, informationReportSize, buffer, bufPos);
+ bufPos = BerEncoder_encodeTL(0xa0, informationReportContentSize, buffer, bufPos);
+
+ bufPos = BerEncoder_encodeTL(0xa1, 5, buffer, bufPos);
+ bufPos = BerEncoder_encodeStringWithTag(0x80, "RPT", buffer, bufPos);
+
+ bufPos = BerEncoder_encodeTL(0xa0, accessResultSize, buffer, bufPos);
+
+ /* encode access-results */
+
+ bufPos = MmsValue_encodeMmsData(rptId, buffer, bufPos, true);
+ bufPos = MmsValue_encodeMmsData(optFlds, buffer, bufPos, true);
+
+ if (hasSeqNum)
+ bufPos = MmsValue_encodeMmsData(sqNum, buffer, bufPos, true);
+
+ if (hasReportTimestamp)
+ bufPos = MmsValue_encodeMmsData(timeOfEntry, buffer, bufPos, true);
+
+ if (hasDataSetReference)
+ bufPos = MmsValue_encodeMmsData(datSet, buffer, bufPos, true);
+
+ if (hasBufOvfl)
+ bufPos = MmsValue_encodeMmsData(bufOvfl, buffer, bufPos, true);
+
+ if (hasEntryId)
+ bufPos = MmsValue_encodeMmsData(entryId, buffer, bufPos, true);
+
+ if (hasConfRev)
+ bufPos = MmsValue_encodeMmsData(self->confRev, buffer, bufPos, true);
+
+ if (segmented) {
+ bufPos = MmsValue_encodeMmsData(subSeqNum, buffer, bufPos, true);
+ bufPos = MmsValue_encodeMmsData(&_moreFollows, buffer, bufPos, true);
+ }
+
+ bufPos = MmsValue_encodeMmsData(self->inclusionField, buffer, bufPos, true);
+
+ /* encode data references if selected */
+ if (MmsValue_getBitStringBit(optFlds, 5)) { /* data-reference */
+ DataSetEntry* dataSetEntry = getDataSetEntryWithIndex(self->dataSet->fcdas, startElementIndex);
+
+ for (i = startElementIndex; i < maxIndex; i++) {
+ assert(dataSetEntry->value != NULL);
+
+ bool addReferenceForEntry = false;
+
+ if (report->flags > 0)
+ addReferenceForEntry = true;
+ else if (MmsValue_getBitStringBit(self->inclusionField, i))
+ addReferenceForEntry = true;
+
+ if (addReferenceForEntry) {
+
+ char dataReference[130];
+ int currentPos = 0;
+
+ int j;
+
+ for (j = 0; j < iedNameLength; j++) {
+ dataReference[currentPos++] = iedName[j];
+ }
+
+ int ldNameLength = strlen(dataSetEntry->logicalDeviceName);
+ for (j = 0; j < ldNameLength; j++) {
+ dataReference[currentPos] = dataSetEntry->logicalDeviceName[j];
+ currentPos++;
+ }
+
+ dataReference[currentPos++] = '/';
+
+ for (j = 0; j < (int) strlen(dataSetEntry->variableName); j++) {
+ dataReference[currentPos++] = dataSetEntry->variableName[j];
+ }
+
+ dataReference[currentPos] = 0;
+
+ MmsValue _dataRef;
+ _dataRef.type = MMS_VISIBLE_STRING;
+ _dataRef.value.visibleString.buf = dataReference;
+ _dataRef.value.visibleString.size = currentPos;
+
+ bufPos = MmsValue_encodeMmsData(&_dataRef, buffer, bufPos, true);
}
+
+ dataSetEntry = dataSetEntry->sibling;
}
}
- /* add reason code to report if requested */
- if (MmsValue_getBitStringBit(optFlds, 3)) {
- currentReportBufferPos = valuesInReportBuffer;
+ /* move to start position in report buffer */
+ currentReportBufferPos = valuesInReportBuffer;
- for (i = 0; i < self->dataSet->elementCount; i++) {
+ /* encode data set value elements */
+ for (i = 0; i < maxIndex; i++) {
- if (report->flags > 0) {
- MmsValue* reason = (MmsValue*) MemoryAllocator_allocate(&ma, sizeof(MmsValue));
+ bool isInBuffer = false;
- if (reason == NULL) goto return_out_of_memory;
+ if (report->flags > 0)
+ isInBuffer = true;
+ else {
+ if (MmsValue_getBitStringBit(inclusionField, i))
+ isInBuffer = true;
+ }
- reason->deleteValue = 0;
- reason->type = MMS_BIT_STRING;
- reason->value.bitString.size = 6;
- reason->value.bitString.buf = (uint8_t*) MemoryAllocator_allocate(&ma, 1);
+ if (isInBuffer)
+ {
+ int length;
- if (reason->value.bitString.buf == NULL) goto return_out_of_memory;
+ int lenSize = BerDecoder_decodeLength(currentReportBufferPos + 1, &length, 0, report->entryLength);
- MmsValue_deleteAllBitStringBits(reason);
+ int dataElementSize = 1 + lenSize + length;
- if (report->flags & 0x02) /* GI */
- MmsValue_setBitStringBit(reason, 5, true);
+ if (i >= startElementIndex) {
+ /* copy value from report entry to message buffer */
+ memcpy(buffer + bufPos, currentReportBufferPos, dataElementSize);
+ bufPos += dataElementSize;
+ }
- if (report->flags & 0x01) /* Integrity */
- MmsValue_setBitStringBit(reason, 4, true);
+ currentReportBufferPos += dataElementSize;
+ }
+ }
+
+ /* add reason code to report if requested */
+ if (withReasonCode) {
- if (MemAllocLinkedList_add(reportElements, reason) == NULL)
- goto return_out_of_memory;
+ /* move to start position in report buffer */
+ currentReportBufferPos = valuesInReportBuffer + dataLen;
- currentReportBufferPos += MemoryAllocator_getAlignedSize(1);
+ uint8_t bsBuf[1];
- MmsValue* dataSetElement = (MmsValue*) currentReportBufferPos;
+ MmsValue _reason;
+ _reason.type = MMS_BIT_STRING;
+ _reason.value.bitString.size = 6;
+ _reason.value.bitString.buf = bsBuf;
- currentReportBufferPos += MmsValue_getSizeInMemory(dataSetElement);
- }
- else if (MmsValue_getBitStringBit(inclusionField, i)) {
- MmsValue* reason = (MmsValue*) MemoryAllocator_allocate(&ma, sizeof(MmsValue));
+ for (i = 0; i < maxIndex; i++) {
- if (reason == NULL) goto return_out_of_memory;
+ bool isIncluded = false;
- reason->deleteValue = 0;
- reason->type = MMS_BIT_STRING;
- reason->value.bitString.size = 6;
- reason->value.bitString.buf = (uint8_t*) MemoryAllocator_allocate(&ma, 1);
+ if (report->flags > 0) {
+ bsBuf[0] = 0; /* clear all bits */
+
+ if (report->flags & 0x02) /* GI */
+ MmsValue_setBitStringBit(&_reason, 5, true);
- if (reason->value.bitString.buf == NULL)
- goto return_out_of_memory;
+ if (report->flags & 0x01) /* Integrity */
+ MmsValue_setBitStringBit(&_reason, 4, true);
- MmsValue_deleteAllBitStringBits(reason);
+ isIncluded = true;
+ }
+ else if (MmsValue_getBitStringBit(self->inclusionField, i)) {
+ bsBuf[0] = 0; /* clear all bits */
switch((int) *currentReportBufferPos) {
case REPORT_CONTROL_QUALITY_CHANGED:
- MmsValue_setBitStringBit(reason, 2, true);
+ MmsValue_setBitStringBit(&_reason, 2, true);
break;
case REPORT_CONTROL_VALUE_CHANGED:
- MmsValue_setBitStringBit(reason, 1, true);
+ MmsValue_setBitStringBit(&_reason, 1, true);
break;
case REPORT_CONTROL_VALUE_UPDATE:
- MmsValue_setBitStringBit(reason, 3, true);
+ MmsValue_setBitStringBit(&_reason, 3, true);
break;
default:
break;
}
- currentReportBufferPos += MemoryAllocator_getAlignedSize(1);
+ isIncluded = true;
+ }
- MmsValue* dataSetElement = (MmsValue*) currentReportBufferPos;
+ if (isIncluded) {
- currentReportBufferPos += MmsValue_getSizeInMemory(dataSetElement);
+ if (i >= startElementIndex)
+ bufPos = MmsValue_encodeMmsData(&_reason, buffer, bufPos, true);
- if (MemAllocLinkedList_add(reportElements, reason) == NULL)
- goto return_out_of_memory;
+ currentReportBufferPos++;
}
}
}
- ReportControl_unlockNotify(self);
+ reportBuffer->size = bufPos;
- MmsServerConnection_sendInformationReportVMDSpecific(self->clientConnection, "RPT", (LinkedList) reportElements, false);
+ MmsServerConnection_sendMessage(self->clientConnection, reportBuffer, false);
- ReportControl_lockNotify(self);
-
- /* Increase sequence number */
- self->sqNum++;
- MmsValue_setUint32(sqNum, self->sqNum);
+ MmsServer_releaseTransmitBuffer(self->server->mmsServer);
- assert(self->reportBuffer->nextToTransmit != self->reportBuffer->nextToTransmit->next);
+ if (moreFollows == false) {
+ /* reset sub sequence number */
+ segmented = false;
+ self->startIndexForNextSegment = 0;
+ }
+ else {
+ /* increase sub sequence number */
+ uint32_t subSeqNumVal = MmsValue_toUint32(subSeqNum);
+ subSeqNumVal++;
+ MmsValue_setUint32(subSeqNum, subSeqNumVal);
- self->reportBuffer->nextToTransmit = self->reportBuffer->nextToTransmit->next;
+ self->startIndexForNextSegment = maxIndex;
+ }
- if (DEBUG_IED_SERVER)
- printf("IED_SERVER: sendNextReportEntry: memory(used/size): %i/%i\n",
- (int) (ma.currentPtr - ma.memoryBlock), ma.size);
+ if (segmented == false) {
-#if (DEBUG_IED_SERVER == 1)
- printf("IED_SERVER: reporting.c nextToTransmit: %p\n", self->reportBuffer->nextToTransmit);
- printEnqueuedReports(self);
-#endif
+ assert(self->reportBuffer->nextToTransmit != self->reportBuffer->nextToTransmit->next);
- goto cleanup_and_return;
+ self->reportBuffer->nextToTransmit = self->reportBuffer->nextToTransmit->next;
-return_out_of_memory:
+ #if (DEBUG_IED_SERVER == 1)
+ printf("IED_SERVER: reporting.c nextToTransmit: %p\n", self->reportBuffer->nextToTransmit);
+ printEnqueuedReports(self);
+ #endif
- if (DEBUG_IED_SERVER)
- printf("IED_SERVER: sendNextReportEntry failed - memory allocation problem!\n");
+ /* Increase sequence number */
+ self->sqNum++;
- /* TODO set some flag to notify application here */
+ MmsValue_setUint16(sqNum, self->sqNum);
-cleanup_and_return:
+ if (self->reportBuffer->isOverflow)
+ self->reportBuffer->isOverflow = false;
+ }
- if (localStorage != NULL)
- GLOBAL_FREEMEM(localStorage);
+exit_function:
+ self->segmented = segmented;
+ Semaphore_post(self->reportBuffer->lock);
+ return moreFollows;
+}
+static void
+sendNextReportEntry(ReportControl* self)
+{
+ while (sendNextReportEntrySegment(self));
}
void
@@ -2463,13 +3113,13 @@ processEventsForReport(ReportControl* rc, uint64_t currentTimeInMs)
if (rc->buffered)
enqueueReport(rc, false, false, currentTimeInMs);
else
- sendReport(rc, false, false);
+ sendReport(rc, false, false, currentTimeInMs);
}
if (rc->buffered)
enqueueReport(rc, false, true, currentTimeInMs);
else
- sendReport(rc, false, true);
+ sendReport(rc, false, true, currentTimeInMs);
rc->gi = false;
@@ -2487,7 +3137,7 @@ processEventsForReport(ReportControl* rc, uint64_t currentTimeInMs)
if (rc->buffered)
enqueueReport(rc, false, false, currentTimeInMs);
else
- sendReport(rc, false, false);
+ sendReport(rc, false, false, currentTimeInMs);
rc->triggered = false;
}
@@ -2497,7 +3147,7 @@ processEventsForReport(ReportControl* rc, uint64_t currentTimeInMs)
if (rc->buffered)
enqueueReport(rc, true, false, currentTimeInMs);
else
- sendReport(rc, true, false);
+ sendReport(rc, true, false, currentTimeInMs);
rc->triggered = false;
}
@@ -2510,7 +3160,7 @@ processEventsForReport(ReportControl* rc, uint64_t currentTimeInMs)
if (rc->buffered)
enqueueReport(rc, false, false, currentTimeInMs);
else
- sendReport(rc, false, false);
+ sendReport(rc, false, false, currentTimeInMs);
rc->triggered = false;
}
diff --git a/src/iec61850/server/model/dynamic_model.c b/src/iec61850/server/model/dynamic_model.c
index 88fd7a0c..4377de8b 100644
--- a/src/iec61850/server/model/dynamic_model.c
+++ b/src/iec61850/server/model/dynamic_model.c
@@ -360,12 +360,29 @@ ReportControlBlock_create(const char* name, LogicalNode* parent, char* rptId, bo
self->bufferTime = bufTm;
self->intPeriod = intgPd;
self->sibling = NULL;
+ self->clientReservation[0] = 0; /* no pre-configured client */
LogicalNode_addReportControlBlock(parent, self);
return self;
}
+void
+ReportControlBlock_setPreconfiguredClient(ReportControlBlock* self, uint8_t clientType, uint8_t* clientAddress)
+{
+ if (clientType == 4) { /* IPv4 address */
+ self->clientReservation[0] = 4;
+ memcpy(self->clientReservation + 1, clientAddress, 4);
+ }
+ else if (clientType == 6) { /* IPv6 address */
+ self->clientReservation[0] = 6;
+ memcpy(self->clientReservation + 1, clientAddress, 6);
+ }
+ else { /* no reservation or unknown type */
+ self->clientReservation[0] = 0;
+ }
+}
+
#if (CONFIG_IEC61850_SETTING_GROUPS == 1)
static void
LogicalNode_addSettingGroupControlBlock(LogicalNode* self, SettingGroupControlBlock* sgcb)
diff --git a/src/mms/inc_private/mms_client_internal.h b/src/mms/inc_private/mms_client_internal.h
index bab9bb7d..2c75a4a9 100644
--- a/src/mms/inc_private/mms_client_internal.h
+++ b/src/mms/inc_private/mms_client_internal.h
@@ -70,6 +70,13 @@ typedef enum {
MMS_CALL_TYPE_GET_FILE_DIR
} eMmsOutstandingCallType;
+typedef union
+{
+ int32_t i32;
+ uint32_t u32;
+ void* ptr;
+} MmsClientInternalParameter;
+
struct sMmsOutstandingCall
{
bool isUsed;
@@ -77,7 +84,7 @@ struct sMmsOutstandingCall
eMmsOutstandingCallType type;
void* userCallback;
void* userParameter;
- void* internalParameter;
+ MmsClientInternalParameter internalParameter;
uint64_t timeout;
};
diff --git a/src/mms/inc_private/mms_common_internal.h b/src/mms/inc_private/mms_common_internal.h
index 59e0b76e..53e6b678 100644
--- a/src/mms/inc_private/mms_common_internal.h
+++ b/src/mms/inc_private/mms_common_internal.h
@@ -56,7 +56,7 @@ LIB61850_INTERNAL bool
mmsMsg_parseFileOpenResponse(uint8_t* buffer, int bufPos, int maxBufPos, int32_t* frsmId, uint32_t* fileSize, uint64_t* lastModified);
LIB61850_INTERNAL bool
-mmsMsg_parseFileReadResponse(uint8_t* buffer, int bufPos, int maxBufPos, bool* moreFollows, uint8_t** dataBuffer, int* dataLength);
+mmsMsg_parseFileReadResponse(uint8_t* buffer, int bufPos, int maxBufPos, uint32_t invokeId, int32_t frsmId, bool* moreFollows, MmsConnection_FileReadHandler handler, void* handlerParameter);
LIB61850_INTERNAL void
mmsMsg_createFileReadResponse(int maxPduSize, uint32_t invokeId, ByteBuffer* response, MmsFileReadStateMachine* frsm);
diff --git a/src/mms/inc_private/mms_server_connection.h b/src/mms/inc_private/mms_server_connection.h
index f78fc3fa..aa65e98b 100644
--- a/src/mms/inc_private/mms_server_connection.h
+++ b/src/mms/inc_private/mms_server_connection.h
@@ -48,6 +48,12 @@ MmsServerConnection_init(MmsServerConnection connection, MmsServer server, IsoCo
LIB61850_INTERNAL void
MmsServerConnection_destroy(MmsServerConnection connection);
+LIB61850_INTERNAL int
+MmsServerConnection_getMaxMmsPduSize(MmsServerConnection self);
+
+LIB61850_INTERNAL void
+MmsServerConnection_sendMessage(MmsServerConnection self, ByteBuffer* message, bool handlerMode);
+
LIB61850_INTERNAL bool
MmsServerConnection_addNamedVariableList(MmsServerConnection self, MmsNamedVariableList variableList);
diff --git a/src/mms/iso_mms/client/mms_client_connection.c b/src/mms/iso_mms/client/mms_client_connection.c
index 7da2ee0b..13aae158 100644
--- a/src/mms/iso_mms/client/mms_client_connection.c
+++ b/src/mms/iso_mms/client/mms_client_connection.c
@@ -270,7 +270,7 @@ checkForOutstandingCall(MmsConnection self, uint32_t invokeId)
}
static bool
-addToOutstandingCalls(MmsConnection self, uint32_t invokeId, eMmsOutstandingCallType type, void* userCallback, void* userParameter, void* internalParameter)
+addToOutstandingCalls(MmsConnection self, uint32_t invokeId, eMmsOutstandingCallType type, void* userCallback, void* userParameter, MmsClientInternalParameter internalParameter)
{
int i = 0;
@@ -333,7 +333,7 @@ sendMessage(MmsConnection self, ByteBuffer* message)
static MmsError
sendAsyncRequest(MmsConnection self, uint32_t invokeId, ByteBuffer* message, eMmsOutstandingCallType type,
- void* userCallback, void* userParameter, void* internalParameter)
+ void* userCallback, void* userParameter, MmsClientInternalParameter internalParameter)
{
if (addToOutstandingCalls(self, invokeId, type, userCallback, userParameter, internalParameter) == false) {
@@ -855,7 +855,7 @@ handleAsyncResponse(MmsConnection self, ByteBuffer* response, uint32_t bufPos, M
handler(outstandingCall->invokeId, outstandingCall->userParameter, err, NULL, false);
}
else {
- LinkedList nameList = (LinkedList) outstandingCall->internalParameter;
+ LinkedList nameList = (LinkedList) outstandingCall->internalParameter.ptr;
bool moreFollows = mmsClient_parseGetNameListResponse(&nameList, response);
@@ -880,7 +880,6 @@ handleAsyncResponse(MmsConnection self, ByteBuffer* response, uint32_t bufPos, M
uint32_t fileSize;
uint64_t lastModified;
-
if (mmsMsg_parseFileOpenResponse(ByteBuffer_getBuffer(response), bufPos, ByteBuffer_getSize(response),
&frsmId, &fileSize, &lastModified) == false)
{
@@ -900,16 +899,14 @@ handleAsyncResponse(MmsConnection self, ByteBuffer* response, uint32_t bufPos, M
}
else {
bool moreFollows;
- uint8_t* dataBuffer;
- int dataLength;
- if (mmsMsg_parseFileReadResponse(ByteBuffer_getBuffer(response), bufPos, ByteBuffer_getSize(response), &moreFollows, &dataBuffer, &dataLength) == false)
+ int32_t frsmId = outstandingCall->internalParameter.i32;
+
+ if (mmsMsg_parseFileReadResponse(ByteBuffer_getBuffer(response), bufPos, ByteBuffer_getSize(response), outstandingCall->invokeId, frsmId, &moreFollows,
+ handler, outstandingCall->userParameter) == false)
{
handler(outstandingCall->invokeId, outstandingCall->userParameter, MMS_ERROR_PARSING_RESPONSE, NULL, 0, false);
}
- else {
- handler(outstandingCall->invokeId, outstandingCall->userParameter, err, dataBuffer, dataLength, moreFollows);
- }
}
}
else if ((outstandingCall->type == MMS_CALL_TYPE_FILE_CLOSE) ||
@@ -1860,7 +1857,10 @@ mmsClient_getNameListSingleRequestAsync(
payload, objectClass, continueAfter);
}
- MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_GET_NAME_LIST, handler, parameter, nameList);
+ MmsClientInternalParameter intParam;
+ intParam.ptr = nameList;
+
+ MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_GET_NAME_LIST, handler, parameter, intParam);
if (mmsError)
*mmsError = err;
@@ -2074,7 +2074,10 @@ MmsConnection_readVariableAsync(MmsConnection self, MmsError* mmsError, const ch
mmsClient_createReadRequest(invokeId, domainId, itemId, payload);
- MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_READ_VARIABLE, handler, parameter, NULL);
+ MmsClientInternalParameter intParam;
+ intParam.ptr = NULL;
+
+ MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_READ_VARIABLE, handler, parameter, intParam);
if (mmsError)
*mmsError = err;
@@ -2135,7 +2138,10 @@ MmsConnection_readVariableComponentAsync(MmsConnection self, MmsError* mmsError,
mmsClient_createReadRequestComponent(invokeId, domainId, itemId, componentId, payload);
- MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_READ_VARIABLE, handler, parameter, NULL);
+ MmsClientInternalParameter intParam;
+ intParam.ptr = NULL;
+
+ MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_READ_VARIABLE, handler, parameter, intParam);
if (mmsError)
*mmsError = err;
@@ -2230,7 +2236,10 @@ MmsConnection_readArrayElementsAsync(MmsConnection self, MmsError* mmsError, con
mmsClient_createReadRequestAlternateAccessIndex(invokeId, domainId, itemId, startIndex,
numberOfElements, payload);
- MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_READ_VARIABLE, handler, parameter, NULL);
+ MmsClientInternalParameter intParam;
+ intParam.ptr = NULL;
+
+ MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_READ_VARIABLE, handler, parameter, intParam);
if (mmsError)
*mmsError = err;
@@ -2293,7 +2302,10 @@ MmsConnection_readSingleArrayElementWithComponentAsync(MmsConnection self, MmsEr
mmsClient_createReadRequestAlternateAccessSingleIndexComponent(invokeId, domainId, itemId, index, componentId,
payload);
- MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_READ_VARIABLE, handler, parameter, NULL);
+ MmsClientInternalParameter intParam;
+ intParam.ptr = NULL;
+
+ MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_READ_VARIABLE, handler, parameter, intParam);
if (mmsError)
*mmsError = err;
@@ -2354,7 +2366,10 @@ MmsConnection_readMultipleVariablesAsync(MmsConnection self, MmsError* mmsError,
mmsClient_createReadRequestMultipleValues(invokeId, domainId, items, payload);
- MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_READ_MULTIPLE_VARIABLES, handler, parameter, NULL);
+ MmsClientInternalParameter intParam;
+ intParam.ptr = NULL;
+
+ MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_READ_MULTIPLE_VARIABLES, handler, parameter, intParam);
if (mmsError)
*mmsError = err;
@@ -2417,7 +2432,10 @@ MmsConnection_readNamedVariableListValuesAsync(MmsConnection self, MmsError* mms
mmsClient_createReadNamedVariableListRequest(invokeId, domainId, listName,
payload, specWithResult);
- MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_READ_MULTIPLE_VARIABLES, handler, parameter, NULL);
+ MmsClientInternalParameter intParam;
+ intParam.ptr = NULL;
+
+ MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_READ_MULTIPLE_VARIABLES, handler, parameter, intParam);
if (mmsError)
*mmsError = err;
@@ -2481,7 +2499,10 @@ MmsConnection_readNamedVariableListValuesAssociationSpecificAsync(MmsConnection
mmsClient_createReadAssociationSpecificNamedVariableListRequest(invokeId, listName,
payload, specWithResult);
- MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_READ_MULTIPLE_VARIABLES, handler, parameter, NULL);
+ MmsClientInternalParameter intParam;
+ intParam.ptr = NULL;
+
+ MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_READ_MULTIPLE_VARIABLES, handler, parameter, intParam);
if (mmsError)
*mmsError = err;
@@ -2567,7 +2588,10 @@ MmsConnection_readNamedVariableListDirectoryAsync(MmsConnection self, MmsError*
mmsClient_createGetNamedVariableListAttributesRequest(invokeId, payload, domainId,
listName);
- MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_READ_NVL_DIRECTORY, handler, parameter, NULL);
+ MmsClientInternalParameter intParam;
+ intParam.ptr = NULL;
+
+ MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_READ_NVL_DIRECTORY, handler, parameter, intParam);
if (mmsError)
*mmsError = err;
@@ -2632,7 +2656,10 @@ MmsConnection_readNamedVariableListDirectoryAssociationSpecificAsync(MmsConnecti
mmsClient_createGetNamedVariableListAttributesRequestAssociationSpecific(invokeId, payload,
listName);
- MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_READ_NVL_DIRECTORY, handler, parameter, NULL);
+ MmsClientInternalParameter intParam;
+ intParam.ptr = NULL;
+
+ MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_READ_NVL_DIRECTORY, handler, parameter, intParam);
if (mmsError)
*mmsError = err;
@@ -2707,7 +2734,10 @@ MmsConnection_defineNamedVariableListAsync(MmsConnection self, MmsError* mmsErro
mmsClient_createDefineNamedVariableListRequest(invokeId, payload, domainId,
listName, variableSpecs, false);
- MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_DEFINE_NVL, handler, parameter, NULL);
+ MmsClientInternalParameter intParam;
+ intParam.ptr = NULL;
+
+ MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_DEFINE_NVL, handler, parameter, intParam);
if (mmsError)
*mmsError = err;
@@ -2762,7 +2792,10 @@ MmsConnection_defineNamedVariableListAssociationSpecificAsync(MmsConnection self
mmsClient_createDefineNamedVariableListRequest(invokeId, payload, NULL,
listName, variableSpecs, true);
- MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_DEFINE_NVL, handler, parameter, NULL);
+ MmsClientInternalParameter intParam;
+ intParam.ptr = NULL;
+
+ MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_DEFINE_NVL, handler, parameter, intParam);
if (mmsError)
*mmsError = err;
@@ -2819,7 +2852,10 @@ MmsConnection_deleteNamedVariableListAsync(MmsConnection self, MmsError* mmsErro
mmsClient_createDeleteNamedVariableListRequest(invokeId, payload, domainId, listName);
- MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_DELETE_NVL, handler, parameter, NULL);
+ MmsClientInternalParameter intParam;
+ intParam.ptr = NULL;
+
+ MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_DELETE_NVL, handler, parameter, intParam);
if (mmsError)
*mmsError = err;
@@ -2877,7 +2913,10 @@ MmsConnection_deleteAssociationSpecificNamedVariableListAsync(MmsConnection self
mmsClient_createDeleteAssociationSpecificNamedVariableListRequest(
invokeId, payload, listName);
- MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_DELETE_NVL, handler, parameter, NULL);
+ MmsClientInternalParameter intParam;
+ intParam.ptr = NULL;
+
+ MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_DELETE_NVL, handler, parameter, intParam);
if (mmsError)
*mmsError = err;
@@ -2954,7 +2993,10 @@ MmsConnection_getVariableAccessAttributesAsync(MmsConnection self, MmsError* mms
mmsClient_createGetVariableAccessAttributesRequest(invokeId, domainId, itemId, payload);
- MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_GET_VAR_ACCESS_ATTR, handler, parameter, NULL);
+ MmsClientInternalParameter intParam;
+ intParam.ptr = NULL;
+
+ MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_GET_VAR_ACCESS_ATTR, handler, parameter, intParam);
if (mmsError)
*mmsError = err;
@@ -3036,7 +3078,10 @@ MmsConnection_identifyAsync(MmsConnection self, MmsError* mmsError,
mmsClient_createIdentifyRequest(invokeId, payload);
- MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_IDENTIFY, handler, parameter, NULL);
+ MmsClientInternalParameter intParam;
+ intParam.ptr = NULL;
+
+ MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_IDENTIFY, handler, parameter, intParam);
if (mmsError)
*mmsError = err;
@@ -3119,7 +3164,10 @@ MmsConnection_getServerStatusAsync(MmsConnection self, MmsError* mmsError, bool
mmsClient_createStatusRequest(invokeId, payload, extendedDerivation);
- MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_GET_SERVER_STATUS, handler, parameter, NULL);
+ MmsClientInternalParameter intParam;
+ intParam.ptr = NULL;
+
+ MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_GET_SERVER_STATUS, handler, parameter, intParam);
if (mmsError)
*mmsError = err;
@@ -3261,7 +3309,10 @@ MmsConnection_readJournalTimeRangeAsync(MmsConnection self, MmsError* mmsError,
mmsClient_createReadJournalRequestWithTimeRange(invokeId, payload, domainId, itemId, startTime, endTime);
- MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_READ_JOURNAL, handler, parameter, NULL);
+ MmsClientInternalParameter intParam;
+ intParam.ptr = NULL;
+
+ MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_READ_JOURNAL, handler, parameter, intParam);
if (mmsError)
*mmsError = err;
@@ -3329,7 +3380,10 @@ MmsConnection_readJournalStartAfterAsync(MmsConnection self, MmsError* mmsError,
mmsClient_createReadJournalRequestStartAfter(invokeId, payload, domainId, itemId, timeSpecification, entrySpecification);
- MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_READ_JOURNAL, handler, parameter, NULL);
+ MmsClientInternalParameter intParam;
+ intParam.ptr = NULL;
+
+ MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_READ_JOURNAL, handler, parameter, intParam);
if (mmsError)
*mmsError = err;
@@ -3428,7 +3482,10 @@ MmsConnection_fileOpenAsync(MmsConnection self, MmsError* mmsError, const char*
mmsClient_createFileOpenRequest(invokeId, payload, filename, initialPosition);
- MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_FILE_OPEN, handler, parameter, NULL);
+ MmsClientInternalParameter intParam;
+ intParam.ptr = NULL;
+
+ MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_FILE_OPEN, handler, parameter, intParam);
if (mmsError)
*mmsError = err;
@@ -3517,7 +3574,10 @@ MmsConnection_fileCloseAsync(MmsConnection self, MmsError* mmsError, uint32_t fr
mmsClient_createFileCloseRequest(invokeId, payload, frsmId);
- MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_FILE_CLOSE, handler, parameter, NULL);
+ MmsClientInternalParameter intParam;
+ intParam.ptr = NULL;
+
+ MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_FILE_CLOSE, handler, parameter, intParam);
if (mmsError)
*mmsError = err;
@@ -3588,7 +3648,10 @@ MmsConnection_fileDeleteAsync(MmsConnection self, MmsError* mmsError, const char
mmsClient_createFileDeleteRequest(invokeId, payload, fileName);
- MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_FILE_DELETE, handler, parameter, NULL);
+ MmsClientInternalParameter intParam;
+ intParam.ptr = NULL;
+
+ MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_FILE_DELETE, handler, parameter, intParam);
if (mmsError)
*mmsError = err;
@@ -3692,7 +3755,10 @@ MmsConnection_fileReadAsync(MmsConnection self, MmsError* mmsError, int32_t frsm
mmsClient_createFileReadRequest(invokeId, payload, frsmId);
- MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_FILE_READ, handler, parameter, NULL);
+ MmsClientInternalParameter intParam;
+ intParam.i32 = frsmId;
+
+ MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_FILE_READ, handler, parameter, intParam);
if (mmsError)
*mmsError = err;
@@ -3796,7 +3862,10 @@ MmsConnection_getFileDirectoryAsync(MmsConnection self, MmsError* mmsError, cons
mmsClient_createFileDirectoryRequest(invokeId, payload, fileSpecification, continueAfter);
- MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_GET_FILE_DIR, handler, parameter, NULL);
+ MmsClientInternalParameter intParam;
+ intParam.ptr = NULL;
+
+ MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_GET_FILE_DIR, handler, parameter, intParam);
if (mmsError)
*mmsError = err;
@@ -3866,7 +3935,10 @@ MmsConnection_fileRenameAsync(MmsConnection self, MmsError* mmsError, const char
mmsClient_createFileRenameRequest(invokeId, payload, currentFileName, newFileName);
- MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_FILE_RENAME, handler, parameter, NULL);
+ MmsClientInternalParameter intParam;
+ intParam.ptr = NULL;
+
+ MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_FILE_RENAME, handler, parameter, intParam);
if (mmsError)
*mmsError = err;
@@ -3944,7 +4016,10 @@ MmsConnection_obtainFileAsync(MmsConnection self, MmsError* mmsError, const char
mmsClient_createObtainFileRequest(invokeId, payload, sourceFile, destinationFile);
- MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_OBTAIN_FILE, handler, parameter, NULL);
+ MmsClientInternalParameter intParam;
+ intParam.ptr = NULL;
+
+ MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_OBTAIN_FILE, handler, parameter, intParam);
if (mmsError)
*mmsError = err;
@@ -4022,7 +4097,10 @@ MmsConnection_writeVariableAsync(MmsConnection self, MmsError* mmsError,
mmsClient_createWriteRequest(invokeId, domainId, itemId, value, payload);
- MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_WRITE_VARIABLE, handler, parameter, NULL);
+ MmsClientInternalParameter intParam;
+ intParam.ptr = NULL;
+
+ MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_WRITE_VARIABLE, handler, parameter, intParam);
if (mmsError)
*mmsError = err;
@@ -4083,7 +4161,10 @@ MmsConnection_writeSingleArrayElementWithComponentAsync(MmsConnection self, MmsE
mmsClient_createWriteRequestAlternateAccessSingleIndexComponent(invokeId, domainId, itemId, arrayIndex,
componentId, value, payload);
- MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_WRITE_VARIABLE, handler, parameter, NULL);
+ MmsClientInternalParameter intParam;
+ intParam.ptr = NULL;
+
+ MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_WRITE_VARIABLE, handler, parameter, intParam);
if (mmsError)
*mmsError = err;
@@ -4170,7 +4251,10 @@ MmsConnection_writeMultipleVariablesAsync(MmsConnection self, MmsError* mmsError
mmsClient_createWriteMultipleItemsRequest(invokeId, domainId, items, values, payload);
- MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_WRITE_MULTIPLE_VARIABLES, handler, parameter, NULL);
+ MmsClientInternalParameter intParam;
+ intParam.ptr = NULL;
+
+ MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_WRITE_MULTIPLE_VARIABLES, handler, parameter, intParam);
if (mmsError)
*mmsError = err;
@@ -4231,7 +4315,10 @@ MmsConnection_writeArrayElementsAsync(MmsConnection self, MmsError* mmsError,
mmsClient_createWriteRequestArray(invokeId, domainId, itemId, index, numberOfElements, value, payload);
- MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_WRITE_VARIABLE, handler, parameter, NULL);
+ MmsClientInternalParameter intParam;
+ intParam.ptr = NULL;
+
+ MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_WRITE_VARIABLE, handler, parameter, intParam);
if (mmsError)
*mmsError = err;
@@ -4298,7 +4385,10 @@ MmsConnection_writeNamedVariableListAsync(MmsConnection self, MmsError* mmsError
mmsClient_createWriteRequestNamedVariableList(invokeId, isAssociationSpecific, domainId, itemId, values, payload);
- MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_WRITE_MULTIPLE_VARIABLES, handler, parameter, NULL);
+ MmsClientInternalParameter intParam;
+ intParam.ptr = NULL;
+
+ MmsError err = sendAsyncRequest(self, invokeId, payload, MMS_CALL_TYPE_WRITE_MULTIPLE_VARIABLES, handler, parameter, intParam);
if (mmsError)
*mmsError = err;
diff --git a/src/mms/iso_mms/client/mms_client_files.c b/src/mms/iso_mms/client/mms_client_files.c
index 776f058a..de799f52 100644
--- a/src/mms/iso_mms/client/mms_client_files.c
+++ b/src/mms/iso_mms/client/mms_client_files.c
@@ -689,12 +689,16 @@ mmsMsg_parseFileOpenResponse(uint8_t* buffer, int bufPos, int maxBufPos, int32_t
}
bool
-mmsMsg_parseFileReadResponse(uint8_t* buffer, int bufPos, int maxBufPos, bool* moreFollows, uint8_t** dataBuffer, int* dataLength)
+mmsMsg_parseFileReadResponse(uint8_t* buffer, int bufPos, int maxBufPos, uint32_t invokeId, int frsmId, bool* moreFollows, MmsConnection_FileReadHandler handler, void* handlerParameter)
{
int length;
+ uint8_t* data = NULL;
+ int dataLen = 0;
+
uint8_t tag = buffer[bufPos++];
+
if (tag != 0xbf) {
if (DEBUG_MMS_CLIENT)
printf("MMS_CLIENT/SERVER: mmsClient_parseFileReadResponse: unknown tag %02x\n", tag);
@@ -704,8 +708,6 @@ mmsMsg_parseFileReadResponse(uint8_t* buffer, int bufPos, int maxBufPos, bool* m
tag = buffer[bufPos++];
*moreFollows = true;
- *dataBuffer = NULL;
- *dataLength = 0;
if (tag != 0x49) {
if (DEBUG_MMS_CLIENT)
@@ -731,11 +733,11 @@ mmsMsg_parseFileReadResponse(uint8_t* buffer, int bufPos, int maxBufPos, bool* m
if (bufPos < 0)
return false;
- switch (tag)
- {
+ switch (tag) {
case 0x80: /* fileData */
- *dataBuffer = buffer + bufPos;
- *dataLength = length;
+ data = buffer + bufPos;
+ dataLen = length;
+
bufPos += length;
break;
@@ -753,8 +755,7 @@ mmsMsg_parseFileReadResponse(uint8_t* buffer, int bufPos, int maxBufPos, bool* m
}
}
- if (*dataBuffer == NULL)
- return false;
+ handler(invokeId, handlerParameter, frsmId, data, dataLen, *moreFollows);
return true;
}
diff --git a/src/mms/iso_mms/common/mms_common_msg.c b/src/mms/iso_mms/common/mms_common_msg.c
index bb6a90d9..3f25e5c2 100644
--- a/src/mms/iso_mms/common/mms_common_msg.c
+++ b/src/mms/iso_mms/common/mms_common_msg.c
@@ -244,163 +244,195 @@ mmsMsg_parseDataElement(Data_t* dataElement)
printf("MMS CLIENT: error parsing data element (invalid structure size)!\n");
}
}
- else if (dataElement->present == Data_PR_integer) {
+ else if (dataElement->present == Data_PR_array) {
- if (dataElement->choice.integer.size > 0) {
- Asn1PrimitiveValue* berInteger = BerInteger_createFromBuffer(
- dataElement->choice.integer.buf, dataElement->choice.integer.size);
+ int componentCount = dataElement->choice.array->list.count;
+
+ if (componentCount > 0) {
+ value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
- value = MmsValue_newIntegerFromBerInteger(berInteger);
+ value->type = MMS_ARRAY;
+ value->value.structure.size = componentCount;
+ value->value.structure.components = (MmsValue**) GLOBAL_CALLOC(componentCount, sizeof(MmsValue*));
+
+ int i;
+
+ for (i = 0; i < componentCount; i++) {
+ value->value.structure.components[i] =
+ mmsMsg_parseDataElement(dataElement->choice.array->list.array[i]);
+
+ if (value->value.structure.components[i] == NULL) {
+ MmsValue_delete(value);
+ value = NULL;
+ break;
+ }
+ }
}
else {
if (DEBUG_MMS_CLIENT)
- printf("MMS CLIENT: error parsing data element (invalid integer size)!\n");
+ printf("MMS CLIENT: error parsing data element (invalid array size)!\n");
}
+
}
- else if (dataElement->present == Data_PR_unsigned) {
+ else {
+ if (dataElement->present == Data_PR_integer) {
- if (dataElement->choice.Unsigned.size > 0) {
- Asn1PrimitiveValue* berInteger = BerInteger_createFromBuffer(
- dataElement->choice.Unsigned.buf, dataElement->choice.Unsigned.size);
+ if (dataElement->choice.integer.size > 0) {
+ Asn1PrimitiveValue* berInteger = BerInteger_createFromBuffer(
+ dataElement->choice.integer.buf, dataElement->choice.integer.size);
- value = MmsValue_newUnsignedFromBerInteger(berInteger);
+ value = MmsValue_newIntegerFromBerInteger(berInteger);
+ }
+ else {
+ if (DEBUG_MMS_CLIENT)
+ printf("MMS CLIENT: error parsing data element (invalid integer size)!\n");
+ }
}
- else {
- if (DEBUG_MMS_CLIENT)
- printf("MMS CLIENT: error parsing data element (invalid unsigned size)!\n");
+ else if (dataElement->present == Data_PR_unsigned) {
+
+ if (dataElement->choice.Unsigned.size > 0) {
+ Asn1PrimitiveValue* berInteger = BerInteger_createFromBuffer(
+ dataElement->choice.Unsigned.buf, dataElement->choice.Unsigned.size);
+
+ value = MmsValue_newUnsignedFromBerInteger(berInteger);
+ }
+ else {
+ if (DEBUG_MMS_CLIENT)
+ printf("MMS CLIENT: error parsing data element (invalid unsigned size)!\n");
+ }
}
- }
- else if (dataElement->present == Data_PR_visiblestring) {
+ else if (dataElement->present == Data_PR_visiblestring) {
- if (dataElement->choice.visiblestring.size >= 0) {
- value = MmsValue_newVisibleStringFromByteArray(dataElement->choice.visiblestring.buf,
- dataElement->choice.visiblestring.size);
+ if (dataElement->choice.visiblestring.size >= 0) {
+ value = MmsValue_newVisibleStringFromByteArray(dataElement->choice.visiblestring.buf,
+ dataElement->choice.visiblestring.size);
+ }
}
- }
- else if (dataElement->present == Data_PR_mMSString) {
+ else if (dataElement->present == Data_PR_mMSString) {
- if ( dataElement->choice.mMSString.size >= 0) {
- value = MmsValue_newMmsStringFromByteArray(dataElement->choice.mMSString.buf,
- dataElement->choice.mMSString.size);
+ if ( dataElement->choice.mMSString.size >= 0) {
+ value = MmsValue_newMmsStringFromByteArray(dataElement->choice.mMSString.buf,
+ dataElement->choice.mMSString.size);
+ }
}
- }
- else if (dataElement->present == Data_PR_bitstring) {
+ else if (dataElement->present == Data_PR_bitstring) {
- int size = dataElement->choice.bitstring.size;
+ int size = dataElement->choice.bitstring.size;
- if (size > 0) {
+ if (size > 0) {
- int maxSize = (size * 8);
- int bitSize = maxSize - dataElement->choice.bitstring.bits_unused;
+ int maxSize = (size * 8);
+ int bitSize = maxSize - dataElement->choice.bitstring.bits_unused;
- if ((bitSize > 0) && (maxSize >= bitSize)) {
- value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
+ if ((bitSize > 0) && (maxSize >= bitSize)) {
+ value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
- value->type = MMS_BIT_STRING;
+ value->type = MMS_BIT_STRING;
- value->value.bitString.size = bitSize;
+ value->value.bitString.size = bitSize;
- value->value.bitString.buf = (uint8_t*) GLOBAL_MALLOC(size);
- memcpy(value->value.bitString.buf,
- dataElement->choice.bitstring.buf, size);
+ value->value.bitString.buf = (uint8_t*) GLOBAL_MALLOC(size);
+ memcpy(value->value.bitString.buf,
+ dataElement->choice.bitstring.buf, size);
+ }
+ else {
+ if (DEBUG_MMS_CLIENT)
+ printf("MMS CLIENT: error parsing data element (bit string padding problem)!\n");
+ }
}
else {
if (DEBUG_MMS_CLIENT)
- printf("MMS CLIENT: error parsing data element (bit string padding problem)!\n");
+ printf("MMS CLIENT: error parsing data element (bit string size 0 or negative)!\n");
}
}
- else {
- if (DEBUG_MMS_CLIENT)
- printf("MMS CLIENT: error parsing data element (bit string size 0 or negative)!\n");
- }
- }
- else if (dataElement->present == Data_PR_floatingpoint) {
+ else if (dataElement->present == Data_PR_floatingpoint) {
- int size = dataElement->choice.floatingpoint.size;
+ int size = dataElement->choice.floatingpoint.size;
- if (size == 5) { /* FLOAT32 */
+ if (size == 5) { /* FLOAT32 */
- value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
- value->type = MMS_FLOAT;
+ value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
+ value->type = MMS_FLOAT;
- value->value.floatingPoint.formatWidth = 32;
- value->value.floatingPoint.exponentWidth = dataElement->choice.floatingpoint.buf[0];
+ value->value.floatingPoint.formatWidth = 32;
+ value->value.floatingPoint.exponentWidth = dataElement->choice.floatingpoint.buf[0];
- uint8_t* floatBuf = (dataElement->choice.floatingpoint.buf + 1);
+ uint8_t* floatBuf = (dataElement->choice.floatingpoint.buf + 1);
- value->value.floatingPoint.buf = (uint8_t*) GLOBAL_MALLOC(4);
+ value->value.floatingPoint.buf = (uint8_t*) GLOBAL_MALLOC(4);
#if (ORDER_LITTLE_ENDIAN == 1)
- memcpyReverseByteOrder(value->value.floatingPoint.buf, floatBuf, 4);
+ memcpyReverseByteOrder(value->value.floatingPoint.buf, floatBuf, 4);
#else
- memcpy(value->value.floatingPoint.buf, floatBuf, 4);
+ memcpy(value->value.floatingPoint.buf, floatBuf, 4);
#endif
- }
+ }
- if (size == 9) { /* FLOAT64 */
+ if (size == 9) { /* FLOAT64 */
- value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
- value->type = MMS_FLOAT;
+ value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
+ value->type = MMS_FLOAT;
- value->value.floatingPoint.formatWidth = 64;
- value->value.floatingPoint.exponentWidth = dataElement->choice.floatingpoint.buf[0];
+ value->value.floatingPoint.formatWidth = 64;
+ value->value.floatingPoint.exponentWidth = dataElement->choice.floatingpoint.buf[0];
- uint8_t* floatBuf = (dataElement->choice.floatingpoint.buf + 1);
+ uint8_t* floatBuf = (dataElement->choice.floatingpoint.buf + 1);
- value->value.floatingPoint.buf = (uint8_t*) GLOBAL_MALLOC(8);
+ value->value.floatingPoint.buf = (uint8_t*) GLOBAL_MALLOC(8);
#if (ORDER_LITTLE_ENDIAN == 1)
- memcpyReverseByteOrder(value->value.floatingPoint.buf, floatBuf, 8);
+ memcpyReverseByteOrder(value->value.floatingPoint.buf, floatBuf, 8);
#else
- memcpy(value->value.floatingPoint.buf, floatBuf, 8);
+ memcpy(value->value.floatingPoint.buf, floatBuf, 8);
#endif
+ }
}
- }
- else if (dataElement->present == Data_PR_utctime) {
+ else if (dataElement->present == Data_PR_utctime) {
- int size = dataElement->choice.utctime.size;
+ int size = dataElement->choice.utctime.size;
- if (size == 8) {
- value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
- value->type = MMS_UTC_TIME;
- memcpy(value->value.utcTime, dataElement->choice.utctime.buf, 8);
- }
- else {
- if (DEBUG_MMS_CLIENT)
- printf("MMS CLIENT: error parsing UTC time (size is %i instead of 8\n", size);
+ if (size == 8) {
+ value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
+ value->type = MMS_UTC_TIME;
+ memcpy(value->value.utcTime, dataElement->choice.utctime.buf, 8);
+ }
+ else {
+ if (DEBUG_MMS_CLIENT)
+ printf("MMS CLIENT: error parsing UTC time (size is %i instead of 8\n", size);
+ }
}
- }
- else if (dataElement->present == Data_PR_octetstring) {
+ else if (dataElement->present == Data_PR_octetstring) {
- if (dataElement->choice.octetstring.size >= 0) {
- value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
- value->type = MMS_OCTET_STRING;
- int size = dataElement->choice.octetstring.size;
- value->value.octetString.size = size;
- value->value.octetString.maxSize = size;
- value->value.octetString.buf = (uint8_t*) GLOBAL_MALLOC(size);
- memcpy(value->value.octetString.buf, dataElement->choice.octetstring.buf, size);
- }
+ if (dataElement->choice.octetstring.size >= 0) {
+ value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
+ value->type = MMS_OCTET_STRING;
+ int size = dataElement->choice.octetstring.size;
+ value->value.octetString.size = size;
+ value->value.octetString.maxSize = size;
+ value->value.octetString.buf = (uint8_t*) GLOBAL_MALLOC(size);
+ memcpy(value->value.octetString.buf, dataElement->choice.octetstring.buf, size);
+ }
- }
- else if (dataElement->present == Data_PR_binarytime) {
- int size = dataElement->choice.binarytime.size;
+ }
+ else if (dataElement->present == Data_PR_binarytime) {
+ int size = dataElement->choice.binarytime.size;
- if ((size == 4) || (size == 6)) {
- value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
- value->type = MMS_BINARY_TIME;
- value->value.binaryTime.size = size;
- memcpy(value->value.binaryTime.buf, dataElement->choice.binarytime.buf, size);
+ if ((size == 4) || (size == 6)) {
+ value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
+ value->type = MMS_BINARY_TIME;
+ value->value.binaryTime.size = size;
+ memcpy(value->value.binaryTime.buf, dataElement->choice.binarytime.buf, size);
+ }
+ else {
+ if (DEBUG_MMS_CLIENT)
+ printf("MMS CLIENT: error parsing binary time (size must be 4 or 6, is %i\n", size);
+ }
}
- else {
- if (DEBUG_MMS_CLIENT)
- printf("MMS CLIENT: error parsing binary time (size must be 4 or 6, is %i\n", size);
+ else if (dataElement->present == Data_PR_boolean) {
+ value = MmsValue_newBoolean(dataElement->choice.boolean);
}
- }
- else if (dataElement->present == Data_PR_boolean) {
- value = MmsValue_newBoolean(dataElement->choice.boolean);
- }
- else if (dataElement->present == Data_PR_booleanArray) {
- if (DEBUG_MMS_CLIENT)
- printf("MMS CLIENT: unsupported type - boolean-array\n");
+ else if (dataElement->present == Data_PR_booleanArray) {
+
+ }
+
}
if (DEBUG_MMS_CLIENT) {
diff --git a/src/mms/iso_mms/server/mms_file_service.c b/src/mms/iso_mms/server/mms_file_service.c
index f93d44ea..7af7ba74 100644
--- a/src/mms/iso_mms/server/mms_file_service.c
+++ b/src/mms/iso_mms/server/mms_file_service.c
@@ -510,6 +510,9 @@ mmsServer_fileUploadTask(MmsServer self, MmsObtainFileTask task)
IsoConnection_sendMessage(task->connection->isoConnection, response, false);
+ FileSystem_closeFile(task->fileHandle);
+ deleteFile(MmsServerConnection_getFilesystemBasepath(task->connection), task->destinationFilename);
+
MmsServer_releaseTransmitBuffer(self);
if (DEBUG_MMS_SERVER)
@@ -529,6 +532,9 @@ mmsServer_fileUploadTask(MmsServer self, MmsObtainFileTask task)
IsoConnection_sendMessage(task->connection->isoConnection, response, false);
+ FileSystem_closeFile(task->fileHandle);
+ deleteFile(MmsServerConnection_getFilesystemBasepath(task->connection), task->destinationFilename);
+
MmsServer_releaseTransmitBuffer(self);
if (DEBUG_MMS_SERVER)
diff --git a/src/mms/iso_mms/server/mms_information_report.c b/src/mms/iso_mms/server/mms_information_report.c
index 30b17d82..932cc473 100644
--- a/src/mms/iso_mms/server/mms_information_report.c
+++ b/src/mms/iso_mms/server/mms_information_report.c
@@ -220,7 +220,6 @@ exit_function:
return;
}
-
void /* send information report for a named variable list */
MmsServerConnection_sendInformationReportVMDSpecific(MmsServerConnection self, char* itemId, LinkedList values,
bool handlerMode)
diff --git a/src/mms/iso_mms/server/mms_server_connection.c b/src/mms/iso_mms/server/mms_server_connection.c
index fb0a4118..8b55b45b 100644
--- a/src/mms/iso_mms/server/mms_server_connection.c
+++ b/src/mms/iso_mms/server/mms_server_connection.c
@@ -453,12 +453,12 @@ getUploadTaskByInvokeId(MmsServer mmsServer, uint32_t invokeId)
}
static void
-mmsFileReadHandler(void* parameter, int32_t frsmId, uint8_t* buffer, uint32_t bytesReceived)
+mmsFileReadHandler(uint32_t invokeId, void* parameter, MmsError mmsError, uint8_t* buffer, uint32_t bytesReceived, bool moreFollows)
{
MmsObtainFileTask task = (MmsObtainFileTask) parameter;
if (DEBUG_MMS_SERVER)
- printf("MMS_SERVER: FILE %i received %i bytes\n", frsmId, bytesReceived);
+ printf("MMS_SERVER: file %i received %i bytes\n", task->frmsId, bytesReceived);
FileSystem_writeFile(task->fileHandle, buffer, bytesReceived);
}
@@ -538,12 +538,8 @@ handleConfirmedResponsePdu(
if (fileTask != NULL) {
bool moreFollows;
- uint8_t* dataBuffer = NULL;
- int dataLength = 0;
- if (mmsMsg_parseFileReadResponse(buffer, startBufPos, maxBufPos, &moreFollows, &dataBuffer, &dataLength)) {
-
- mmsFileReadHandler((void*) fileTask, fileTask->frmsId, dataBuffer, dataLength);
+ if (mmsMsg_parseFileReadResponse(buffer, startBufPos, maxBufPos, invokeId, fileTask->frmsId, &moreFollows, mmsFileReadHandler, (void*) fileTask)) {
if (moreFollows) {
fileTask->state = MMS_FILE_UPLOAD_STATE_SEND_FILE_READ;
@@ -743,6 +739,18 @@ MmsServerConnection_destroy(MmsServerConnection self)
GLOBAL_FREEMEM(self);
}
+int
+MmsServerConnection_getMaxMmsPduSize(MmsServerConnection self)
+{
+ return self->maxPduSize;
+}
+
+void
+MmsServerConnection_sendMessage(MmsServerConnection self, ByteBuffer* message, bool handlerMode)
+{
+ IsoConnection_sendMessage(self->isoConnection, message, false);
+}
+
#if (MMS_DYNAMIC_DATA_SETS == 1)
bool
MmsServerConnection_addNamedVariableList(MmsServerConnection self, MmsNamedVariableList variableList)
diff --git a/src/mms/iso_mms/server/mms_write_service.c b/src/mms/iso_mms/server/mms_write_service.c
index acc24bad..ca4d8f95 100644
--- a/src/mms/iso_mms/server/mms_write_service.c
+++ b/src/mms/iso_mms/server/mms_write_service.c
@@ -80,7 +80,6 @@ mmsServer_createMmsWriteResponse(MmsServerConnection connection,
response->size = bufPos;
}
-
void
MmsServerConnection_sendWriteResponse(MmsServerConnection self, uint32_t invokeId, MmsDataAccessError indication, bool handlerMode)
{
diff --git a/tools/model_generator/genmodel.jar b/tools/model_generator/genmodel.jar
index 2da7859e..34e4bfb2 100644
Binary files a/tools/model_generator/genmodel.jar and b/tools/model_generator/genmodel.jar differ
diff --git a/tools/model_generator/src/com/libiec61850/scl/SclParser.java b/tools/model_generator/src/com/libiec61850/scl/SclParser.java
index fc73748d..a606b27f 100644
--- a/tools/model_generator/src/com/libiec61850/scl/SclParser.java
+++ b/tools/model_generator/src/com/libiec61850/scl/SclParser.java
@@ -320,4 +320,32 @@ public class SclParser
return null;
}
+ public ConnectedAP getConnectedAP(String iedName, String accessPointName) {
+ communication = this.getCommunication();
+
+ if (communication != null) {
+ List subNetworks = communication.getSubNetworks();
+
+ for (SubNetwork subNetwork : subNetworks) {
+ List connectedAPs = subNetwork.getConnectedAPs();
+
+ for (ConnectedAP connectedAP : connectedAPs) {
+ if (connectedAP.getIedName().equals(iedName)) {
+
+ if (connectedAP.getApName().equals(accessPointName)) {
+
+ if (withOutput)
+ System.out.println("Found connectedAP " + accessPointName + " for IED " + iedName);
+
+ return connectedAP;
+ }
+
+ }
+ }
+
+ }
+ }
+
+ return null;
+ }
}
diff --git a/tools/model_generator/src/com/libiec61850/scl/communication/ConnectedAP.java b/tools/model_generator/src/com/libiec61850/scl/communication/ConnectedAP.java
index bfa61d39..26abfbeb 100644
--- a/tools/model_generator/src/com/libiec61850/scl/communication/ConnectedAP.java
+++ b/tools/model_generator/src/com/libiec61850/scl/communication/ConnectedAP.java
@@ -36,6 +36,8 @@ public class ConnectedAP {
private List gses;
private List smvs;
+
+ private Address address = null;
public ConnectedAP(Node node) throws SclParserException {
iedName = ParserUtils.parseAttribute(node, "iedName");
@@ -56,7 +58,12 @@ public class ConnectedAP {
List smvNodes = ParserUtils.getChildNodesWithTag(node, "SMV");
for (Node smvNode : smvNodes)
- smvs.add(new SMV(smvNode));
+ smvs.add(new SMV(smvNode));
+
+ Node addressNode = ParserUtils.getChildNodeWithTag(node, "Address");
+
+ if (addressNode != null)
+ address = new Address(addressNode);
}
public String getIedName() {
@@ -66,6 +73,10 @@ public class ConnectedAP {
public String getApName() {
return apName;
}
+
+ public Address getAddress() {
+ return address;
+ }
public List getGses() {
return gses;
diff --git a/tools/model_generator/src/com/libiec61850/scl/model/RptEnabled.java b/tools/model_generator/src/com/libiec61850/scl/model/RptEnabled.java
index 6fb90d35..9282ebf3 100644
--- a/tools/model_generator/src/com/libiec61850/scl/model/RptEnabled.java
+++ b/tools/model_generator/src/com/libiec61850/scl/model/RptEnabled.java
@@ -1,5 +1,8 @@
package com.libiec61850.scl.model;
+import java.util.LinkedList;
+import java.util.List;
+
import org.w3c.dom.Node;
import com.libiec61850.scl.ParserUtils;
@@ -8,6 +11,8 @@ public class RptEnabled {
private int maxInstances = 1;
private String desc = null;
+
+ private List clientLNs = new LinkedList();
public RptEnabled(Node rptEnabledNode) {
this.desc = ParserUtils.parseAttribute(rptEnabledNode, "desc");
@@ -16,6 +21,14 @@ public class RptEnabled {
if (maxString != null) {
maxInstances = new Integer(maxString);
}
+
+ List clientLNNodes = ParserUtils.getChildNodesWithTag(rptEnabledNode, "ClientLN");
+
+ for (Node clientLNNode : clientLNNodes) {
+ ClientLN clientLN = new ClientLN(clientLNNode);
+
+ clientLNs.add(clientLN);
+ }
}
public int getMaxInstances() {
@@ -25,4 +38,9 @@ public class RptEnabled {
public String getDesc() {
return desc;
}
+
+ public List getClientLNs()
+ {
+ return clientLNs;
+ }
}
diff --git a/tools/model_generator/src/com/libiec61850/tools/ModelViewer.java b/tools/model_generator/src/com/libiec61850/tools/ModelViewer.java
index 82fde106..0997a4d9 100644
--- a/tools/model_generator/src/com/libiec61850/tools/ModelViewer.java
+++ b/tools/model_generator/src/com/libiec61850/tools/ModelViewer.java
@@ -184,6 +184,21 @@ public class ModelViewer {
String lNodePrefix = devPrefix + lNode.getName();
printObjectList(lNode.getDataObjects(), output, lNodePrefix);
+
+// for (DataObject dObject : lNode.getDataObjects()) {
+//
+// String dOPrefix = lNodePrefix + "." + dObject.getName();
+//
+// for (DataAttribute dAttribute : dObject.getDataAttributes()) {
+//
+// String daPrefix = dOPrefix + "." + dAttribute.getName();
+//
+// output.println(daPrefix + " [" + dAttribute.getFc().toString() + "]");
+//
+// printSubAttributeList(dAttribute, output, daPrefix);
+// }
+//
+// }
}
}
diff --git a/tools/model_generator/src/com/libiec61850/tools/StaticModelGenerator.java b/tools/model_generator/src/com/libiec61850/tools/StaticModelGenerator.java
index c790ed6a..5bc26a10 100644
--- a/tools/model_generator/src/com/libiec61850/tools/StaticModelGenerator.java
+++ b/tools/model_generator/src/com/libiec61850/tools/StaticModelGenerator.java
@@ -29,17 +29,24 @@ import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.PrintStream;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
import java.util.LinkedList;
import java.util.List;
import com.libiec61850.scl.SclParser;
import com.libiec61850.scl.SclParserException;
+import com.libiec61850.scl.communication.Address;
import com.libiec61850.scl.communication.Communication;
import com.libiec61850.scl.communication.ConnectedAP;
import com.libiec61850.scl.communication.GSE;
+import com.libiec61850.scl.communication.P;
import com.libiec61850.scl.communication.PhyComAddress;
import com.libiec61850.scl.communication.SubNetwork;
import com.libiec61850.scl.model.AccessPoint;
+import com.libiec61850.scl.model.ClientLN;
import com.libiec61850.scl.model.DataAttribute;
import com.libiec61850.scl.model.DataModelValue;
import com.libiec61850.scl.model.DataObject;
@@ -53,6 +60,7 @@ import com.libiec61850.scl.model.LogControl;
import com.libiec61850.scl.model.LogicalDevice;
import com.libiec61850.scl.model.LogicalNode;
import com.libiec61850.scl.model.ReportControlBlock;
+import com.libiec61850.scl.model.RptEnabled;
import com.libiec61850.scl.model.SampledValueControl;
import com.libiec61850.scl.model.Server;
import com.libiec61850.scl.model.SettingControl;
@@ -103,6 +111,8 @@ public class StaticModelGenerator {
private String hDefineName;
private String modelPrefix;
private boolean initializeOnce;
+
+ private SclParser sclParser;
public StaticModelGenerator(InputStream stream, String icdFile, PrintStream cOut, PrintStream hOut,
String outputFileName, String iedName, String accessPointName, String modelPrefix,
@@ -131,7 +141,7 @@ public class StaticModelGenerator {
this.logs = new StringBuffer();
this.logVariableNames = new LinkedList();
- SclParser sclParser = new SclParser(stream);
+ sclParser = new SclParser(stream);
this.outputFileName = outputFileName;
this.hDefineName = outputFileName.toUpperCase().replace( '.', '_' ).replace( '-', '_' ) + "_H_";
@@ -1078,6 +1088,51 @@ public class StaticModelGenerator {
gseControlNumber++;
}
}
+
+ private String getIpAddressByIedName(SclParser sclParser, String iedName, String apRef)
+ {
+ Communication com = sclParser.getCommunication();
+
+ if (com != null) {
+
+ for (SubNetwork subNetWork : com.getSubNetworks()) {
+
+ for (ConnectedAP ap : subNetWork.getConnectedAPs()) {
+
+ if (apRef != null) {
+ boolean isMatching = false;
+
+ String apName = ap.getApName();
+
+ if (apName != null) {
+ if (apName.equals(apRef))
+ isMatching = true;
+ }
+
+ if (isMatching == false)
+ continue;
+ }
+
+ String apIedName = ap.getIedName();
+
+ if (apIedName != null) {
+ if (apIedName.equals(iedName)) {
+ Address address = ap.getAddress();
+
+ if (address != null) {
+ P ip = address.getAddressParameter("IP");
+
+ if (ip != null)
+ return ip.getText();
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return null;
+ }
private void printReportControlBlocks(String lnPrefix, LogicalNode logicalNode) {
List reportControlBlocks = logicalNode.getReportControlBlocks();
@@ -1091,20 +1146,75 @@ public class StaticModelGenerator {
if (rcb.isIndexed()) {
int maxInstances = 1;
+
+ List clientLNs = null;
+
+ if (rcb.getRptEna() != null) {
+ RptEnabled rptEna = rcb.getRptEna();
+
+ maxInstances = rptEna.getMaxInstances();
- if (rcb.getRptEna() != null)
- maxInstances = rcb.getRptEna().getMaxInstances();
+ clientLNs = rptEna.getClientLNs();
+ }
+
for (int i = 0; i < maxInstances; i++) {
String index = String.format("%02d", (i + 1));
System.out.println("print report instance " + index);
+
+ byte[] clientAddress = new byte[17];
+ clientAddress[0] = 0;
+
+ if (clientLNs != null) {
+ try {
+ ClientLN clientLN = clientLNs.get(i);
+
+ if (clientLN != null) {
+
+ String iedName = clientLN.getIedName();
+ String apRef = clientLN.getApRef();
+
+ if (iedName != null) {
+ String ipAddress = getIpAddressByIedName(sclParser, iedName, apRef);
+
+ try {
+ InetAddress inetAddr = InetAddress.getByName(ipAddress);
+
+ if (inetAddr instanceof Inet4Address) {
+ clientAddress[0] = 4;
+ for (int j = 0; j < 4; j++)
+ clientAddress[j + 1] = inetAddr.getAddress()[j];
+ }
+ else if (inetAddr instanceof Inet6Address) {
+ clientAddress[0] = 6;
+ for (int j = 0; j < 16; j++)
+ clientAddress[j + 1] = inetAddr.getAddress()[j];
+ }
+
+ inetAddr.getAddress();
+ } catch (UnknownHostException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ }
+ }
+ catch (IndexOutOfBoundsException ex) {
+ /* no ClientLN defined for this report instance */
+ }
+ }
+
- printReportControlBlockInstance(lnPrefix, rcb, index, reportNumber, reportsCount);
+ printReportControlBlockInstance(lnPrefix, rcb, index, reportNumber, reportsCount, clientAddress);
reportNumber++;
}
} else {
- printReportControlBlockInstance(lnPrefix, rcb, "", reportNumber, reportsCount);
+ byte[] clientAddress = new byte[17];
+ clientAddress[0] = 0;
+
+ printReportControlBlockInstance(lnPrefix, rcb, "", reportNumber, reportsCount, clientAddress);
reportNumber++;
}
}
@@ -1259,7 +1369,7 @@ public class StaticModelGenerator {
this.logControlBlocks.append(lcbString);
}
- private void printReportControlBlockInstance(String lnPrefix, ReportControlBlock rcb, String index, int reportNumber, int reportsCount)
+ private void printReportControlBlockInstance(String lnPrefix, ReportControlBlock rcb, String index, int reportNumber, int reportsCount, byte[] clientIpAddr)
{
String rcbVariableName = lnPrefix + "_report" + reportNumber;
@@ -1326,9 +1436,19 @@ public class StaticModelGenerator {
rcbString += rcb.getIntegrityPeriod().toString() + ", ";
else
rcbString += "0, ";
+
+ rcbString += "{";
+ for (int i = 0; i < 17; i++) {
+ rcbString += "0x" + Integer.toHexString((int) (clientIpAddr[i] & 0xff));
+ if (i == 16)
+ rcbString += "}, ";
+ else
+ rcbString += ", ";
+ }
+
currentRcbVariableNumber++;
-
+
if (currentRcbVariableNumber < rcbVariableNames.size())
rcbString += "&" + rcbVariableNames.get(currentRcbVariableNumber);
else