diff --git a/CHANGELOG b/CHANGELOG
index 25ac39bf..dc24b4be 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,29 @@
+Changes to version 1.2.0
+------------------------
+
+- IEC 61850/MMS client/server: Added TLS support (TLS API and implementation for mbedtls)
+- IEC 61850/MMS server: removed deprecated AttributeChangedHandler
+- Added pkg-config file
+- The Sampled Values APIs have been renamed. The old version of the API is deprecated but still supported and will be removed in the next major version of the library.
+- SV Publisher/Subscriber: a lot of small fixed and improvements
+- .NET API: Added support for sampled values (SV) subscriber
+- .NET API: Added support for GOOSE subscriber
+- SV subscriber: added function SVReceiver_enableDestAddrCheck
+- IEC 61850 server: fixed bug in buffered report module - report can be lost under some circumstances when BRCB is enabled
+- SV subscriber: replaced code that caused unaligned memory access
+- IEC 61850 server: added memory alignement for buffered reporting
+
+
+Changes to version 1.1.2
+------------------------
+
+- MMS client: fixed parsing initiate response message
+- SV publisher: conditional encoding for SmpRate
+- MmsValue_update function now allows adjusting octet-string size of target object
+- .NET API: Added DeleteFile
+- CDC helper functions: added helper functions for VSS and VSG CDC
+- added additional locks in client and server
+
Changes to version 1.1.1
------------------------
@@ -19,7 +45,6 @@ Changes to version 1.1.1
- MMS client: MmsConnection_getVariableAccessAttributes support for VMD specific variables
- Java SCL parser: added support for "Val" elements for Octet64 types
-
Changes to version 1.1.0
------------------------
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 95e47983..690ac7bf 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -11,8 +11,9 @@ project(libiec61850)
ENABLE_TESTING()
set(LIB_VERSION_MAJOR "1")
-set(LIB_VERSION_MINOR "1")
-set(LIB_VERSION_PATCH "1")
+set(LIB_VERSION_MINOR "2")
+set(LIB_VERSION_PATCH "0")
+set(LIB_VERSION "${LIB_VERSION_MAJOR}.${LIB_VERSION_MINOR}.${LIB_VERSION_PATCH}")
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/third_party/cmake/modules/")
@@ -45,35 +46,56 @@ set(CONFIG_REPORTING_DEFAULT_REPORT_BUFFER_SIZE "8000" CACHE STRING "Default buf
# advanced options
option(DEBUG "Enable debugging mode (include assertions)" OFF)
-option(DEBUG_SOCKET "Enable printf debugging for socket layer" OFF)
-option(DEBUG_COTP "Enable COTP printf debugging" OFF)
-option(DEBUG_ISO_SERVER "Enable ISO SERVER printf debugging" OFF)
-option(DEBUG_ISO_CLIENT "Enable ISO CLIENT printf debugging" OFF)
-option(DEBUG_IED_SERVER "Enable IED SERVER printf debugging" OFF)
-option(DEBUG_IED_CLIENT "Enable IED CLIENT printf debugging" OFF)
-option(DEBUG_MMS_SERVER "Enable MMS SERVER printf debugging" OFF)
-option(DEBUG_MMS_CLIENT "Enable MMS CLIENT printf debugging" OFF)
-#mark_as_advanced(DEBUG DEBUG_COTP DEBUG_ISO_SERVER DEBUG_ISO_CLIENT DEBUG_IED_SERVER
-# DEBUG_IED_CLIENT DEBUG_MMS_SERVER DEBUG_MMS_CLIENT)
+option(DEBUG_SOCKET "Enable printf debugging for socket layer" ${DEBUG})
+option(DEBUG_COTP "Enable COTP printf debugging" ${DEBUG})
+option(DEBUG_ISO_SERVER "Enable ISO SERVER printf debugging" ${DEBUG})
+option(DEBUG_ISO_CLIENT "Enable ISO CLIENT printf debugging" ${DEBUG})
+option(DEBUG_IED_SERVER "Enable IED SERVER printf debugging" ${DEBUG})
+option(DEBUG_IED_CLIENT "Enable IED CLIENT printf debugging" ${DEBUG})
+option(DEBUG_MMS_SERVER "Enable MMS SERVER printf debugging" ${DEBUG})
+option(DEBUG_MMS_CLIENT "Enable MMS CLIENT printf debugging" ${DEBUG})
+option(DEBUG_GOOSE_SUBSCRIBER "Enable GOOSE subscriber printf debugging" ${DEBUG})
+option(DEBUG_GOOSE_PUBLISHER "Enable GOOSE publisher printf debugging" ${DEBUG})
+option(DEBUG_SV_SUBSCRIBER "Enable Sampled Values subscriber debugging" ${DEBUG})
+option(DEBUG_SV_PUBLISHER "Enable Sampled Values publisher debugging" ${DEBUG})
+option(DEBUG_HAL_ETHERNET "Enable Ethernet HAL printf debugging" ${DEBUG})
+
+#mark_as_advanced(
+# DEBUG_SOCKET
+# DEBUG_COTP
+# DEBUG_ISO_SERVER
+# DEBUG_ISO_CLIENT
+# DEBUG_IED_SERVER
+# DEBUG_IED_CLIENT
+# DEBUG_MMS_SERVER
+# DEBUG_MMS_CLIENT
+# DEBUG_GOOSE_SUBSCRIBER
+# DEBUG_GOOSE_PUBLISHER
+# DEBUG_SV_SUBSCRIBER
+# DEBUG_SV_PUBLISHER
+# DEBUG_HAL_ETHERNET
+#)
include_directories(
${CMAKE_CURRENT_BINARY_DIR}/config
- src/common/inc
- src/goose
- src/sampled_values
- src/hal/inc
- src/iec61850/inc
- src/iec61850/inc_private
- src/mms/inc
- src/mms/inc_private
- src/mms/iso_mms/asn1c
- src/logging
+ ${CMAKE_CURRENT_LIST_DIR}/src/common/inc
+ ${CMAKE_CURRENT_LIST_DIR}/src/goose
+ ${CMAKE_CURRENT_LIST_DIR}/src/sampled_values
+ ${CMAKE_CURRENT_LIST_DIR}/src/hal/inc
+ ${CMAKE_CURRENT_LIST_DIR}/src/iec61850/inc
+ ${CMAKE_CURRENT_LIST_DIR}/src/iec61850/inc_private
+ ${CMAKE_CURRENT_LIST_DIR}/src/mms/inc
+ ${CMAKE_CURRENT_LIST_DIR}/src/mms/inc_private
+ ${CMAKE_CURRENT_LIST_DIR}/src/mms/iso_mms/asn1c
+ ${CMAKE_CURRENT_LIST_DIR}/src/logging
+ ${CMAKE_CURRENT_LIST_DIR}/src/tls
)
-set(API_HEADERS
- src/hal/inc/hal_time.h
+set(API_HEADERS
+ src/hal/inc/hal_time.h
src/hal/inc/hal_thread.h
- src/hal/inc/hal_filesystem.h
+ src/hal/inc/hal_filesystem.h
+ src/hal/inc/hal_ethernet.h
src/hal/inc/platform_endian.h
src/common/inc/libiec61850_common_api.h
src/common/inc/libiec61850_platform_includes.h
@@ -106,15 +128,33 @@ set(API_HEADERS
src/sampled_values/sv_subscriber.h
src/sampled_values/sv_publisher.h
src/logging/logging_api.h
+ src/tls/tls_api.h
${CMAKE_CURRENT_BINARY_DIR}/config/stack_config.h
)
if(MSVC)
include_directories(
- src/vs
+ ${CMAKE_CURRENT_LIST_DIR}/src/vs
)
endif(MSVC)
+if(EXISTS ${CMAKE_CURRENT_LIST_DIR}/third_party/mbedtls/mbedtls-2.6.0)
+set(WITH_MBEDTLS 1)
+endif(EXISTS ${CMAKE_CURRENT_LIST_DIR}/third_party/mbedtls/mbedtls-2.6.0)
+
+if(WITH_MBEDTLS)
+include_directories(
+ ${CMAKE_CURRENT_LIST_DIR}/src/tls/mbedtls
+ ${CMAKE_CURRENT_LIST_DIR}/third_party/mbedtls/mbedtls-2.6.0/include
+)
+
+file(GLOB tls_SRCS ${CMAKE_CURRENT_LIST_DIR}/third_party/mbedtls/mbedtls-2.6.0/library/*.c)
+
+add_definitions(-DCONFIG_MMS_SUPPORT_TLS=1)
+add_definitions(-DMBEDTLS_CONFIG_FILE="mbedtls_config.h")
+
+endif(WITH_MBEDTLS)
+
# write the detected stuff to this file
configure_file(
${CMAKE_CURRENT_LIST_DIR}/config/stack_config.h.cmake
@@ -122,7 +162,7 @@ configure_file(
)
if(BUILD_EXAMPLES)
- add_subdirectory(examples)
+ add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/examples)
endif(BUILD_EXAMPLES)
add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/src)
@@ -133,21 +173,21 @@ if(BUILD_PYTHON_BINDINGS)
add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/pyiec61850)
endif(BUILD_PYTHON_BINDINGS)
+set(CPACK_PACKAGE_DESCRIPTION "IEC 61850 MMS/GOOSE client and server library")
+set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "IEC 61850 MMS/GOOSE client and server library")
+set(CPACK_PACKAGE_VENDOR "MZ Automation GmbH")
+set(CPACK_PACKAGE_CONTACT "info@libiec61850.com")
+set(CPACK_PACKAGE_VERSION_MAJOR "${LIB_VERSION_MAJOR}")
+set(CPACK_PACKAGE_VERSION_MINOR "${LIB_VERSION_MINOR}")
+set(CPACK_PACKAGE_VERSION_PATCH "${LIB_VERSION_PATCH}")
+set(CPACK_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME}_${LIB_VERSION_MAJOR}.${LIB_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}_${CMAKE_SYSTEM_PROCESSOR}")
+set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME}_${LIB_VERSION_MAJOR}.${LIB_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}")
+
+set(CPACK_COMPONENTS_ALL Libraries Development Applications)
+#set(CPACK_PACKAGE_INSTALL_DIRECTORY "${CMAKE_PROJECT_NAME}")
+
if(EXISTS "${CMAKE_ROOT}/Modules/CPack.cmake")
include(InstallRequiredSystemLibraries)
-
- set(CPACK_PACKAGE_DESCRIPTION "IEC 61850 MMS/GOOSE client and server library")
- set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "IEC 61850 MMS/GOOSE client and server library")
- set(CPACK_PACKAGE_VENDOR "MZ Automation GmbH")
- set(CPACK_PACKAGE_CONTACT "info@libiec61850.com")
- set(CPACK_PACKAGE_VERSION_MAJOR "${LIB_VERSION_MAJOR}")
- set(CPACK_PACKAGE_VERSION_MINOR "${LIB_VERSION_MINOR}")
- set(CPACK_PACKAGE_VERSION_PATCH "${LIB_VERSION_PATCH}")
- set(CPACK_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME}_${LIB_VERSION_MAJOR}.${LIB_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}_${CMAKE_SYSTEM_PROCESSOR}")
- set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME}_${LIB_VERSION_MAJOR}.${LIB_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}")
-
- set(CPACK_COMPONENTS_ALL Libraries Development Applications)
- #set(CPACK_PACKAGE_INSTALL_DIRECTORY "${CMAKE_PROJECT_NAME}")
include(CPack)
endif(EXISTS "${CMAKE_ROOT}/Modules/CPack.cmake")
diff --git a/Makefile b/Makefile
index 2aec4a61..f4ccb697 100644
--- a/Makefile
+++ b/Makefile
@@ -60,10 +60,20 @@ LIB_INCLUDE_DIRS += src/sampled_values
LIB_INCLUDE_DIRS += src/iec61850/inc
LIB_INCLUDE_DIRS += src/iec61850/inc_private
LIB_INCLUDE_DIRS += src/logging
+LIB_INCLUDE_DIRS += src/tls
ifeq ($(HAL_IMPL), WIN32)
LIB_INCLUDE_DIRS += third_party/winpcap/Include
endif
+ifdef WITH_MBEDTLS
+LIB_SOURCE_DIRS += third_party/mbedtls/mbedtls-2.6.0/library
+LIB_SOURCE_DIRS += src/tls/mbedtls
+LIB_INCLUDE_DIRS += third_party/mbedtls/mbedtls-2.6.0/include
+LIB_INCLUDE_DIRS += src/tls/mbedtls
+CFLAGS += -D'MBEDTLS_CONFIG_FILE="mbedtls_config.h"'
+CFLAGS += -D'CONFIG_MMS_SUPPORT_TLS=1'
+endif
+
LIB_INCLUDES = $(addprefix -I,$(LIB_INCLUDE_DIRS))
ifndef INSTALL_PREFIX
@@ -102,6 +112,7 @@ LIB_API_HEADER_FILES += src/goose/goose_publisher.h
LIB_API_HEADER_FILES += src/sampled_values/sv_subscriber.h
LIB_API_HEADER_FILES += src/sampled_values/sv_publisher.h
LIB_API_HEADER_FILES += src/logging/logging_api.h
+LIB_API_HEADER_FILES += src/tls/tls_api.h
get_sources_from_directory = $(wildcard $1/*.c)
get_sources = $(foreach dir, $1, $(call get_sources_from_directory,$(dir)))
diff --git a/README.md b/README.md
index 1cd1ac84..b45cb7ad 100644
--- a/README.md
+++ b/README.md
@@ -25,9 +25,33 @@ libiec61850 is an open-source (GPLv3) implementation of an IEC 61850 client and
For commercial projects licenses and support is provided by MZ Automation GmbH. Please contact info@mz-automation.de for more details on licensing options.
+
+## Features
+
+The library support the following IEC 61850 protocol features:
+
+* MMS client/server, GOOSE (IEC 61850-8-1)
+* Sampled Values (SV - IEC 61850-9-2)
+* Support for buffered and unbuffered reports
+* Online report control block configuration
+* Data access service (get data, set data)
+* online data model discovery and browsing
+* all data set services (get values, set values, browse)
+* dynamic data set services (create and delete)
+* log service
+** flexible API to connect custom data bases
+** comes with sqlite implementation
+* MMS file services (browse, get file, set file, delete/rename file)
+** required to download COMTRADE files
+* Setting group handling
+* GOOSE and SV control block handling
+* TLS support
+* C and C#/.NET API
+
+
## Building and running the examples with the provided makefiles
-In the project root directoy type
+In the project root directory type
```
make examples
@@ -38,14 +62,23 @@ If the build succeeds you can find a few binary files in the projects root direc
Run the sample applications in the example folders. E.g.:
```
-cd examples/server_example1
-sudo ./server_example1
+cd examples/server_example_basic_io
+sudo ./server_example_basic_io
```
on the Linux command line.
You can test the server examples by using a generic client or the provided client example applications.
+## Building the library with TLS support
+
+Download, unpack, and copy mbedtls-2.6.0 into the third_party/mbedtls folder.
+
+In the main libiec61850 folder run
+
+```
+make WITH_MBEDTLS=1
+```
## Installing the library and the API headers
diff --git a/config/stack_config.h b/config/stack_config.h
index b25c7da1..f19a43fe 100644
--- a/config/stack_config.h
+++ b/config/stack_config.h
@@ -157,6 +157,9 @@
/* include support for IEC 61850 log services */
#define CONFIG_IEC61850_LOG_SERVICE 1
+/* Force memory alignment - required for some platforms (required more memory for buffered reporting) */
+#define CONFIG_IEC61850_FORCE_MEMORY_ALIGNMENT 1
+
/* overwrite default results for MMS identify service */
//#define CONFIG_DEFAULT_MMS_VENDOR_NAME "libiec61850.com"
//#define CONFIG_DEFAULT_MMS_MODEL_NAME "LIBIEC61850"
diff --git a/config/stack_config.h.cmake b/config/stack_config.h.cmake
index c36f782d..6e9197f7 100644
--- a/config/stack_config.h.cmake
+++ b/config/stack_config.h.cmake
@@ -151,6 +151,9 @@
/* include support for IEC 61850 log services */
#cmakedefine01 CONFIG_IEC61850_LOG_SERVICE
+/* Force memory alignment - required for some platforms (required more memory for buffered reporting) */
+#define CONFIG_IEC61850_FORCE_MEMORY_ALIGNMENT 1
+
/* default results for MMS identify service */
#define CONFIG_DEFAULT_MMS_VENDOR_NAME "libiec61850.com"
#define CONFIG_DEFAULT_MMS_MODEL_NAME "LIBIEC61850"
diff --git a/dotnet/IEC61850forCSharp/GooseControlBlock.cs b/dotnet/IEC61850forCSharp/GooseControlBlock.cs
new file mode 100644
index 00000000..03df5709
--- /dev/null
+++ b/dotnet/IEC61850forCSharp/GooseControlBlock.cs
@@ -0,0 +1,261 @@
+/*
+ * GooseControlBlock.cs
+ *
+ * Copyright 2017 Michael Zillgith
+ *
+ * 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.
+ */
+using System;
+using System.Runtime.InteropServices;
+using System.Diagnostics;
+
+using IEC61850.Common;
+
+namespace IEC61850
+{
+ namespace Client
+ {
+
+ public class GooseControlBlock {
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern IntPtr ClientGooseControlBlock_create (string dataAttributeReference);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern void ClientGooseControlBlock_destroy(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern IntPtr IedConnection_getGoCBValues (IntPtr connection, out int error, string rcbReference, IntPtr updateRcb);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern void IedConnection_setGoCBValues (IntPtr connection, out int error, IntPtr rcb, UInt32 parametersMask, bool singleRequest);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ [return: MarshalAs(UnmanagedType.I1)]
+ static extern bool ClientGooseControlBlock_getGoEna (IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern void ClientGooseControlBlock_setGoEna(IntPtr self, bool rptEna);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern IntPtr ClientGooseControlBlock_getGoID (IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern void ClientGooseControlBlock_setGoID (IntPtr self, string goId);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern IntPtr ClientGooseControlBlock_getDatSet (IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern void ClientGooseControlBlock_setDatSet (IntPtr self, string datSet);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern UInt32 ClientGooseControlBlock_getConfRev (IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ [return: MarshalAs(UnmanagedType.I1)]
+ static extern bool ClientGooseControlBlock_getNdsComm (IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern UInt32 ClientGooseControlBlock_getMinTime (IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern UInt32 ClientGooseControlBlock_getMaxTime (IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ [return: MarshalAs(UnmanagedType.I1)]
+ static extern bool ClientGooseControlBlock_getFixedOffs (IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern PhyComAddress ClientGooseControlBlock_getDstAddress (IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern void ClientGooseControlBlock_setDstAddress (IntPtr self, PhyComAddress value);
+
+
+ private IntPtr self;
+ private IntPtr connection;
+ private string objectReference;
+
+ private bool isDisposed = false;
+
+ private bool flagGoEna = false;
+ private bool flagGoID = false;
+ private bool flagDatSet = false;
+ private bool flagDstAddress = false;
+
+ internal GooseControlBlock(string objectReference, IntPtr connection)
+ {
+ self = ClientGooseControlBlock_create (objectReference);
+ this.connection = connection;
+ this.objectReference = objectReference;
+ }
+
+ public string GetObjectReference ()
+ {
+ return this.objectReference;
+ }
+
+ ///
+ /// Read all GoCB values from the server
+ ///
+ /// This exception is thrown if there is a connection or service error
+ public void GetCBValues ()
+ {
+ int error;
+
+ IedConnection_getGoCBValues (connection, out error, objectReference, self);
+
+ if (error != 0)
+ throw new IedConnectionException ("getGoCBValues service failed", error);
+ }
+
+ private void
+ resetSendFlags()
+ {
+ flagGoEna = false;
+ flagGoID = false;
+ flagDatSet = false;
+ flagDstAddress = false;
+ }
+
+ public void SetCBValues (bool singleRequest)
+ {
+ UInt32 parametersMask = 0;
+
+ if (flagGoEna)
+ parametersMask += 1;
+
+ if (flagGoID)
+ parametersMask += 2;
+
+ if (flagDatSet)
+ parametersMask += 4;
+
+ if (flagDstAddress)
+ parametersMask += 32;
+
+ int error;
+
+ IedConnection_setGoCBValues (connection, out error, self, parametersMask, singleRequest);
+
+ resetSendFlags ();
+
+ if (error != 0)
+ throw new IedConnectionException ("setGoCBValues service failed", error);
+ }
+
+ public void SetCBValues ()
+ {
+ SetCBValues (true);
+ }
+
+ public bool GetGoEna()
+ {
+ return ClientGooseControlBlock_getGoEna (self);
+ }
+
+ public void SetGoEna(bool value)
+ {
+ ClientGooseControlBlock_setGoEna (self, value);
+
+ flagGoEna = true;
+ }
+
+ public string GetGoID()
+ {
+ IntPtr goIdRef = ClientGooseControlBlock_getGoID (self);
+
+ return Marshal.PtrToStringAnsi (goIdRef);
+ }
+
+ public void SetGoID (string goID)
+ {
+ ClientGooseControlBlock_setGoID (self, goID);
+
+ flagGoID = true;
+ }
+
+ public string GetDatSet()
+ {
+ IntPtr datSetRef = ClientGooseControlBlock_getDatSet (self);
+
+ return Marshal.PtrToStringAnsi (datSetRef);
+ }
+
+ public void SetDataSet(string datSet)
+ {
+ ClientGooseControlBlock_setDatSet (self, datSet);
+
+ flagDatSet = true;
+ }
+
+ public UInt32 GetConfRev()
+ {
+ return ClientGooseControlBlock_getConfRev (self);
+ }
+
+ public bool GetNdsComm()
+ {
+ return ClientGooseControlBlock_getNdsComm (self);
+ }
+
+ public UInt32 GetMinTime()
+ {
+ return ClientGooseControlBlock_getMinTime (self);
+ }
+
+ public UInt32 GetMaxTime()
+ {
+ return ClientGooseControlBlock_getMaxTime (self);
+ }
+
+ public bool GetFixedOffs()
+ {
+ return ClientGooseControlBlock_getFixedOffs (self);
+ }
+
+ public PhyComAddress GetDstAddress()
+ {
+ return ClientGooseControlBlock_getDstAddress (self);
+ }
+
+ public void SetDstAddress(PhyComAddress value)
+ {
+ ClientGooseControlBlock_setDstAddress (self, value);
+
+ flagDstAddress = true;
+ }
+
+ public void Dispose()
+ {
+ if (isDisposed == false) {
+ isDisposed = true;
+ ClientGooseControlBlock_destroy (self);
+ self = IntPtr.Zero;
+ }
+ }
+
+ ~GooseControlBlock()
+ {
+ Dispose ();
+ }
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/dotnet/IEC61850forCSharp/GooseSubscriber.cs b/dotnet/IEC61850forCSharp/GooseSubscriber.cs
new file mode 100644
index 00000000..9b2c6e69
--- /dev/null
+++ b/dotnet/IEC61850forCSharp/GooseSubscriber.cs
@@ -0,0 +1,313 @@
+/*
+ * GooseSubscriber.cs
+ *
+ * Copyright 2017 Michael Zillgith
+ *
+ * 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.
+ */
+
+using System;
+using System.Runtime.InteropServices;
+using IEC61850.Common;
+
+namespace IEC61850
+{
+ namespace GOOSE
+ {
+
+ namespace Subscriber
+ {
+
+ ///
+ /// GOOSE listener.
+ ///
+ public delegate void GooseListener (GooseSubscriber report, object parameter);
+
+ public class GooseReceiver : IDisposable
+ {
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern IntPtr GooseReceiver_create ();
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern void GooseReceiver_addSubscriber(IntPtr self, IntPtr subscriber);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern void GooseReceiver_removeSubscriber(IntPtr self, IntPtr subscriber);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern void GooseReceiver_start(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern void GooseReceiver_stop(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ [return: MarshalAs(UnmanagedType.I1)]
+ private static extern bool GooseReceiver_isRunning (IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern void GooseReceiver_destroy(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern void GooseReceiver_setInterfaceId(IntPtr self, string interfaceId);
+
+ private IntPtr self;
+
+ private bool isDisposed = false;
+
+ public GooseReceiver()
+ {
+ self = GooseReceiver_create ();
+ }
+
+ public void SetInterfaceId(string interfaceId)
+ {
+ GooseReceiver_setInterfaceId (self, interfaceId);
+ }
+
+ public void AddSubscriber(GooseSubscriber subscriber)
+ {
+ GooseReceiver_addSubscriber (self, subscriber.self);
+ }
+
+ public void RemoveSubscriber(GooseSubscriber subscriber)
+ {
+ GooseReceiver_removeSubscriber (self, subscriber.self);
+ }
+
+ public void Start()
+ {
+ GooseReceiver_start (self);
+ }
+
+ public void Stop()
+ {
+ GooseReceiver_stop (self);
+ }
+
+ public bool IsRunning()
+ {
+ return GooseReceiver_isRunning (self);
+ }
+
+ public void Dispose()
+ {
+ if (isDisposed == false) {
+ isDisposed = true;
+ GooseReceiver_destroy (self);
+ self = IntPtr.Zero;
+ }
+ }
+
+ ~GooseReceiver()
+ {
+ Dispose ();
+ }
+ }
+
+
+ ///
+ /// Representing a GOOSE subscriber
+ ///
+ ///
+ /// NOTE: After SetListener is called, do not call any function outside of
+ /// the callback handler!
+ ///
+ public class GooseSubscriber : IDisposable
+ {
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ private delegate void InternalGooseListener (IntPtr subscriber, IntPtr parameter);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern IntPtr GooseSubscriber_create (string goCbRef, IntPtr dataSetValue);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern void GooseSubscriber_setAppId(IntPtr self, UInt16 appId);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ [return: MarshalAs(UnmanagedType.I1)]
+ private static extern bool GooseSubscriber_isValid (IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern UInt32 GooseSubscriber_getStNum (IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern UInt32 GooseSubscriber_getSqNum (IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ [return: MarshalAs(UnmanagedType.I1)]
+ private static extern bool GooseSubscriber_isTest (IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern UInt32 GooseSubscriber_getConfRev (IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ [return: MarshalAs(UnmanagedType.I1)]
+ private static extern bool GooseSubscriber_needsCommission (IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern UInt32 GooseSubscriber_getTimeAllowedToLive (IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern UInt64 GooseSubscriber_getTimestamp (IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern IntPtr GooseSubscriber_getDataSetValues(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern void GooseSubscriber_destroy(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern void GooseSubscriber_setListener (IntPtr self, InternalGooseListener listener, IntPtr parameter);
+
+ internal IntPtr self;
+
+ private bool isDisposed = false;
+
+ private GooseListener listener = null;
+ private object listenerParameter = null;
+
+ private event InternalGooseListener internalListener = null;
+
+ private void internalGooseListener (IntPtr subscriber, IntPtr parameter)
+ {
+ try {
+
+ if (listener != null) {
+ listener(this, listenerParameter);
+ }
+
+ } catch (Exception e)
+ {
+ // older versions of mono 2.10 (for linux?) cause this exception
+ Console.WriteLine(e.Message);
+ }
+ }
+
+ public GooseSubscriber(string goCbRef)
+ {
+ self = GooseSubscriber_create (goCbRef, IntPtr.Zero);
+ }
+
+ public void SetAppId(UInt16 appId)
+ {
+ GooseSubscriber_setAppId (self, appId);
+ }
+
+ public bool IsValid ()
+ {
+ return GooseSubscriber_isValid (self);
+ }
+
+
+ public void SetListener(GooseListener listener, object parameter)
+ {
+ this.listener = listener;
+ this.listenerParameter = parameter;
+
+ if (internalListener == null) {
+ internalListener = new InternalGooseListener (internalGooseListener);
+
+ GooseSubscriber_setListener (self, internalListener, IntPtr.Zero);
+ }
+ }
+
+ public UInt32 GetStNum()
+ {
+ return GooseSubscriber_getStNum (self);
+ }
+
+ public UInt32 GetSqNum()
+ {
+ return GooseSubscriber_getSqNum (self);
+ }
+
+ public bool IsTest()
+ {
+ return GooseSubscriber_isTest (self);
+ }
+
+ public UInt32 GetConfRev()
+ {
+ return GooseSubscriber_getConfRev (self);
+ }
+
+ public bool NeedsCommission()
+ {
+ return GooseSubscriber_needsCommission (self);
+ }
+
+ public UInt32 GetTimeAllowedToLive()
+ {
+ return GooseSubscriber_getTimeAllowedToLive (self);
+ }
+
+ public UInt64 GetTimestamp ()
+ {
+ return GooseSubscriber_getTimestamp (self);
+ }
+
+ public DateTimeOffset GetTimestampsDateTimeOffset ()
+ {
+ UInt64 entryTime = GetTimestamp ();
+
+ DateTimeOffset retVal = new DateTimeOffset (1970, 1, 1, 0, 0, 0, TimeSpan.Zero);
+
+ return retVal.AddMilliseconds (entryTime);
+ }
+
+ ///
+ /// Get the values of the GOOSE data set from the last received GOOSE message
+ ///
+ ///
+ /// The MmsValue instance is only valid in the context of the GooseLister callback.
+ /// Do not store for outside use!
+ ///
+ /// The data set values.
+ public MmsValue GetDataSetValues()
+ {
+ IntPtr mmsValueRef = GooseSubscriber_getDataSetValues (self);
+
+ return (new MmsValue (mmsValueRef));
+ }
+
+ ///
+ /// Releases all resource used by the object.
+ ///
+ /// >
+ /// This function has only to be called when the
+ /// has not been added to the GooseReceiver or has been removed from the GooseReceiver.
+ /// When the GooseReceiver holds a reference it will take care for releasing the resources.
+ /// In this case Dispose MUST not be called! Otherwise the natice resources will be
+ /// released twice.
+ ///
+ public void Dispose()
+ {
+ if (isDisposed == false) {
+ isDisposed = true;
+ GooseSubscriber_destroy (self);
+ self = IntPtr.Zero;
+ }
+ }
+
+ }
+
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/dotnet/IEC61850forCSharp/IEC61850forCSharp.csproj b/dotnet/IEC61850forCSharp/IEC61850.NET.csproj
similarity index 84%
rename from dotnet/IEC61850forCSharp/IEC61850forCSharp.csproj
rename to dotnet/IEC61850forCSharp/IEC61850.NET.csproj
index dc2a4dc5..750d6a4b 100644
--- a/dotnet/IEC61850forCSharp/IEC61850forCSharp.csproj
+++ b/dotnet/IEC61850forCSharp/IEC61850.NET.csproj
@@ -7,6 +7,8 @@
Libraryiec61850dotnetiec61850dotnet
+ 8.0.30703
+ 2.0true
@@ -45,6 +47,11 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs b/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs
index de02a23a..441eefd2 100644
--- a/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs
+++ b/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs
@@ -27,6 +27,7 @@ using System.Collections.Generic;
using System.Collections;
using IEC61850.Common;
+using IEC61850.TLS;
///
/// IEC 61850 API for the libiec61850 .NET wrapper library
@@ -276,6 +277,9 @@ namespace IEC61850
[DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)]
static extern IntPtr IedConnection_create ();
+ [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)]
+ static extern IntPtr IedConnection_createWithTlsSupport (IntPtr tlsConfig);
+
[DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)]
static extern void IedConnection_destroy (IntPtr self);
@@ -405,11 +409,23 @@ namespace IEC61850
private InternalConnectionClosedHandler connectionClosedHandler;
private ConnectionClosedHandler userProvidedHandler = null;
+ ///
+ /// Initializes a new instance of the class.
+ ///
public IedConnection ()
{
connection = IedConnection_create ();
}
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// TLS configuration to use
+ public IedConnection (TLSConfiguration tlsConfig)
+ {
+ connection = IedConnection_createWithTlsSupport (tlsConfig.GetNativeInstance ());
+ }
+
///
/// Releases all resource used by the object.
///
@@ -504,7 +520,7 @@ namespace IEC61850
/// This exception is thrown if there is a connection or service error.
public void Connect (string hostname)
{
- Connect (hostname, 102);
+ Connect (hostname, -1);
}
/// This exception is thrown if there is a connection or service error
@@ -515,10 +531,28 @@ namespace IEC61850
return controlObject;
}
+ ///
+ /// Creates a new SampledValuesControlBlock instance.
+ ///
+ /// >
+ /// This function will also read the SVCB values from the server.
+ ///
+ /// The new SVCB instance
+ /// The object reference of the SVCB
+ public SampledValuesControlBlock GetSvControlBlock (string svcbObjectReference)
+ {
+ return new SampledValuesControlBlock (connection, svcbObjectReference);
+ }
-
-
-
+ ///
+ /// Creates a new SampledValuesControlBlock instance.
+ ///
+ /// The new GoCB instance
+ /// The object reference of the GoCB
+ public GooseControlBlock GetGooseControlBlock (string gocbObjectReference)
+ {
+ return new GooseControlBlock (gocbObjectReference, connection);
+ }
///
/// Updates the device model by quering the server.
@@ -1035,6 +1069,18 @@ namespace IEC61850
if (error != 0)
throw new IedConnectionException ("Write value failed", error);
+ }
+
+ /// Delete file
+ /// The name of the file.
+ /// This exception is thrown if there is a connection or service error
+ public void DeleteFile (string fileName)
+ {
+ int error;
+ IedConnection_deleteFile (connection, out error, fileName);
+
+ if (error != 0)
+ throw new IedConnectionException ("Deleting file " + fileName + " failed", error);
}
/// Delete file
diff --git a/dotnet/IEC61850forCSharp/IEC61850CommonAPI.cs b/dotnet/IEC61850forCSharp/IEC61850CommonAPI.cs
index 0e800715..925cb797 100644
--- a/dotnet/IEC61850forCSharp/IEC61850CommonAPI.cs
+++ b/dotnet/IEC61850forCSharp/IEC61850CommonAPI.cs
@@ -1,4 +1,27 @@
-using System;
+/*
+ * IEC61850CommonAPI.cs
+ *
+ * Copyright 2014-2017 Michael Zillgith
+ *
+ * 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.
+ */
+
+using System;
using System.Runtime.InteropServices;
namespace IEC61850
@@ -49,6 +72,17 @@ namespace IEC61850
}
}
+ [StructLayout(LayoutKind.Sequential)]
+ public class PhyComAddress
+ {
+ public byte vlanPriority;
+ public UInt16 vlanId;
+ public UInt16 appId;
+
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst=6)]
+ public byte[] dstAddress = new byte[6];
+ }
+
///
/// MMS data access error for MmsValue type MMS_DATA_ACCESS_ERROR
///
@@ -85,6 +119,29 @@ namespace IEC61850
GI = 16
}
+ ///
+ /// SmpMod values
+ ///
+ public enum SmpMod {
+ SAMPLES_PER_PERIOD = 0,
+ SAMPLES_PER_SECOND = 1,
+ SECONDS_PER_SAMPLE = 2
+ }
+
+ ///
+ /// Values for Sampled Values (SV) OptFlds
+ ///
+ [Flags]
+ public enum SVOptions {
+ NONE = 0,
+ REFRESH_TIME = 1,
+ SAMPLE_SYNC = 2,
+ SAMPLE_RATE = 4,
+ DATA_SET = 8,
+ SECURITY = 16,
+ ALL = 31
+ }
+
[Flags]
public enum ReportOptions {
NONE = 0,
@@ -96,7 +153,9 @@ namespace IEC61850
BUFFER_OVERFLOW = 32,
ENTRY_ID = 64,
CONF_REV = 128,
- ALL = 255
+ SEGMENTATION = 256,
+ ALL = SEQ_NUM | TIME_STAMP | REASON_FOR_INCLUSION | DATA_SET | DATA_REFERENCE |
+ BUFFER_OVERFLOW | ENTRY_ID | CONF_REV | SEGMENTATION
}
public enum Validity
@@ -112,9 +171,26 @@ namespace IEC61850
///
public class Quality
{
-
private UInt16 value;
+ private const UInt16 QUALITY_DETAIL_OVERFLOW = 4;
+ private const UInt16 QUALITY_DETAIL_OUT_OF_RANGE = 8;
+ private const UInt16 QUALITY_DETAIL_BAD_REFERENCE = 16;
+ private const UInt16 QUALITY_DETAIL_OSCILLATORY = 32;
+ private const UInt16 QUALITY_DETAIL_FAILURE = 64;
+ private const UInt16 QUALITY_DETAIL_OLD_DATA = 128;
+ private const UInt16 QUALITY_DETAIL_INCONSISTENT = 256;
+ private const UInt16 QUALITY_DETAIL_INACCURATE = 512;
+ private const UInt16 QUALITY_SOURCE_SUBSTITUTED = 1024;
+ private const UInt16 QUALITY_TEST = 2048;
+ private const UInt16 QUALITY_OPERATOR_BLOCKED = 4096;
+
+ public override string ToString ()
+ {
+ return GetValidity ().ToString ();
+
+ }
+
public Quality (int bitStringValue)
{
value = (UInt16)bitStringValue;
@@ -138,6 +214,133 @@ namespace IEC61850
value += (ushort)validity;
}
+
+ public Validity Validity
+ {
+ get {return GetValidity ();}
+ set { SetValidity (value); }
+ }
+
+ public bool Overflow
+ {
+ get { return ((this.value & QUALITY_DETAIL_OVERFLOW) != 0);}
+ set {
+ if (value)
+ this.value |= QUALITY_DETAIL_OVERFLOW;
+ else
+ this.value = (ushort) ((int) this.value & (~QUALITY_DETAIL_OVERFLOW));
+ }
+ }
+
+ public bool OutOfRange
+ {
+ get { return ((this.value & QUALITY_DETAIL_OUT_OF_RANGE) != 0);}
+ set {
+ if (value)
+ this.value |= QUALITY_DETAIL_OUT_OF_RANGE;
+ else
+ this.value = (ushort) ((int) this.value & (~QUALITY_DETAIL_OUT_OF_RANGE));
+ }
+ }
+
+ public bool BadReference
+ {
+ get { return ((this.value & QUALITY_DETAIL_BAD_REFERENCE) != 0);}
+ set {
+ if (value)
+ this.value |= QUALITY_DETAIL_BAD_REFERENCE;
+ else
+ this.value = (ushort) ((int) this.value & (~QUALITY_DETAIL_BAD_REFERENCE));
+ }
+ }
+
+ public bool Oscillatory
+ {
+ get { return ((this.value & QUALITY_DETAIL_OSCILLATORY) != 0);}
+ set {
+ if (value)
+ this.value |= QUALITY_DETAIL_OSCILLATORY;
+ else
+ this.value = (ushort) ((int) this.value & (~QUALITY_DETAIL_OSCILLATORY));
+ }
+ }
+
+ public bool Failure
+ {
+ get { return ((this.value & QUALITY_DETAIL_FAILURE) != 0);}
+ set {
+ if (value)
+ this.value |= QUALITY_DETAIL_FAILURE;
+ else
+ this.value = (ushort) ((int) this.value & (~QUALITY_DETAIL_FAILURE));
+ }
+ }
+
+ public bool OldData
+ {
+ get { return ((this.value & QUALITY_DETAIL_OLD_DATA) != 0);}
+ set {
+ if (value)
+ this.value |= QUALITY_DETAIL_OLD_DATA;
+ else
+ this.value = (ushort) ((int) this.value & (~QUALITY_DETAIL_OLD_DATA));
+ }
+ }
+
+ public bool Inconsistent
+ {
+ get { return ((this.value & QUALITY_DETAIL_INCONSISTENT) != 0);}
+ set {
+ if (value)
+ this.value |= QUALITY_DETAIL_INCONSISTENT;
+ else
+ this.value = (ushort) ((int) this.value & (~QUALITY_DETAIL_INCONSISTENT));
+ }
+ }
+
+ public bool Inaccurate
+ {
+ get { return ((this.value & QUALITY_DETAIL_INACCURATE) != 0);}
+ set {
+ if (value)
+ this.value |= QUALITY_DETAIL_INACCURATE;
+ else
+ this.value = (ushort) ((int) this.value & (~QUALITY_DETAIL_INACCURATE));
+ }
+ }
+
+ public bool Substituted
+ {
+ get { return ((this.value & QUALITY_SOURCE_SUBSTITUTED) != 0);}
+ set {
+ if (value)
+ this.value |= QUALITY_SOURCE_SUBSTITUTED;
+ else
+ this.value = (ushort) ((int) this.value & (~QUALITY_SOURCE_SUBSTITUTED));
+ }
+ }
+
+ public bool Test
+ {
+ get { return ((this.value & QUALITY_TEST) != 0);}
+ set {
+ if (value)
+ this.value |= QUALITY_TEST;
+ else
+ this.value = (ushort) ((int) this.value & (~QUALITY_TEST));
+ }
+ }
+
+ public bool OperatorBlocked
+ {
+ get { return ((this.value & QUALITY_OPERATOR_BLOCKED) != 0);}
+ set {
+ if (value)
+ this.value |= QUALITY_OPERATOR_BLOCKED;
+ else
+ this.value = (ushort) ((int) this.value & (~QUALITY_OPERATOR_BLOCKED));
+ }
+ }
}
///
@@ -148,6 +351,9 @@ namespace IEC61850
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr Timestamp_create ();
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern IntPtr Timestamp_createFromByteArray(byte[] byteArry);
+
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void Timestamp_destroy (IntPtr self);
@@ -198,12 +404,12 @@ namespace IEC61850
static extern void Timestamp_setByMmsUtcTime (IntPtr self, IntPtr mmsValue);
internal IntPtr timestampRef = IntPtr.Zero;
- private bool responsableForDeletion;
+ private bool responsibleForDeletion;
internal Timestamp(IntPtr timestampRef, bool selfAllocated)
{
this.timestampRef = timestampRef;
- this.responsableForDeletion = selfAllocated;
+ this.responsibleForDeletion = selfAllocated;
}
public Timestamp (DateTime timestamp) : this ()
@@ -220,12 +426,18 @@ namespace IEC61850
{
timestampRef = Timestamp_create ();
LeapSecondKnown = true;
- responsableForDeletion = true;
+ responsibleForDeletion = true;
+ }
+
+ public Timestamp(byte[] value)
+ {
+ timestampRef = Timestamp_createFromByteArray (value);
+ responsibleForDeletion = true;
}
~Timestamp ()
{
- if (responsableForDeletion)
+ if (responsibleForDeletion)
Timestamp_destroy (timestampRef);
}
@@ -335,6 +547,15 @@ namespace IEC61850
Timestamp_setByMmsUtcTime (timestampRef, mmsValue.valueReference);
}
+ public DateTime AsDateTime()
+ {
+ DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
+
+ DateTime retVal = epoch.AddMilliseconds ((double) GetTimeInMilliseconds ());
+
+ return retVal;
+ }
+
}
public enum ACSIClass
diff --git a/dotnet/IEC61850forCSharp/IEC61850ServerAPI.cs b/dotnet/IEC61850forCSharp/IEC61850ServerAPI.cs
index fc08dd8f..0e245f6d 100644
--- a/dotnet/IEC61850forCSharp/IEC61850ServerAPI.cs
+++ b/dotnet/IEC61850forCSharp/IEC61850ServerAPI.cs
@@ -474,9 +474,9 @@ namespace IEC61850
public IntPtr self = IntPtr.Zero;
public ReportControlBlock(string name, LogicalNode parent, string rptId, bool isBuffered,
- string dataSetName, uint confRef, byte trgOps, byte options, uint bufTm, uint intgPd)
+ string dataSetName, uint confRev, byte trgOps, byte options, uint bufTm, uint intgPd)
{
- self = ReportControlBlock_create(name, parent.self, rptId, isBuffered, dataSetName, confRef, trgOps, options, bufTm, intgPd);
+ self = ReportControlBlock_create(name, parent.self, rptId, isBuffered, dataSetName, confRev, trgOps, options, bufTm, intgPd);
}
}
diff --git a/dotnet/IEC61850forCSharp/MmsValue.cs b/dotnet/IEC61850forCSharp/MmsValue.cs
index ed9787ab..ee9de699 100644
--- a/dotnet/IEC61850forCSharp/MmsValue.cs
+++ b/dotnet/IEC61850forCSharp/MmsValue.cs
@@ -430,9 +430,13 @@ namespace IEC61850
public MmsDataAccessError GetDataAccessError ()
{
- int errorCode = MmsValue_getDataAccessError (valueReference);
+ if (GetType () == MmsType.MMS_DATA_ACCESS_ERROR) {
+ int errorCode = MmsValue_getDataAccessError (valueReference);
- return (MmsDataAccessError)errorCode;
+ return (MmsDataAccessError)errorCode;
+ }
+ else
+ throw new MmsValueException ("Value is of wrong type");
}
///
diff --git a/dotnet/IEC61850forCSharp/SampledValuesControlBlock.cs b/dotnet/IEC61850forCSharp/SampledValuesControlBlock.cs
new file mode 100644
index 00000000..e306fcaf
--- /dev/null
+++ b/dotnet/IEC61850forCSharp/SampledValuesControlBlock.cs
@@ -0,0 +1,203 @@
+/*
+ * SampledValuesControlBlock.cs
+ *
+ * Copyright 2017 Michael Zillgith
+ *
+ * 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.
+ */
+using System;
+using System.Runtime.InteropServices;
+using System.Diagnostics;
+
+using IEC61850.Common;
+
+namespace IEC61850
+{
+ namespace Client
+ {
+ ///
+ /// Sampled values control bloc (SvCB) representation.
+ ///
+ ///
+ /// This class is used as a client side representation (copy) of a sampled values control block (SvCB).
+ ///
+ public class SampledValuesControlBlock : IDisposable
+ {
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern IntPtr ClientSVControlBlock_create (IntPtr iedConnection, string reference);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern void ClientSVControlBlock_destroy(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern int ClientSVControlBlock_getLastComError (IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ [return: MarshalAs(UnmanagedType.I1)]
+ static extern bool ClientSVControlBlock_isMulticast (IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ [return: MarshalAs(UnmanagedType.I1)]
+ static extern bool ClientSVControlBlock_setSvEna (IntPtr self, bool value);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ [return: MarshalAs(UnmanagedType.I1)]
+ static extern bool ClientSVControlBlock_setResv (IntPtr self, bool value);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ [return: MarshalAs(UnmanagedType.I1)]
+ static extern bool ClientSVControlBlock_getSvEna (IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ [return: MarshalAs(UnmanagedType.I1)]
+ static extern bool ClientSVControlBlock_getResv (IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern IntPtr ClientSVControlBlock_getMsvID (IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern IntPtr ClientSVControlBlock_getDatSet (IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern UInt32 ClientSVControlBlock_getConfRev (IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern UInt16 ClientSVControlBlock_getSmpRate (IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern int ClientSVControlBlock_getOptFlds (IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern byte ClientSVControlBlock_getSmpMod(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern int ClientSVControlBlock_getNoASDU (IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern PhyComAddress ClientSVControlBlock_getDstAddress (IntPtr self);
+
+ private IntPtr self;
+ private string objectReference;
+
+ private bool isDisposed = false;
+
+
+ internal SampledValuesControlBlock(IntPtr iedConnection, string objectReference)
+ {
+ self = ClientSVControlBlock_create (iedConnection, objectReference);
+ this.objectReference = objectReference;
+ }
+
+ public string GetObjectReference ()
+ {
+ return this.objectReference;
+ }
+
+ public IedClientError GetLastComError()
+ {
+ return (IedClientError)ClientSVControlBlock_getLastComError (self);
+ }
+
+ public bool IsMulticast()
+ {
+ return ClientSVControlBlock_isMulticast (self);
+ }
+
+ public bool GetResv()
+ {
+ return ClientSVControlBlock_getResv (self);
+ }
+
+ public bool SetResv(bool value)
+ {
+ return ClientSVControlBlock_setResv (self, value);
+ }
+
+ public bool GetSvEna()
+ {
+ return ClientSVControlBlock_getSvEna (self);
+ }
+
+ public bool SetSvEna(bool value)
+ {
+ return ClientSVControlBlock_setSvEna (self, value);
+ }
+
+ public string GetMsvID ()
+ {
+ IntPtr msvIdPtr = ClientSVControlBlock_getMsvID (self);
+
+ return Marshal.PtrToStringAnsi (msvIdPtr);
+ }
+
+ public string GetDatSet ()
+ {
+ IntPtr datSetPtr = ClientSVControlBlock_getDatSet (self);
+
+ return Marshal.PtrToStringAnsi (datSetPtr);
+ }
+
+ public UInt32 GetConfRev ()
+ {
+ return ClientSVControlBlock_getConfRev (self);
+ }
+
+ public UInt16 GetSmpRate ()
+ {
+ return ClientSVControlBlock_getSmpRate (self);
+ }
+
+ public SVOptions GetOptFlds ()
+ {
+ return (SVOptions)ClientSVControlBlock_getOptFlds (self);
+ }
+
+ public SmpMod GetSmpMod ()
+ {
+ return (SmpMod)ClientSVControlBlock_getSmpMod (self);
+ }
+
+ public int GetNoASDU ()
+ {
+ return ClientSVControlBlock_getNoASDU (self);
+ }
+
+ public PhyComAddress GetDstAddress()
+ {
+ return ClientSVControlBlock_getDstAddress (self);
+ }
+
+ public void Dispose()
+ {
+ if (isDisposed == false) {
+ isDisposed = true;
+ ClientSVControlBlock_destroy (self);
+ self = IntPtr.Zero;
+ }
+ }
+
+ ~SampledValuesControlBlock()
+ {
+ Dispose ();
+ }
+
+ }
+
+
+ }
+}
diff --git a/dotnet/IEC61850forCSharp/SampledValuesSubscriber.cs b/dotnet/IEC61850forCSharp/SampledValuesSubscriber.cs
new file mode 100644
index 00000000..5da087a0
--- /dev/null
+++ b/dotnet/IEC61850forCSharp/SampledValuesSubscriber.cs
@@ -0,0 +1,474 @@
+/*
+ * SampledValuedSubscriber.cs
+ *
+ * Copyright 2017 Michael Zillgith
+ *
+ * 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.
+ */
+
+using System;
+using System.Runtime.InteropServices;
+using IEC61850.Common;
+
+namespace IEC61850
+{
+ namespace SV
+ {
+
+ namespace Subscriber
+ {
+ ///
+ /// SV receiver.
+ ///
+ /// A receiver is responsible for processing all SV message for a single Ethernet interface.
+ /// In order to process messages from multiple Ethernet interfaces you have to create multiple
+ /// instances.
+ public class SVReceiver : IDisposable
+ {
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern IntPtr SVReceiver_create ();
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern void SVReceiver_disableDestAddrCheck(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern void SVReceiver_enableDestAddrCheck(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern void SVReceiver_addSubscriber(IntPtr self, IntPtr subscriber);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern void SVReceiver_removeSubscriber(IntPtr self, IntPtr subscriber);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern void SVReceiver_start(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern void SVReceiver_stop(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ [return: MarshalAs(UnmanagedType.I1)]
+ private static extern bool SVReceiver_isRunning (IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern void SVReceiver_destroy(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern void SVReceiver_setInterfaceId(IntPtr self, string interfaceId);
+
+ private IntPtr self;
+
+ private bool isDisposed = false;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+
+ public SVReceiver()
+ {
+ self = SVReceiver_create ();
+ }
+
+ public void SetInterfaceId(string interfaceId)
+ {
+ SVReceiver_setInterfaceId (self, interfaceId);
+ }
+
+ public void DisableDestAddrCheck()
+ {
+ SVReceiver_disableDestAddrCheck (self);
+ }
+
+ public void EnableDestAddrCheck()
+ {
+ SVReceiver_enableDestAddrCheck (self);
+ }
+
+ ///
+ /// Add a subscriber to handle
+ ///
+ /// Subscriber.
+ public void AddSubscriber(SVSubscriber subscriber)
+ {
+ SVReceiver_addSubscriber (self, subscriber.self);
+ }
+
+
+ public void RemoveSubscriber(SVSubscriber subscriber)
+ {
+ SVReceiver_removeSubscriber (self, subscriber.self);
+ }
+
+ ///
+ /// Start handling SV messages
+ ///
+ public void Start()
+ {
+ SVReceiver_start (self);
+ }
+
+ ///
+ /// Stop handling SV messges
+ ///
+ public void Stop()
+ {
+ SVReceiver_stop (self);
+ }
+
+ public bool IsRunning()
+ {
+ return SVReceiver_isRunning (self);
+ }
+
+ ///
+ /// Releases all resource used by the object.
+ ///
+ /// Call when you are finished using the . The
+ /// method leaves the in an unusable state.
+ /// After calling , you must release all references to the
+ /// so the garbage collector can reclaim the memory that the
+ /// was occupying.
+ public void Dispose()
+ {
+ if (isDisposed == false) {
+ isDisposed = true;
+ SVReceiver_destroy (self);
+ self = IntPtr.Zero;
+ }
+ }
+
+ ~SVReceiver()
+ {
+ Dispose ();
+ }
+ }
+
+
+ ///
+ /// SV listener.
+ ///
+ public delegate void SVUpdateListener (SVSubscriber report, object parameter, SVSubscriberASDU asdu);
+
+ ///
+ /// Sampled Values (SV) Subscriber
+ ///
+ /// A subscriber is an instance associated with a single stream of measurement data. It is identified
+ /// by the Ethernet destination address, the appID value (both are on SV message level) and the svID value
+ /// that is part of each ASDU.
+ ///
+ public class SVSubscriber : IDisposable
+ {
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ private delegate void InternalSVUpdateListener (IntPtr subscriber, IntPtr parameter, IntPtr asdu);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern IntPtr SVSubscriber_create([Out] byte[] ethAddr, UInt16 appID);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern IntPtr SVSubscriber_create(IntPtr ethAddr, UInt16 appID);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern void SVSubscriber_setListener(IntPtr self, InternalSVUpdateListener listener, IntPtr parameter);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern void SVSubscriber_destroy(IntPtr self);
+
+ internal IntPtr self;
+
+ private bool isDisposed = false;
+
+ private SVUpdateListener listener;
+ private object listenerParameter = null;
+
+ private event InternalSVUpdateListener internalListener = null;
+
+ private void internalSVUpdateListener (IntPtr subscriber, IntPtr parameter, IntPtr asdu)
+ {
+ try {
+
+ if (listener != null) {
+ listener(this, listenerParameter, new SVSubscriberASDU(asdu));
+ }
+
+ }
+ catch (Exception e) {
+ // older versions of mono 2.10 (for linux?) cause this exception
+ Console.WriteLine(e.Message);
+ }
+ }
+
+ public SVSubscriber(byte[] ethAddr, UInt16 appID)
+ {
+ if (ethAddr == null) {
+ self = SVSubscriber_create (IntPtr.Zero, appID);
+ } else {
+
+ if (ethAddr.Length != 6)
+ throw new ArgumentException ("ethAddr argument has to be of 6 byte size");
+
+ self = SVSubscriber_create (ethAddr, appID);
+ }
+ }
+
+ public void SetListener(SVUpdateListener listener, object parameter)
+ {
+ this.listener = listener;
+ this.listenerParameter = parameter;
+
+ if (internalListener == null) {
+ internalListener = new InternalSVUpdateListener (internalSVUpdateListener);
+
+ SVSubscriber_setListener (self, internalListener, IntPtr.Zero);
+ }
+ }
+
+ public void Dispose()
+ {
+ if (isDisposed == false) {
+ isDisposed = true;
+ SVSubscriber_destroy (self);
+ self = IntPtr.Zero;
+ }
+ }
+ }
+
+
+ public class SVSubscriberASDU
+ {
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern UInt16 SVSubscriber_ASDU_getSmpCnt(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern IntPtr SVSubscriber_ASDU_getSvId(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern IntPtr SVSubscriber_ASDU_getDatSet(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern UInt32 SVSubscriber_ASDU_getConfRev(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern byte SVSubscriber_ASDU_getSmpMod(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern UInt16 SVSubscriber_ASDU_getSmpRate(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ [return: MarshalAs(UnmanagedType.I1)]
+ private static extern bool SVSubscriber_ASDU_hasDatSet(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ [return: MarshalAs(UnmanagedType.I1)]
+ private static extern bool SVSubscriber_ASDU_hasRefrTm(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ [return: MarshalAs(UnmanagedType.I1)]
+ private static extern bool SVSubscriber_ASDU_hasSmpMod(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ [return: MarshalAs(UnmanagedType.I1)]
+ private static extern bool SVSubscriber_ASDU_hasSmpRate(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern UInt64 SVSubscriber_ASDU_getRefrTmAsMs(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern sbyte SVSubscriber_ASDU_getINT8(IntPtr self, int index);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern Int16 SVSubscriber_ASDU_getINT16(IntPtr self, int index);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern Int32 SVSubscriber_ASDU_getINT32(IntPtr self, int index);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern Int64 SVSubscriber_ASDU_getINT64(IntPtr self, int index);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern byte SVSubscriber_ASDU_getINT8U(IntPtr self, int index);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern UInt16 SVSubscriber_ASDU_getINT16U(IntPtr self, int index);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern UInt32 SVSubscriber_ASDU_getINT32U(IntPtr self, int index);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern UInt64 SVSubscriber_ASDU_getINT64U(IntPtr self, int index);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern float SVSubscriber_ASDU_getFLOAT32(IntPtr self, int index);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern double SVSubscriber_ASDU_getFLOAT64(IntPtr self, int index);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern UInt16 SVSubscriber_ASDU_getQuality(IntPtr self, int index);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern int SVSubscriber_ASDU_getDataSize(IntPtr self);
+
+ private IntPtr self;
+
+ internal SVSubscriberASDU (IntPtr self)
+ {
+ this.self = self;
+ }
+
+ public UInt16 GetSmpCnt()
+ {
+ return SVSubscriber_ASDU_getSmpCnt (self);
+ }
+
+ public string GetSvId()
+ {
+ return Marshal.PtrToStringAnsi (SVSubscriber_ASDU_getSvId(self));
+ }
+
+ public string GetDatSet()
+ {
+ return Marshal.PtrToStringAnsi (SVSubscriber_ASDU_getDatSet(self));
+ }
+
+ public UInt32 GetConfRev()
+ {
+ return SVSubscriber_ASDU_getConfRev (self);
+ }
+
+ public SmpMod GetSmpMod()
+ {
+ return (SmpMod) SVSubscriber_ASDU_getSmpMod (self);
+ }
+
+ public UInt16 GetSmpRate()
+ {
+ return (UInt16)SVSubscriber_ASDU_getSmpRate (self);
+ }
+
+ public bool HasDatSet()
+ {
+ return SVSubscriber_ASDU_hasDatSet (self);
+ }
+
+ public bool HasRefrRm()
+ {
+ return SVSubscriber_ASDU_hasRefrTm (self);
+ }
+
+ public bool HasSmpMod()
+ {
+ return SVSubscriber_ASDU_hasSmpMod (self);
+ }
+
+ public bool HasSmpRate()
+ {
+ return SVSubscriber_ASDU_hasSmpRate (self);
+ }
+
+ public UInt64 GetRefrTmAsMs()
+ {
+ return SVSubscriber_ASDU_getRefrTmAsMs (self);
+ }
+
+ public sbyte GetINT8(int index)
+ {
+ return SVSubscriber_ASDU_getINT8 (self, index);
+ }
+
+ public Int16 GetINT16(int index)
+ {
+ return SVSubscriber_ASDU_getINT16 (self, index);
+ }
+
+ public Int32 GetINT32(int index)
+ {
+ return SVSubscriber_ASDU_getINT32 (self, index);
+ }
+
+ public Int64 GetINT64(int index)
+ {
+ return SVSubscriber_ASDU_getINT64 (self, index);
+ }
+
+ public byte GetINT8U(int index)
+ {
+ return SVSubscriber_ASDU_getINT8U (self, index);
+ }
+
+ public UInt16 GetINT16U(int index)
+ {
+ return SVSubscriber_ASDU_getINT16U (self, index);
+ }
+
+ public UInt32 GetINT32U(int index)
+ {
+ return SVSubscriber_ASDU_getINT32U (self, index);
+ }
+
+ public UInt64 GetINT64U(int index)
+ {
+ return SVSubscriber_ASDU_getINT64U (self, index);
+ }
+
+ public float GetFLOAT32(int index)
+ {
+ return SVSubscriber_ASDU_getFLOAT32 (self, index);
+ }
+
+ public double GetFLOAT64(int index)
+ {
+ return SVSubscriber_ASDU_getFLOAT64 (self, index);
+ }
+
+ private struct PTimestamp
+ {
+ [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.I1, SizeConst = 8)]
+ public byte[] val;
+ }
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern PTimestamp SVSubscriber_ASDU_getTimestamp(IntPtr self, int index);
+
+ public Timestamp GetTimestamp(int index)
+ {
+ PTimestamp retVal = SVSubscriber_ASDU_getTimestamp (self, index);
+
+ return new Timestamp (retVal.val);
+ }
+
+ public Quality GetQuality(int index)
+ {
+ UInt16 qValue = SVSubscriber_ASDU_getQuality (self, index);
+
+ return new Quality (qValue);
+ }
+
+ ///
+ /// Gets the size of the payload data in bytes. The payload comprises the data set data.
+ ///
+ /// The payload data size in byte
+ public int GetDataSize()
+ {
+ return SVSubscriber_ASDU_getDataSize (self);
+ }
+ }
+ }
+
+ }
+}
+
diff --git a/dotnet/IEC61850forCSharp/TLS.cs b/dotnet/IEC61850forCSharp/TLS.cs
new file mode 100644
index 00000000..2b3b49d8
--- /dev/null
+++ b/dotnet/IEC61850forCSharp/TLS.cs
@@ -0,0 +1,215 @@
+/*
+ * TLS.cs
+ *
+ * Copyright 2017 Michael Zillgith
+ *
+ * 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.
+ */
+using System;
+using System.Text;
+using System.Runtime.InteropServices;
+using System.Collections.Generic;
+using System.Collections;
+using System.Security.Cryptography.X509Certificates;
+using System.Security.Cryptography;
+
+using IEC61850.Common;
+
+///
+/// IEC 61850 API for the libiec61850 .NET wrapper library
+///
+namespace IEC61850
+{
+ namespace TLS
+ {
+ ///
+ /// A container for TLS configuration and certificates.
+ ///
+ public class TLSConfiguration : IDisposable
+ {
+ private IntPtr self = IntPtr.Zero;
+
+ private bool allowOnlyKnownCerts = false;
+ private bool chainValidation = true;
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern IntPtr TLSConfiguration_create();
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern void TLSConfiguration_destroy(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern void TLSConfiguration_setAllowOnlyKnownCertificates(IntPtr self, bool value);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern void TLSConfiguration_setChainValidation (IntPtr self, bool value);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern void TLSConfiguration_setClientMode(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern bool TLSConfiguration_setOwnCertificate(IntPtr self, byte[] certificate, int certLen);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern bool TLSConfiguration_setOwnCertificateFromFile(IntPtr self, string filename);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern bool TLSConfiguration_setOwnKey(IntPtr self, byte[] key, int keyLen, string keyPassword);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern bool TLSConfiguration_setOwnKeyFromFile (IntPtr self, string filename, string keyPassword);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern bool TLSConfiguration_addAllowedCertificate(IntPtr self, byte[] certificate, int certLen);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern bool TLSConfiguration_addAllowedCertificateFromFile(IntPtr self, string filename);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern bool TLSConfiguration_addCACertificate(IntPtr self, byte[] certificate, int certLen);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern bool TLSConfiguration_addCACertificateFromFile(IntPtr self, string filename);
+
+ public TLSConfiguration() {
+ self = TLSConfiguration_create ();
+ }
+
+ ~TLSConfiguration()
+ {
+ Dispose ();
+ }
+
+ internal IntPtr GetNativeInstance()
+ {
+ return self;
+ }
+
+ public bool AllowOnlyKnownCertificates
+ {
+ set {
+ TLSConfiguration_setAllowOnlyKnownCertificates (self, value);
+ allowOnlyKnownCerts = value;
+ }
+ get {
+ return allowOnlyKnownCerts;
+ }
+ }
+
+ public bool ChainValidation
+ {
+ set {
+ TLSConfiguration_setChainValidation (self, value);
+ chainValidation = value;
+ }
+ get {
+ return chainValidation;
+ }
+ }
+
+
+ public void SetClientMode()
+ {
+ TLSConfiguration_setClientMode (self);
+ }
+
+ public void SetOwnCertificate(string filename)
+ {
+ if (TLSConfiguration_setOwnCertificateFromFile (self, filename) == false) {
+ Console.WriteLine ("Failed to read certificate from file!");
+ throw new CryptographicException ("Failed to read certificate from file");
+ }
+ }
+
+ public void SetOwnCertificate(X509Certificate2 cert)
+ {
+ byte[] certBytes = cert.GetRawCertData ();
+
+ if (TLSConfiguration_setOwnCertificate (self, certBytes, certBytes.Length) == false) {
+ Console.WriteLine ("Failed to set certificate!");
+ throw new CryptographicException ("Failed to set certificate");
+ }
+ }
+
+ public void AddAllowedCertificate(string filename)
+ {
+ if (TLSConfiguration_addAllowedCertificateFromFile (self, filename) == false) {
+ Console.WriteLine ("Failed to read allowed certificate from file!");
+ throw new CryptographicException ("Failed to read allowed certificate from file");
+ }
+ }
+
+ public void AddAllowedCertificate(X509Certificate2 cert)
+ {
+ byte[] certBytes = cert.GetRawCertData ();
+
+ if (TLSConfiguration_addAllowedCertificate (self, certBytes, certBytes.Length) == false) {
+ Console.WriteLine ("Failed to add allowed certificate!");
+ throw new CryptographicException ("Failed to add allowed certificate");
+ }
+ }
+
+ public void AddCACertificate(string filename)
+ {
+ if (TLSConfiguration_addCACertificateFromFile (self, filename) == false) {
+ Console.WriteLine ("Failed to read CA certificate from file!");
+ throw new CryptographicException ("Failed to read CA certificate from file");
+ }
+ }
+
+ public void AddCACertificate(X509Certificate2 cert)
+ {
+ byte[] certBytes = cert.GetRawCertData ();
+
+ if (TLSConfiguration_addCACertificate (self, certBytes, certBytes.Length) == false) {
+ Console.WriteLine ("Failed to add CA certificate!");
+ throw new CryptographicException ("Failed to add CA certificate");
+ }
+ }
+
+ public void SetOwnKey (string filename, string password)
+ {
+ if (TLSConfiguration_setOwnKeyFromFile (self, filename, password) == false) {
+ Console.WriteLine ("Failed to read own key from file!");
+ throw new CryptographicException ("Failed to read own key from file");
+ }
+ }
+
+ public void SetOwnKey (X509Certificate2 key, string password)
+ {
+ byte[] certBytes = key.Export (X509ContentType.Pkcs12);
+
+ if (TLSConfiguration_setOwnKey (self, certBytes, certBytes.Length, password) == false) {
+ Console.WriteLine ("Failed to set own key!");
+ throw new CryptographicException ("Failed to set own key");
+ }
+ }
+
+ public void Dispose()
+ {
+ lock (this) {
+ if (self != IntPtr.Zero) {
+ TLSConfiguration_destroy (self);
+ self = IntPtr.Zero;
+ }
+ }
+ }
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/dotnet/authenticate/authenticate.csproj b/dotnet/authenticate/authenticate.csproj
index 09bbea29..c05c41f8 100644
--- a/dotnet/authenticate/authenticate.csproj
+++ b/dotnet/authenticate/authenticate.csproj
@@ -35,9 +35,9 @@
-
+ {C35D624E-5506-4560-8074-1728F1FA1A4D}
- IEC61850forCSharp
+ IEC61850.NET
\ No newline at end of file
diff --git a/dotnet/control/control.csproj b/dotnet/control/control.csproj
index c6a4e07f..efe7f4ca 100644
--- a/dotnet/control/control.csproj
+++ b/dotnet/control/control.csproj
@@ -35,9 +35,9 @@
-
+ {C35D624E-5506-4560-8074-1728F1FA1A4D}
- IEC61850forCSharp
+ IEC61850.NET
\ No newline at end of file
diff --git a/dotnet/datasets/datasets.csproj b/dotnet/datasets/datasets.csproj
index 17802618..312ccbfd 100644
--- a/dotnet/datasets/datasets.csproj
+++ b/dotnet/datasets/datasets.csproj
@@ -35,9 +35,9 @@
-
+ {C35D624E-5506-4560-8074-1728F1FA1A4D}
- IEC61850forCSharp
+ IEC61850.NET
\ No newline at end of file
diff --git a/dotnet/dotnet.sln b/dotnet/dotnet.sln
index 79e8b7fd..067ccaf9 100644
--- a/dotnet/dotnet.sln
+++ b/dotnet/dotnet.sln
@@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2012
VisualStudioVersion = 12.0.40629.0
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IEC61850forCSharp", "IEC61850forCSharp\IEC61850forCSharp.csproj", "{C35D624E-5506-4560-8074-1728F1FA1A4D}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IEC61850.NET", "IEC61850forCSharp\IEC61850.NET.csproj", "{C35D624E-5506-4560-8074-1728F1FA1A4D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "example1", "example1\example1.csproj", "{C616A6DF-831E-443C-9310-3F343A6E3D1A}"
EndProject
@@ -36,6 +36,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{0D2F61
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "server1", "server1\server1.csproj", "{9286D2AB-96ED-4631-AB3C-ED20FF5D6E6C}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "tls_client_example", "tls_client_example\tls_client_example.csproj", "{6734BF52-2D0D-476B-8EA2-C9C2D1D69B03}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "goose_subscriber", "goose_subscriber\goose_subscriber.csproj", "{1285372C-2E62-494A-A661-8D5D3873318C}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "sv_subscriber", "sv_subscriber\sv_subscriber.csproj", "{44651D2D-3252-4FD5-8B8B-5552DBE1B499}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -46,6 +52,10 @@ Global
{0BECEC77-2315-4B95-AFF9-E6007E644BBF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0BECEC77-2315-4B95-AFF9-E6007E644BBF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0BECEC77-2315-4B95-AFF9-E6007E644BBF}.Release|Any CPU.Build.0 = Release|Any CPU
+ {1285372C-2E62-494A-A661-8D5D3873318C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {1285372C-2E62-494A-A661-8D5D3873318C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {1285372C-2E62-494A-A661-8D5D3873318C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {1285372C-2E62-494A-A661-8D5D3873318C}.Release|Any CPU.Build.0 = Release|Any CPU
{14C71267-2F38-460D-AA55-6803EE80AFB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{14C71267-2F38-460D-AA55-6803EE80AFB4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{14C71267-2F38-460D-AA55-6803EE80AFB4}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -54,6 +64,10 @@ Global
{2A226B6D-1D1F-4BFE-B8CC-158116F71270}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2A226B6D-1D1F-4BFE-B8CC-158116F71270}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2A226B6D-1D1F-4BFE-B8CC-158116F71270}.Release|Any CPU.Build.0 = Release|Any CPU
+ {44651D2D-3252-4FD5-8B8B-5552DBE1B499}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {44651D2D-3252-4FD5-8B8B-5552DBE1B499}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {44651D2D-3252-4FD5-8B8B-5552DBE1B499}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {44651D2D-3252-4FD5-8B8B-5552DBE1B499}.Release|Any CPU.Build.0 = Release|Any CPU
{59B85486-F48D-4978-BD35-8F5C3A8288D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{59B85486-F48D-4978-BD35-8F5C3A8288D4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{59B85486-F48D-4978-BD35-8F5C3A8288D4}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -62,6 +76,10 @@ Global
{5E5D0FE0-DF44-48D8-A10E-1FB07D34DEA2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5E5D0FE0-DF44-48D8-A10E-1FB07D34DEA2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5E5D0FE0-DF44-48D8-A10E-1FB07D34DEA2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {6734BF52-2D0D-476B-8EA2-C9C2D1D69B03}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {6734BF52-2D0D-476B-8EA2-C9C2D1D69B03}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {6734BF52-2D0D-476B-8EA2-C9C2D1D69B03}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {6734BF52-2D0D-476B-8EA2-C9C2D1D69B03}.Release|Any CPU.Build.0 = Release|Any CPU
{71485F99-2976-45E6-B73D-4946E594C15C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{71485F99-2976-45E6-B73D-4946E594C15C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{71485F99-2976-45E6-B73D-4946E594C15C}.Release|Any CPU.ActiveCfg = Release|Any CPU
diff --git a/dotnet/example1/Main.cs b/dotnet/example1/Main.cs
index eb70ce5c..738d839e 100644
--- a/dotnet/example1/Main.cs
+++ b/dotnet/example1/Main.cs
@@ -26,7 +26,6 @@ namespace example1
Console.WriteLine("Connect to " + hostname);
-
try
{
con.Connect(hostname, port);
diff --git a/dotnet/example1/example1.csproj b/dotnet/example1/example1.csproj
index 453058eb..592905b5 100644
--- a/dotnet/example1/example1.csproj
+++ b/dotnet/example1/example1.csproj
@@ -35,9 +35,9 @@
-
+ {C35D624E-5506-4560-8074-1728F1FA1A4D}
- IEC61850forCSharp
+ IEC61850.NET
\ No newline at end of file
diff --git a/dotnet/example2/example2.csproj b/dotnet/example2/example2.csproj
index 496e11cb..612fcdb5 100644
--- a/dotnet/example2/example2.csproj
+++ b/dotnet/example2/example2.csproj
@@ -35,9 +35,9 @@
-
+ {C35D624E-5506-4560-8074-1728F1FA1A4D}
- IEC61850forCSharp
+ IEC61850.NET
\ No newline at end of file
diff --git a/dotnet/example3/example3.csproj b/dotnet/example3/example3.csproj
index 53285216..4f60434a 100644
--- a/dotnet/example3/example3.csproj
+++ b/dotnet/example3/example3.csproj
@@ -35,9 +35,9 @@
-
+ {C35D624E-5506-4560-8074-1728F1FA1A4D}
- IEC61850forCSharp
+ IEC61850.NET
\ No newline at end of file
diff --git a/dotnet/files/files.csproj b/dotnet/files/files.csproj
index 2ecf30fe..ba8c3186 100644
--- a/dotnet/files/files.csproj
+++ b/dotnet/files/files.csproj
@@ -35,9 +35,9 @@
-
+ {C35D624E-5506-4560-8074-1728F1FA1A4D}
- IEC61850forCSharp
+ IEC61850.NET
\ No newline at end of file
diff --git a/dotnet/goose_subscriber/Program.cs b/dotnet/goose_subscriber/Program.cs
new file mode 100644
index 00000000..df84f032
--- /dev/null
+++ b/dotnet/goose_subscriber/Program.cs
@@ -0,0 +1,68 @@
+using System;
+
+using IEC61850.GOOSE.Subscriber;
+using System.Threading;
+using IEC61850.Common;
+
+namespace goose_subscriber
+{
+ class MainClass
+ {
+ private static void gooseListener (GooseSubscriber subscriber, object parameter)
+ {
+ Console.WriteLine ("Received GOOSE message:\n-------------------------");
+
+ Console.WriteLine (" stNum: " + subscriber.GetStNum ());
+
+ Console.WriteLine (" sqNum: " + subscriber.GetSqNum ());
+
+
+ MmsValue values = subscriber.GetDataSetValues ();
+
+ Console.WriteLine (" values: " +values.Size ().ToString ());
+
+ foreach (MmsValue value in values) {
+ Console.WriteLine (" value: " + value.ToString ());
+ }
+ }
+
+ public static void Main (string[] args)
+ {
+ Console.WriteLine ("Starting GOOSE subscriber...");
+
+ GooseReceiver receiver = new GooseReceiver ();
+
+ receiver.SetInterfaceId ("eth0");
+
+ GooseSubscriber subscriber = new GooseSubscriber ("simpleIOGenericIO/LLN0$GO$gcbAnalogValues");
+
+ subscriber.SetAppId(1000);
+
+ subscriber.SetListener (gooseListener, null);
+
+ receiver.AddSubscriber (subscriber);
+
+ receiver.Start ();
+
+ if (receiver.IsRunning ()) {
+
+ bool running = true;
+
+ /* run until Ctrl-C is pressed */
+ Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e) {
+ e.Cancel = true;
+ running = false;
+ };
+
+ while (running) {
+ Thread.Sleep (100);
+ }
+
+ receiver.Stop ();
+ } else
+ Console.WriteLine ("Failed to start GOOSE receiver. Running as root?");
+
+ receiver.Dispose ();
+ }
+ }
+}
diff --git a/dotnet/goose_subscriber/Properties/AssemblyInfo.cs b/dotnet/goose_subscriber/Properties/AssemblyInfo.cs
new file mode 100644
index 00000000..d42b17b9
--- /dev/null
+++ b/dotnet/goose_subscriber/Properties/AssemblyInfo.cs
@@ -0,0 +1,27 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+// Information about this assembly is defined by the following attributes.
+// Change them to the values specific to your project.
+
+[assembly: AssemblyTitle ("goose_subscriber")]
+[assembly: AssemblyDescription ("")]
+[assembly: AssemblyConfiguration ("")]
+[assembly: AssemblyCompany ("")]
+[assembly: AssemblyProduct ("")]
+[assembly: AssemblyCopyright ("mzillgit")]
+[assembly: AssemblyTrademark ("")]
+[assembly: AssemblyCulture ("")]
+
+// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
+// The form "{Major}.{Minor}.*" will automatically update the build and revision,
+// and "{Major}.{Minor}.{Build}.*" will update just the revision.
+
+[assembly: AssemblyVersion ("1.0.*")]
+
+// The following attributes are used to specify the signing key for the assembly,
+// if desired. See the Mono documentation for more information about signing.
+
+//[assembly: AssemblyDelaySign(false)]
+//[assembly: AssemblyKeyFile("")]
+
diff --git a/dotnet/goose_subscriber/goose_subscriber.csproj b/dotnet/goose_subscriber/goose_subscriber.csproj
new file mode 100644
index 00000000..077b65df
--- /dev/null
+++ b/dotnet/goose_subscriber/goose_subscriber.csproj
@@ -0,0 +1,44 @@
+
+
+
+ Debug
+ AnyCPU
+ {1285372C-2E62-494A-A661-8D5D3873318C}
+ Exe
+ goose_subscriber
+ goose_subscriber
+ v4.5
+
+
+ true
+ full
+ false
+ bin\Debug
+ DEBUG;
+ prompt
+ 4
+ true
+
+
+ full
+ true
+ bin\Release
+ prompt
+ 4
+ true
+
+
+
+
+
+
+
+
+
+
+
+ {C35D624E-5506-4560-8074-1728F1FA1A4D}
+ IEC61850.NET
+
+
+
\ No newline at end of file
diff --git a/dotnet/log_client/log_client.csproj b/dotnet/log_client/log_client.csproj
index 28c90c24..23243060 100644
--- a/dotnet/log_client/log_client.csproj
+++ b/dotnet/log_client/log_client.csproj
@@ -36,9 +36,9 @@
-
+ {C35D624E-5506-4560-8074-1728F1FA1A4D}
- IEC61850forCSharp
+ IEC61850.NET
\ No newline at end of file
diff --git a/dotnet/model_browsing/model_browsing.csproj b/dotnet/model_browsing/model_browsing.csproj
index 0827b41d..8162b3f8 100644
--- a/dotnet/model_browsing/model_browsing.csproj
+++ b/dotnet/model_browsing/model_browsing.csproj
@@ -35,9 +35,9 @@
-
+ {C35D624E-5506-4560-8074-1728F1FA1A4D}
- IEC61850forCSharp
+ IEC61850.NET
\ No newline at end of file
diff --git a/dotnet/report_new_dataset/report_new_dataset.csproj b/dotnet/report_new_dataset/report_new_dataset.csproj
index b91d522c..ccf2dc93 100644
--- a/dotnet/report_new_dataset/report_new_dataset.csproj
+++ b/dotnet/report_new_dataset/report_new_dataset.csproj
@@ -35,9 +35,9 @@
-
+ {C35D624E-5506-4560-8074-1728F1FA1A4D}
- IEC61850forCSharp
+ IEC61850.NET
\ No newline at end of file
diff --git a/dotnet/reporting/reporting.csproj b/dotnet/reporting/reporting.csproj
index 81a9d0ea..53a5829e 100644
--- a/dotnet/reporting/reporting.csproj
+++ b/dotnet/reporting/reporting.csproj
@@ -51,9 +51,9 @@
-
+ {C35D624E-5506-4560-8074-1728F1FA1A4D}
- IEC61850forCSharp
+ IEC61850.NET
diff --git a/dotnet/server1/server1.csproj b/dotnet/server1/server1.csproj
index 617705c1..5d820daf 100644
--- a/dotnet/server1/server1.csproj
+++ b/dotnet/server1/server1.csproj
@@ -36,9 +36,9 @@
-
+ {C35D624E-5506-4560-8074-1728F1FA1A4D}
- IEC61850forCSharp
+ IEC61850.NET
\ No newline at end of file
diff --git a/dotnet/sv_subscriber/Program.cs b/dotnet/sv_subscriber/Program.cs
new file mode 100644
index 00000000..17426e6f
--- /dev/null
+++ b/dotnet/sv_subscriber/Program.cs
@@ -0,0 +1,74 @@
+using System;
+
+using IEC61850.SV.Subscriber;
+using IEC61850.Common;
+using System.Threading;
+
+namespace sv_subscriber
+{
+ class MainClass
+ {
+ private static void svUpdateListener(SVSubscriber subscriber, object parameter, SVSubscriberASDU asdu)
+ {
+ Console.WriteLine ("RECV ASDU:");
+
+ string svID = asdu.GetSvId ();
+
+ if (svID != null)
+ Console.WriteLine (" svID=" + svID);
+
+ Console.WriteLine (" smpCnt: " + asdu.GetSmpCnt ());
+ Console.WriteLine (" confRev: " + asdu.GetConfRev ());
+
+ if (asdu.GetDataSize () >= 8) {
+ Console.WriteLine (" DATA[0]: " + asdu.GetFLOAT32(0));
+ Console.WriteLine (" DATA[1]: " + asdu.GetFLOAT32 (4));
+ }
+
+ if (asdu.GetDataSize () >= 16) {
+ Console.WriteLine (" DATA[2]: " + asdu.GetTimestamp (8).AsDateTime().ToString());
+ }
+
+ }
+
+ public static void Main (string[] args)
+ {
+ Console.WriteLine ("Starting SV subscriber");
+
+ SVReceiver receiver = new SVReceiver ();
+
+ if (args.Length > 0) {
+ receiver.SetInterfaceId (args [0]);
+ }
+
+ SVSubscriber subscriber = new SVSubscriber (null, 0x4000);
+
+ subscriber.SetListener (svUpdateListener, null);
+
+ receiver.AddSubscriber (subscriber);
+
+ receiver.Start ();
+
+ if (receiver.IsRunning ()) {
+
+ bool running = true;
+
+ /* run until Ctrl-C is pressed */
+ Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e) {
+ e.Cancel = true;
+ running = false;
+ };
+
+ while (running) {
+ Thread.Sleep (100);
+ }
+
+ receiver.Stop ();
+ } else
+ Console.WriteLine ("Failed to start SV receiver. Running as root?");
+
+ receiver.Dispose ();
+
+ }
+ }
+}
diff --git a/dotnet/sv_subscriber/Properties/AssemblyInfo.cs b/dotnet/sv_subscriber/Properties/AssemblyInfo.cs
new file mode 100644
index 00000000..ae4b1a2a
--- /dev/null
+++ b/dotnet/sv_subscriber/Properties/AssemblyInfo.cs
@@ -0,0 +1,27 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+// Information about this assembly is defined by the following attributes.
+// Change them to the values specific to your project.
+
+[assembly: AssemblyTitle ("sv_subscriber")]
+[assembly: AssemblyDescription ("")]
+[assembly: AssemblyConfiguration ("")]
+[assembly: AssemblyCompany ("")]
+[assembly: AssemblyProduct ("")]
+[assembly: AssemblyCopyright ("mzillgit")]
+[assembly: AssemblyTrademark ("")]
+[assembly: AssemblyCulture ("")]
+
+// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
+// The form "{Major}.{Minor}.*" will automatically update the build and revision,
+// and "{Major}.{Minor}.{Build}.*" will update just the revision.
+
+[assembly: AssemblyVersion ("1.0.*")]
+
+// The following attributes are used to specify the signing key for the assembly,
+// if desired. See the Mono documentation for more information about signing.
+
+//[assembly: AssemblyDelaySign(false)]
+//[assembly: AssemblyKeyFile("")]
+
diff --git a/dotnet/sv_subscriber/sv_subscriber.csproj b/dotnet/sv_subscriber/sv_subscriber.csproj
new file mode 100644
index 00000000..dc8f53fe
--- /dev/null
+++ b/dotnet/sv_subscriber/sv_subscriber.csproj
@@ -0,0 +1,44 @@
+
+
+
+ Debug
+ AnyCPU
+ {44651D2D-3252-4FD5-8B8B-5552DBE1B499}
+ Exe
+ sv_subscriber
+ sv_subscriber
+ v4.5
+
+
+ true
+ full
+ false
+ bin\Debug
+ DEBUG;
+ prompt
+ 4
+ true
+
+
+ full
+ true
+ bin\Release
+ prompt
+ 4
+ true
+
+
+
+
+
+
+
+
+
+
+
+ {C35D624E-5506-4560-8074-1728F1FA1A4D}
+ IEC61850.NET
+
+
+
\ No newline at end of file
diff --git a/dotnet/tests/Test.cs b/dotnet/tests/Test.cs
index 8ec403eb..ce22168f 100644
--- a/dotnet/tests/Test.cs
+++ b/dotnet/tests/Test.cs
@@ -454,6 +454,33 @@ namespace tests
iedServer.Stop ();
}
+
+ [Test()]
+ public void Quality()
+ {
+ Quality q = new Quality ();
+
+ Assert.AreEqual (false, q.Overflow);
+
+ q.Overflow = true;
+
+ Assert.AreEqual (true, q.Overflow);
+
+ q.Overflow = false;
+
+ Assert.AreEqual (false, q.Overflow);
+
+ Assert.AreEqual (Validity.GOOD, q.Validity);
+
+ q.Substituted = true;
+
+ Assert.AreEqual (true, q.Substituted);
+ Assert.AreEqual (false, q.Overflow);
+
+ q.Validity = Validity.QUESTIONABLE;
+
+ Assert.AreEqual (Validity.QUESTIONABLE, q.Validity);
+ }
}
}
diff --git a/dotnet/tests/tests.csproj b/dotnet/tests/tests.csproj
index 8d35ba82..ecaf4e89 100644
--- a/dotnet/tests/tests.csproj
+++ b/dotnet/tests/tests.csproj
@@ -31,9 +31,9 @@
-
+ {C35D624E-5506-4560-8074-1728F1FA1A4D}
- IEC61850forCSharp
+ IEC61850.NET
diff --git a/dotnet/tls_client_example/Program.cs b/dotnet/tls_client_example/Program.cs
new file mode 100644
index 00000000..835b33d6
--- /dev/null
+++ b/dotnet/tls_client_example/Program.cs
@@ -0,0 +1,101 @@
+using System;
+using IEC61850.Client;
+using IEC61850.Common;
+using IEC61850.TLS;
+using System.Threading;
+using System.Collections.Generic;
+using System.Security.Cryptography.X509Certificates;
+
+namespace tls_client_example
+{
+ class MainClass
+ {
+ public static void Main (string[] args)
+ {
+ TLSConfiguration tlsConfig = new TLSConfiguration ();
+
+ tlsConfig.SetOwnCertificate (new X509Certificate2 ("client1.cer"));
+
+ tlsConfig.SetOwnKey ("client1-key.pem", null);
+
+ // Add a CA certificate to check the certificate provided by the server - not required when ChainValidation == false
+ tlsConfig.AddCACertificate (new X509Certificate2 ("root.cer"));
+
+ // Check if the certificate is signed by a provided CA
+ tlsConfig.ChainValidation = true;
+
+ // Check that the shown server certificate is in the list of allowed certificates
+ tlsConfig.AllowOnlyKnownCertificates = false;
+
+ IedConnection con = new IedConnection (tlsConfig);
+
+ string hostname;
+
+ if (args.Length > 0)
+ hostname = args[0];
+ else
+ hostname = "127.0.0.1";
+
+ int port = -1;
+
+ if (args.Length > 1)
+ port = Int32.Parse(args [1]);
+
+ Console.WriteLine("Connect to " + hostname);
+
+ try
+ {
+ con.Connect(hostname, port);
+
+ List serverDirectory = con.GetServerDirectory(false);
+
+ foreach (string entry in serverDirectory)
+ {
+ Console.WriteLine("LD: " + entry);
+ }
+
+ List lnDirectory = con.GetLogicalNodeDirectory("simpleIOGenericIO/LLN0", ACSIClass.ACSI_CLASS_DATA_SET);
+
+ foreach (string entry in lnDirectory)
+ {
+ Console.WriteLine("Dataset: " + entry);
+ }
+
+ string vendor = con.ReadStringValue ("simpleIOGenericIO/LLN0.NamPlt.vendor", FunctionalConstraint.DC);
+ Console.WriteLine ("Vendor: " + vendor);
+
+ /* read FCDO */
+ MmsValue value = con.ReadValue("simpleIOGenericIO/GGIO1.AnIn1", FunctionalConstraint.MX);
+
+ if (value.GetType() == MmsType.MMS_STRUCTURE)
+ {
+ Console.WriteLine("Value is of complex type");
+
+ for (int i = 0; i < value.Size(); i++)
+ {
+ Console.WriteLine(" element: " + value.GetElement(i).GetType());
+ if (value.GetElement(i).GetType() == MmsType.MMS_UTC_TIME)
+ {
+ Console.WriteLine(" -> " + value.GetElement(i).GetUtcTimeAsDateTimeOffset());
+ }
+ }
+ }
+
+ DataSet dataSet = con.ReadDataSetValues("simpleIOGenericIO/LLN0.Events", null);
+
+ Console.WriteLine("Read data set " + dataSet.GetReference());
+
+ con.Abort();
+ }
+ catch (IedConnectionException e)
+ {
+ Console.WriteLine(e.Message);
+ }
+
+ System.Threading.Thread.Sleep(2000);
+
+ // release all resources - do NOT use the object after this call!!
+ con.Dispose ();
+ }
+ }
+}
diff --git a/dotnet/tls_client_example/Properties/AssemblyInfo.cs b/dotnet/tls_client_example/Properties/AssemblyInfo.cs
new file mode 100644
index 00000000..00fcb3e8
--- /dev/null
+++ b/dotnet/tls_client_example/Properties/AssemblyInfo.cs
@@ -0,0 +1,27 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+// Information about this assembly is defined by the following attributes.
+// Change them to the values specific to your project.
+
+[assembly: AssemblyTitle ("tls_client_example")]
+[assembly: AssemblyDescription ("")]
+[assembly: AssemblyConfiguration ("")]
+[assembly: AssemblyCompany ("")]
+[assembly: AssemblyProduct ("")]
+[assembly: AssemblyCopyright ("mzillgit")]
+[assembly: AssemblyTrademark ("")]
+[assembly: AssemblyCulture ("")]
+
+// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
+// The form "{Major}.{Minor}.*" will automatically update the build and revision,
+// and "{Major}.{Minor}.{Build}.*" will update just the revision.
+
+[assembly: AssemblyVersion ("1.0.*")]
+
+// The following attributes are used to specify the signing key for the assembly,
+// if desired. See the Mono documentation for more information about signing.
+
+//[assembly: AssemblyDelaySign(false)]
+//[assembly: AssemblyKeyFile("")]
+
diff --git a/dotnet/tls_client_example/client1-key.pem b/dotnet/tls_client_example/client1-key.pem
new file mode 100644
index 00000000..c39425cc
--- /dev/null
+++ b/dotnet/tls_client_example/client1-key.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAxAMUXdnem99n5J8Z8Wa0fdPtoMCTdkQJrOO6WJ4XePrpQgHU
+HDziSmdIZDDkpJ3Ey0Byy+b+iiRDmOuIZGSCsI0ehggWaia12h2osUK0BLyThuZ/
+RQw54K0dy61eviNaYsftiBcxHYKyKmWch/wLLYxdd1qLzd0reAbSUaHDkDzrj9hO
+8qr7DhKpqx7PoVh1gFhAKPKuY6b+4xqv5eZvt8QflQTWYGxaxmUIEinqCnzh1l5d
+tp0rhnBsz9Y4y8dXjh0m7pbXmRNY6opMxXatqgYEqsntLy1N6x7DvWLBqtVvEmox
+Tc5bbAoRW3eEToClDdFQBzLsMVcSEX8vwttk3QIDAQABAoIBABHr1ijeiqPlwTH9
++flAUrBOeCOCd/kQL3JHP/pqOestxbXrROFwD6CN4OiIL999LUkIE3bhH9SxjByn
+LElBh1FtFaVbh/EcqPPQUmQinSLxuutSl8BQZdpM+bRtnYP054awkN8of60bDf8i
+WzVzrfH0K3eGJ9Iirp7CwOgFykOdpQyxsI+HG8grcwA87x1ZsAIfHhiKmQByliNl
+BkbJmYBOtfVgXje5QdxTptlTNljFSbZcaCXv1P3aOqctcgJMQjg0T+E37Y8Cav80
+6SuXbpv/cdacG695MAT7Vtywue0Axh59DvxAzc+deyQT70Hzw+Mo6pgi0clFnwzU
+Y5ViDWECgYEAxxhRKzpz7klnmGob5CZvrbqDfC3JUEOxKH0e342S/HmT05bTI21w
+N8A0KStNjQXS1mmkAkY/OO1Zutmf6yjqsxAIEO5UMTCSEP7YLRB7qBdN7dOt3JaK
+4wxErMCljdT68Vj5Qj8YzIXJkWPk871oFTvVNe2qxgrCUigE5ai2I8cCgYEA/Akv
+E0L+2uXayEucEamzO3n9xVziNanjyHilnJJvduvO9gd+crBbxSKqaXSdfPnp2mSa
++e3N7elxP2b/kPrGkzZekSaMh1nPH4Upu+ISK117r1x+vmnxZHRpehrVh1QzOQ5p
+Ljt+GaXa3ur3P/6uW5KMbtGGW6MEgDwLMLvpqjsCgYA5pnfyfYWOTWEbCDa1VM/n
+zWc/cP6nKELHR5vF/fe+9fFxRm4zBwCElDpGZYyaNkJ75bEhG3g5Irll2phs/rcf
+TJgZVvm4GKljFHhCbFByNvVQ1Ye1pT3oSugj4dDOhgp4Elxy61Rh/KeGWxez4Heg
+FmhBqmVV3U2xfncUjUrYhwKBgQCKtPM3gpOIHSA/Q31tKxv9C7JiQDAuoIU/+0YJ
+2X2G0VhhhtZMgErBP8bRquBRu6i8DMpN6lZ/LQ6qeiEExT8sHawF7lVA2GhpTHwf
+btfZDeXYKOuIF/5F7ttt2/7QL8LRD+FLFGrd6q1+KYpRqfSDaS/ofV+YZys+98yg
+0YpTqQKBgQCWJpV2ySgXcKJzAUh14VNpLTRzJOMSpsU576nwz0TLUREVjiH6rvKr
+gxllDEe1bVNMEekaZ+dOqiJX+4aTnEbIrEXki5Dvz0vq8biImW9RRdPEHgYVTv/d
+qBOPHiIq2JiY6abD9XNPM3VQ/z8em6/4mkC8COCJRd2mA89FOYRxOQ==
+-----END RSA PRIVATE KEY-----
diff --git a/dotnet/tls_client_example/client1.cer b/dotnet/tls_client_example/client1.cer
new file mode 100644
index 00000000..a5aa8db3
Binary files /dev/null and b/dotnet/tls_client_example/client1.cer differ
diff --git a/dotnet/tls_client_example/root.cer b/dotnet/tls_client_example/root.cer
new file mode 100644
index 00000000..87683444
Binary files /dev/null and b/dotnet/tls_client_example/root.cer differ
diff --git a/dotnet/tls_client_example/tls_client_example.csproj b/dotnet/tls_client_example/tls_client_example.csproj
new file mode 100644
index 00000000..389abef9
--- /dev/null
+++ b/dotnet/tls_client_example/tls_client_example.csproj
@@ -0,0 +1,55 @@
+
+
+
+ Debug
+ AnyCPU
+ {6734BF52-2D0D-476B-8EA2-C9C2D1D69B03}
+ Exe
+ tls_client_example
+ tls_client_example
+ v4.5
+
+
+ true
+ full
+ false
+ bin\Debug
+ DEBUG;
+ prompt
+ 4
+ true
+
+
+ full
+ true
+ bin\Release
+ prompt
+ 4
+ true
+
+
+
+
+
+
+
+
+
+
+
+ {C35D624E-5506-4560-8074-1728F1FA1A4D}
+ IEC61850.NET
+
+
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+
\ No newline at end of file
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index 2502ff10..2d802c9b 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -33,6 +33,11 @@ else()
set(BUILD_SV_GOOSE_EXAMPLES ON)
endif()
+if(WITH_MBEDTLS)
+add_subdirectory(tls_client_example)
+add_subdirectory(tls_server_example)
+endif(WITH_MBEDTLS)
+
if(${BUILD_SV_GOOSE_EXAMPLES})
add_subdirectory(server_example_goose)
add_subdirectory(goose_subscriber)
diff --git a/examples/goose_publisher/goose_publisher_example.c b/examples/goose_publisher/goose_publisher_example.c
index 916be700..7abf6f57 100644
--- a/examples/goose_publisher/goose_publisher_example.c
+++ b/examples/goose_publisher/goose_publisher_example.c
@@ -16,6 +16,14 @@
int
main(int argc, char** argv)
{
+ char* interface;
+
+ if (argc > 1)
+ interface = argv[1];
+ else
+ interface = "eth0";
+
+ printf("Using interface %s\n", interface);
LinkedList dataSetValues = LinkedList_create();
@@ -41,7 +49,7 @@ main(int argc, char** argv)
* is NULL the interface name as defined with CONFIG_ETHERNET_INTERFACE_ID in
* stack_config.h is used.
*/
- GoosePublisher publisher = GoosePublisher_create(&gooseCommParameters, NULL);
+ GoosePublisher publisher = GoosePublisher_create(&gooseCommParameters, interface);
GoosePublisher_setGoCbRef(publisher, "simpleIOGenericIO/LLN0$GO$gcbAnalogValues");
GoosePublisher_setConfRev(publisher, 1);
diff --git a/examples/goose_subscriber/goose_subscriber_example.c b/examples/goose_subscriber/goose_subscriber_example.c
index 5d28534b..511a9cf8 100644
--- a/examples/goose_subscriber/goose_subscriber_example.c
+++ b/examples/goose_subscriber/goose_subscriber_example.c
@@ -7,6 +7,7 @@
*/
#include "goose_receiver.h"
+#include "goose_subscriber.h"
#include "hal_thread.h"
#include
diff --git a/examples/iec61850_9_2_LE_example/iec61850_9_2_LE_example.c b/examples/iec61850_9_2_LE_example/iec61850_9_2_LE_example.c
index e4c9407d..c49347b1 100644
--- a/examples/iec61850_9_2_LE_example/iec61850_9_2_LE_example.c
+++ b/examples/iec61850_9_2_LE_example/iec61850_9_2_LE_example.c
@@ -53,27 +53,27 @@ static int vol2;
static int vol3;
static int vol4;
-static SampledValuesPublisher svPublisher;
-static SV_ASDU asdu;
+static SVPublisher svPublisher;
+static SVPublisher_ASDU asdu;
static void
setupSVPublisher(const char* svInterface)
{
- svPublisher = SampledValuesPublisher_create(NULL, svInterface);
+ svPublisher = SVPublisher_create(NULL, svInterface);
- asdu = SampledValuesPublisher_addASDU(svPublisher, "xxxxMUnn01", NULL, 1);
+ asdu = SVPublisher_addASDU(svPublisher, "xxxxMUnn01", NULL, 1);
- amp1 = SV_ASDU_addINT32(asdu);
- amp2 = SV_ASDU_addINT32(asdu);
- amp3 = SV_ASDU_addINT32(asdu);
- amp4 = SV_ASDU_addINT32(asdu);
+ amp1 = SVPublisher_ASDU_addINT32(asdu);
+ amp2 = SVPublisher_ASDU_addINT32(asdu);
+ amp3 = SVPublisher_ASDU_addINT32(asdu);
+ amp4 = SVPublisher_ASDU_addINT32(asdu);
- vol1 = SV_ASDU_addINT32(asdu);
- vol2 = SV_ASDU_addINT32(asdu);
- vol3 = SV_ASDU_addINT32(asdu);
- vol4 = SV_ASDU_addINT32(asdu);
+ vol1 = SVPublisher_ASDU_addINT32(asdu);
+ vol2 = SVPublisher_ASDU_addINT32(asdu);
+ vol3 = SVPublisher_ASDU_addINT32(asdu);
+ vol4 = SVPublisher_ASDU_addINT32(asdu);
- SampledValuesPublisher_setupComplete(svPublisher);
+ SVPublisher_setupComplete(svPublisher);
}
static void sVCBEventHandler (SVControlBlock* svcb, int event, void* parameter)
@@ -143,19 +143,19 @@ main(int argc, char** argv)
if (svcbEnabled) {
- SV_ASDU_setINT32(asdu, amp1, current);
- SV_ASDU_setINT32(asdu, amp2, current);
- SV_ASDU_setINT32(asdu, amp3, current);
- SV_ASDU_setINT32(asdu, amp4, current);
+ SVPublisher_ASDU_setINT32(asdu, amp1, current);
+ SVPublisher_ASDU_setINT32(asdu, amp2, current);
+ SVPublisher_ASDU_setINT32(asdu, amp3, current);
+ SVPublisher_ASDU_setINT32(asdu, amp4, current);
- SV_ASDU_setINT32(asdu, vol1, voltage);
- SV_ASDU_setINT32(asdu, vol2, voltage);
- SV_ASDU_setINT32(asdu, vol3, voltage);
- SV_ASDU_setINT32(asdu, vol4, voltage);
+ SVPublisher_ASDU_setINT32(asdu, vol1, voltage);
+ SVPublisher_ASDU_setINT32(asdu, vol2, voltage);
+ SVPublisher_ASDU_setINT32(asdu, vol3, voltage);
+ SVPublisher_ASDU_setINT32(asdu, vol4, voltage);
- SV_ASDU_increaseSmpCnt(asdu);
+ SVPublisher_ASDU_increaseSmpCnt(asdu);
- SampledValuesPublisher_publish(svPublisher);
+ SVPublisher_publish(svPublisher);
}
voltage++;
@@ -168,7 +168,7 @@ main(int argc, char** argv)
IedServer_stop(iedServer);
/* Cleanup - free all resources */
- SampledValuesPublisher_destroy(svPublisher);
+ SVPublisher_destroy(svPublisher);
IedServer_destroy(iedServer);
return 0;
diff --git a/examples/iec61850_client_example1/client_example1.c b/examples/iec61850_client_example1/client_example1.c
index 1142c768..f5b23575 100644
--- a/examples/iec61850_client_example1/client_example1.c
+++ b/examples/iec61850_client_example1/client_example1.c
@@ -1,7 +1,7 @@
/*
* client_example1.c
*
- * This example is intended to be used with server_example3 or server_example_goose.
+ * This example is intended to be used with server_example_basic_io or server_example_goose.
*/
#include "iec61850_client.h"
@@ -50,8 +50,6 @@ int main(int argc, char** argv) {
if (error == IED_ERROR_OK) {
- IedConnection_getServerDirectory(con, &error, false);
-
/* read an analog measurement value from server */
MmsValue* value = IedConnection_readObject(con, &error, "simpleIOGenericIO/GGIO1.AnIn1.mag.f", IEC61850_FC_MX);
diff --git a/examples/server_example_basic_io/Makefile b/examples/server_example_basic_io/Makefile
index 4e4e5956..ed1ce6a1 100644
--- a/examples/server_example_basic_io/Makefile
+++ b/examples/server_example_basic_io/Makefile
@@ -22,6 +22,7 @@ model: $(PROJECT_ICD_FILE)
$(PROJECT_BINARY_NAME): $(PROJECT_SOURCES) $(LIB_NAME)
$(CC) $(CFLAGS) $(LDFLAGS) -o $(PROJECT_BINARY_NAME) $(PROJECT_SOURCES) $(INCLUDES) $(LIB_NAME) $(LDLIBS)
+ mkdir -p vmd-filestore
$(CP) $(PROJECT_BINARY_NAME) vmd-filestore/IEDSERVER.BIN
clean:
diff --git a/examples/server_example_password_auth/server_example_password_auth.c b/examples/server_example_password_auth/server_example_password_auth.c
index 92f7aac5..40f3d804 100644
--- a/examples/server_example_password_auth/server_example_password_auth.c
+++ b/examples/server_example_password_auth/server_example_password_auth.c
@@ -37,7 +37,8 @@ void sigint_handler(int signalId)
static char* password1 = "user1@testpw";
static char* password2 = "user2@testpw";
-static void printAppTitle(ItuObjectIdentifier* oid)
+static void
+printAppTitle(ItuObjectIdentifier* oid)
{
int i;
diff --git a/examples/sv_publisher/sv_publisher_example.c b/examples/sv_publisher/sv_publisher_example.c
index e1128602..311b6ff6 100644
--- a/examples/sv_publisher/sv_publisher_example.c
+++ b/examples/sv_publisher/sv_publisher_example.c
@@ -29,39 +29,48 @@ main(int argc, char** argv)
printf("Using interface %s\n", interface);
- SampledValuesPublisher svPublisher = SampledValuesPublisher_create(NULL, interface);
+ SVPublisher svPublisher = SVPublisher_create(NULL, interface);
- SV_ASDU asdu1 = SampledValuesPublisher_addASDU(svPublisher, "svpub1", NULL, 1);
+ SVPublisher_ASDU asdu1 = SVPublisher_addASDU(svPublisher, "svpub1", NULL, 1);
- int float1 = SV_ASDU_addFLOAT(asdu1);
- int float2 = SV_ASDU_addFLOAT(asdu1);
+ int float1 = SVPublisher_ASDU_addFLOAT(asdu1);
+ int float2 = SVPublisher_ASDU_addFLOAT(asdu1);
+ int ts1 = SVPublisher_ASDU_addTimestamp(asdu1);
- SV_ASDU asdu2 = SampledValuesPublisher_addASDU(svPublisher, "svpub2", NULL, 1);
+ SVPublisher_ASDU asdu2 = SVPublisher_addASDU(svPublisher, "svpub2", NULL, 1);
- int float3 = SV_ASDU_addFLOAT(asdu2);
- int float4 = SV_ASDU_addFLOAT(asdu2);
+ int float3 = SVPublisher_ASDU_addFLOAT(asdu2);
+ int float4 = SVPublisher_ASDU_addFLOAT(asdu2);
+ int ts2 = SVPublisher_ASDU_addTimestamp(asdu2);
- SampledValuesPublisher_setupComplete(svPublisher);
+ SVPublisher_setupComplete(svPublisher);
float fVal1 = 1234.5678f;
float fVal2 = 0.12345f;
- int i;
-
while (running) {
- SV_ASDU_setFLOAT(asdu1, float1, fVal1);
- SV_ASDU_setFLOAT(asdu1, float2, fVal2);
+ Timestamp ts;
+ Timestamp_clearFlags(&ts);
+ Timestamp_setTimeInMilliseconds(&ts, Hal_getTimeInMs());
+
+ SVPublisher_ASDU_setFLOAT(asdu1, float1, fVal1);
+ SVPublisher_ASDU_setFLOAT(asdu1, float2, fVal2);
+ SVPublisher_ASDU_setTimestamp(asdu1, ts1, ts);
+
+ SVPublisher_ASDU_setFLOAT(asdu2, float3, fVal1 * 2);
+ SVPublisher_ASDU_setFLOAT(asdu2, float4, fVal2 * 2);
+ SVPublisher_ASDU_setTimestamp(asdu2, ts2, ts);
- SV_ASDU_increaseSmpCnt(asdu1);
- SV_ASDU_increaseSmpCnt(asdu2);
+ SVPublisher_ASDU_increaseSmpCnt(asdu1);
+ SVPublisher_ASDU_increaseSmpCnt(asdu2);
fVal1 += 1.1f;
fVal2 += 0.1f;
- SampledValuesPublisher_publish(svPublisher);
+ SVPublisher_publish(svPublisher);
Thread_sleep(50);
}
- SampledValuesPublisher_destroy(svPublisher);
+ SVPublisher_destroy(svPublisher);
}
diff --git a/examples/sv_subscriber/sv_subscriber_example.c b/examples/sv_subscriber/sv_subscriber_example.c
index d8046478..1a1f1deb 100644
--- a/examples/sv_subscriber/sv_subscriber_example.c
+++ b/examples/sv_subscriber/sv_subscriber_example.c
@@ -21,17 +21,17 @@ void sigint_handler(int signalId)
/* Callback handler for received SV messages */
static void
-svUpdateListener (SVSubscriber subscriber, void* parameter, SVClientASDU asdu)
+svUpdateListener (SVSubscriber subscriber, void* parameter, SVSubscriber_ASDU asdu)
{
printf("svUpdateListener called\n");
- const char* svID = SVClientASDU_getSvId(asdu);
+ const char* svID = SVSubscriber_ASDU_getSvId(asdu);
if (svID != NULL)
printf(" svID=(%s)\n", svID);
- printf(" smpCnt: %i\n", SVClientASDU_getSmpCnt(asdu));
- printf(" confRev: %u\n", SVClientASDU_getConfRev(asdu));
+ printf(" smpCnt: %i\n", SVSubscriber_ASDU_getSmpCnt(asdu));
+ printf(" confRev: %u\n", SVSubscriber_ASDU_getConfRev(asdu));
/*
* Access to the data requires a priori knowledge of the data set.
@@ -43,9 +43,9 @@ svUpdateListener (SVSubscriber subscriber, void* parameter, SVClientASDU asdu)
* To prevent damages due configuration, please check the length of the
* data block of the SV message before accessing the data.
*/
- if (SVClientASDU_getDataSize(asdu) >= 8) {
- printf(" DATA[0]: %f\n", SVClientASDU_getFLOAT32(asdu, 0));
- printf(" DATA[1]: %f\n", SVClientASDU_getFLOAT32(asdu, 4));
+ if (SVSubscriber_ASDU_getDataSize(asdu) >= 8) {
+ printf(" DATA[0]: %f\n", SVSubscriber_ASDU_getFLOAT32(asdu, 0));
+ printf(" DATA[1]: %f\n", SVSubscriber_ASDU_getFLOAT32(asdu, 4));
}
}
diff --git a/examples/tls_client_example/CMakeLists.txt b/examples/tls_client_example/CMakeLists.txt
new file mode 100644
index 00000000..3a54e2d9
--- /dev/null
+++ b/examples/tls_client_example/CMakeLists.txt
@@ -0,0 +1,17 @@
+
+set(example_SRCS
+ tls_client_example.c
+)
+
+IF(WIN32)
+set_source_files_properties(${example_SRCS}
+ PROPERTIES LANGUAGE CXX)
+ENDIF(WIN32)
+
+add_executable(tls_client_example
+ ${example_SRCS}
+)
+
+target_link_libraries(tls_client_example
+ iec61850
+)
diff --git a/examples/tls_client_example/Makefile b/examples/tls_client_example/Makefile
new file mode 100644
index 00000000..a9bce6a7
--- /dev/null
+++ b/examples/tls_client_example/Makefile
@@ -0,0 +1,17 @@
+LIBIEC_HOME=../..
+
+PROJECT_BINARY_NAME = tls_client_example
+PROJECT_SOURCES = tls_client_example.c
+
+include $(LIBIEC_HOME)/make/target_system.mk
+include $(LIBIEC_HOME)/make/stack_includes.mk
+
+all: $(PROJECT_BINARY_NAME)
+
+include $(LIBIEC_HOME)/make/common_targets.mk
+
+$(PROJECT_BINARY_NAME): $(PROJECT_SOURCES) $(LIB_NAME)
+ $(CC) $(CFLAGS) $(LDFLAGS) -o $(PROJECT_BINARY_NAME) $(PROJECT_SOURCES) $(INCLUDES) $(LIB_NAME) $(LDLIBS)
+
+clean:
+ rm -f $(PROJECT_BINARY_NAME)
diff --git a/examples/tls_client_example/client1-key.pem b/examples/tls_client_example/client1-key.pem
new file mode 100644
index 00000000..c39425cc
--- /dev/null
+++ b/examples/tls_client_example/client1-key.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAxAMUXdnem99n5J8Z8Wa0fdPtoMCTdkQJrOO6WJ4XePrpQgHU
+HDziSmdIZDDkpJ3Ey0Byy+b+iiRDmOuIZGSCsI0ehggWaia12h2osUK0BLyThuZ/
+RQw54K0dy61eviNaYsftiBcxHYKyKmWch/wLLYxdd1qLzd0reAbSUaHDkDzrj9hO
+8qr7DhKpqx7PoVh1gFhAKPKuY6b+4xqv5eZvt8QflQTWYGxaxmUIEinqCnzh1l5d
+tp0rhnBsz9Y4y8dXjh0m7pbXmRNY6opMxXatqgYEqsntLy1N6x7DvWLBqtVvEmox
+Tc5bbAoRW3eEToClDdFQBzLsMVcSEX8vwttk3QIDAQABAoIBABHr1ijeiqPlwTH9
++flAUrBOeCOCd/kQL3JHP/pqOestxbXrROFwD6CN4OiIL999LUkIE3bhH9SxjByn
+LElBh1FtFaVbh/EcqPPQUmQinSLxuutSl8BQZdpM+bRtnYP054awkN8of60bDf8i
+WzVzrfH0K3eGJ9Iirp7CwOgFykOdpQyxsI+HG8grcwA87x1ZsAIfHhiKmQByliNl
+BkbJmYBOtfVgXje5QdxTptlTNljFSbZcaCXv1P3aOqctcgJMQjg0T+E37Y8Cav80
+6SuXbpv/cdacG695MAT7Vtywue0Axh59DvxAzc+deyQT70Hzw+Mo6pgi0clFnwzU
+Y5ViDWECgYEAxxhRKzpz7klnmGob5CZvrbqDfC3JUEOxKH0e342S/HmT05bTI21w
+N8A0KStNjQXS1mmkAkY/OO1Zutmf6yjqsxAIEO5UMTCSEP7YLRB7qBdN7dOt3JaK
+4wxErMCljdT68Vj5Qj8YzIXJkWPk871oFTvVNe2qxgrCUigE5ai2I8cCgYEA/Akv
+E0L+2uXayEucEamzO3n9xVziNanjyHilnJJvduvO9gd+crBbxSKqaXSdfPnp2mSa
++e3N7elxP2b/kPrGkzZekSaMh1nPH4Upu+ISK117r1x+vmnxZHRpehrVh1QzOQ5p
+Ljt+GaXa3ur3P/6uW5KMbtGGW6MEgDwLMLvpqjsCgYA5pnfyfYWOTWEbCDa1VM/n
+zWc/cP6nKELHR5vF/fe+9fFxRm4zBwCElDpGZYyaNkJ75bEhG3g5Irll2phs/rcf
+TJgZVvm4GKljFHhCbFByNvVQ1Ye1pT3oSugj4dDOhgp4Elxy61Rh/KeGWxez4Heg
+FmhBqmVV3U2xfncUjUrYhwKBgQCKtPM3gpOIHSA/Q31tKxv9C7JiQDAuoIU/+0YJ
+2X2G0VhhhtZMgErBP8bRquBRu6i8DMpN6lZ/LQ6qeiEExT8sHawF7lVA2GhpTHwf
+btfZDeXYKOuIF/5F7ttt2/7QL8LRD+FLFGrd6q1+KYpRqfSDaS/ofV+YZys+98yg
+0YpTqQKBgQCWJpV2ySgXcKJzAUh14VNpLTRzJOMSpsU576nwz0TLUREVjiH6rvKr
+gxllDEe1bVNMEekaZ+dOqiJX+4aTnEbIrEXki5Dvz0vq8biImW9RRdPEHgYVTv/d
+qBOPHiIq2JiY6abD9XNPM3VQ/z8em6/4mkC8COCJRd2mA89FOYRxOQ==
+-----END RSA PRIVATE KEY-----
diff --git a/examples/tls_client_example/client1.cer b/examples/tls_client_example/client1.cer
new file mode 100644
index 00000000..a5aa8db3
Binary files /dev/null and b/examples/tls_client_example/client1.cer differ
diff --git a/examples/tls_client_example/root.cer b/examples/tls_client_example/root.cer
new file mode 100644
index 00000000..87683444
Binary files /dev/null and b/examples/tls_client_example/root.cer differ
diff --git a/examples/tls_client_example/tls_client_example.c b/examples/tls_client_example/tls_client_example.c
new file mode 100644
index 00000000..77e2b994
--- /dev/null
+++ b/examples/tls_client_example/tls_client_example.c
@@ -0,0 +1,151 @@
+/*
+ * tls_client_exmaple.c
+ *
+ * This example shows how to configure TLS
+ */
+
+#include "iec61850_client.h"
+
+#include
+#include
+
+#include "hal_thread.h"
+
+void
+reportCallbackFunction(void* parameter, ClientReport report)
+{
+ MmsValue* dataSetValues = ClientReport_getDataSetValues(report);
+
+ printf("received report for %s\n", ClientReport_getRcbReference(report));
+
+ int i;
+ for (i = 0; i < 4; i++) {
+ ReasonForInclusion reason = ClientReport_getReasonForInclusion(report, i);
+
+ if (reason != IEC61850_REASON_NOT_INCLUDED) {
+ printf(" GGIO1.SPCSO%i.stVal: %i (included for reason %i)\n", i,
+ MmsValue_getBoolean(MmsValue_getElement(dataSetValues, i)), reason);
+ }
+ }
+}
+
+int main(int argc, char** argv) {
+
+ char* hostname;
+
+ if (argc > 1)
+ hostname = argv[1];
+ else
+ hostname = "localhost";
+
+ TLSConfiguration tlsConfig = TLSConfiguration_create();
+
+ TLSConfiguration_setChainValidation(tlsConfig, true);
+ TLSConfiguration_setAllowOnlyKnownCertificates(tlsConfig, false);
+
+ if (!TLSConfiguration_setOwnKeyFromFile(tlsConfig, "client1-key.pem", NULL)) {
+ printf("ERROR: Failed to load private key!\n");
+ return 0;
+ }
+
+ if (!TLSConfiguration_setOwnCertificateFromFile(tlsConfig, "client1.cer")) {
+ printf("ERROR: Failed to load own certificate!\n");
+ return 0;
+ }
+
+ if (!TLSConfiguration_addCACertificateFromFile(tlsConfig, "root.cer")) {
+ printf("ERROR: Failed to load root certificate\n");
+ return 0;
+ }
+
+ IedClientError error;
+
+ IedConnection con = IedConnection_createWithTlsSupport(tlsConfig);
+
+ IedConnection_connect(con, &error, hostname, -1);
+
+ if (error == IED_ERROR_OK) {
+
+ IedConnection_getServerDirectory(con, &error, false);
+
+ /* read an analog measurement value from server */
+ MmsValue* value = IedConnection_readObject(con, &error, "simpleIOGenericIO/GGIO1.AnIn1.mag.f", IEC61850_FC_MX);
+
+ if (value != NULL) {
+ float fval = MmsValue_toFloat(value);
+ printf("read float value: %f\n", fval);
+ MmsValue_delete(value);
+ }
+
+ /* write a variable to the server */
+ value = MmsValue_newVisibleString("libiec61850.com");
+ IedConnection_writeObject(con, &error, "simpleIOGenericIO/GGIO1.NamPlt.vendor", IEC61850_FC_DC, value);
+
+ if (error != IED_ERROR_OK)
+ printf("failed to write simpleIOGenericIO/GGIO1.NamPlt.vendor!\n");
+
+ MmsValue_delete(value);
+
+
+ /* read data set */
+ ClientDataSet clientDataSet = IedConnection_readDataSetValues(con, &error, "simpleIOGenericIO/LLN0.Events", NULL);
+
+ if (clientDataSet == NULL)
+ printf("failed to read dataset\n");
+
+ /* Read RCB values */
+ ClientReportControlBlock rcb =
+ IedConnection_getRCBValues(con, &error, "simpleIOGenericIO/LLN0.RP.EventsRCB01", NULL);
+
+
+ bool rptEna = ClientReportControlBlock_getRptEna(rcb);
+
+ printf("RptEna = %i\n", rptEna);
+
+ /* Install handler for reports */
+ IedConnection_installReportHandler(con, "simpleIOGenericIO/LLN0.RP.EventsRCB01",
+ ClientReportControlBlock_getRptId(rcb), reportCallbackFunction, NULL);
+
+ /* Set trigger options and enable report */
+ ClientReportControlBlock_setTrgOps(rcb, TRG_OPT_DATA_UPDATE | TRG_OPT_INTEGRITY | TRG_OPT_GI);
+ ClientReportControlBlock_setRptEna(rcb, true);
+ ClientReportControlBlock_setIntgPd(rcb, 5000);
+ IedConnection_setRCBValues(con, &error, rcb, RCB_ELEMENT_RPT_ENA | RCB_ELEMENT_TRG_OPS | RCB_ELEMENT_INTG_PD, true);
+
+ if (error != IED_ERROR_OK)
+ printf("report activation failed (code: %i)\n", error);
+
+ Thread_sleep(1000);
+
+ /* trigger GI report */
+ ClientReportControlBlock_setGI(rcb, true);
+ IedConnection_setRCBValues(con, &error, rcb, RCB_ELEMENT_GI, true);
+
+ if (error != IED_ERROR_OK)
+ printf("Error triggering a GI report (code: %i)\n", error);
+
+ Thread_sleep(60000);
+
+ /* disable reporting */
+ ClientReportControlBlock_setRptEna(rcb, false);
+ IedConnection_setRCBValues(con, &error, rcb, RCB_ELEMENT_RPT_ENA, true);
+
+ if (error != IED_ERROR_OK)
+ printf("disable reporting failed (code: %i)\n", error);
+
+ ClientDataSet_destroy(clientDataSet);
+
+ ClientReportControlBlock_destroy(rcb);
+
+ close_connection:
+
+ IedConnection_close(con);
+ }
+ else {
+ printf("Failed to connect to %s\n", hostname);
+ }
+
+ IedConnection_destroy(con);
+}
+
+
diff --git a/examples/tls_server_example/CMakeLists.txt b/examples/tls_server_example/CMakeLists.txt
new file mode 100644
index 00000000..4299b8b0
--- /dev/null
+++ b/examples/tls_server_example/CMakeLists.txt
@@ -0,0 +1,21 @@
+include_directories(
+ .
+)
+
+set(example_SRCS
+ tls_server_example.c
+ static_model.c
+)
+
+IF(WIN32)
+set_source_files_properties(${example_SRCS}
+ PROPERTIES LANGUAGE CXX)
+ENDIF(WIN32)
+
+add_executable(tls_server_example
+ ${example_SRCS}
+)
+
+target_link_libraries(tls_server_example
+ iec61850
+)
diff --git a/examples/tls_server_example/Makefile b/examples/tls_server_example/Makefile
new file mode 100644
index 00000000..2ddb3e43
--- /dev/null
+++ b/examples/tls_server_example/Makefile
@@ -0,0 +1,27 @@
+LIBIEC_HOME=../..
+
+PROJECT_BINARY_NAME = tls_server_example
+PROJECT_SOURCES = tls_server_example.c
+PROJECT_SOURCES += static_model.c
+
+PROJECT_ICD_FILE = simpleIO_direct_control.icd
+
+include $(LIBIEC_HOME)/make/target_system.mk
+include $(LIBIEC_HOME)/make/stack_includes.mk
+
+all: $(PROJECT_BINARY_NAME)
+
+include $(LIBIEC_HOME)/make/common_targets.mk
+
+LDLIBS += -lm
+
+model: $(PROJECT_ICD_FILE)
+ java -jar $(LIBIEC_HOME)/tools/model_generator/genmodel.jar $(PROJECT_ICD_FILE)
+
+$(PROJECT_BINARY_NAME): $(PROJECT_SOURCES) $(LIB_NAME)
+ $(CC) $(CFLAGS) $(LDFLAGS) -o $(PROJECT_BINARY_NAME) $(PROJECT_SOURCES) $(INCLUDES) $(LIB_NAME) $(LDLIBS)
+
+clean:
+ rm -f $(PROJECT_BINARY_NAME)
+
+
diff --git a/examples/tls_server_example/client1.cer b/examples/tls_server_example/client1.cer
new file mode 100644
index 00000000..a5aa8db3
Binary files /dev/null and b/examples/tls_server_example/client1.cer differ
diff --git a/examples/tls_server_example/client2.cer b/examples/tls_server_example/client2.cer
new file mode 100644
index 00000000..f482289b
Binary files /dev/null and b/examples/tls_server_example/client2.cer differ
diff --git a/examples/tls_server_example/root.cer b/examples/tls_server_example/root.cer
new file mode 100644
index 00000000..87683444
Binary files /dev/null and b/examples/tls_server_example/root.cer differ
diff --git a/examples/tls_server_example/server-key.pem b/examples/tls_server_example/server-key.pem
new file mode 100644
index 00000000..6fe35295
--- /dev/null
+++ b/examples/tls_server_example/server-key.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAu3Fjxb904UdyV/dDfvs8SFi6zJeNoMYjmpXm/LBcFSH3zGoK
+wdcMovrUTED3Cc6Ww84AYpJ5MRMPTct7DfKJkWfSnkzOPmLldTSTv3RvzGVb4NzK
+QqA5aSVDqAzPiP5RnFT6Q4KWRe69TMFxpw7zMXCJx9jDggqN1oojGGkmSgYGXnFd
+Nc20Mujejh5pihgwnN4Y/bPFyxJwvIMj+D8qr9klhEmXKPTiX9UFd8oLkn9JCB6+
+SiHhNyFIo+Llossn1Q2hxCGty36fAhEWzpfBTaY510VLjie9y4q9GPTwxITDqSQd
+xcX8IuvrbxX0DyEK507SMmTJmB9448eF9ZCWFQIDAQABAoIBAC80BuQtqslwrKLq
+adz4d93gOmp7X/c07pJnXZwU7ZuEylp3+e2Gsm/4qq3pTkzx8ZWtsvsf19U774av
+z3VbtrkfZDLpNKcRUKeLbgmw0NawT8r4zxaoMsz/zWHsl/bv1K2B2ORXZnCGBrXl
+oTFo2mWA6bGiLNn6vm1grCXhlPreywyG/kFK3pi2VvkpvG3XZSI7mmZ0Dq/MD3nO
+03oOZBqwwnMObfQQdhKE7646/+KgeuF/JsXaUH4bkHmtzYWyocWYMqpC0hjpNWlQ
+cKuQ7t1kfmpsGD9aNW4+ND2ok9BdxIiC+rPXS9NDqZxoWLp+a8seU++uqk1l8RPq
+tPE3LqECgYEAz1NmemNLiUsKvyemUvjp8+dJupzWtdV7fsnCbYhj/5gDA2UhFKCf
+dP9xiHCdNe0797oAqHY7c3JhS4ug8haDy9aDIu5GG2DNYzjX/oYm4ywbCdRx+uEN
+RcTw69FjSYVGkObmxWYszwsFybRasV6PYamg65qYR3FlvW2Td4Fndy8CgYEA53L/
+zHtBRQiNGJU9jfMHeX0bTtXIAt622Qn78jw0it/rhXWi2RwG2Cw5Q2aPRJ6uMt9F
+yk1+GAPZcwYqwjq/nKRrl71Tn+KDWIk5rz1fNYRkaXtnMLs2MOogqoDTBshW0QBq
+tnPrFNsaLKX6V92Az69wHjd2uwvLQLTvS/EuNfsCgYEAr3to/uhytAd3VirKRep3
+o0E+D5zWw1upxrwhPDK4aUuSKVp8sIfvz8iyoQiomE9vdZPTIMPKOEI1BgtuM9pI
+vcyYfIVvg5bg4T3o3H9SBPB9BknyG6ZHZKl4PjGht0X+X4GBDM4Z2Tj8Mijcpsph
+1AkOsrzMbZQWyEoqCnnWSHMCgYAFEHUcak4BTrCXqxxPsNOnCt/AF9lqhqkFkrxa
+joqvxzqGDw7jJUPZEw6ltObJn5c8Mbp7NLrfl6X4aFgjK9npeYeJKHFd/DzXgRks
+BnHA4Aa6cCLP5CjJZTYVxP/ZFCUiKZosJ9kq+ahW9cLGjWg2IyaW4qvMZ/OolMzv
+onVaZQKBgQCir8u1vDsyA4JQXMytPHBJe27XaLRGULvteNydVB59Vt21a99o5gt1
+5B9gwWArZdZby3/KZiliNmzp8lMCrLJYjTL5WK6dbWdq92X5hCOofKPIjEcgHjhk
+mvnAos3HeC83bJQtADXhw9jR7Vr6GJLM9HDcIgeIMzX7+BuqlMgaHA==
+-----END RSA PRIVATE KEY-----
diff --git a/examples/tls_server_example/server.cer b/examples/tls_server_example/server.cer
new file mode 100644
index 00000000..957bdc30
Binary files /dev/null and b/examples/tls_server_example/server.cer differ
diff --git a/examples/tls_server_example/static_model.c b/examples/tls_server_example/static_model.c
new file mode 100644
index 00000000..ddc8dd64
--- /dev/null
+++ b/examples/tls_server_example/static_model.c
@@ -0,0 +1,2003 @@
+/*
+ * static_model.c
+ *
+ * automatically generated from simpleIO_direct_control.icd
+ */
+#include "../server_example_basic_io/static_model.h"
+
+static void initializeValues();
+
+extern DataSet iedModelds_GenericIO_LLN0_Events;
+extern DataSet iedModelds_GenericIO_LLN0_Events2;
+extern DataSet iedModelds_GenericIO_LLN0_Measurements;
+
+
+extern DataSetEntry iedModelds_GenericIO_LLN0_Events_fcda0;
+extern DataSetEntry iedModelds_GenericIO_LLN0_Events_fcda1;
+extern DataSetEntry iedModelds_GenericIO_LLN0_Events_fcda2;
+extern DataSetEntry iedModelds_GenericIO_LLN0_Events_fcda3;
+
+DataSetEntry iedModelds_GenericIO_LLN0_Events_fcda0 = {
+ "GenericIO",
+ false,
+ "GGIO1$ST$SPCSO1$stVal",
+ -1,
+ NULL,
+ NULL,
+ &iedModelds_GenericIO_LLN0_Events_fcda1
+};
+
+DataSetEntry iedModelds_GenericIO_LLN0_Events_fcda1 = {
+ "GenericIO",
+ false,
+ "GGIO1$ST$SPCSO2$stVal",
+ -1,
+ NULL,
+ NULL,
+ &iedModelds_GenericIO_LLN0_Events_fcda2
+};
+
+DataSetEntry iedModelds_GenericIO_LLN0_Events_fcda2 = {
+ "GenericIO",
+ false,
+ "GGIO1$ST$SPCSO3$stVal",
+ -1,
+ NULL,
+ NULL,
+ &iedModelds_GenericIO_LLN0_Events_fcda3
+};
+
+DataSetEntry iedModelds_GenericIO_LLN0_Events_fcda3 = {
+ "GenericIO",
+ false,
+ "GGIO1$ST$SPCSO4$stVal",
+ -1,
+ NULL,
+ NULL,
+ NULL
+};
+
+DataSet iedModelds_GenericIO_LLN0_Events = {
+ "GenericIO",
+ "LLN0$Events",
+ 4,
+ &iedModelds_GenericIO_LLN0_Events_fcda0,
+ &iedModelds_GenericIO_LLN0_Events2
+};
+
+extern DataSetEntry iedModelds_GenericIO_LLN0_Events2_fcda0;
+extern DataSetEntry iedModelds_GenericIO_LLN0_Events2_fcda1;
+extern DataSetEntry iedModelds_GenericIO_LLN0_Events2_fcda2;
+extern DataSetEntry iedModelds_GenericIO_LLN0_Events2_fcda3;
+
+DataSetEntry iedModelds_GenericIO_LLN0_Events2_fcda0 = {
+ "GenericIO",
+ false,
+ "GGIO1$ST$SPCSO1",
+ -1,
+ NULL,
+ NULL,
+ &iedModelds_GenericIO_LLN0_Events2_fcda1
+};
+
+DataSetEntry iedModelds_GenericIO_LLN0_Events2_fcda1 = {
+ "GenericIO",
+ false,
+ "GGIO1$ST$SPCSO2",
+ -1,
+ NULL,
+ NULL,
+ &iedModelds_GenericIO_LLN0_Events2_fcda2
+};
+
+DataSetEntry iedModelds_GenericIO_LLN0_Events2_fcda2 = {
+ "GenericIO",
+ false,
+ "GGIO1$ST$SPCSO3",
+ -1,
+ NULL,
+ NULL,
+ &iedModelds_GenericIO_LLN0_Events2_fcda3
+};
+
+DataSetEntry iedModelds_GenericIO_LLN0_Events2_fcda3 = {
+ "GenericIO",
+ false,
+ "GGIO1$ST$SPCSO4",
+ -1,
+ NULL,
+ NULL,
+ NULL
+};
+
+DataSet iedModelds_GenericIO_LLN0_Events2 = {
+ "GenericIO",
+ "LLN0$Events2",
+ 4,
+ &iedModelds_GenericIO_LLN0_Events2_fcda0,
+ &iedModelds_GenericIO_LLN0_Measurements
+};
+
+extern DataSetEntry iedModelds_GenericIO_LLN0_Measurements_fcda0;
+extern DataSetEntry iedModelds_GenericIO_LLN0_Measurements_fcda1;
+extern DataSetEntry iedModelds_GenericIO_LLN0_Measurements_fcda2;
+extern DataSetEntry iedModelds_GenericIO_LLN0_Measurements_fcda3;
+extern DataSetEntry iedModelds_GenericIO_LLN0_Measurements_fcda4;
+extern DataSetEntry iedModelds_GenericIO_LLN0_Measurements_fcda5;
+extern DataSetEntry iedModelds_GenericIO_LLN0_Measurements_fcda6;
+extern DataSetEntry iedModelds_GenericIO_LLN0_Measurements_fcda7;
+
+DataSetEntry iedModelds_GenericIO_LLN0_Measurements_fcda0 = {
+ "GenericIO",
+ false,
+ "GGIO1$MX$AnIn1$mag$f",
+ -1,
+ NULL,
+ NULL,
+ &iedModelds_GenericIO_LLN0_Measurements_fcda1
+};
+
+DataSetEntry iedModelds_GenericIO_LLN0_Measurements_fcda1 = {
+ "GenericIO",
+ false,
+ "GGIO1$MX$AnIn1$q",
+ -1,
+ NULL,
+ NULL,
+ &iedModelds_GenericIO_LLN0_Measurements_fcda2
+};
+
+DataSetEntry iedModelds_GenericIO_LLN0_Measurements_fcda2 = {
+ "GenericIO",
+ false,
+ "GGIO1$MX$AnIn2$mag$f",
+ -1,
+ NULL,
+ NULL,
+ &iedModelds_GenericIO_LLN0_Measurements_fcda3
+};
+
+DataSetEntry iedModelds_GenericIO_LLN0_Measurements_fcda3 = {
+ "GenericIO",
+ false,
+ "GGIO1$MX$AnIn2$q",
+ -1,
+ NULL,
+ NULL,
+ &iedModelds_GenericIO_LLN0_Measurements_fcda4
+};
+
+DataSetEntry iedModelds_GenericIO_LLN0_Measurements_fcda4 = {
+ "GenericIO",
+ false,
+ "GGIO1$MX$AnIn3$mag$f",
+ -1,
+ NULL,
+ NULL,
+ &iedModelds_GenericIO_LLN0_Measurements_fcda5
+};
+
+DataSetEntry iedModelds_GenericIO_LLN0_Measurements_fcda5 = {
+ "GenericIO",
+ false,
+ "GGIO1$MX$AnIn3$q",
+ -1,
+ NULL,
+ NULL,
+ &iedModelds_GenericIO_LLN0_Measurements_fcda6
+};
+
+DataSetEntry iedModelds_GenericIO_LLN0_Measurements_fcda6 = {
+ "GenericIO",
+ false,
+ "GGIO1$MX$AnIn4$mag$f",
+ -1,
+ NULL,
+ NULL,
+ &iedModelds_GenericIO_LLN0_Measurements_fcda7
+};
+
+DataSetEntry iedModelds_GenericIO_LLN0_Measurements_fcda7 = {
+ "GenericIO",
+ false,
+ "GGIO1$MX$AnIn4$q",
+ -1,
+ NULL,
+ NULL,
+ NULL
+};
+
+DataSet iedModelds_GenericIO_LLN0_Measurements = {
+ "GenericIO",
+ "LLN0$Measurements",
+ 8,
+ &iedModelds_GenericIO_LLN0_Measurements_fcda0,
+ NULL
+};
+
+LogicalDevice iedModel_GenericIO = {
+ LogicalDeviceModelType,
+ "GenericIO",
+ (ModelNode*) &iedModel,
+ NULL,
+ (ModelNode*) &iedModel_GenericIO_LLN0
+};
+
+LogicalNode iedModel_GenericIO_LLN0 = {
+ LogicalNodeModelType,
+ "LLN0",
+ (ModelNode*) &iedModel_GenericIO,
+ (ModelNode*) &iedModel_GenericIO_LPHD1,
+ (ModelNode*) &iedModel_GenericIO_LLN0_Mod,
+};
+
+DataObject iedModel_GenericIO_LLN0_Mod = {
+ DataObjectModelType,
+ "Mod",
+ (ModelNode*) &iedModel_GenericIO_LLN0,
+ (ModelNode*) &iedModel_GenericIO_LLN0_Beh,
+ (ModelNode*) &iedModel_GenericIO_LLN0_Mod_stVal,
+ 0
+};
+
+DataAttribute iedModel_GenericIO_LLN0_Mod_stVal = {
+ DataAttributeModelType,
+ "stVal",
+ (ModelNode*) &iedModel_GenericIO_LLN0_Mod,
+ (ModelNode*) &iedModel_GenericIO_LLN0_Mod_q,
+ NULL,
+ 0,
+ IEC61850_FC_ST,
+ IEC61850_INT32,
+ 0 + TRG_OPT_DATA_CHANGED,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_LLN0_Mod_q = {
+ DataAttributeModelType,
+ "q",
+ (ModelNode*) &iedModel_GenericIO_LLN0_Mod,
+ (ModelNode*) &iedModel_GenericIO_LLN0_Mod_t,
+ NULL,
+ 0,
+ IEC61850_FC_ST,
+ IEC61850_QUALITY,
+ 0 + TRG_OPT_QUALITY_CHANGED,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_LLN0_Mod_t = {
+ DataAttributeModelType,
+ "t",
+ (ModelNode*) &iedModel_GenericIO_LLN0_Mod,
+ (ModelNode*) &iedModel_GenericIO_LLN0_Mod_ctlModel,
+ NULL,
+ 0,
+ IEC61850_FC_ST,
+ IEC61850_TIMESTAMP,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_LLN0_Mod_ctlModel = {
+ DataAttributeModelType,
+ "ctlModel",
+ (ModelNode*) &iedModel_GenericIO_LLN0_Mod,
+ NULL,
+ NULL,
+ 0,
+ IEC61850_FC_CF,
+ IEC61850_ENUMERATED,
+ 0,
+ NULL,
+ 0};
+
+DataObject iedModel_GenericIO_LLN0_Beh = {
+ DataObjectModelType,
+ "Beh",
+ (ModelNode*) &iedModel_GenericIO_LLN0,
+ (ModelNode*) &iedModel_GenericIO_LLN0_Health,
+ (ModelNode*) &iedModel_GenericIO_LLN0_Beh_stVal,
+ 0
+};
+
+DataAttribute iedModel_GenericIO_LLN0_Beh_stVal = {
+ DataAttributeModelType,
+ "stVal",
+ (ModelNode*) &iedModel_GenericIO_LLN0_Beh,
+ (ModelNode*) &iedModel_GenericIO_LLN0_Beh_q,
+ NULL,
+ 0,
+ IEC61850_FC_ST,
+ IEC61850_INT32,
+ 0 + TRG_OPT_DATA_CHANGED,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_LLN0_Beh_q = {
+ DataAttributeModelType,
+ "q",
+ (ModelNode*) &iedModel_GenericIO_LLN0_Beh,
+ (ModelNode*) &iedModel_GenericIO_LLN0_Beh_t,
+ NULL,
+ 0,
+ IEC61850_FC_ST,
+ IEC61850_QUALITY,
+ 0 + TRG_OPT_QUALITY_CHANGED,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_LLN0_Beh_t = {
+ DataAttributeModelType,
+ "t",
+ (ModelNode*) &iedModel_GenericIO_LLN0_Beh,
+ NULL,
+ NULL,
+ 0,
+ IEC61850_FC_ST,
+ IEC61850_TIMESTAMP,
+ 0,
+ NULL,
+ 0};
+
+DataObject iedModel_GenericIO_LLN0_Health = {
+ DataObjectModelType,
+ "Health",
+ (ModelNode*) &iedModel_GenericIO_LLN0,
+ (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt,
+ (ModelNode*) &iedModel_GenericIO_LLN0_Health_stVal,
+ 0
+};
+
+DataAttribute iedModel_GenericIO_LLN0_Health_stVal = {
+ DataAttributeModelType,
+ "stVal",
+ (ModelNode*) &iedModel_GenericIO_LLN0_Health,
+ (ModelNode*) &iedModel_GenericIO_LLN0_Health_q,
+ NULL,
+ 0,
+ IEC61850_FC_ST,
+ IEC61850_INT32,
+ 0 + TRG_OPT_DATA_CHANGED,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_LLN0_Health_q = {
+ DataAttributeModelType,
+ "q",
+ (ModelNode*) &iedModel_GenericIO_LLN0_Health,
+ (ModelNode*) &iedModel_GenericIO_LLN0_Health_t,
+ NULL,
+ 0,
+ IEC61850_FC_ST,
+ IEC61850_QUALITY,
+ 0 + TRG_OPT_QUALITY_CHANGED,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_LLN0_Health_t = {
+ DataAttributeModelType,
+ "t",
+ (ModelNode*) &iedModel_GenericIO_LLN0_Health,
+ NULL,
+ NULL,
+ 0,
+ IEC61850_FC_ST,
+ IEC61850_TIMESTAMP,
+ 0,
+ NULL,
+ 0};
+
+DataObject iedModel_GenericIO_LLN0_NamPlt = {
+ DataObjectModelType,
+ "NamPlt",
+ (ModelNode*) &iedModel_GenericIO_LLN0,
+ NULL,
+ (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt_vendor,
+ 0
+};
+
+DataAttribute iedModel_GenericIO_LLN0_NamPlt_vendor = {
+ DataAttributeModelType,
+ "vendor",
+ (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt,
+ (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt_swRev,
+ NULL,
+ 0,
+ IEC61850_FC_DC,
+ IEC61850_VISIBLE_STRING_255,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_LLN0_NamPlt_swRev = {
+ DataAttributeModelType,
+ "swRev",
+ (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt,
+ (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt_d,
+ NULL,
+ 0,
+ IEC61850_FC_DC,
+ IEC61850_VISIBLE_STRING_255,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_LLN0_NamPlt_d = {
+ DataAttributeModelType,
+ "d",
+ (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt,
+ (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt_configRev,
+ NULL,
+ 0,
+ IEC61850_FC_DC,
+ IEC61850_VISIBLE_STRING_255,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_LLN0_NamPlt_configRev = {
+ DataAttributeModelType,
+ "configRev",
+ (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt,
+ (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt_ldNs,
+ NULL,
+ 0,
+ IEC61850_FC_DC,
+ IEC61850_VISIBLE_STRING_255,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_LLN0_NamPlt_ldNs = {
+ DataAttributeModelType,
+ "ldNs",
+ (ModelNode*) &iedModel_GenericIO_LLN0_NamPlt,
+ NULL,
+ NULL,
+ 0,
+ IEC61850_FC_EX,
+ IEC61850_VISIBLE_STRING_255,
+ 0,
+ NULL,
+ 0};
+
+LogicalNode iedModel_GenericIO_LPHD1 = {
+ LogicalNodeModelType,
+ "LPHD1",
+ (ModelNode*) &iedModel_GenericIO,
+ (ModelNode*) &iedModel_GenericIO_GGIO1,
+ (ModelNode*) &iedModel_GenericIO_LPHD1_PhyNam,
+};
+
+DataObject iedModel_GenericIO_LPHD1_PhyNam = {
+ DataObjectModelType,
+ "PhyNam",
+ (ModelNode*) &iedModel_GenericIO_LPHD1,
+ (ModelNode*) &iedModel_GenericIO_LPHD1_PhyHealth,
+ (ModelNode*) &iedModel_GenericIO_LPHD1_PhyNam_vendor,
+ 0
+};
+
+DataAttribute iedModel_GenericIO_LPHD1_PhyNam_vendor = {
+ DataAttributeModelType,
+ "vendor",
+ (ModelNode*) &iedModel_GenericIO_LPHD1_PhyNam,
+ NULL,
+ NULL,
+ 0,
+ IEC61850_FC_DC,
+ IEC61850_VISIBLE_STRING_255,
+ 0,
+ NULL,
+ 0};
+
+DataObject iedModel_GenericIO_LPHD1_PhyHealth = {
+ DataObjectModelType,
+ "PhyHealth",
+ (ModelNode*) &iedModel_GenericIO_LPHD1,
+ (ModelNode*) &iedModel_GenericIO_LPHD1_Proxy,
+ (ModelNode*) &iedModel_GenericIO_LPHD1_PhyHealth_stVal,
+ 0
+};
+
+DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_stVal = {
+ DataAttributeModelType,
+ "stVal",
+ (ModelNode*) &iedModel_GenericIO_LPHD1_PhyHealth,
+ (ModelNode*) &iedModel_GenericIO_LPHD1_PhyHealth_q,
+ NULL,
+ 0,
+ IEC61850_FC_ST,
+ IEC61850_INT32,
+ 0 + TRG_OPT_DATA_CHANGED,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_q = {
+ DataAttributeModelType,
+ "q",
+ (ModelNode*) &iedModel_GenericIO_LPHD1_PhyHealth,
+ (ModelNode*) &iedModel_GenericIO_LPHD1_PhyHealth_t,
+ NULL,
+ 0,
+ IEC61850_FC_ST,
+ IEC61850_QUALITY,
+ 0 + TRG_OPT_QUALITY_CHANGED,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_t = {
+ DataAttributeModelType,
+ "t",
+ (ModelNode*) &iedModel_GenericIO_LPHD1_PhyHealth,
+ NULL,
+ NULL,
+ 0,
+ IEC61850_FC_ST,
+ IEC61850_TIMESTAMP,
+ 0,
+ NULL,
+ 0};
+
+DataObject iedModel_GenericIO_LPHD1_Proxy = {
+ DataObjectModelType,
+ "Proxy",
+ (ModelNode*) &iedModel_GenericIO_LPHD1,
+ NULL,
+ (ModelNode*) &iedModel_GenericIO_LPHD1_Proxy_stVal,
+ 0
+};
+
+DataAttribute iedModel_GenericIO_LPHD1_Proxy_stVal = {
+ DataAttributeModelType,
+ "stVal",
+ (ModelNode*) &iedModel_GenericIO_LPHD1_Proxy,
+ (ModelNode*) &iedModel_GenericIO_LPHD1_Proxy_q,
+ NULL,
+ 0,
+ IEC61850_FC_ST,
+ IEC61850_BOOLEAN,
+ 0 + TRG_OPT_DATA_CHANGED,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_LPHD1_Proxy_q = {
+ DataAttributeModelType,
+ "q",
+ (ModelNode*) &iedModel_GenericIO_LPHD1_Proxy,
+ (ModelNode*) &iedModel_GenericIO_LPHD1_Proxy_t,
+ NULL,
+ 0,
+ IEC61850_FC_ST,
+ IEC61850_QUALITY,
+ 0 + TRG_OPT_QUALITY_CHANGED,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_LPHD1_Proxy_t = {
+ DataAttributeModelType,
+ "t",
+ (ModelNode*) &iedModel_GenericIO_LPHD1_Proxy,
+ NULL,
+ NULL,
+ 0,
+ IEC61850_FC_ST,
+ IEC61850_TIMESTAMP,
+ 0,
+ NULL,
+ 0};
+
+LogicalNode iedModel_GenericIO_GGIO1 = {
+ LogicalNodeModelType,
+ "GGIO1",
+ (ModelNode*) &iedModel_GenericIO,
+ NULL,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_Mod,
+};
+
+DataObject iedModel_GenericIO_GGIO1_Mod = {
+ DataObjectModelType,
+ "Mod",
+ (ModelNode*) &iedModel_GenericIO_GGIO1,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_Beh,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_Mod_q,
+ 0
+};
+
+DataAttribute iedModel_GenericIO_GGIO1_Mod_q = {
+ DataAttributeModelType,
+ "q",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_Mod,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_Mod_t,
+ NULL,
+ 0,
+ IEC61850_FC_ST,
+ IEC61850_QUALITY,
+ 0 + TRG_OPT_QUALITY_CHANGED,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_Mod_t = {
+ DataAttributeModelType,
+ "t",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_Mod,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_Mod_ctlModel,
+ NULL,
+ 0,
+ IEC61850_FC_ST,
+ IEC61850_TIMESTAMP,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_Mod_ctlModel = {
+ DataAttributeModelType,
+ "ctlModel",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_Mod,
+ NULL,
+ NULL,
+ 0,
+ IEC61850_FC_CF,
+ IEC61850_ENUMERATED,
+ 0,
+ NULL,
+ 0};
+
+DataObject iedModel_GenericIO_GGIO1_Beh = {
+ DataObjectModelType,
+ "Beh",
+ (ModelNode*) &iedModel_GenericIO_GGIO1,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_Health,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_Beh_stVal,
+ 0
+};
+
+DataAttribute iedModel_GenericIO_GGIO1_Beh_stVal = {
+ DataAttributeModelType,
+ "stVal",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_Beh,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_Beh_q,
+ NULL,
+ 0,
+ IEC61850_FC_ST,
+ IEC61850_INT32,
+ 0 + TRG_OPT_DATA_CHANGED,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_Beh_q = {
+ DataAttributeModelType,
+ "q",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_Beh,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_Beh_t,
+ NULL,
+ 0,
+ IEC61850_FC_ST,
+ IEC61850_QUALITY,
+ 0 + TRG_OPT_QUALITY_CHANGED,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_Beh_t = {
+ DataAttributeModelType,
+ "t",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_Beh,
+ NULL,
+ NULL,
+ 0,
+ IEC61850_FC_ST,
+ IEC61850_TIMESTAMP,
+ 0,
+ NULL,
+ 0};
+
+DataObject iedModel_GenericIO_GGIO1_Health = {
+ DataObjectModelType,
+ "Health",
+ (ModelNode*) &iedModel_GenericIO_GGIO1,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_NamPlt,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_Health_stVal,
+ 0
+};
+
+DataAttribute iedModel_GenericIO_GGIO1_Health_stVal = {
+ DataAttributeModelType,
+ "stVal",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_Health,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_Health_q,
+ NULL,
+ 0,
+ IEC61850_FC_ST,
+ IEC61850_INT32,
+ 0 + TRG_OPT_DATA_CHANGED,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_Health_q = {
+ DataAttributeModelType,
+ "q",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_Health,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_Health_t,
+ NULL,
+ 0,
+ IEC61850_FC_ST,
+ IEC61850_QUALITY,
+ 0 + TRG_OPT_QUALITY_CHANGED,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_Health_t = {
+ DataAttributeModelType,
+ "t",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_Health,
+ NULL,
+ NULL,
+ 0,
+ IEC61850_FC_ST,
+ IEC61850_TIMESTAMP,
+ 0,
+ NULL,
+ 0};
+
+DataObject iedModel_GenericIO_GGIO1_NamPlt = {
+ DataObjectModelType,
+ "NamPlt",
+ (ModelNode*) &iedModel_GenericIO_GGIO1,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_NamPlt_vendor,
+ 0
+};
+
+DataAttribute iedModel_GenericIO_GGIO1_NamPlt_vendor = {
+ DataAttributeModelType,
+ "vendor",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_NamPlt,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_NamPlt_swRev,
+ NULL,
+ 0,
+ IEC61850_FC_DC,
+ IEC61850_VISIBLE_STRING_255,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_NamPlt_swRev = {
+ DataAttributeModelType,
+ "swRev",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_NamPlt,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_NamPlt_d,
+ NULL,
+ 0,
+ IEC61850_FC_DC,
+ IEC61850_VISIBLE_STRING_255,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_NamPlt_d = {
+ DataAttributeModelType,
+ "d",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_NamPlt,
+ NULL,
+ NULL,
+ 0,
+ IEC61850_FC_DC,
+ IEC61850_VISIBLE_STRING_255,
+ 0,
+ NULL,
+ 0};
+
+DataObject iedModel_GenericIO_GGIO1_AnIn1 = {
+ DataObjectModelType,
+ "AnIn1",
+ (ModelNode*) &iedModel_GenericIO_GGIO1,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1_mag,
+ 0
+};
+
+DataAttribute iedModel_GenericIO_GGIO1_AnIn1_mag = {
+ DataAttributeModelType,
+ "mag",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1_q,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1_mag_f,
+ 0,
+ IEC61850_FC_MX,
+ IEC61850_CONSTRUCTED,
+ 0 + TRG_OPT_DATA_CHANGED,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_AnIn1_mag_f = {
+ DataAttributeModelType,
+ "f",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1_mag,
+ NULL,
+ NULL,
+ 0,
+ IEC61850_FC_MX,
+ IEC61850_FLOAT32,
+ 0 + TRG_OPT_DATA_CHANGED,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_AnIn1_q = {
+ DataAttributeModelType,
+ "q",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1_t,
+ NULL,
+ 0,
+ IEC61850_FC_MX,
+ IEC61850_QUALITY,
+ 0 + TRG_OPT_QUALITY_CHANGED,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_AnIn1_t = {
+ DataAttributeModelType,
+ "t",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn1,
+ NULL,
+ NULL,
+ 0,
+ IEC61850_FC_MX,
+ IEC61850_TIMESTAMP,
+ 0,
+ NULL,
+ 0};
+
+DataObject iedModel_GenericIO_GGIO1_AnIn2 = {
+ DataObjectModelType,
+ "AnIn2",
+ (ModelNode*) &iedModel_GenericIO_GGIO1,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2_mag,
+ 0
+};
+
+DataAttribute iedModel_GenericIO_GGIO1_AnIn2_mag = {
+ DataAttributeModelType,
+ "mag",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2_q,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2_mag_f,
+ 0,
+ IEC61850_FC_MX,
+ IEC61850_CONSTRUCTED,
+ 0 + TRG_OPT_DATA_CHANGED,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_AnIn2_mag_f = {
+ DataAttributeModelType,
+ "f",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2_mag,
+ NULL,
+ NULL,
+ 0,
+ IEC61850_FC_MX,
+ IEC61850_FLOAT32,
+ 0 + TRG_OPT_DATA_CHANGED,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_AnIn2_q = {
+ DataAttributeModelType,
+ "q",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2_t,
+ NULL,
+ 0,
+ IEC61850_FC_MX,
+ IEC61850_QUALITY,
+ 0 + TRG_OPT_QUALITY_CHANGED,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_AnIn2_t = {
+ DataAttributeModelType,
+ "t",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn2,
+ NULL,
+ NULL,
+ 0,
+ IEC61850_FC_MX,
+ IEC61850_TIMESTAMP,
+ 0,
+ NULL,
+ 0};
+
+DataObject iedModel_GenericIO_GGIO1_AnIn3 = {
+ DataObjectModelType,
+ "AnIn3",
+ (ModelNode*) &iedModel_GenericIO_GGIO1,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3_mag,
+ 0
+};
+
+DataAttribute iedModel_GenericIO_GGIO1_AnIn3_mag = {
+ DataAttributeModelType,
+ "mag",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3_q,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3_mag_f,
+ 0,
+ IEC61850_FC_MX,
+ IEC61850_CONSTRUCTED,
+ 0 + TRG_OPT_DATA_CHANGED,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_AnIn3_mag_f = {
+ DataAttributeModelType,
+ "f",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3_mag,
+ NULL,
+ NULL,
+ 0,
+ IEC61850_FC_MX,
+ IEC61850_FLOAT32,
+ 0 + TRG_OPT_DATA_CHANGED,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_AnIn3_q = {
+ DataAttributeModelType,
+ "q",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3_t,
+ NULL,
+ 0,
+ IEC61850_FC_MX,
+ IEC61850_QUALITY,
+ 0 + TRG_OPT_QUALITY_CHANGED,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_AnIn3_t = {
+ DataAttributeModelType,
+ "t",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn3,
+ NULL,
+ NULL,
+ 0,
+ IEC61850_FC_MX,
+ IEC61850_TIMESTAMP,
+ 0,
+ NULL,
+ 0};
+
+DataObject iedModel_GenericIO_GGIO1_AnIn4 = {
+ DataObjectModelType,
+ "AnIn4",
+ (ModelNode*) &iedModel_GenericIO_GGIO1,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4_mag,
+ 0
+};
+
+DataAttribute iedModel_GenericIO_GGIO1_AnIn4_mag = {
+ DataAttributeModelType,
+ "mag",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4_q,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4_mag_f,
+ 0,
+ IEC61850_FC_MX,
+ IEC61850_CONSTRUCTED,
+ 0 + TRG_OPT_DATA_CHANGED,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_AnIn4_mag_f = {
+ DataAttributeModelType,
+ "f",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4_mag,
+ NULL,
+ NULL,
+ 0,
+ IEC61850_FC_MX,
+ IEC61850_FLOAT32,
+ 0 + TRG_OPT_DATA_CHANGED,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_AnIn4_q = {
+ DataAttributeModelType,
+ "q",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4_t,
+ NULL,
+ 0,
+ IEC61850_FC_MX,
+ IEC61850_QUALITY,
+ 0 + TRG_OPT_QUALITY_CHANGED,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_AnIn4_t = {
+ DataAttributeModelType,
+ "t",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_AnIn4,
+ NULL,
+ NULL,
+ 0,
+ IEC61850_FC_MX,
+ IEC61850_TIMESTAMP,
+ 0,
+ NULL,
+ 0};
+
+DataObject iedModel_GenericIO_GGIO1_SPCSO1 = {
+ DataObjectModelType,
+ "SPCSO1",
+ (ModelNode*) &iedModel_GenericIO_GGIO1,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_stVal,
+ 0
+};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_stVal = {
+ DataAttributeModelType,
+ "stVal",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_q,
+ NULL,
+ 0,
+ IEC61850_FC_ST,
+ IEC61850_BOOLEAN,
+ 0 + TRG_OPT_DATA_CHANGED,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_q = {
+ DataAttributeModelType,
+ "q",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper,
+ NULL,
+ 0,
+ IEC61850_FC_ST,
+ IEC61850_QUALITY,
+ 0 + TRG_OPT_QUALITY_CHANGED,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper = {
+ DataAttributeModelType,
+ "Oper",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_ctlModel,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlVal,
+ 0,
+ IEC61850_FC_CO,
+ IEC61850_CONSTRUCTED,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlVal = {
+ DataAttributeModelType,
+ "ctlVal",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin,
+ NULL,
+ 0,
+ IEC61850_FC_CO,
+ IEC61850_BOOLEAN,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin = {
+ DataAttributeModelType,
+ "origin",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlNum,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orCat,
+ 0,
+ IEC61850_FC_CO,
+ IEC61850_CONSTRUCTED,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orCat = {
+ DataAttributeModelType,
+ "orCat",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orIdent,
+ NULL,
+ 0,
+ IEC61850_FC_CO,
+ IEC61850_ENUMERATED,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orIdent = {
+ DataAttributeModelType,
+ "orIdent",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin,
+ NULL,
+ NULL,
+ 0,
+ IEC61850_FC_CO,
+ IEC61850_OCTET_STRING_64,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlNum = {
+ DataAttributeModelType,
+ "ctlNum",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_T,
+ NULL,
+ 0,
+ IEC61850_FC_CO,
+ IEC61850_INT8U,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_T = {
+ DataAttributeModelType,
+ "T",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_Test,
+ NULL,
+ 0,
+ IEC61850_FC_CO,
+ IEC61850_TIMESTAMP,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_Test = {
+ DataAttributeModelType,
+ "Test",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper_Check,
+ NULL,
+ 0,
+ IEC61850_FC_CO,
+ IEC61850_BOOLEAN,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_Check = {
+ DataAttributeModelType,
+ "Check",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO1_Oper,
+ NULL,
+ NULL,
+ 0,
+ IEC61850_FC_CO,
+ IEC61850_CHECK,
+ 0,
+ 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",
+ (ModelNode*) &iedModel_GenericIO_GGIO1,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_stVal,
+ 0
+};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_stVal = {
+ DataAttributeModelType,
+ "stVal",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_q,
+ NULL,
+ 0,
+ IEC61850_FC_ST,
+ IEC61850_BOOLEAN,
+ 0 + TRG_OPT_DATA_CHANGED,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_q = {
+ DataAttributeModelType,
+ "q",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper,
+ NULL,
+ 0,
+ IEC61850_FC_ST,
+ IEC61850_QUALITY,
+ 0 + TRG_OPT_QUALITY_CHANGED,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper = {
+ DataAttributeModelType,
+ "Oper",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_ctlModel,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlVal,
+ 0,
+ IEC61850_FC_CO,
+ IEC61850_CONSTRUCTED,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlVal = {
+ DataAttributeModelType,
+ "ctlVal",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin,
+ NULL,
+ 0,
+ IEC61850_FC_CO,
+ IEC61850_BOOLEAN,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin = {
+ DataAttributeModelType,
+ "origin",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlNum,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orCat,
+ 0,
+ IEC61850_FC_CO,
+ IEC61850_CONSTRUCTED,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orCat = {
+ DataAttributeModelType,
+ "orCat",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orIdent,
+ NULL,
+ 0,
+ IEC61850_FC_CO,
+ IEC61850_ENUMERATED,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orIdent = {
+ DataAttributeModelType,
+ "orIdent",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin,
+ NULL,
+ NULL,
+ 0,
+ IEC61850_FC_CO,
+ IEC61850_OCTET_STRING_64,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlNum = {
+ DataAttributeModelType,
+ "ctlNum",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_T,
+ NULL,
+ 0,
+ IEC61850_FC_CO,
+ IEC61850_INT8U,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_T = {
+ DataAttributeModelType,
+ "T",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_Test,
+ NULL,
+ 0,
+ IEC61850_FC_CO,
+ IEC61850_TIMESTAMP,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_Test = {
+ DataAttributeModelType,
+ "Test",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper_Check,
+ NULL,
+ 0,
+ IEC61850_FC_CO,
+ IEC61850_BOOLEAN,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_Check = {
+ DataAttributeModelType,
+ "Check",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_Oper,
+ NULL,
+ NULL,
+ 0,
+ IEC61850_FC_CO,
+ IEC61850_CHECK,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_ctlModel = {
+ DataAttributeModelType,
+ "ctlModel",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2_t,
+ NULL,
+ 0,
+ IEC61850_FC_CF,
+ IEC61850_ENUMERATED,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_t = {
+ DataAttributeModelType,
+ "t",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO2,
+ NULL,
+ NULL,
+ 0,
+ IEC61850_FC_ST,
+ IEC61850_TIMESTAMP,
+ 0,
+ NULL,
+ 0};
+
+DataObject iedModel_GenericIO_GGIO1_SPCSO3 = {
+ DataObjectModelType,
+ "SPCSO3",
+ (ModelNode*) &iedModel_GenericIO_GGIO1,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_stVal,
+ 0
+};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_stVal = {
+ DataAttributeModelType,
+ "stVal",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_q,
+ NULL,
+ 0,
+ IEC61850_FC_ST,
+ IEC61850_BOOLEAN,
+ 0 + TRG_OPT_DATA_CHANGED,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_q = {
+ DataAttributeModelType,
+ "q",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper,
+ NULL,
+ 0,
+ IEC61850_FC_ST,
+ IEC61850_QUALITY,
+ 0 + TRG_OPT_QUALITY_CHANGED,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper = {
+ DataAttributeModelType,
+ "Oper",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_ctlModel,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlVal,
+ 0,
+ IEC61850_FC_CO,
+ IEC61850_CONSTRUCTED,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlVal = {
+ DataAttributeModelType,
+ "ctlVal",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin,
+ NULL,
+ 0,
+ IEC61850_FC_CO,
+ IEC61850_BOOLEAN,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin = {
+ DataAttributeModelType,
+ "origin",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlNum,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orCat,
+ 0,
+ IEC61850_FC_CO,
+ IEC61850_CONSTRUCTED,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orCat = {
+ DataAttributeModelType,
+ "orCat",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orIdent,
+ NULL,
+ 0,
+ IEC61850_FC_CO,
+ IEC61850_ENUMERATED,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orIdent = {
+ DataAttributeModelType,
+ "orIdent",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin,
+ NULL,
+ NULL,
+ 0,
+ IEC61850_FC_CO,
+ IEC61850_OCTET_STRING_64,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlNum = {
+ DataAttributeModelType,
+ "ctlNum",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_T,
+ NULL,
+ 0,
+ IEC61850_FC_CO,
+ IEC61850_INT8U,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_T = {
+ DataAttributeModelType,
+ "T",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_Test,
+ NULL,
+ 0,
+ IEC61850_FC_CO,
+ IEC61850_TIMESTAMP,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_Test = {
+ DataAttributeModelType,
+ "Test",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper_Check,
+ NULL,
+ 0,
+ IEC61850_FC_CO,
+ IEC61850_BOOLEAN,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_Check = {
+ DataAttributeModelType,
+ "Check",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_Oper,
+ NULL,
+ NULL,
+ 0,
+ IEC61850_FC_CO,
+ IEC61850_CHECK,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_ctlModel = {
+ DataAttributeModelType,
+ "ctlModel",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3_t,
+ NULL,
+ 0,
+ IEC61850_FC_CF,
+ IEC61850_ENUMERATED,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_t = {
+ DataAttributeModelType,
+ "t",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO3,
+ NULL,
+ NULL,
+ 0,
+ IEC61850_FC_ST,
+ IEC61850_TIMESTAMP,
+ 0,
+ NULL,
+ 0};
+
+DataObject iedModel_GenericIO_GGIO1_SPCSO4 = {
+ DataObjectModelType,
+ "SPCSO4",
+ (ModelNode*) &iedModel_GenericIO_GGIO1,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_Ind1,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_stVal,
+ 0
+};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_stVal = {
+ DataAttributeModelType,
+ "stVal",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_q,
+ NULL,
+ 0,
+ IEC61850_FC_ST,
+ IEC61850_BOOLEAN,
+ 0 + TRG_OPT_DATA_CHANGED,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_q = {
+ DataAttributeModelType,
+ "q",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper,
+ NULL,
+ 0,
+ IEC61850_FC_ST,
+ IEC61850_QUALITY,
+ 0 + TRG_OPT_QUALITY_CHANGED,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper = {
+ DataAttributeModelType,
+ "Oper",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_ctlModel,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlVal,
+ 0,
+ IEC61850_FC_CO,
+ IEC61850_CONSTRUCTED,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlVal = {
+ DataAttributeModelType,
+ "ctlVal",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin,
+ NULL,
+ 0,
+ IEC61850_FC_CO,
+ IEC61850_BOOLEAN,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin = {
+ DataAttributeModelType,
+ "origin",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlNum,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orCat,
+ 0,
+ IEC61850_FC_CO,
+ IEC61850_CONSTRUCTED,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orCat = {
+ DataAttributeModelType,
+ "orCat",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orIdent,
+ NULL,
+ 0,
+ IEC61850_FC_CO,
+ IEC61850_ENUMERATED,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orIdent = {
+ DataAttributeModelType,
+ "orIdent",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin,
+ NULL,
+ NULL,
+ 0,
+ IEC61850_FC_CO,
+ IEC61850_OCTET_STRING_64,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlNum = {
+ DataAttributeModelType,
+ "ctlNum",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_T,
+ NULL,
+ 0,
+ IEC61850_FC_CO,
+ IEC61850_INT8U,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_T = {
+ DataAttributeModelType,
+ "T",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_Test,
+ NULL,
+ 0,
+ IEC61850_FC_CO,
+ IEC61850_TIMESTAMP,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_Test = {
+ DataAttributeModelType,
+ "Test",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper_Check,
+ NULL,
+ 0,
+ IEC61850_FC_CO,
+ IEC61850_BOOLEAN,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_Check = {
+ DataAttributeModelType,
+ "Check",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO4_Oper,
+ NULL,
+ NULL,
+ 0,
+ IEC61850_FC_CO,
+ IEC61850_CHECK,
+ 0,
+ 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",
+ (ModelNode*) &iedModel_GenericIO_GGIO1,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_Ind2,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_Ind1_stVal,
+ 0
+};
+
+DataAttribute iedModel_GenericIO_GGIO1_Ind1_stVal = {
+ DataAttributeModelType,
+ "stVal",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_Ind1,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_Ind1_q,
+ NULL,
+ 0,
+ IEC61850_FC_ST,
+ IEC61850_BOOLEAN,
+ 0 + TRG_OPT_DATA_CHANGED,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_Ind1_q = {
+ DataAttributeModelType,
+ "q",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_Ind1,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_Ind1_t,
+ NULL,
+ 0,
+ IEC61850_FC_ST,
+ IEC61850_QUALITY,
+ 0 + TRG_OPT_QUALITY_CHANGED,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_Ind1_t = {
+ DataAttributeModelType,
+ "t",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_Ind1,
+ NULL,
+ NULL,
+ 0,
+ IEC61850_FC_ST,
+ IEC61850_TIMESTAMP,
+ 0,
+ NULL,
+ 0};
+
+DataObject iedModel_GenericIO_GGIO1_Ind2 = {
+ DataObjectModelType,
+ "Ind2",
+ (ModelNode*) &iedModel_GenericIO_GGIO1,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_Ind3,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_Ind2_stVal,
+ 0
+};
+
+DataAttribute iedModel_GenericIO_GGIO1_Ind2_stVal = {
+ DataAttributeModelType,
+ "stVal",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_Ind2,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_Ind2_q,
+ NULL,
+ 0,
+ IEC61850_FC_ST,
+ IEC61850_BOOLEAN,
+ 0 + TRG_OPT_DATA_CHANGED,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_Ind2_q = {
+ DataAttributeModelType,
+ "q",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_Ind2,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_Ind2_t,
+ NULL,
+ 0,
+ IEC61850_FC_ST,
+ IEC61850_QUALITY,
+ 0 + TRG_OPT_QUALITY_CHANGED,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_Ind2_t = {
+ DataAttributeModelType,
+ "t",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_Ind2,
+ NULL,
+ NULL,
+ 0,
+ IEC61850_FC_ST,
+ IEC61850_TIMESTAMP,
+ 0,
+ NULL,
+ 0};
+
+DataObject iedModel_GenericIO_GGIO1_Ind3 = {
+ DataObjectModelType,
+ "Ind3",
+ (ModelNode*) &iedModel_GenericIO_GGIO1,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_Ind4,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_Ind3_stVal,
+ 0
+};
+
+DataAttribute iedModel_GenericIO_GGIO1_Ind3_stVal = {
+ DataAttributeModelType,
+ "stVal",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_Ind3,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_Ind3_q,
+ NULL,
+ 0,
+ IEC61850_FC_ST,
+ IEC61850_BOOLEAN,
+ 0 + TRG_OPT_DATA_CHANGED,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_Ind3_q = {
+ DataAttributeModelType,
+ "q",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_Ind3,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_Ind3_t,
+ NULL,
+ 0,
+ IEC61850_FC_ST,
+ IEC61850_QUALITY,
+ 0 + TRG_OPT_QUALITY_CHANGED,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_Ind3_t = {
+ DataAttributeModelType,
+ "t",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_Ind3,
+ NULL,
+ NULL,
+ 0,
+ IEC61850_FC_ST,
+ IEC61850_TIMESTAMP,
+ 0,
+ NULL,
+ 0};
+
+DataObject iedModel_GenericIO_GGIO1_Ind4 = {
+ DataObjectModelType,
+ "Ind4",
+ (ModelNode*) &iedModel_GenericIO_GGIO1,
+ NULL,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_Ind4_stVal,
+ 0
+};
+
+DataAttribute iedModel_GenericIO_GGIO1_Ind4_stVal = {
+ DataAttributeModelType,
+ "stVal",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_Ind4,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_Ind4_q,
+ NULL,
+ 0,
+ IEC61850_FC_ST,
+ IEC61850_BOOLEAN,
+ 0 + TRG_OPT_DATA_CHANGED,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_Ind4_q = {
+ DataAttributeModelType,
+ "q",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_Ind4,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_Ind4_t,
+ NULL,
+ 0,
+ IEC61850_FC_ST,
+ IEC61850_QUALITY,
+ 0 + TRG_OPT_QUALITY_CHANGED,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_Ind4_t = {
+ DataAttributeModelType,
+ "t",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_Ind4,
+ NULL,
+ NULL,
+ 0,
+ IEC61850_FC_ST,
+ IEC61850_TIMESTAMP,
+ 0,
+ NULL,
+ 0};
+
+extern ReportControlBlock iedModel_GenericIO_LLN0_report0;
+extern ReportControlBlock iedModel_GenericIO_LLN0_report1;
+extern ReportControlBlock iedModel_GenericIO_LLN0_report2;
+extern ReportControlBlock iedModel_GenericIO_LLN0_report3;
+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};
+
+
+
+
+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 = {
+ "simpleIO",
+ &iedModel_GenericIO,
+ &iedModelds_GenericIO_LLN0_Events,
+ &iedModel_GenericIO_LLN0_report0,
+ NULL,
+ NULL,
+ NULL,
+ &iedModel_GenericIO_LLN0_lcb0,
+ &iedModel_GenericIO_LLN0_log0,
+ initializeValues
+};
+
+static void
+initializeValues()
+{
+
+iedModel_GenericIO_LLN0_Mod_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(0);
+
+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_d.mmsValue = MmsValue_newVisibleString("libiec61850 server example");
+
+iedModel_GenericIO_GGIO1_Mod_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(0);
+
+iedModel_GenericIO_GGIO1_SPCSO1_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(1);
+
+iedModel_GenericIO_GGIO1_SPCSO2_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(1);
+
+iedModel_GenericIO_GGIO1_SPCSO3_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(1);
+
+iedModel_GenericIO_GGIO1_SPCSO4_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(1);
+}
diff --git a/examples/tls_server_example/static_model.h b/examples/tls_server_example/static_model.h
new file mode 100644
index 00000000..b5670e9f
--- /dev/null
+++ b/examples/tls_server_example/static_model.h
@@ -0,0 +1,301 @@
+/*
+ * static_model.h
+ *
+ * automatically generated from simpleIO_direct_control.icd
+ */
+
+#ifndef STATIC_MODEL_H_
+#define STATIC_MODEL_H_
+
+#include
+#include "iec61850_model.h"
+
+extern IedModel iedModel;
+extern LogicalDevice iedModel_GenericIO;
+extern LogicalNode iedModel_GenericIO_LLN0;
+extern DataObject iedModel_GenericIO_LLN0_Mod;
+extern DataAttribute iedModel_GenericIO_LLN0_Mod_stVal;
+extern DataAttribute iedModel_GenericIO_LLN0_Mod_q;
+extern DataAttribute iedModel_GenericIO_LLN0_Mod_t;
+extern DataAttribute iedModel_GenericIO_LLN0_Mod_ctlModel;
+extern DataObject iedModel_GenericIO_LLN0_Beh;
+extern DataAttribute iedModel_GenericIO_LLN0_Beh_stVal;
+extern DataAttribute iedModel_GenericIO_LLN0_Beh_q;
+extern DataAttribute iedModel_GenericIO_LLN0_Beh_t;
+extern DataObject iedModel_GenericIO_LLN0_Health;
+extern DataAttribute iedModel_GenericIO_LLN0_Health_stVal;
+extern DataAttribute iedModel_GenericIO_LLN0_Health_q;
+extern DataAttribute iedModel_GenericIO_LLN0_Health_t;
+extern DataObject iedModel_GenericIO_LLN0_NamPlt;
+extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_vendor;
+extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_swRev;
+extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_d;
+extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_configRev;
+extern DataAttribute iedModel_GenericIO_LLN0_NamPlt_ldNs;
+extern LogicalNode iedModel_GenericIO_LPHD1;
+extern DataObject iedModel_GenericIO_LPHD1_PhyNam;
+extern DataAttribute iedModel_GenericIO_LPHD1_PhyNam_vendor;
+extern DataObject iedModel_GenericIO_LPHD1_PhyHealth;
+extern DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_stVal;
+extern DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_q;
+extern DataAttribute iedModel_GenericIO_LPHD1_PhyHealth_t;
+extern DataObject iedModel_GenericIO_LPHD1_Proxy;
+extern DataAttribute iedModel_GenericIO_LPHD1_Proxy_stVal;
+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_q;
+extern DataAttribute iedModel_GenericIO_GGIO1_Mod_t;
+extern DataAttribute iedModel_GenericIO_GGIO1_Mod_ctlModel;
+extern DataObject iedModel_GenericIO_GGIO1_Beh;
+extern DataAttribute iedModel_GenericIO_GGIO1_Beh_stVal;
+extern DataAttribute iedModel_GenericIO_GGIO1_Beh_q;
+extern DataAttribute iedModel_GenericIO_GGIO1_Beh_t;
+extern DataObject iedModel_GenericIO_GGIO1_Health;
+extern DataAttribute iedModel_GenericIO_GGIO1_Health_stVal;
+extern DataAttribute iedModel_GenericIO_GGIO1_Health_q;
+extern DataAttribute iedModel_GenericIO_GGIO1_Health_t;
+extern DataObject iedModel_GenericIO_GGIO1_NamPlt;
+extern DataAttribute iedModel_GenericIO_GGIO1_NamPlt_vendor;
+extern DataAttribute iedModel_GenericIO_GGIO1_NamPlt_swRev;
+extern DataAttribute iedModel_GenericIO_GGIO1_NamPlt_d;
+extern DataObject iedModel_GenericIO_GGIO1_AnIn1;
+extern DataAttribute iedModel_GenericIO_GGIO1_AnIn1_mag;
+extern DataAttribute iedModel_GenericIO_GGIO1_AnIn1_mag_f;
+extern DataAttribute iedModel_GenericIO_GGIO1_AnIn1_q;
+extern DataAttribute iedModel_GenericIO_GGIO1_AnIn1_t;
+extern DataObject iedModel_GenericIO_GGIO1_AnIn2;
+extern DataAttribute iedModel_GenericIO_GGIO1_AnIn2_mag;
+extern DataAttribute iedModel_GenericIO_GGIO1_AnIn2_mag_f;
+extern DataAttribute iedModel_GenericIO_GGIO1_AnIn2_q;
+extern DataAttribute iedModel_GenericIO_GGIO1_AnIn2_t;
+extern DataObject iedModel_GenericIO_GGIO1_AnIn3;
+extern DataAttribute iedModel_GenericIO_GGIO1_AnIn3_mag;
+extern DataAttribute iedModel_GenericIO_GGIO1_AnIn3_mag_f;
+extern DataAttribute iedModel_GenericIO_GGIO1_AnIn3_q;
+extern DataAttribute iedModel_GenericIO_GGIO1_AnIn3_t;
+extern DataObject iedModel_GenericIO_GGIO1_AnIn4;
+extern DataAttribute iedModel_GenericIO_GGIO1_AnIn4_mag;
+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_stVal;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_q;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlVal;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orCat;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orIdent;
+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;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlVal;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orCat;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orIdent;
+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_stVal;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_q;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlVal;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orCat;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orIdent;
+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_stVal;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_q;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlVal;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orCat;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orIdent;
+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;
+extern DataAttribute iedModel_GenericIO_GGIO1_Ind1_t;
+extern DataObject iedModel_GenericIO_GGIO1_Ind2;
+extern DataAttribute iedModel_GenericIO_GGIO1_Ind2_stVal;
+extern DataAttribute iedModel_GenericIO_GGIO1_Ind2_q;
+extern DataAttribute iedModel_GenericIO_GGIO1_Ind2_t;
+extern DataObject iedModel_GenericIO_GGIO1_Ind3;
+extern DataAttribute iedModel_GenericIO_GGIO1_Ind3_stVal;
+extern DataAttribute iedModel_GenericIO_GGIO1_Ind3_q;
+extern DataAttribute iedModel_GenericIO_GGIO1_Ind3_t;
+extern DataObject iedModel_GenericIO_GGIO1_Ind4;
+extern DataAttribute iedModel_GenericIO_GGIO1_Ind4_stVal;
+extern DataAttribute iedModel_GenericIO_GGIO1_Ind4_q;
+extern DataAttribute iedModel_GenericIO_GGIO1_Ind4_t;
+
+
+
+#define IEDMODEL_GenericIO (&iedModel_GenericIO)
+#define IEDMODEL_GenericIO_LLN0 (&iedModel_GenericIO_LLN0)
+#define IEDMODEL_GenericIO_LLN0_Mod (&iedModel_GenericIO_LLN0_Mod)
+#define IEDMODEL_GenericIO_LLN0_Mod_stVal (&iedModel_GenericIO_LLN0_Mod_stVal)
+#define IEDMODEL_GenericIO_LLN0_Mod_q (&iedModel_GenericIO_LLN0_Mod_q)
+#define IEDMODEL_GenericIO_LLN0_Mod_t (&iedModel_GenericIO_LLN0_Mod_t)
+#define IEDMODEL_GenericIO_LLN0_Mod_ctlModel (&iedModel_GenericIO_LLN0_Mod_ctlModel)
+#define IEDMODEL_GenericIO_LLN0_Beh (&iedModel_GenericIO_LLN0_Beh)
+#define IEDMODEL_GenericIO_LLN0_Beh_stVal (&iedModel_GenericIO_LLN0_Beh_stVal)
+#define IEDMODEL_GenericIO_LLN0_Beh_q (&iedModel_GenericIO_LLN0_Beh_q)
+#define IEDMODEL_GenericIO_LLN0_Beh_t (&iedModel_GenericIO_LLN0_Beh_t)
+#define IEDMODEL_GenericIO_LLN0_Health (&iedModel_GenericIO_LLN0_Health)
+#define IEDMODEL_GenericIO_LLN0_Health_stVal (&iedModel_GenericIO_LLN0_Health_stVal)
+#define IEDMODEL_GenericIO_LLN0_Health_q (&iedModel_GenericIO_LLN0_Health_q)
+#define IEDMODEL_GenericIO_LLN0_Health_t (&iedModel_GenericIO_LLN0_Health_t)
+#define IEDMODEL_GenericIO_LLN0_NamPlt (&iedModel_GenericIO_LLN0_NamPlt)
+#define IEDMODEL_GenericIO_LLN0_NamPlt_vendor (&iedModel_GenericIO_LLN0_NamPlt_vendor)
+#define IEDMODEL_GenericIO_LLN0_NamPlt_swRev (&iedModel_GenericIO_LLN0_NamPlt_swRev)
+#define IEDMODEL_GenericIO_LLN0_NamPlt_d (&iedModel_GenericIO_LLN0_NamPlt_d)
+#define IEDMODEL_GenericIO_LLN0_NamPlt_configRev (&iedModel_GenericIO_LLN0_NamPlt_configRev)
+#define IEDMODEL_GenericIO_LLN0_NamPlt_ldNs (&iedModel_GenericIO_LLN0_NamPlt_ldNs)
+#define IEDMODEL_GenericIO_LPHD1 (&iedModel_GenericIO_LPHD1)
+#define IEDMODEL_GenericIO_LPHD1_PhyNam (&iedModel_GenericIO_LPHD1_PhyNam)
+#define IEDMODEL_GenericIO_LPHD1_PhyNam_vendor (&iedModel_GenericIO_LPHD1_PhyNam_vendor)
+#define IEDMODEL_GenericIO_LPHD1_PhyHealth (&iedModel_GenericIO_LPHD1_PhyHealth)
+#define IEDMODEL_GenericIO_LPHD1_PhyHealth_stVal (&iedModel_GenericIO_LPHD1_PhyHealth_stVal)
+#define IEDMODEL_GenericIO_LPHD1_PhyHealth_q (&iedModel_GenericIO_LPHD1_PhyHealth_q)
+#define IEDMODEL_GenericIO_LPHD1_PhyHealth_t (&iedModel_GenericIO_LPHD1_PhyHealth_t)
+#define IEDMODEL_GenericIO_LPHD1_Proxy (&iedModel_GenericIO_LPHD1_Proxy)
+#define IEDMODEL_GenericIO_LPHD1_Proxy_stVal (&iedModel_GenericIO_LPHD1_Proxy_stVal)
+#define IEDMODEL_GenericIO_LPHD1_Proxy_q (&iedModel_GenericIO_LPHD1_Proxy_q)
+#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_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)
+#define IEDMODEL_GenericIO_GGIO1_Beh (&iedModel_GenericIO_GGIO1_Beh)
+#define IEDMODEL_GenericIO_GGIO1_Beh_stVal (&iedModel_GenericIO_GGIO1_Beh_stVal)
+#define IEDMODEL_GenericIO_GGIO1_Beh_q (&iedModel_GenericIO_GGIO1_Beh_q)
+#define IEDMODEL_GenericIO_GGIO1_Beh_t (&iedModel_GenericIO_GGIO1_Beh_t)
+#define IEDMODEL_GenericIO_GGIO1_Health (&iedModel_GenericIO_GGIO1_Health)
+#define IEDMODEL_GenericIO_GGIO1_Health_stVal (&iedModel_GenericIO_GGIO1_Health_stVal)
+#define IEDMODEL_GenericIO_GGIO1_Health_q (&iedModel_GenericIO_GGIO1_Health_q)
+#define IEDMODEL_GenericIO_GGIO1_Health_t (&iedModel_GenericIO_GGIO1_Health_t)
+#define IEDMODEL_GenericIO_GGIO1_NamPlt (&iedModel_GenericIO_GGIO1_NamPlt)
+#define IEDMODEL_GenericIO_GGIO1_NamPlt_vendor (&iedModel_GenericIO_GGIO1_NamPlt_vendor)
+#define IEDMODEL_GenericIO_GGIO1_NamPlt_swRev (&iedModel_GenericIO_GGIO1_NamPlt_swRev)
+#define IEDMODEL_GenericIO_GGIO1_NamPlt_d (&iedModel_GenericIO_GGIO1_NamPlt_d)
+#define IEDMODEL_GenericIO_GGIO1_AnIn1 (&iedModel_GenericIO_GGIO1_AnIn1)
+#define IEDMODEL_GenericIO_GGIO1_AnIn1_mag (&iedModel_GenericIO_GGIO1_AnIn1_mag)
+#define IEDMODEL_GenericIO_GGIO1_AnIn1_mag_f (&iedModel_GenericIO_GGIO1_AnIn1_mag_f)
+#define IEDMODEL_GenericIO_GGIO1_AnIn1_q (&iedModel_GenericIO_GGIO1_AnIn1_q)
+#define IEDMODEL_GenericIO_GGIO1_AnIn1_t (&iedModel_GenericIO_GGIO1_AnIn1_t)
+#define IEDMODEL_GenericIO_GGIO1_AnIn2 (&iedModel_GenericIO_GGIO1_AnIn2)
+#define IEDMODEL_GenericIO_GGIO1_AnIn2_mag (&iedModel_GenericIO_GGIO1_AnIn2_mag)
+#define IEDMODEL_GenericIO_GGIO1_AnIn2_mag_f (&iedModel_GenericIO_GGIO1_AnIn2_mag_f)
+#define IEDMODEL_GenericIO_GGIO1_AnIn2_q (&iedModel_GenericIO_GGIO1_AnIn2_q)
+#define IEDMODEL_GenericIO_GGIO1_AnIn2_t (&iedModel_GenericIO_GGIO1_AnIn2_t)
+#define IEDMODEL_GenericIO_GGIO1_AnIn3 (&iedModel_GenericIO_GGIO1_AnIn3)
+#define IEDMODEL_GenericIO_GGIO1_AnIn3_mag (&iedModel_GenericIO_GGIO1_AnIn3_mag)
+#define IEDMODEL_GenericIO_GGIO1_AnIn3_mag_f (&iedModel_GenericIO_GGIO1_AnIn3_mag_f)
+#define IEDMODEL_GenericIO_GGIO1_AnIn3_q (&iedModel_GenericIO_GGIO1_AnIn3_q)
+#define IEDMODEL_GenericIO_GGIO1_AnIn3_t (&iedModel_GenericIO_GGIO1_AnIn3_t)
+#define IEDMODEL_GenericIO_GGIO1_AnIn4 (&iedModel_GenericIO_GGIO1_AnIn4)
+#define IEDMODEL_GenericIO_GGIO1_AnIn4_mag (&iedModel_GenericIO_GGIO1_AnIn4_mag)
+#define IEDMODEL_GenericIO_GGIO1_AnIn4_mag_f (&iedModel_GenericIO_GGIO1_AnIn4_mag_f)
+#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_stVal (&iedModel_GenericIO_GGIO1_SPCSO1_stVal)
+#define IEDMODEL_GenericIO_GGIO1_SPCSO1_q (&iedModel_GenericIO_GGIO1_SPCSO1_q)
+#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)
+#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orCat)
+#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_origin_orIdent)
+#define IEDMODEL_GenericIO_GGIO1_SPCSO1_Oper_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO1_Oper_ctlNum)
+#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)
+#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)
+#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orCat)
+#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_origin_orIdent)
+#define IEDMODEL_GenericIO_GGIO1_SPCSO2_Oper_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO2_Oper_ctlNum)
+#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_stVal (&iedModel_GenericIO_GGIO1_SPCSO3_stVal)
+#define IEDMODEL_GenericIO_GGIO1_SPCSO3_q (&iedModel_GenericIO_GGIO1_SPCSO3_q)
+#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)
+#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orCat)
+#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_origin_orIdent)
+#define IEDMODEL_GenericIO_GGIO1_SPCSO3_Oper_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO3_Oper_ctlNum)
+#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_stVal (&iedModel_GenericIO_GGIO1_SPCSO4_stVal)
+#define IEDMODEL_GenericIO_GGIO1_SPCSO4_q (&iedModel_GenericIO_GGIO1_SPCSO4_q)
+#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)
+#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orCat)
+#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_origin_orIdent)
+#define IEDMODEL_GenericIO_GGIO1_SPCSO4_Oper_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO4_Oper_ctlNum)
+#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)
+#define IEDMODEL_GenericIO_GGIO1_Ind1_t (&iedModel_GenericIO_GGIO1_Ind1_t)
+#define IEDMODEL_GenericIO_GGIO1_Ind2 (&iedModel_GenericIO_GGIO1_Ind2)
+#define IEDMODEL_GenericIO_GGIO1_Ind2_stVal (&iedModel_GenericIO_GGIO1_Ind2_stVal)
+#define IEDMODEL_GenericIO_GGIO1_Ind2_q (&iedModel_GenericIO_GGIO1_Ind2_q)
+#define IEDMODEL_GenericIO_GGIO1_Ind2_t (&iedModel_GenericIO_GGIO1_Ind2_t)
+#define IEDMODEL_GenericIO_GGIO1_Ind3 (&iedModel_GenericIO_GGIO1_Ind3)
+#define IEDMODEL_GenericIO_GGIO1_Ind3_stVal (&iedModel_GenericIO_GGIO1_Ind3_stVal)
+#define IEDMODEL_GenericIO_GGIO1_Ind3_q (&iedModel_GenericIO_GGIO1_Ind3_q)
+#define IEDMODEL_GenericIO_GGIO1_Ind3_t (&iedModel_GenericIO_GGIO1_Ind3_t)
+#define IEDMODEL_GenericIO_GGIO1_Ind4 (&iedModel_GenericIO_GGIO1_Ind4)
+#define IEDMODEL_GenericIO_GGIO1_Ind4_stVal (&iedModel_GenericIO_GGIO1_Ind4_stVal)
+#define IEDMODEL_GenericIO_GGIO1_Ind4_q (&iedModel_GenericIO_GGIO1_Ind4_q)
+#define IEDMODEL_GenericIO_GGIO1_Ind4_t (&iedModel_GenericIO_GGIO1_Ind4_t)
+
+#endif /* STATIC_MODEL_H_ */
+
diff --git a/examples/tls_server_example/tls_server_example.c b/examples/tls_server_example/tls_server_example.c
new file mode 100644
index 00000000..46316994
--- /dev/null
+++ b/examples/tls_server_example/tls_server_example.c
@@ -0,0 +1,228 @@
+/*
+ * tls_server_example.c
+ *
+ * How to configure a TLS server
+ */
+
+#include "iec61850_server.h"
+#include "hal_thread.h"
+#include
+#include
+#include
+#include
+
+#include "static_model.h"
+
+/* import IEC 61850 device model created from SCL-File */
+extern IedModel iedModel;
+
+static int running = 0;
+static IedServer iedServer = NULL;
+
+void
+sigint_handler(int signalId)
+{
+ running = 0;
+}
+
+static ControlHandlerResult
+controlHandlerForBinaryOutput(void* parameter, MmsValue* value, bool test)
+{
+ if (test)
+ return CONTROL_RESULT_FAILED;
+
+ if (MmsValue_getType(value) == MMS_BOOLEAN) {
+ printf("received binary control command: ");
+
+ if (MmsValue_getBoolean(value))
+ printf("on\n");
+ else
+ printf("off\n");
+ }
+ else
+ return CONTROL_RESULT_FAILED;
+
+ uint64_t timeStamp = Hal_getTimeInMs();
+
+ if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO1) {
+ IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO1_t, timeStamp);
+ IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO1_stVal, value);
+ }
+
+ if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO2) {
+ IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO2_t, timeStamp);
+ IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO2_stVal, value);
+ }
+
+ if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO3) {
+ IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO3_t, timeStamp);
+ IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO3_stVal, value);
+ }
+
+ if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO4) {
+ IedServer_updateUTCTimeAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO4_t, timeStamp);
+ IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO4_stVal, value);
+ }
+
+ return CONTROL_RESULT_OK;
+}
+
+
+static void
+connectionHandler (IedServer self, ClientConnection connection, bool connected, void* parameter)
+{
+ if (connected)
+ printf("Connection opened\n");
+ else
+ printf("Connection closed\n");
+}
+
+static void
+printAppTitle(ItuObjectIdentifier* oid)
+{
+ int i;
+
+ for (i = 0; i < oid->arcCount; i++) {
+ printf("%i", oid->arc[i]);
+
+ if (i != (oid->arcCount - 1))
+ printf(".");
+ }
+}
+
+static bool
+clientAuthenticator(void* parameter, AcseAuthenticationParameter authParameter, void** securityToken, IsoApplicationReference* appRef)
+{
+ printf("ACSE Authenticator:\n");
+ printf(" client ap-title: "); printAppTitle(&(appRef->apTitle)); printf("\n");
+ printf(" client ae-qualifier: %i\n", appRef->aeQualifier);
+ printf(" auth-mechanism: %i\n", authParameter->mechanism);
+
+ return true;
+}
+
+int
+main(int argc, char** argv)
+{
+ printf("Using libIEC61850 version %s\n", LibIEC61850_getVersionString());
+
+ TLSConfiguration tlsConfig = TLSConfiguration_create();
+
+ TLSConfiguration_setChainValidation(tlsConfig, false);
+ TLSConfiguration_setAllowOnlyKnownCertificates(tlsConfig, true);
+
+ if (!TLSConfiguration_setOwnKeyFromFile(tlsConfig, "server-key.pem", NULL)) {
+ printf("Failed to load private key!\n");
+ return 0;
+ }
+
+ if (!TLSConfiguration_setOwnCertificateFromFile(tlsConfig, "server.cer")) {
+ printf("ERROR: Failed to load own certificate!\n");
+ return 0;
+ }
+
+ if (!TLSConfiguration_addCACertificateFromFile(tlsConfig, "root.cer")) {
+ printf("ERROR: Failed to load root certificate\n");
+ return 0;
+ }
+
+ /**
+ * Configure two allowed clients
+ */
+
+ if (!TLSConfiguration_addAllowedCertificateFromFile(tlsConfig, "client1.cer")) {
+ printf("ERROR: Failed to load allowed client certificate\n");
+ return 0;
+ }
+
+ if (!TLSConfiguration_addAllowedCertificateFromFile(tlsConfig, "client2.cer")) {
+ printf("ERROR: Failed to load allowed client certificate\n");
+ return 0;
+ }
+
+ iedServer = IedServer_createWithTlsSupport(&iedModel, tlsConfig);
+
+ IedServer_setAuthenticator(iedServer, clientAuthenticator, NULL);
+
+ /* Install handler for operate command */
+ IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO1,
+ (ControlHandler) controlHandlerForBinaryOutput,
+ IEDMODEL_GenericIO_GGIO1_SPCSO1);
+
+ IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO2,
+ (ControlHandler) controlHandlerForBinaryOutput,
+ IEDMODEL_GenericIO_GGIO1_SPCSO2);
+
+ IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO3,
+ (ControlHandler) controlHandlerForBinaryOutput,
+ IEDMODEL_GenericIO_GGIO1_SPCSO3);
+
+ IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO4,
+ (ControlHandler) controlHandlerForBinaryOutput,
+ IEDMODEL_GenericIO_GGIO1_SPCSO4);
+
+ IedServer_setConnectionIndicationHandler(iedServer, (IedConnectionIndicationHandler) connectionHandler, NULL);
+
+ /* MMS server will be instructed to start listening to client connections. */
+ IedServer_start(iedServer, -1);
+
+ if (!IedServer_isRunning(iedServer)) {
+ printf("Starting server failed! Exit.\n");
+ IedServer_destroy(iedServer);
+ exit(-1);
+ }
+
+ running = 1;
+
+ signal(SIGINT, sigint_handler);
+
+ float t = 0.f;
+
+ while (running) {
+ uint64_t timestamp = Hal_getTimeInMs();
+
+ t += 0.1f;
+
+ float an1 = sinf(t);
+ float an2 = sinf(t + 1.f);
+ float an3 = sinf(t + 2.f);
+ float an4 = sinf(t + 3.f);
+
+ IedServer_lockDataModel(iedServer);
+
+ Timestamp iecTimestamp;
+
+ Timestamp_clearFlags(&iecTimestamp);
+ Timestamp_setTimeInMilliseconds(&iecTimestamp, timestamp);
+ Timestamp_setLeapSecondKnown(&iecTimestamp, true);
+
+ /* toggle clock-not-synchronized flag in timestamp */
+ if (((int) t % 2) == 0)
+ Timestamp_setClockNotSynchronized(&iecTimestamp, true);
+
+ IedServer_updateTimestampAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn1_t, &iecTimestamp);
+ IedServer_updateFloatAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn1_mag_f, an1);
+
+ IedServer_updateTimestampAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn2_t, &iecTimestamp);
+ IedServer_updateFloatAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn2_mag_f, an2);
+
+ IedServer_updateTimestampAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn3_t, &iecTimestamp);
+ IedServer_updateFloatAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn3_mag_f, an3);
+
+ IedServer_updateTimestampAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn4_t, &iecTimestamp);
+ IedServer_updateFloatAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_AnIn4_mag_f, an4);
+
+ IedServer_unlockDataModel(iedServer);
+
+ Thread_sleep(100);
+ }
+
+ /* stop MMS server - close TCP server socket and all client sockets */
+ IedServer_stop(iedServer);
+
+ /* Cleanup - free all resources */
+ IedServer_destroy(iedServer);
+
+ TLSConfiguration_destroy(tlsConfig);
+
+} /* main() */
diff --git a/make/stack_includes.mk b/make/stack_includes.mk
index f1afbeb3..8812255b 100644
--- a/make/stack_includes.mk
+++ b/make/stack_includes.mk
@@ -9,3 +9,4 @@ INCLUDES += -I$(LIBIEC_HOME)/src/hal/inc
INCLUDES += -I$(LIBIEC_HOME)/src/goose
INCLUDES += -I$(LIBIEC_HOME)/src/sampled_values
INCLUDES += -I$(LIBIEC_HOME)/src/logging
+INCLUDES += -I$(LIBIEC_HOME)/src/tls
diff --git a/make/target_system.mk b/make/target_system.mk
index b01e9887..107f9b0b 100644
--- a/make/target_system.mk
+++ b/make/target_system.mk
@@ -1,7 +1,7 @@
UNAME := $(shell uname)
MIPSEL_TOOLCHAIN_PREFIX=mipsel-openwrt-linux-
-ARM_TOOLCHAIN_PREFIX=arm-linux-gnueabihf-
+ARM_TOOLCHAIN_PREFIX=arm-linux-
#ARM_TOOLCHAIN_PREFIX=arm-linux-gnueabi-
#ARM_TOOLCHAIN_PREFIX=arm-poky-linux-gnueabi-
#ARM_TOOLCHAIN_PREFIX=arm-linux-gnueabi-
@@ -57,7 +57,7 @@ endif
ifeq ($(TARGET), LINUX-ARM)
TOOLCHAIN_PREFIX=$(ARM_TOOLCHAIN_PREFIX)
-CFLAGS += -mno-unaligned-access
+#CFLAGS += -mno-unaligned-access
#CFLAGS += -mcpu=arm926ej-s
endif
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 49938c32..81fbd3cc 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -80,6 +80,15 @@ set (lib_common_SRCS
./logging/log_storage.c
)
+if(WITH_MBEDTLS)
+set (lib_common_SRCS ${lib_common_SRCS}
+./tls/mbedtls/tls_mbedtls.c
+)
+
+list (APPEND lib_common_SRCS ${tls_SRCS})
+
+endif(WITH_MBEDTLS)
+
set (lib_asn1c_SRCS
./mms/iso_mms/asn1c/DataAccessError.c
./mms/iso_mms/asn1c/DeleteNamedVariableListRequest.c
@@ -367,10 +376,22 @@ if(MSVC)
endif()
ENDIF(WITH_WPCAP)
+if(UNIX)
+ configure_file(
+ ${CMAKE_CURRENT_LIST_DIR}/libiec61850.pc.in
+ ${CMAKE_CURRENT_BINARY_DIR}/libiec61850.pc @ONLY
+ )
+ install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libiec61850.pc" DESTINATION "${CMAKE_INSTALL_PREFIX}/share/pkgconfig")
+endif()
+
+find_package(Doxygen)
+if(DOXYGEN_FOUND)
+ configure_file(Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile @ONLY)
+ add_custom_target(doc ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMMENT "Generating API documentation with Doxygen" VERBATIM)
+endif(DOXYGEN_FOUND)
install (TARGETS iec61850 iec61850-shared
RUNTIME DESTINATION bin COMPONENT Applications
ARCHIVE DESTINATION lib COMPONENT Libraries
LIBRARY DESTINATION lib COMPONENT Libraries
)
-
diff --git a/src/Doxyfile.in b/src/Doxyfile.in
new file mode 100644
index 00000000..bc9fe073
--- /dev/null
+++ b/src/Doxyfile.in
@@ -0,0 +1,2449 @@
+# Doxyfile 1.8.13
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME = "@PROJECT_NAME@"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER = @LIB_VERSION@
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF = "@CPACK_PACKAGE_DESCRIPTION_SUMMARY@"
+
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
+
+PROJECT_LOGO =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = @CMAKE_CURRENT_BINARY_DIR@/../doxydoc
+
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE = 8
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note: For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT = YES
+
+# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up
+# to that level are automatically included in the table of contents, even if
+# they do not have an id attribute.
+# Note: This feature currently applies only to Markdown headings.
+# Minimum value: 0, maximum value: 99, default value: 0.
+# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
+
+TOC_INCLUDE_HEADINGS = 0
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# If one adds a struct or class to a group and this option is enabled, then also
+# any nested class or struct is added to the same group. By default this option
+# is disabled and one has to add nested compounds explicitly via \ingroup.
+# The default value is: NO.
+
+GROUP_NESTED_COMPOUNDS = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT = YES
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE = NO
+
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. If set to YES, local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO, these classes will be included in the various overviews. This option
+# has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO, these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO, these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES, upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES, the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
+# append additional text to a page's title, such as Class Reference. If set to
+# YES the compound reference will be hidden.
+# The default value is: NO.
+
+HIDE_COMPOUND_REFERENCE= NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if ... \endif and \cond
+# ... \endcond blocks.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES, the
+# list will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE = doxygen/DoxygenLayout.xml
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO, doxygen will only warn about wrong or incomplete
+# parameter documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC = NO
+
+# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
+# a warning is encountered.
+# The default value is: NO.
+
+WARN_AS_ERROR = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
+# Note: If this tag is empty the current directory is searched.
+
+INPUT = "iec61850/inc/iec61850_client.h" \
+ "mms/inc/mms_value.h" \
+ "common/inc/linked_list.h" \
+ "doxygen/mainpage.doxygen" \
+ "iec61850/inc/iec61850_server.h" \
+ "iec61850/inc/iec61850_common.h" \
+ "iec61850/inc/iec61850_model.h" \
+ "iec61850/inc/iec61850_dynamic_model.h" \
+ "iec61850/inc/iec61850_config_file_parser.h" \
+ "iec61850/inc/iec61850_cdc.h" \
+ "goose/goose_subscriber.h" \
+ "goose/goose_receiver.h" \
+ "sampled_values/sv_subscriber.h" \
+ "sampled_values/sv_publisher.h" \
+ "mms/inc/mms_device_model.h" \
+ "mms/inc/mms_types.h" \
+ "mms/inc/mms_common.h" \
+ "mms/inc/mms_server.h" \
+ "mms/inc/iso_server.h" \
+ "mms/inc/mms_named_variable_list.h" \
+ "mms/inc/mms_type_spec.h" \
+ "mms/inc/mms_types.h" \
+ "mms/inc/mms_client_connection.h" \
+ "mms/inc/iso_connection_parameters.h" \
+ "hal/inc/hal_socket.h" \
+ "hal/inc/hal_thread.h" \
+ "hal/inc/hal_ethernet.h" \
+ "hal/inc/hal_filesystem.h" \
+ "hal/inc/hal_time.h" \
+ "logging/logging_api.h"
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# read by doxygen.
+#
+# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
+# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
+# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
+# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08,
+# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf.
+
+FILE_PATTERNS =
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+#
+#
+# where is the value of the INPUT_FILTER tag, and is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX = YES
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER = doxygen/header.html
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER = doxygen/footer.html
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET = doxygen/doxygen.css
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefore more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the style sheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to YES can help to show when doxygen was last run and thus if the
+# documentation is up to date.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the master .chm file (NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH = 250
+
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH = http://www.mathjax.org/mathjax
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use + S
+# (what the is depends on the OS and browser, but it is typically
+# , /