From 549de2f7ed58a18af59df8267b11c7a9127171e2 Mon Sep 17 00:00:00 2001 From: Michael Zillgith Date: Fri, 15 Feb 2019 11:38:47 +0100 Subject: [PATCH] - IEC 61850 server: added support for pre configured client with ClientLN --- examples/Makefile | 2 + .../client_example2.c | 2 +- .../simpleIO_direct_control.cid | 31 +- .../server_example_basic_io/static_model.c | 22 +- examples/server_example_config_file/model.cfg | 4 +- examples/server_example_files/static_model.c | 14 +- examples/server_example_goose/static_model.c | 4 +- .../server_example_logging/static_model.c | 14 +- .../static_model.c | 2 +- examples/server_example_simple/static_model.c | 4 +- .../static_model.c | 4 +- .../server_example_threadless/static_model.c | 8 +- .../static_model.c | 4 +- examples/tls_server_example/Makefile | 2 +- .../simpleIO_direct_control.cid | 360 ++++++++++++++++++ examples/tls_server_example/static_model.c | 189 ++++++--- examples/tls_server_example/static_model.h | 20 +- src/iec61850/inc/iec61850_dynamic_model.h | 12 + src/iec61850/inc/iec61850_model.h | 4 + src/iec61850/server/mms_mapping/reporting.c | 37 +- src/iec61850/server/model/dynamic_model.c | 17 + tools/model_generator/genmodel.jar | Bin 89615 -> 93579 bytes .../src/com/libiec61850/scl/SclParser.java | 28 ++ .../scl/communication/Address.java | 42 ++ .../scl/communication/ConnectedAP.java | 13 +- .../com/libiec61850/scl/communication/P.java | 38 ++ .../com/libiec61850/scl/model/ClientLN.java | 72 ++++ .../com/libiec61850/scl/model/RptEnabled.java | 18 + .../tools/StaticModelGenerator.java | 107 +++++- 29 files changed, 959 insertions(+), 115 deletions(-) create mode 100644 examples/tls_server_example/simpleIO_direct_control.cid create mode 100644 tools/model_generator/src/com/libiec61850/scl/communication/Address.java create mode 100644 tools/model_generator/src/com/libiec61850/scl/communication/P.java create mode 100644 tools/model_generator/src/com/libiec61850/scl/model/ClientLN.java diff --git a/examples/Makefile b/examples/Makefile index a6d6d5d9..3b97707c 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -42,7 +42,9 @@ MODEL_DIRS += server_example_threadless MODEL_DIRS += server_example_setting_groups MODEL_DIRS += server_example_logging MODEL_DIRS += server_example_files +MODEL_DIRS += server_example_substitution MODEL_DIRS += iec61850_9_2_LE_example +MODEL_DIRS += tls_server_example all: examples diff --git a/examples/iec61850_client_example2/client_example2.c b/examples/iec61850_client_example2/client_example2.c index f2e6be37..92afae44 100644 --- a/examples/iec61850_client_example2/client_example2.c +++ b/examples/iec61850_client_example2/client_example2.c @@ -124,7 +124,7 @@ main(int argc, char** argv) while (dataSet != NULL) { char* dataSetName = (char*) dataSet->data; bool isDeletable; - char dataSetRef[129]; + char dataSetRef[130]; sprintf(dataSetRef, "%s.%s", lnRef, dataSetName); LinkedList dataSetMembers = IedConnection_getDataSetDirectory(con, &error, dataSetRef, diff --git a/examples/server_example_basic_io/simpleIO_direct_control.cid b/examples/server_example_basic_io/simpleIO_direct_control.cid index e4845770..ad1a69c6 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 @@ + @@ -74,12 +87,28 @@ + + + + + + + + + + + + + + + + diff --git a/examples/server_example_basic_io/static_model.c b/examples/server_example_basic_io/static_model.c index ead912c0..276d60da 100644 --- a/examples/server_example_basic_io/static_model.c +++ b/examples/server_example_basic_io/static_model.c @@ -2009,15 +2009,19 @@ extern ReportControlBlock iedModel_GenericIO_LLN0_report4; extern ReportControlBlock iedModel_GenericIO_LLN0_report5; extern ReportControlBlock iedModel_GenericIO_LLN0_report6; extern ReportControlBlock iedModel_GenericIO_LLN0_report7; - -ReportControlBlock iedModel_GenericIO_LLN0_report0 = {&iedModel_GenericIO_LLN0, "EventsRCB01", "Events1", false, "Events", 1, 24, 175, 50, 1000, &iedModel_GenericIO_LLN0_report1}; -ReportControlBlock iedModel_GenericIO_LLN0_report1 = {&iedModel_GenericIO_LLN0, "EventsBRCB01", "Events2", true, "Events", 1, 24, 175, 50, 1000, &iedModel_GenericIO_LLN0_report2}; -ReportControlBlock iedModel_GenericIO_LLN0_report2 = {&iedModel_GenericIO_LLN0, "EventsIndexed01", "Events2", false, "Events", 1, 24, 175, 50, 1000, &iedModel_GenericIO_LLN0_report3}; -ReportControlBlock iedModel_GenericIO_LLN0_report3 = {&iedModel_GenericIO_LLN0, "EventsIndexed02", "Events2", false, "Events", 1, 24, 175, 50, 1000, &iedModel_GenericIO_LLN0_report4}; -ReportControlBlock iedModel_GenericIO_LLN0_report4 = {&iedModel_GenericIO_LLN0, "EventsIndexed03", "Events2", false, "Events", 1, 24, 175, 50, 1000, &iedModel_GenericIO_LLN0_report5}; -ReportControlBlock iedModel_GenericIO_LLN0_report5 = {&iedModel_GenericIO_LLN0, "Measurements01", "Measurements", true, "Measurements", 1, 16, 239, 50, 1000, &iedModel_GenericIO_LLN0_report6}; -ReportControlBlock iedModel_GenericIO_LLN0_report6 = {&iedModel_GenericIO_LLN0, "Measurements02", "Measurements", true, "Measurements", 1, 16, 239, 50, 1000, &iedModel_GenericIO_LLN0_report7}; -ReportControlBlock iedModel_GenericIO_LLN0_report7 = {&iedModel_GenericIO_LLN0, "Measurements03", "Measurements", true, "Measurements", 1, 16, 239, 50, 1000, NULL}; +extern ReportControlBlock iedModel_GenericIO_LLN0_report8; +extern ReportControlBlock iedModel_GenericIO_LLN0_report9; + +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_config_file/model.cfg b/examples/server_example_config_file/model.cfg index 8f79d452..6957c7b4 100644 --- a/examples/server_example_config_file/model.cfg +++ b/examples/server_example_config_file/model.cfg @@ -35,8 +35,8 @@ DE(GGIO1$MX$AnIn2); DE(GGIO1$MX$AnIn3); DE(GGIO1$MX$AnIn4); } -RC(EventsRCB01 Events 0 Events 1 24 111 50 1000); -RC(AnalogValuesRCB01 AnalogValues 0 AnalogValues 1 24 111 50 1000); +RC(EventsRCB01 Events 0 Events 1 24 239 50 1000); +RC(AnalogValuesRCB01 AnalogValues 0 AnalogValues 1 24 239 50 1000); LC(EventLog Events GenericIO/LLN0$EventLog 19 0 0 1); LC(GeneralLog - - 19 0 0 1); LOG(GeneralLog); 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/Makefile b/examples/tls_server_example/Makefile index 2ddb3e43..1f7ea160 100644 --- a/examples/tls_server_example/Makefile +++ b/examples/tls_server_example/Makefile @@ -4,7 +4,7 @@ PROJECT_BINARY_NAME = tls_server_example PROJECT_SOURCES = tls_server_example.c PROJECT_SOURCES += static_model.c -PROJECT_ICD_FILE = simpleIO_direct_control.icd +PROJECT_ICD_FILE = simpleIO_direct_control.cid include $(LIBIEC_HOME)/make/target_system.mk include $(LIBIEC_HOME)/make/stack_includes.mk diff --git a/examples/tls_server_example/simpleIO_direct_control.cid b/examples/tls_server_example/simpleIO_direct_control.cid new file mode 100644 index 00000000..ad1a69c6 --- /dev/null +++ b/examples/tls_server_example/simpleIO_direct_control.cid @@ -0,0 +1,360 @@ + + +
+
+ + + Station bus + +
+

0.0.0.0

+

255.255.255.0

+

192.168.2.1

+

1,3,9999,33

+

33

+

00000001

+

0001

+

0001

+

102

+
+
+ +
+

192.168.2.9

+

255.255.255.0

+

192.168.2.1

+

1,3,9999,33

+

33

+

00000001

+

0001

+

0001

+

102

+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + on + + + status-only + + + + + on + + + + + ok + + + + + + MZ Automation + + + 1.3.0 + + + libiec61850 server example + + + + + + + ok + + + + + + + on + + + status-only + + + + + on + + + + + ok + + + + + direct-with-normal-security + + + + + direct-with-normal-security + + + + + direct-with-normal-security + + + + + direct-with-normal-security + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + on + blocked + test + test/blocked + off + + + + ok + warning + alarm + + + + status-only + direct-with-normal-security + sbo-with-normal-security + direct-with-enhanced-security + sbo-with-enhanced-security + + + + not-supported + bay-control + station-control + remote-control + automatic-bay + automatic-station + automatic-remote + maintenance + process + + + +
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/src/iec61850/inc/iec61850_dynamic_model.h b/src/iec61850/inc/iec61850_dynamic_model.h index 78c9ee76..4bcb0e9f 100644 --- a/src/iec61850/inc/iec61850_dynamic_model.h +++ b/src/iec61850/inc/iec61850_dynamic_model.h @@ -160,6 +160,18 @@ 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) + */ +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 86e64021..b4b6e95d 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/server/mms_mapping/reporting.c b/src/iec61850/server/mms_mapping/reporting.c index 0f1a260c..9459349d 100644 --- a/src/iec61850/server/mms_mapping/reporting.c +++ b/src/iec61850/server/mms_mapping/reporting.c @@ -1158,7 +1158,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; @@ -1329,7 +1339,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; @@ -1695,7 +1719,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"); @@ -1760,7 +1785,8 @@ Reporting_RCBWriteAccessHandler(MmsMapping* self, ReportControl* rc, char* eleme rc->reserved = false; - updateOwner(rc, NULL); + if (rc->resvTms != -1) + updateOwner(rc, NULL); } rc->enabled = false; @@ -2008,7 +2034,8 @@ Reporting_deactivateReportsForConnection(MmsMapping* self, MmsServerConnection c MmsValue* resv = ReportControl_getRCBValue(rc, "Resv"); MmsValue_setBoolean(resv, false); - updateOwner(rc, NULL); + if (rc->resvTms != -1) + updateOwner(rc, NULL); } else { if (rc->resvTms == 0) diff --git a/src/iec61850/server/model/dynamic_model.c b/src/iec61850/server/model/dynamic_model.c index a1de52ed..1749f058 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/tools/model_generator/genmodel.jar b/tools/model_generator/genmodel.jar index 2da7859e584b8deaed1abca51a5fcab5397bc2de..4d6ee5d4a6b82892bb7d747228eeb28970870f13 100644 GIT binary patch delta 31164 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 @gYQ0fAx|z(Asj z;SA&fKPY+d=L#g5I|-C0UVIC|Kd60R!UtqeP#ppo9!Q3O4)h8M{Dz9#9j&j(aT2PB z+rmfXG?DTLqtqXUXDXehLcsD^!Lf=12(LOo`>cnnKcab|3gjC%Ai9O4^_4tsvi@cq zHz5A4p&G=6<47&Xa@wHr2t(zf{^%mVUwrB$zrXa>gAXJW9#ot{rU9416Oqdal^{0o zAL3je81Fy@h$9YAp8X0={$~qPhy%(V8mc}CK^VYK|)G5uyOxn72l)m z1HB$h-TA>ViQ}jmS8!x@gI?gNtQm)ynBuah zRjRZZKP?fyIceBt%W8(rP$h@POGaBNwJu9KC;_Fm#c|Z?m|Ofw=NL{>-PG)r4gyN8 z8=*PPM4U@%n0cH_dYBWo#WD1Pp&d2U-FC%2)PAcx5&v8yO}^I~dhJ8~1u6fU=7Y6Qb#RmG)I&A<85Q*zmv^-<*0^R7`@ z=IPYd4(9RH=l16L)QgcW=rj)I;6Dn)r^GXKB~xD1&Df~MQd4b*E27k=)9uWo5ZAMz z-niW8u}9VAr|Ia*OM{c;<*QW{q}r&{mw-#IY`DdMkknQ6W)o4Mk~jPyY@VuPYo*=dC<89H9P0I+&G%z3d2UsAZYpon;a4?hil#&5X{Tk$ zJnGx!(Y@?W8O&GvV_~J;hA3Fg2U19(f#zi$j`m#wxHkx-f2cgI#a1yf{aItRJ%B6P3hrCB4_MRU8fwx? z8_KSJWINLuQ*eWz;~I;x(eubWt}EngW2vvJdeDNY5YV@0z{d1TPY{}}0jAB9QhB0E z3)wKD;2@~;%lY~AYnAD&z)h|zb=RPRqvEj%#0t%Q86j$;#SYuiu$V{$sIfx?4iRCJ zN-!O&?Q1Ml+u&2V%*AjwM#np!Fk$w4Rrk%7^Vt3SfEDX2PnsQ2XQQQ8Vkh%HW4kyvCVj~9&<}zk*BGe z-h84QP@0MT-pETAh!c|3ggj!Pcs^-1+Ue;rTO6stD&y#~uELXB(E>jr43jsz9^9x9 zdz(w_9AAHDk8I74RpUU4KW>>S^$V+XXNVR?gZ+foSixo&$c#YJ28F;G4Ekp$j=iIl zOBYJycE4#p%cwmGG85~uoldNIe&L6N$=vM{R-q>+F8hSAUJ{o7@I-UK*?=h-TWx_p z#cU#}HYW&Q#Z{^yA2r?nmwV4Dgq^YDS5xyNjVdL8L1tssM<+|x4I)manLPa6qB3X3 z9rLX1vML<}a1ljOpV0mcXJH*@!%epO=!VzgV(8_fItds%+sAhaty8jKcwA$Y`5X1u znXUR8j^2?-B^9Ub!Z<&=_bwKsGb2-EO29q_0^;&XqB$=OrS>&$Rv{rXC6&dkKxCn1Eo$!tS@%}KIQ z$FFf?0O-%LaE|QDk-U5!U9FW2*DFUY?*SJ-aR0 z{k+EZJbmCb&@>dDGr%l#dyTx|_fHlIThg*v20&+*qMi?tKAJcJqsm5t)Lv$iU9QXG zMuPEa*LE+d^Z7-mdhG@{Dv>nbA5wkvZ4#P{x_zVtYhw1y6X^3-#-2DojXQPjaozuD zYC{W^X|<(M5d&ovwvIs+SbTeH9D!vbn>siwu2n4)TbR{8YB(%W8Q+_9dW)lVzCYlj z15e$e|9u+>d}l^WWPtj?p={Vo_f^+IQ7dLclB{c7acZRK1K|&uw(^bj^it3GjKxi= z9eMmO#^iN~LBz`UhjbqT4jWe9AJ&5g=QB^K@AOL95f=$WHj8}ACs_qC1QZE2yyabK zoeX$gU^TsK`A6r%v>n;v7qW=A?t&w8b%1i|@}RzxqlMr|oOrz+ewQfDU8J|0ge^wz zqOBxqP|3G!y`Ye*W1$COd&Q&%!VSCxzUB$stq?Y#zUjL{vwqYcO+BdyC_C*l%@A@_ zJ3j7T%F*OLap*$lUWi5d7t*{sR+*mRLXw^P7Pq6@v$cl$dTqta8dleukAi!NEx?;x zOiP{ko$Uq&AGMWN%B`dM;0JceujJL&NL1SQ#9!%$$95XQ!Ohfb^IL08(3Xkc90-Q! zkvcxcTE4SCU8n*%ZRPjziZ~=m?KLMADh2#P3neiLV^Xpz$Y+yKL3(pu^Ro{eNl_~o;Vw3AC?D#r$~DS&<}428@* z?)mZ-4^ofkeck9=`SOZSov8j6t0&DR#3-WW1|GJpCz_`N}P4t%1m!i#`!Of5h&yD z88;@XKSTA*52|rl6sVx+Gobq|?e94#O-c`EAnHKtA%giO<-8hk&O*uvpgk84;DZljhh4J!MTQs~p7rX<(*{M-l80`GFPyHW<9xSft$>qTD2&UvYsm|y zW#(G}GydZF*1|Q8QLtt8X*ZTS#zOQs%W4@prfXI@{We-UUTd`Yanm(_^|DyTYGf%E z#1x6hdZEoxXj3FLU$uNj)N)ugZ3?5(T>=AxpCc$GwnyKn9it#=+s5Bov7poSS1TUk zL|i_b-_fRANrfVz2%wx%SH(xs?t9J&!f%+tvcEaB6|y_O37_G1tfn?u*zNz zG~4_O@+j5@*TB=xP#mXj zhPb(c-v6qZ2hZw4yvEL~%tb2DYEdWrsiCTR@VYQ4t9zD`bRSmYm|1x;D-9gbD{BZ9 zwfW1mDa?)x2|&?o;u;G6*q>HxZVH0fn|Q$sKeca*ynhR` zgr5dM%d%sz0N^V4oxZJUq|0#Xljx`HDnz!5=9HLK{s=I#&*;EMOUo=)Hw z5=_=7hI0j9EOfRsYxho3FHpQ9?I1>to^M`99j`?x)I2E3w8Zu&yg*`OFz6G*&a;!e zBx!=1zc2W*Csg|>P!B845`97_^N;De0YPmw>2lxMSq-gWc_DnsiTWxoh1b-t2nQ2y zz{<@RU`k$!18HiDU;y5L9Thul(DLxy2;>k3XHCC?ba5$pp5ukh_%IAp{cZm=24_g1 zUga-6c7izgjX!L@#9GA#(`i5Oz)+eOo6VkSUSLeOleH{r=%o$Xm531_@o|);@*YY(bqJY}a`Dh()UxKYE+4T2{%72PY!Dto+32`@cdjCm`KPBZ zxs|2Z5Y}n8xQS3>e*`n4t#(*wAcB$;y%H^x@?yn|9h5HyxKf5xcP^PtwR<|Vjm8|I z{JA=NLh^fRuHqDgys{W7Gmd(NRO>wO-6`-&io5Vx9-7$jnzBo4uu!5o0(1pVU%4F8Lu28;__=*QD{J z8_b%1vJ1|48Z*lI`;pM@XQ|09V{2 zZKvbdfLCjLm9@6chyA!8WMsFK^{xcnx4PzC2giDjiTF6gWK-fji^PNC6z1Q&umbi& z^dE_gRsV^j^Abd3zBVi+W{v?sMc8=?qAdmzTa;gWtS^!237Y23p^+nx&2vnS@FrMy zf*4NFI?XpifR=elM&fvvt^on+N2Ss*@1iO)iI(x!^*Fd&;mcNPf|s%GtDP6jlFqs( z^smY$8_sK%d0Kosj-7p4@iq1*U$9@o=i~e=uQ)v3lL{aQx*v0Wu(G3o+FT9RE*94e z=kHVT`U(Jgm^44Q^raBh&IFXig2-da~cU8k!k9N5STK z$}Ejz{o}_;b5*a?_?3kLu4u;JbBRc%ypa;A@4<159Ewqcwy-)SaLNdu5as(5#^a_? z1PlEX^~IQSJr80*djgO-C;P{V>52{G&8g!(E1Bu3$NA?PhxC`7!~WABY|L+S$~^no37B^u z8-9oOhMf6g{|1E7pa;2z1|3DN?05agd@V8GANm4!;0$sNNrhLAz(TIi_bT@yenyNj z8n%b=l*Ca6ZE6WtY@wGFO(}l{xs54I&nh~7k4oa3swAtUFBSrP&{Y^4su^3v!CHS$ zSu&^O80n#hK_3VLMr=AexXVfIVFhreqf3&n)caVZ;nxFT&iF`jWPfkFTrf+PmAMvK zu!&)nq_B^*T>`9}##Xa21oWc^P`H9Z4Ly|+DR6(!6`$zZ%+m9}sK>=|g|XUYS>zH` zWtAG+6F#xx;@cFyGpUJ7vNy^sApng&az!24AWhT>kl!Hy^21HOK`%S;%uYJEem6qu z)YsBDZYUi|p|pT*YLnv;)YHXF6aCJ|l+}0gz~t;n^h(+}^?lzbT(7OQy}Qy?dlUcI zc=xL=lAK;go_z3>haT4-YLXtp%QUsu*&Io4lW9C-r0B@F#HJ#+(!8BCy| zJ;7cqwS^iPn~-^_f-&Tx#N{BU?6q&X7n^t82`H^^z&3XMWVd1bD05=Bv@@OhkktY5 zHYf77s-*2!S*IOYC%;l|3iTak^&MgL-|?$no8Uwj)*BKPf;#C2TQGS|SGbP9j34rL-O^Uod}+%7g7VsCVS!CG{_9eaKZ{v z#af&a&y+VI>sof}(JU>hQ1s3A^U#1`LPoQMTA{>ewA1nzWHFK8yF2YyQq)Q+D9A>` zh}oiK1LPr5MhkEH;|c%{ChTz2iItb3f;e2&-Ow_5A_q<4DY z_lO!jYQq`#BYtiyXVVi?CIR&ICi2d#xgdirh|V~su$?XW&JZIQ?`AI5iTa41CEYu# z*TGLm4#COxVeEDyV(GE{@M(b1oaI>2ova8viKgnBDy^@!xsTp|?5&3flu>o9_0vNMxu( z^wZOlL2bL71p(r5Bf#$WR2iH`q;}#cK+AG5b^mJ8ANUl^IY#Vw5E^nJjM< z%;G0gL6^Wlv!(b=8c}&=zg~~bNX1}8l*!Kqm9j2QGCLy$SwRY;5T@~@rsts)CY4&F zr44(BD@08o)I3M*yS#KJ3FSR=DNGP23_Y)gKxBk~&QH@V6Srg`ze*cjGNXwv6?Mz8 ze919)xgw1sN2;6~8V7t|99i<<_aYZ<9xJAWk_p@e=QzLpne~>%wGm9yt!|U!`iHfG zxY6A>e;ex*q$@ke_B^$jNkr@p%SbxlCU1OZi-ugVKH0 zMI1cl^=h8YksT<9JBF>9BC}ajX=6MC;ua%OEcglKgQ0XsrwL@+s71Z}B*>45x6Pdx zjIj-75mVVj+`30V3fD2??1f4B=?Ws4K6HW`6tE4w8~T0^o_#Q(3R^G;c~58lPG}s? za%A*|@G`_>8+cIk{uz1xim4D}qAT;3ha91^iOV}WeZ-or16i;96APg<$v8#s#ihK_ zWYKi8wOmx)9uiP5tGZ^Y5K59OY9kb}9VG3z0HZ~|gfnzAbyNtzWBqtxYrkpoPQIr{mfGC zG~kk$Qp(bUO4AMabM?{Fm5oNiBTcSUGy{wUZNXNxTu^$^L$Q>H5u{31 zcSJv>HqU;%1W5rl&xC{n-&S*{=gbxoMNz`a$SxyZG}rJhnKVNK;EdeU&YC1tjS|D` z+hddQiDJZm+qRb^bR##@Dw6j}gQbr{^0-%&H zSOpk5h=H%Pio}1-@9yC@(CQ0FPb2p(HhOpj_l`S>8VgYntvd@;9&NU~EJ$W*j0)U? zmF0y|$Jfg4NkSAUKCsFBu_TeDYvF9!4(*<^e*(*wOxp@*WSz76^vM#ge1UCF=)(-z zl92_Rm>TvmtVUae<=oWevDjwa)qILq)a5Ts!>#3fiZ_aiMEapuzs^~^&^6j!FV%`# zesiJZ#b|p~#OJVWwka|E{mxdMgIQO*>DgEG)G_>%cdx!<>WQcBq#T<&ioDE@}~YPX_g&lXEsV#m7q@6>Na%g-57EHR^MTg9V`UeKi6Xu;|XvrbI;8>~)` z#x{n_`8>!%m*;ZcPn7yMbQkUwij^K~{Fx}*Z$zzH5k?!xBR?-j=`M*wH!s0!3*UPo zg7LqN=#HcWW9KbPj(h|o^X4a;RE#M`V*vG0I(tFiu(G8~lX!cAl7-Bs-0n!U4|mQK zO_Lr-lRILg*%xHbUEpGc_;%t*_U|XtvCO7<(xkj3%QZWgV1;E`2D^wXxg8x8}G zOQZY)TTSwmW7e!G_*NYB8E3oUycI)PLS6DkM_$9!z4Z93-~d;82M|a^M8tRi+|4 zb|RT9F###77j_XWYyF(AUCF8-8IGy)ea`f-bE;_v42AUl+-=n6?HvTDar2O9ad)(8 za(9eRmpds~dZ1398>h~F(&o(3<}lIbM5uA^sB)8~DhW+n3rwG*r_Pno<`B{5DV|;U)P~gB1DV6AIy84(o7*cF;!c zXOG&?g(5H$QSkoIhkwSpW5z*GuD{*+{E6~MWxuRmsC%Q&IyQIinE_`jVbiuWO}qxWb*y@Kisl-4VPYFdQ1v4zd44H+ z7M8gB5x@L_Du2h2y8r*w;GgHO6xjzVwt*rg@1Kvr1gQV7NvhJGnw5u+f|ZANts{S{ zB=vBxPOi(2RA|FM;S3q}S4`__?4(;)!=}hnrhka)YC#7zc zM3X73m~vyhi6}nr`iuOr-mP~DgJ3(k*Jd86n9;TVK7Q79wY3L&jh9nG!C9V(i1x`(PW6wWwLSo6;`Ne)0+;v8bDpr?{iQ7ayWD9TYUZY)Z-&|w_$4bKUv|sb)ybkQV z0e}&zr}j46U=O)3zP$IlYpp>HYz5Z74Kwdkm2?^38Cz21AXz zjgX+6J@7UZxm|!rJgY3;wjk3cg1**|wiZZV{mH5Mk)nE2QL?=t+Ex%{FM^12zg3G_ zFyr_5&X`g#+x$*<4b`8RH{Ey5*q^xv%qeU_?oJq=lwC6!kAIy8&inGc-plVt=sbZ3 z;E_y020)-bro2%K=QOY?TEJbJt-PTtl~j1)j%Nw{O6v1>7{Mp~hBb0>%eBW&(NLqi z{)8DAXg!d*P62S%$r#c|d$l{t7-p|*rR(QATJp1#%Y`AR2tld11V=ejSx5N+=QiIH=>tWggkhp0pG=?9lX^L5KAoI!F-Y-0)g>tEHi+tx?)OHjQWvtX_UcEXC)p?C2@q083u+`t z8;YX;zzF^UGx?i)z_+i_vd^_zeri5GwO3O$cF4KH@c??AnIylc@cH! zuqI~vM+0S|F44S{*Sn-s16?D~>WIktMfflBE(Dbc=NWl?c~Av1uK?xd9gj7$0Gj6B z;}9#5x%M2V5V0GM`zhuKJrF)%kR>bx#9sb5qsKpx+;-uh>mA5NFxOya1@iM^7zo;% z-)Q!KPCfwY2p|0ii(m7|eO1;w zX1G19S+*A(v&L2f9bJU2H)sbp?Q_4cV*LT_S!;^~x$`E`Oa%7~>hvk!PRg)m0pK(bEOiD_vHlo(uSk^GJ;b9< z$zr92u=wzi$I6=cLMq)>zY;hh()}97kTVrOqoSR&oC3?f2#r8t{UpKv&T-S<91i>= zn~gpBq6$1gjPXxhq~{WOFXkC#Z+a`E6~rPWi?w?%+d$Ia9J~~ea{Vdl&Sql7bsXGm zAm+IWXRB={ECnm9VkXOEisX>tFT*kvY3+(tiSuhGsECpL2ia1Ay-%`bnnLh@>m05# zoa3{BcCj*UOT#JSp>ecvaxt_mB7Pe=%bCZdD1ole3X!vX= zkn^r!T|hQO_6eB0J%X+3s8u=Jo<84-uKQ%?HF<*byV9v9gThi^?E1&|pYr1aVNhQ} zFv=pL{Quzjp9+d#|3SOIHLynhgBf`vam5iqT6m(kPe!}%OT15!HFa`5*wm(M5+=_= zMyuQ8T*_v`pqpjcZp2TT){f$Q`6+8-AnE^7?h3SYghddc8Eu&@<$0qE`S2{oBw+Tv zOD2tdUPeqynFPjNPPkx)yh*cdHgzwLP^(CB{*5B}^^?5^KZ+eT~-9(JR z{)DV3aLi$&6HM5ZR)MX!z{Si>c2H^{-vF}r&fmJlhHON=#cVdKxl30eEt{(k=sWcJXVtvHA3DlfxzHPOt}usai_o|2?!C}Na@ngDb3 z=1D}HXpByU)M0D2@Q+EVMuj(~loalo`DUFbu_OyJ!<;LU-sbi5kV+(ofx867)|R8t z?X2f-=eh~38t(4o4J?RC5>6yUG39I>c9o$+f#lXfrA;VJgG3VZ6DHKE6}pAZzsFA7Q)ZBaO<~S| zZ*#|1$qb?SC;rb3=5GSW5w9DzB96_-)G;Avg~yS#8?hrsjhf4Rgr6I@J3vMT;;sej z5=B>t595kHbVkpPy$U_p-J<9q*TTRFp=SOVoTSC2NsMjp9)9`v^zs?x+m z^z+94q?nn?4DziQ97b0crkv(=Zysjr@M>z??~)MNuXayY=B_o5Y1x_0`F>rB2PM9U zF*|KFnQ+exE=e*d_D4CIK-CH3h!@f|6svLZwz#sz#15+_m#4~gE$~R*@{0&(W^r6M z{3g7%vvH)@jDU@vg}86k%_lOB6^r3Ec6n14(OGjvbTvTSlf$0XlKVWbtmyI55@UYJ z!9tI_d@9}|huqPS(@f8!Lp<0}azJL&K44Zyk)RN;u&+uhBxLz{j4CW#&u)lC?7>i~ z_U#r@OWXUtZc_f9A0UkBzd(>hb0|#f#NUo~D9Y<34v!=-3)h9EI<}52b`FzoB8E8j z>XhCE-x-zmQQ3t@Hpl!;_G^>Xjfa5c)~q7hU$3n*!HAsLw8O$EZ*$lys_vQy-5iMa z+ZPiYmWd_`2;Q8+i82ak^9eSg&Ob$ssdz^`*89raq}YzU0HlD2Vq8XJjHglKCdFQQ z?Wm1Wu481kgg2h{{>X`jnDStk)g_v;)loQ}2U*lNZSn9$Xg zo1ma{ZW@*sa6ZFmQ-8MXpNGxs@gTRE)i9?J+xZ)wjJrwCyYKd&_r|}}9+VdL_@4Y{ zm9F3LaYRmECf*zGaZQTO(?%*^J-2^HaYbUZpyPH=H>n@Oi7x+bicMf>Z-V}^mNgM* zPa>}G0DJcxm*E34JRpkhqXM(wH~C+SiGSN5omv99H-w6f3?}juQ-4{(*VdgLf%;Z!wR!U*Xro0~tnPse4kz*JOXE zjm>*!0W7NK1YQ;Em>H}3PN|n~ER$d61%$L;i4*eF5wdg%Db<4gW4Ac}I4=VKlyn|o zvi~*h{#$v=lhx5Yukh#=62m6!C>7J|6zwY_EE!EE?|iKh=`f-~woafzwz=A-${b==|MMq68~&=5KU;RuWltD`U87 z&i_`Yo%tYdWk6K_w)xXpXjy%uk@8$DlQ4W*03!K}RyL`msDUts0}oZ=OcIxgW+=*? zeKwV5SX~beXR^vQE*ECQVsFl!f0sJuFpv+Ddq(fRG1n=whNKdCao>+UrwHIa^ z73lp66%PbcpAAV`7aZFLIf}L)YZHuLENd{F>_*@^Fxtw`221ml9r5Ty={aYeC@bo$ zVE)=dVvh=cHIL^#4Tw#{7Io-CQ!m4TnH*zP$37ucFwK3&YxRaz7Ws-&YfGTu;04Q) zbs;c7K7@IagU$VEuewo-?=x)gs*^9T4zNkFub@rAHkJNW`>%_O@*6G2uKJ8U)&x5) zvx8|W5^kv%wfafRJJ_>0xyDHMUohFf@F)bqlKU3uz6>+&)ho4$9v!(3CgpnsKa?#* z`qhR%FGI3T?H;7<}<9r-7lSN5#nu zn-G=!|5Mgg$3@jIeU=6(DXAr-yF)sp8!74T?p|r>SYT;I8tE=YIwS-{N|5eWK|*+U zS)Y3!-wXeo&v)`yGkfOj&WZa{M^?3h=%;If-Zc{UJhd~;I~~&C zl0cj@GOgl_G&F}Btl{JA-%j5#OtMw(C9sx;^iFNxN%kS=;q%cus*xW3aZl-kjj|ch zP$8Na0xt{JUI{KYHW$s*9Z8M57ZhJhC@jXaHoR9d1V5Oy5!(#sn5B23jDuSW)D3Xe zhpl{@b!+krS0du{=m(K(cY zOj{oRbN)7WP!RDX&Uv|}`-4^eMzr>)X@ygE z7Y2t0K(G1*be?u>N8-{ti}lj-)nsK}Go{DBJA@6(;s7h2)XYoR!Q`qvsGQEbDsHDT zC-qCOr}bX47xZ({Z~C}R>J2A9wUt=6F9~0q>+d2C00~Kzv5=Kb&d~yw)V)t66EH={ zFUZ$-T7De=patVwX(19BM}W@PxyoOfXtGN6XKGs>G%L!!U6x(tZjlzLaPab^KaRvX z3o&Y$B?)hWsu z0cF~&Gv3YZ8_Y|TZ!}#SH6Lp(_09}$<8H>ezNsjPVR>g<`iLMOo_6SM14!D6>o>x= z1bV|kI6cTbhv#3NvztZ7`J5*gcX^Iqx-M+8bAt};Ud_)nPTJ~5j0)Q0=nO85h}Dgx zJbGwa|ElwPIT zEJR%z3uURhW(OxEns+lq$n-WQQ2oUDxn6-*$|Jea|1r6)CC z_qqDi`WN==DZ1Qn@096h2Sp3JXs<}$wdo{#S=j!rm5SnQbALc+VViZ09@YaaLgA10 zK<*zOZx|bCr&YDwj_83LYEBG|g%Mk9gA8IN(L!gZd4s+Kf6J{$V}GyjkvMuUo_%)f z4l2(b7=O@zS$_7Bn2h_e$R4FWN5gTb-ee`Y>GzM)+x!w&wi_?FPj?o}DbH_lpO}pn zPCJY{^$vN)&Q$@4+K4w>G#)W&!yh%X%U9y2|*IrhVwuHb&_^r`ju zB|FK3aQf({)1G`Yw2NWfZJ#ze7MO6pkwopJS>FXBlE<6Yn0{k+8m%I~Z~>n3f$APB zS~`|rt%!J|QB{hN_`m%SB}pT^>z-Vs5`jfeb;Ziqqo_nPs#(&5xk)$ohOpam1j|o4 z3qzf?!K{S`*F<-#S8!x_w3y9oc!asKYR#HdiJScOFZ~p)fi32cW~Jw`tR^TO(&ZNW zY1Rh<^dAJ6rOtD;K8owVX=k{Zc)Is~v1tDtw3~)Sl!#V%|P`?Lpb4`Q+8N zH%3Fp+8k>gY0AGAN33rwH$C2)wrP23e0jM#!f%o5QN^U=f;TggV3AO-`?aW&z?VfZ z1})vN&u3Hjw5{Ic=Cu5%(U=3E$-m@~@bb0c;O`e$LVpwSt;18~UE?y0CN|9j2 zWd^22r>~9((3@f~d!_}@mpSR_G9|HWGl`@tryGwDjjWH5ZDMR1Y%*KY2crs8MvZT| z=Ejc>4u~*ra~7yw68r*O30i8!n^xnBV^w7VmWsK(kW@myY$cUs{ziIx(No28>~s?+ za?V+e^C4Fz+2wWX^UcA`{mV}(;TrCE;|df_RKioWmAJYL0xQ)LG{oF56v;RijN`#Z zxE&Z>#;rj$y{-zAw^XoZ9Gak3A6WqegxCo958M9LE$7aQ1Kx{++xsWV{S}xcP!xXQ z5cm|NyZDS;hvW{3K40s^92KYGtemdQ@rhkFIma%Zu#TobO1YffyP+d0(h7X!!t|3T zc>nH`ukBSVFR@aV<}0rOG*jSRdLmI*gCcc=kTlg<-f`}C75iJlwHnJ}>*Y@41T-?^%P=gY4uocYm<4^!` zh#61$)``D8-)e3N{w4hZ`0%ime(Hwfo5@3WTvHF#)yKnv+Aj4ykv+0nFBl|k@vw~J zSV^aD>iDf?Ql?|GQV9~RGt1pkYf@Pc0<@Z4c=?Fp&k|EIETayS6@z;evSPt4Lk^7= zpuoo^HoP7S3S{lVqFg*)vduG%Dvnv5_RzKtR;vEO-2CE-?xH?6y&>=LV&-K9BYbioxurnA&1NY?&Z{DpKSAg1XrfqRzp2ur`T6H_`t5OJ zkCz8E$VDW5<*GUpr%#d9Rd&Z!V(K#_Ye8i8KdlIu&lr-$54E;ANg-gt5T{eVw9^#~ zNYiZGv$ZPbys_$SPeOq=_8BhEJ`{gA1p`en@~MZv?)BOUJi`jgjQ60TBOsXXEZ&>N zGKnp*`@-ivGubrs)jD6Z$GQ@ei>}h#SXwZE?#G+xf>MLCi0u4lY=$j36$5x|59UGk zb9tn_%@`r2#os2#GpfB=aPkXvDrW#y`C9qRRUxFDYBM22$rq4NdX6yxa!dv@i{3PnybiEB)zm> zVKs}7(Kjz67nf-ft9EeVv3#gieYFnXSa5IRp}XmAdtW0dc>0?*M)I;``!puV7P2S{ zj?{bEWq`IMKq3^pxP~7r)4mhFC53$~IpyF-&`#TgLLyyFSz>BB-}&mjOT4MmR1JdD z%g289ww#Sf#F*EP`Gx1CqD3=p*@8c4MZ2Vny06K}E~wd}f4>KQzN1(OZ|w|^vQ6%} z<(-%mT5O4Hz&gD(=HnKXdc^Ds;<`b+%Z&b7EXK#_>*w>SKJE({o7mFbKG##jxjTl) zmG^`eqtmO*sJmMR+)6-M`$d^+5BVh=VI|Gmn{Kf=gkf&JRIE=aVMUQU9SiblKc@5J zF;X?LEKrWSySXUMk&}kk106m;Y7CtD`Qr#Ilkh?+bd>tNbjJ%CKriRRAW&ptD&@d6 z$InrEPvk0Ambq z+Z%P-jX2xgB&le$kbk_?-Ls32Xm&rcquJD=$?-RDKGpRjca@N0ot?O73lN*-bb<~m z+!>g*o*US(s-peS{2OtBZ7yT0t(`JjAe_N$d8Gwu#h@(!V-0c*6F zhwE4y#WVWDS9&g150f8La&ftQ8m? zq}l|4+rSv=iF6*sz{;gnExdXsDsasVxDh;JeqDa8{fi z76`T(fS^ICAOHi-Wk>*Ef!LV=2pdq}y1+F;?y)`?)?8JDdGAVtN$VlJzZrOPpQXXS zGX?H;15S@DGF&+nhcH?I@ETGEy#GL@+bj(xW5WQr3f77Ke;WW)3V_)_u#pVsYAD@i_>VbZkh7MtBY_m57`P~l&IRn_{I=@L z=Vpicn5B@{ge=mhNQjC=g(y_Mf--aM^ATfDgTLcmzBa33`n3}-p(NHpEWL;)$7r{!EYZ~Fnihr6dXMrY&qJxMt_nT`70)NNpLYN!j(!B5OLY~V zS44N-yiAcS-;Lfg`|PRnW6B*#w`6hQbh$BCDwXl@Ek1F%aj~Iol!9Ibg-rdeP?lA- zRvw>n!4j2he!$+~S@9#J-*oZCBIMk&AFv!yu~b0hOmFBk1>GKz6K?k)HdwxsE7Q@F zJw;jkz(9=hMXZ|eS9MM2wPDAFz+u6oIWZ36xpe_VUdt5Qqm(l~U(EjW1?6BihsY5BSdp=uJIoO+B+Pox&3~_Pq4Ix)}gRL_(bA!v>KOI5dG;QK2wW$F-?TTiyB*rfv=GFrSBxg_*Y8`xywJoNNS#|bM%Nxro z+TR%e5Y&nMp3jJ^YHTQcF`D;%S?uDyAn5LTkqSZ0Tr5G5i+!~+f)t|xe_WACF%#@2 z9xgSyFO=MU-3m(XmSx)!Dzj7=tWA6fEEFE_Vsp@+s%1+)JDivm!3MZLqXr6Lci?9x zWW3PjMQX4>L(FP+zB2Kgd^>L*FulyskRx>+H$%_S(7Dz8?AYdQ-eH2sVzs2{5{_<8 zcgC(yD~C9D8%y$zOMS}$pR;b&!l9$hjCIK?ovKAg8&*(|+Sn6S#>__~xlDnF0jEc4 zI+gwjYr?Y-hL*HzB5cTx%VoZG3*w;T6&c5aokUX%Lkm@bneAV*K8s2sw^M4C&j-H+ zRW+TYJA?=Mmx{U6wk}eCV>@WfEceT6wyqJHI(v`3Y0+P|lnuJc@E;sqLs%YNdmUkp zA%ibRN0AERVljt)e5rJ3P3_l7o7X0GWIBkSvL17ftLjjjsjJ!r^V+Hr27hE1uv=h% zZ=!7`nZe#}(_r$oY`LCY;0Yd(D(|R*SahOkZ0jzqO#cYYX0c_l#-=i=o&H3Z(_b%8 z%+1Jv)M>cX?JiF0lTSt7i+G{?BxFS8_EPYyxce=v-23sZ zF#5gfi!6|=nEP?S_OZs)(^Ry-ZypMUaGil!ZUndodp_8UtJ20bI9Wt7*knlzI$?az z?6uAX4SI)+9Ba(u{-&~$HTYfs^?+%4(;|Qvmt;NdChMAL*XV{hA|f*)BBC{-2w62O zUs+U^#nmdmz_se+(UnJ}Y4T=8=OmS4|Jgvk0!xbExt!K%CpVrV{r7?Q3Q8Zz<>-pH z6Mm;??+w4j2rhO5Un-X7*s(`o%OD(0BCQ={TJ! zU!m{+LME?0r7^NGC|jYl4WKggdrAH)JJ!{W;MSNow_JB-nxJBSrv|WCyIw7*rj(C3eVKvs zSc6&hX)$Hp+%vKyrQo%g{3$E#0El0Gsdk)F7hV1y^GxB?bzgb@l(zO&vY&x*JTE5z z77bK8O&zPCk$?#8f1-gyAUqv5)c)rFPYz*e!9@i4!ZT(|EINQ1PHBN=?sC-oK+yut zhFpNZ6H-eXAz=Sc`h~@jSvvqh%jP415IQ`PKvORt{7RDznqC9!0YojC)PVPYLJusj zx!D6SA+z=X?3NUIz>7c09Tu=)gcb=V0L~vzpc=;ixC_hl_heOWfEFBs59a^weutb-Uy3-kzNAOrX7h^MO2t0)YlHg3e=*2X69w+sCX3ng)emiAT6 zF=Xgd6-$jxRZTNrstgt#s=jc1X)jjXX}cI3uo^<7x_Eaz9x!n^(ROjxcN$HJTAR7x zF`4LEwlffN>eDg;>J{wgVk-GI(%<5qgz`<(o%4v`RhMJ;Mc?-qC}{oPL%Ppjpy0+1 z({PiH^m5^Bn(h8l296v@QvwLRjiU|)e0#Qj;M3@F-ZG{a)QNAtsha;wflj^ z?VB)(GJQ6_PP&6GHkCWgZdMjuvn~{n)`{(d+c$4;YPQUoO+NOTp0<sJ>(;4MXa}~elcw@E8Z#L|Lu(M`Ow6kIbY4t4H zLg;bs^{cQ#7GaRPO1C?aG0A%9YrOK-8k@@?o82VTAQSbzM_A~F~MnC~J18n!<{2}+qkHY|RqZu)7S%xq$TmS$<%w5w?k z5yvpFZ+&S7v_+aMo$DS+7|GU|>K)j5B{^DNp2d%jLRRxe=lFTY?BT9$p|V9TwCUsQ zu+w`<*WfJ_`sq>)j>4f&vkEs@yYYv}9Kq^aX=6=C&; z(q|78It(LQFb?WmzF;K$((>b4gcLX|+Jx$ZEc2Ut4Aevr;YZ<-9lmVWMfvh`oURN@ z2gxi&saxRcc+V3^gnMEmdEHu6&pQT=k?xnl+e0}lZ#guWk~G-tcg@z13X@AT-ai~2 z>o)6SuiGvgJ+Rhcn9I2q6E|^H+-$~DF#nDcfk^7-Lb3dEdAc>`ld*rSRUXIA)c3U7 z?uTL{#t9%Z`;#k6@4{xZLYkW8HG&!KPe(sp@ij5n@tXM#`Z%y3ey!|I3c(g!5ym#{ zf$$^aX_sjfKF)s11WswZ@OwqE*kTZTeE$GPqvj z9diBJJ^f{x%&Id(a?^8n-~r>pUA}NYfhOtLXFK9~B9>V@fw4(DjCBD#h4hVSE26z}G@=FrvP|pkxw?2IMK0l?#sNulSZyBDZ$Q;<)E2s z@vdtH9lb0})o`EsP+Xa#x~QH^mBiV>Y3Azc0h;%9!@#KIo+?jlU3Dbm|HP7@J3UWU zRY2N#*U_gG!67}<=jetK_{8W|s75ZKF{7n@D`n4(~h(@C}vR%eaF=ci*q6)#&9IL0L-uFdC`sj%EVcczif z%|Mb6sW{pCTn)0pVmn#pj$Y)=EQO4+qmTSXW5J^lAOBHyZh@wMK&YA_#y9- z&ngu|%Us7O@$s*PScw^Z?o=z8-(Qzj@^A7|WuW$rPGH9I=C%CNw>hOJHsm?_M2L&H zuX`nG-twODv0#Y!+iWBc9{TZD_&);HU)bcH4)FHHdr0j+ z72eJ>4lBkDe&jgb^puzUwnT<5FACrk(R%2)v7uFIXjzwrJR#gh@jyFYAyI|}buB`f zpETWi%Vtd1hdx0e(^puyPwFg9Meb$l$)o7qc-w}J0+W)0LQcZ3?9~YPVg$e)Bm2cl ztMQC#JTjhFX2#_rwy%z;l1=tSL^VNHpm4@d>)YuV{EzO*6ZuIJLZs7*6kQ!Y_ zs57YJnp&L=`ukY)tRE^F)n&~TqXp0g*RL7&dmA-VKTjonL!)-NHp3Jcc}SY`93;E7 z-nz!=sRiCsKgISxil*l`xS z2}lEhiMD2vxIgG>j7UAa*Gl>Y*iv4fVr<&U3%+o&ifQ0Q7xBx8G`U?zY7N@H21t1J zA4-m28hn^|yaoI~FB%2yBFg9DNhw~m2~qLy^hrB)D>=y`arBWHMPP&G#*HXT zye!E(Zx+LqpDSaGTC!Q`)*5zGYSliL{(y@5A-agig#$_Kk-VAWPA=o zyX*9Arx{ z7T`d zDxsK@&KXg@TAgpW`E9)g^271>3w7=qHR813F_C6ANx4-Cw~r@PLFGVUBh3-4)^h_t zK{0#276A0D46n1tpIjl_(09Zs{L;@Mj_OSKpuLqT&zXPMEFgisa~u#DuDqi*d(H9n|kx#g3b+Ajq3_Yleu7hmwZpp?@Eau(leQPYcJk>b4n? z6)Zn_Mp;dbJ*y?|QjGXjDzY`npNje|)-natpqbtY%6MhOCFs$UF;=T=*QR;#r^62u zgLvLl{OZzVTgt0z7Mw8mPBOD3Hk#ov+FG<+{YnQ7P^qEH)gM^6r0Iu>%dybON9@{v z^dSnz^7v5q8*w0QvT}R=bW(f$_OrRc0a?F4;=7zhxyfZ6-gq3}`h7A~n{JiOq0%Qz z1#L0yzbg*9OnX7I2{`?PV79J6U?NQ})uIJuuk#vr#DlL*_>FIH`^^HI{J^b;d<#>= zp~&INb($h&y88WcPOc}%nV(~Ui3ENrguUT)}&E4WxvEl*XG$T zR#B~XC(nx`q89 zq<*ZkiZR^f#}5XZ_s`mW9~~E4Aki($^(SrK!EOuti;0j1p^X>O$^U&@2&>T|w1}w! z(EpS+xxMLHoHYO~|Gu|^R#lN(G;{zZe`=RkdH_LmSa}KdE(ypJeSq-&Z6d^19{_*Q z1u2JNFb>GJK0p$F#rhmzi~+;$+tx!;o&)sYgoEb*GDHLnuql89LTvzGgey}vfTDEN z|Db4KV`>73hyehL8m8mlZ6q20^R5cmMI<};6+1KJ=pW91KbPbBi&H}QUOBwwBq~J3 z5P$`D$jA_Cdd&?y2_}Xl!qEFlc0LRxbiYSG83KTC^c03-`$ADVHVtI}A|V323qMTc z-(_*$zf7y%3xIP2AO4R}-uOkP67=>x4BFJ6=Px14AgC33Fk>k0{|M1llcBvpK|laP z3-J7Z31Pp0xdzEH22jBr?lguvd=hz&-uwp*GJ&F8F;JA9=>HFcSOTJz4hb~@5FygU zLrzTq@K=~XI8323xJghMVp!pw89sRlFjP7NoN`I=mz%Ivv#d`lGQ)tsdxZTjHv=*t zr=|cAxC$;as0#kqFcq-6JT)ARhoPHq?onuEo|+mq#hRBLJ$caCdIl|aF#M(QW7Rz; zwK;$UE-z{hmG7*BpG{?I)q^l_};zR-=y$$g{_u&ifx1{bc$nf5fJ_!=HT~xN1$~tJP3vDKjUPx zh5G1pbx(qNP6+X{1>nOcHxWikzP%^SVL{{6GEC||EF3{eNMa}eNS!%=9KvAt&vsR^ zgW~R}e{g8E3>%VU_m8PpP$FV12IRyBKn+>61CYbb+@BpJd zL1&xuuh|lTOTdb3G;pV0*+cb*th z=XHZO)Xo5u>u)=}lyHTCYycw2D~EpuQ{wK;JmVCNFHeqY=8xTl~4#ezQC_&cb%a@`AMH~|=G zV2kkY+y*@<|N1N920$hyp!Go~C#c!`1q*V5E=;HRJx&R+R|Vig$e~0Un8_-nRFZh; z*vFt_r~j841cYHJ0JtuT2m;NG4 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/Address.java b/tools/model_generator/src/com/libiec61850/scl/communication/Address.java new file mode 100644 index 00000000..6906a2d1 --- /dev/null +++ b/tools/model_generator/src/com/libiec61850/scl/communication/Address.java @@ -0,0 +1,42 @@ +package com.libiec61850.scl.communication; + +import java.util.LinkedList; +import java.util.List; + +import org.w3c.dom.Node; + +import com.libiec61850.scl.ParserUtils; +import com.libiec61850.scl.SclParserException; + +public class Address +{ + Node node; + + private List

addressParameters = new LinkedList

(); + + public Address(Node addressNode) + throws SclParserException + { + node = addressNode; + + List pNodes = ParserUtils.getChildNodesWithTag(node, "P"); + + for (Node pNode : pNodes) + addressParameters.add(new P(pNode)); + } + + public List

getAddressParameters() + { + return addressParameters; + } + + public P getAddressParameter(String type) + { + for (P p : addressParameters) { + if (p.getType().equals(type)) + return p; + } + + 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/communication/P.java b/tools/model_generator/src/com/libiec61850/scl/communication/P.java new file mode 100644 index 00000000..32794865 --- /dev/null +++ b/tools/model_generator/src/com/libiec61850/scl/communication/P.java @@ -0,0 +1,38 @@ +package com.libiec61850.scl.communication; + +import org.w3c.dom.Node; + +import com.libiec61850.scl.ParserUtils; +import com.libiec61850.scl.SclParserException; + +public class P +{ + private Node node; + + private String type; + + public P(Node pNode) throws SclParserException + { + node = pNode; + + this.type = ParserUtils.parseAttribute(node, "type"); + + if (this.type == null) + throw new SclParserException(node, "type is missing in P element!"); + } + + public String getType() + { + return type; + } + + public String getText() + { + return node.getTextContent(); + } + + public void setText(String text) + { + node.setTextContent(text); + } +} diff --git a/tools/model_generator/src/com/libiec61850/scl/model/ClientLN.java b/tools/model_generator/src/com/libiec61850/scl/model/ClientLN.java new file mode 100644 index 00000000..b3275aea --- /dev/null +++ b/tools/model_generator/src/com/libiec61850/scl/model/ClientLN.java @@ -0,0 +1,72 @@ +package com.libiec61850.scl.model; + +/* + * Copyright 2013-2019 Michael Zillgith, MZ Automation GmbH + * + * This file is part of libIEC61850. + * + * libIEC61850 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libIEC61850 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libIEC61850. If not, see . + * + * See COPYING file for the complete license text. + */ + +import org.w3c.dom.Node; + +import com.libiec61850.scl.ParserUtils; + +public class ClientLN +{ + private Node node; + + public ClientLN(Node node) + { + this.node = node; + } + + public String getIedName() + { + return ParserUtils.parseAttribute(node, "iedName"); + } + + public String getApRef() + { + return ParserUtils.parseAttribute(node, "apRef"); + } + + public String getLdInst() + { + return ParserUtils.parseAttribute(node, "ldInst"); + } + + public String getPrefix() + { + return ParserUtils.parseAttribute(node, "prefix"); + } + + public String getLnClass() + { + return ParserUtils.parseAttribute(node, "lnClass"); + } + + public String getLnInst() + { + return ParserUtils.parseAttribute(node, "lnInst"); + } + + public String getDesc() + { + return ParserUtils.parseAttribute(node, "desc"); + } + +} 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/StaticModelGenerator.java b/tools/model_generator/src/com/libiec61850/tools/StaticModelGenerator.java index c790ed6a..c8febe3b 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,24 @@ public class StaticModelGenerator { gseControlNumber++; } } + + private String getIpAddressByIedName(SclParser sclParser, String iedName, String apRef) + { + ConnectedAP ap = sclParser.getConnectedAP(iedName, apRef); + + if (ap != null) { + 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 +1119,75 @@ public class StaticModelGenerator { if (rcb.isIndexed()) { int maxInstances = 1; + + List clientLNs = null; - if (rcb.getRptEna() != null) - maxInstances = rcb.getRptEna().getMaxInstances(); + if (rcb.getRptEna() != null) { + RptEnabled rptEna = rcb.getRptEna(); + + maxInstances = rptEna.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) && (apRef != 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 +1342,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 +1409,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