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