diff --git a/CHANGELOG b/CHANGELOG
index 7ea34044..2019cf3b 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,39 @@
+Changes to version 0.8.2
+------------------------
+- Client: Added adjustable timeout to connect functions
+- Client: Support for T selectors with different size than two bytes
+- GOOSE publisher: added support for explicit GoID
+- GOOSE subscriber: refactored subscriber
+- Server: Added support for setting groups
+- Server: Added support for data references in reports
+- SCL parser: support for "Val" attributes in DA type definitions
+- Server: Added function to disable all GOOSE publishing
+- Client/Server: added helper functions for Dbpos
+- C# API: more features and improved stability
+
+Changes to version 0.8.1
+------------------------
+- IEC 61850/MMS client: IedConnection and MmsConnection objects can now be reused
+- reorganization of library header files
+- C# API provides support for bit string and octet string data type
+- IEC 61850 client/server: Added support for CommandTermination-
+- C# API added handler for CommandTermination messages
+- IEC 61850 server: IED name for static device model can now be configured at runtime
+- Client/server: Fixed problem with association specific data sets
+- GOOSE: fixed triggering GOOSE reports for data set members without trigger condition set
+- Linux/Windows/BSD: added support for select based socket read (reduces CPU load)
+- C# API added support for file services
+- a lot of small bug fixes
+
+Changes to version 0.8
+-----------------------
+- HAL: socket layer. Some changes. read and accept are now non-blocking. Changes the standard implementations (Linux/POSIX, WIN32, BSD) accordingly
+- server stack: added single-threaded and threadless operation modes to better fit to resource constraint devices (added new configuration option CONFIG_MMS_SINGLE_THREADED)
+- some small changes in server side control model handling (ControlHandler return values and behaviour) to enable threadless and single-threaded operation.
+- C# client API extended and XML documentation completed
+- some smaller bug fixes and extensions
+
+
Changes to version 0.7.8
------------------------
- IED client: added client side support for Ed.1 compliant control (client side automatically detects if a control is ed1 or ed2 compliant)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0bcab8ee..4c597cc4 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -10,8 +10,8 @@ endif()
project(libiec61850)
set(LIB_VERSION_MAJOR "0")
-set(LIB_VERSION_MINOR "7")
-set(LIB_VERSION_PATCH "8")
+set(LIB_VERSION_MINOR "8")
+set(LIB_VERSION_PATCH "2")
# feature checks
include(CheckLibraryExists)
@@ -26,6 +26,9 @@ set(CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS 5 CACHE STRING "Configure the maximum
option(BUILD_EXAMPLES "Build the examples" ON)
+option(CONFIG_MMS_SINGLE_THREADED "Compile for single threaded version" OFF)
+option(CONFIG_MMS_THREADLESS_STACK "Optimize stack for threadless operation (warning: single- or multi-threaded server will not work!)" OFF)
+
# choose the library features which shall be included
option(CONFIG_INCLUDE_GOOSE_SUPPORT "Build with GOOSE support" ON)
@@ -33,12 +36,15 @@ option(CONFIG_IEC61850_CONTROL_SERVICE "Build with support for IEC 61850 control
option(CONFIG_IEC61850_REPORT_SERVICE "Build with support for IEC 61850 reporting services" ON)
+option(CONFIG_IEC61850_SETTING_GROUPS "Build with support for IEC 61850 setting group services" ON)
+
option(CONFIG_ACTIVATE_TCP_KEEPALIVE "Activate TCP keepalive" ON)
set(CONFIG_REPORTING_DEFAULT_REPORT_BUFFER_SIZE "8000" CACHE STRING "Default buffer size for buffered reports in byte" )
# 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)
@@ -51,64 +57,45 @@ option(DEBUG_MMS_CLIENT "Enable MMS CLIENT printf debugging" OFF)
include_directories(
${CMAKE_CURRENT_BINARY_DIR}/config
- src/common
+ src/common/inc
src/goose
- src/hal
- src/hal/ethernet
- src/hal/socket
- src/hal/thread
- src/hal/filesystem
- src/hal/time
- src/iedclient
- src/iedcommon
- src/iedserver
- src/iedserver/impl
- src/iedserver/mms_mapping
- src/iedserver/model
- src/mms/asn1
- src/mms/iso_acse
- src/mms/iso_client
- src/mms/iso_cotp
+ src/hal/inc
+ src/iec61850/inc
+ src/iec61850/inc_private
+ src/mms/inc
+ src/mms/inc_private
src/mms/iso_mms/asn1c
- src/mms/iso_mms/client
- src/mms/iso_mms/common
- src/mms/iso_mms/server
- src/mms/iso_presentation
- src/mms/iso_server
- src/mms/iso_common
- src/mms/iso_session
)
set(API_HEADERS
- src/hal/time/time_hal.h
- src/hal/ethernet/ethernet.h
- src/hal/thread/thread.h
- src/hal/filesystem/filesystem.h
- src/common/libiec61850_common_api.h
- src/common/linked_list.h
- src/common/byte_buffer.h
- src/iedclient/iec61850_client.h
- src/iedcommon/iec61850_common.h
- src/iedserver/iec61850_server.h
- src/iedserver/model/model.h
- src/iedserver/model/cdc.h
- src/iedserver/model/dynamic_model.h
- src/iedserver/model/config_file_parser.h
- src/mms/iso_mms/common/mms_value.h
- src/mms/iso_mms/common/mms_common.h
- src/mms/iso_mms/common/mms_types.h
- src/mms/iso_mms/server/mms_device_model.h
- src/mms/iso_mms/server/mms_server.h
- src/mms/iso_mms/server/mms_named_variable_list.h
- src/mms/iso_mms/common/mms_type_spec.h
- src/mms/asn1/ber_integer.h
- src/mms/asn1/asn1_ber_primitive_value.h
- src/mms/iso_server/iso_server.h
- src/mms/iso_common/iso_connection_parameters.h
+ src/hal/inc/hal_time.h
+ src/hal/inc/hal_thread.h
+ src/hal/inc/hal_filesystem.h
+ src/common/inc/libiec61850_common_api.h
+ src/common/inc/linked_list.h
+ src/common/inc/byte_buffer.h
+ src/common/inc/lib_memory.h
+ src/iec61850/inc/iec61850_client.h
+ src/iec61850/inc/iec61850_common.h
+ src/iec61850/inc/iec61850_server.h
+ src/iec61850/inc/iec61850_model.h
+ src/iec61850/inc/iec61850_cdc.h
+ src/iec61850/inc/iec61850_dynamic_model.h
+ src/iec61850/inc/iec61850_config_file_parser.h
+ src/mms/inc/mms_value.h
+ src/mms/inc/mms_common.h
+ src/mms/inc/mms_types.h
+ src/mms/inc/mms_device_model.h
+ src/mms/inc/mms_server.h
+ src/mms/inc/mms_named_variable_list.h
+ src/mms/inc/mms_type_spec.h
+ src/mms/inc/mms_client_connection.h
+ src/mms/inc/iso_connection_parameters.h
+ src/mms/inc/iso_server.h
+ src/mms/inc/ber_integer.h
+ src/mms/inc/asn1_ber_primitive_value.h
src/goose/goose_subscriber.h
- src/mms/iso_mms/client/mms_client_connection.h
- src/mms/iso_client/iso_client_connection.h
- src/hal/socket/socket.h
+ src/goose/goose_receiver.h
)
IF(WIN32)
@@ -129,3 +116,30 @@ add_subdirectory(src)
INSTALL(FILES ${API_HEADERS} DESTINATION include/libiec61850)
+IF(EXISTS "${CMAKE_ROOT}/Modules/CPack.cmake")
+INCLUDE(InstallRequiredSystemLibraries)
+
+SET(CPACK_SET_DESTDIR "on")
+SET(CPACK_INSTALL_PREFIX "/usr")
+SET(CPACK_GENERATOR "DEB")
+
+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 "The libIEC61850 project")
+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_DEBIAN_PACKAGE_PRIORITY "optional")
+SET(CPACK_DEBIAN_ARCHITECTURE ${CMAKE_SYSTEM_PROCESSOR})
+
+SET(CPACK_COMPONENTS_ALL Libraries ApplicationData)
+INCLUDE(CPack)
+
+ENDIF(EXISTS "${CMAKE_ROOT}/Modules/CPack.cmake")
+
+
+
diff --git a/Makefile b/Makefile
index 0369ec80..3fd46ac3 100644
--- a/Makefile
+++ b/Makefile
@@ -12,7 +12,7 @@ LIB_SOURCE_DIRS += src/mms/asn1
LIB_SOURCE_DIRS += src/mms/iso_cotp
LIB_SOURCE_DIRS += src/mms/iso_mms/server
LIB_SOURCE_DIRS += src/mms/iso_mms/client
-LIB_SOURCE_DIRS += src/mms/iso_client/impl
+LIB_SOURCE_DIRS += src/mms/iso_client
LIB_SOURCE_DIRS += src/mms/iso_common
LIB_SOURCE_DIRS += src/mms/iso_mms/common
LIB_SOURCE_DIRS += src/mms/iso_mms/asn1c
@@ -20,13 +20,12 @@ LIB_SOURCE_DIRS += src/mms/iso_server
ifndef EXCLUDE_ETHERNET_WINDOWS
LIB_SOURCE_DIRS += src/goose
endif
-LIB_SOURCE_DIRS += src/iedclient/impl
-LIB_SOURCE_DIRS += src/iedcommon
-LIB_SOURCE_DIRS += src/iedserver
-LIB_SOURCE_DIRS += src/iedserver/model
-LIB_SOURCE_DIRS += src/iedserver/mms_mapping
-LIB_SOURCE_DIRS += src/iedserver/impl
-LIB_SOURCE_DIRS += src/hal
+LIB_SOURCE_DIRS += src/iec61850/client
+LIB_SOURCE_DIRS += src/iec61850/common
+LIB_SOURCE_DIRS += src/iec61850/server
+LIB_SOURCE_DIRS += src/iec61850/server/model
+LIB_SOURCE_DIRS += src/iec61850/server/mms_mapping
+LIB_SOURCE_DIRS += src/iec61850/server/impl
ifeq ($(HAL_IMPL), WIN32)
LIB_SOURCE_DIRS += src/hal/socket/win32
LIB_SOURCE_DIRS += src/hal/thread/win32
@@ -46,34 +45,15 @@ LIB_SOURCE_DIRS += src/hal/ethernet/bsd
LIB_SOURCE_DIRS += src/hal/filesystem/linux
LIB_SOURCE_DIRS += src/hal/time/unix
endif
-
-LIB_INCLUDE_DIRS += src/mms/iso_presentation
-LIB_INCLUDE_DIRS += src/mms/iso_session
-LIB_INCLUDE_DIRS += src/mms/iso_cotp
-LIB_INCLUDE_DIRS += src/mms/iso_acse
LIB_INCLUDE_DIRS += config
-LIB_INCLUDE_DIRS += src/mms/asn1
-LIB_INCLUDE_DIRS += src/mms/iso_client
-LIB_INCLUDE_DIRS += src/mms/iso_mms/server
-LIB_INCLUDE_DIRS += src/mms/iso_mms/common
-LIB_INCLUDE_DIRS += src/mms/iso_mms/client
-LIB_INCLUDE_DIRS += src/mms/iso_mms/asn1c
-LIB_INCLUDE_DIRS += src/common
-LIB_INCLUDE_DIRS += src/hal/socket
-LIB_INCLUDE_DIRS += src/hal/thread
-LIB_INCLUDE_DIRS += src/hal/ethernet
-LIB_INCLUDE_DIRS += src/hal/filesystem
-LIB_INCLUDE_DIRS += src/hal/time
-LIB_INCLUDE_DIRS += src/hal
+LIB_INCLUDE_DIRS += src/common/inc
+LIB_INCLUDE_DIRS += src/mms/iso_mms/asn1c
+LIB_INCLUDE_DIRS += src/mms/inc
+LIB_INCLUDE_DIRS += src/mms/inc_private
+LIB_INCLUDE_DIRS += src/hal/inc
LIB_INCLUDE_DIRS += src/goose
-LIB_INCLUDE_DIRS += src/mms/iso_server
-LIB_INCLUDE_DIRS += src/mms/iso_common
-LIB_INCLUDE_DIRS += src/iedclient
-LIB_INCLUDE_DIRS += src/iedcommon
-LIB_INCLUDE_DIRS += src/iedserver
-LIB_INCLUDE_DIRS += src/iedserver/model
-LIB_INCLUDE_DIRS += src/iedserver/mms_mapping
-LIB_INCLUDE_DIRS += src/iedserver/impl
+LIB_INCLUDE_DIRS += src/iec61850/inc
+LIB_INCLUDE_DIRS += src/iec61850/inc_private
ifeq ($(HAL_IMPL), WIN32)
LIB_INCLUDE_DIRS += third_party/winpcap/Include
endif
@@ -84,35 +64,34 @@ ifndef INSTALL_PREFIX
INSTALL_PREFIX = ./.install
endif
-LIB_API_HEADER_FILES = src/hal/time/time_hal.h
-LIB_API_HEADER_FILES += src/hal/ethernet/ethernet.h
-LIB_API_HEADER_FILES += src/hal/thread/thread.h
-LIB_API_HEADER_FILES += src/hal/filesystem/filesystem.h
-LIB_API_HEADER_FILES += src/common/libiec61850_common_api.h
-LIB_API_HEADER_FILES += src/common/linked_list.h
-LIB_API_HEADER_FILES += src/common/byte_buffer.h
-LIB_API_HEADER_FILES += src/iedclient/iec61850_client.h
-LIB_API_HEADER_FILES += src/iedcommon/iec61850_common.h
-LIB_API_HEADER_FILES += src/iedserver/iec61850_server.h
-LIB_API_HEADER_FILES += src/iedserver/model/model.h
-LIB_API_HEADER_FILES += src/iedserver/model/cdc.h
-LIB_API_HEADER_FILES += src/iedserver/model/dynamic_model.h
-LIB_API_HEADER_FILES += src/iedserver/model/config_file_parser.h
-LIB_API_HEADER_FILES += src/mms/iso_mms/common/mms_value.h
-LIB_API_HEADER_FILES += src/mms/iso_mms/common/mms_common.h
-LIB_API_HEADER_FILES += src/mms/iso_mms/common/mms_types.h
-LIB_API_HEADER_FILES += src/mms/iso_mms/server/mms_device_model.h
-LIB_API_HEADER_FILES += src/mms/iso_mms/server/mms_server.h
-LIB_API_HEADER_FILES += src/mms/iso_mms/server/mms_named_variable_list.h
-LIB_API_HEADER_FILES += src/mms/iso_mms/common/mms_type_spec.h
-LIB_API_HEADER_FILES += src/mms/asn1/ber_integer.h
-LIB_API_HEADER_FILES += src/mms/asn1/asn1_ber_primitive_value.h
-LIB_API_HEADER_FILES += src/mms/iso_server/iso_server.h
-LIB_API_HEADER_FILES += src/mms/iso_common/iso_connection_parameters.h
+LIB_API_HEADER_FILES = src/hal/inc/hal_time.h
+LIB_API_HEADER_FILES += src/hal/inc/hal_thread.h
+LIB_API_HEADER_FILES += src/hal/inc/hal_filesystem.h
+LIB_API_HEADER_FILES += src/common/inc/libiec61850_common_api.h
+LIB_API_HEADER_FILES += src/common/inc/linked_list.h
+LIB_API_HEADER_FILES += src/common/inc/byte_buffer.h
+LIB_API_HEADER_FILES += src/common/inc/lib_memory.h
+LIB_API_HEADER_FILES += src/iec61850/inc/iec61850_client.h
+LIB_API_HEADER_FILES += src/iec61850/inc/iec61850_common.h
+LIB_API_HEADER_FILES += src/iec61850/inc/iec61850_server.h
+LIB_API_HEADER_FILES += src/iec61850/inc/iec61850_model.h
+LIB_API_HEADER_FILES += src/iec61850/inc/iec61850_cdc.h
+LIB_API_HEADER_FILES += src/iec61850/inc/iec61850_dynamic_model.h
+LIB_API_HEADER_FILES += src/iec61850/inc/iec61850_config_file_parser.h
+LIB_API_HEADER_FILES += src/mms/inc/mms_value.h
+LIB_API_HEADER_FILES += src/mms/inc/mms_common.h
+LIB_API_HEADER_FILES += src/mms/inc/mms_types.h
+LIB_API_HEADER_FILES += src/mms/inc/mms_device_model.h
+LIB_API_HEADER_FILES += src/mms/inc/mms_server.h
+LIB_API_HEADER_FILES += src/mms/inc/mms_named_variable_list.h
+LIB_API_HEADER_FILES += src/mms/inc/mms_type_spec.h
+LIB_API_HEADER_FILES += src/mms/inc/mms_client_connection.h
+LIB_API_HEADER_FILES += src/mms/inc/iso_connection_parameters.h
+LIB_API_HEADER_FILES += src/mms/inc/iso_server.h
+LIB_API_HEADER_FILES += src/mms/inc/ber_integer.h
+LIB_API_HEADER_FILES += src/mms/inc/asn1_ber_primitive_value.h
LIB_API_HEADER_FILES += src/goose/goose_subscriber.h
-LIB_API_HEADER_FILES += src/mms/iso_mms/client/mms_client_connection.h
-LIB_API_HEADER_FILES += src/mms/iso_client/iso_client_connection.h
-LIB_API_HEADER_FILES += src/hal/socket/socket.h
+LIB_API_HEADER_FILES += src/goose/goose_receiver.h
get_sources_from_directory = $(wildcard $1/*.c)
get_sources = $(foreach dir, $1, $(call get_sources_from_directory,$(dir)))
diff --git a/config/stack_config.h b/config/stack_config.h
index 1c38acbb..e995ab0d 100644
--- a/config/stack_config.h
+++ b/config/stack_config.h
@@ -10,9 +10,10 @@
#define STACK_CONFIG_H_
/* include asserts if set to 1 */
-#define DEBUG 0
+#define DEBUG 1
/* print debugging information with printf if set to 1 */
+#define DEBUG_SOCKET 0
#define DEBUG_COTP 0
#define DEBUG_ISO_SERVER 0
#define DEBUG_ISO_CLIENT 0
@@ -20,10 +21,28 @@
#define DEBUG_IED_CLIENT 0
#define DEBUG_MMS_CLIENT 0
#define DEBUG_MMS_SERVER 0
+#define DEBUG_GOOSE_SUBSCRIBER 0
+#define DEBUG_GOOSE_PUBLISHER 0
/* Maximum MMS PDU SIZE - default is 65000 */
#define CONFIG_MMS_MAXIMUM_PDU_SIZE 65000
+/*
+ * Enable single threaded mode
+ *
+ * 1 ==> server runs in single threaded mode (a single thread for the server and all client connections)
+ * 0 ==> server runs in multi-threaded mode (one thread for each connection and
+ * one server background thread )
+ */
+#define CONFIG_MMS_SINGLE_THREADED 1
+
+/*
+ * Optimize stack for threadless operation - don't use semaphores
+ *
+ * WARNING: If set to 1 normal single- and multi-threaded server are no longer working!
+ */
+#define CONFIG_MMS_THREADLESS_STACK 0
+
/* number of concurrent MMS client connections the server accepts, -1 for no limit */
#define CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS 5
@@ -48,6 +67,7 @@
/* Ethernet interface ID for GOOSE and SV */
#define CONFIG_ETHERNET_INTERFACE_ID "eth0"
//#define CONFIG_ETHERNET_INTERFACE_ID "vboxnet0"
+//#define CONFIG_ETHERNET_INTERFACE_ID "eth-f"
//#define CONFIG_ETHERNET_INTERFACE_ID "en0" // OS X uses enX in place of ethX as ethernet NIC names.
/* Set to 1 to include GOOSE support in the build. Otherwise set to 0 */
@@ -102,10 +122,16 @@
/* The default buffer size of buffered RCBs in bytes */
#define CONFIG_REPORTING_DEFAULT_REPORT_BUFFER_SIZE 65536
+/* include support for setting groups */
+#define CONFIG_IEC61850_SETTING_GROUPS 1
+
+/* default reservation time of a setting group control block in s */
+#define CONFIG_IEC61850_SG_RESVTMS 10
+
/* default results for MMS identify service */
#define CONFIG_DEFAULT_MMS_VENDOR_NAME "libiec61850.com"
#define CONFIG_DEFAULT_MMS_MODEL_NAME "LIBIEC61850"
-#define CONFIG_DEFAULT_MMS_REVISION "0.7.8"
+#define CONFIG_DEFAULT_MMS_REVISION "0.8.2"
/* MMS virtual file store base path - where file services are looking for files */
#define CONFIG_VIRTUAL_FILESTORE_BASEPATH "./vmd-filestore/"
@@ -113,6 +139,12 @@
/* Maximum number of open file per MMS connection (for MMS file read service) */
#define CONFIG_MMS_MAX_NUMBER_OF_OPEN_FILES_PER_CONNECTION 5
+#define CONFIG_MMS_MAX_NUMBER_OF_DOMAIN_SPECIFIC_DATA_SETS 10
+
+#define CONFIG_MMS_MAX_NUMBER_OF_ASSOCIATION_SPECIFIC_DATA_SETS 10
+
+#define CONFIG_MMS_MAX_NUMBER_OF_VMD_SPECIFIC_DATA_SETS 10
+
/* Definition of supported services */
#define MMS_DEFAULT_PROFILE 1
@@ -140,4 +172,6 @@
/* VMD scope named variables are not used by IEC 61850 */
#define CONFIG_MMS_SUPPORT_VMD_SCOPE_NAMED_VARIABLES 0
+#define CONFIG_INCLUDE_PLATFORM_SPECIFIC_HEADERS 0
+
#endif /* STACK_CONFIG_H_ */
diff --git a/config/stack_config.h.cmake b/config/stack_config.h.cmake
index 249d8f24..3f46e272 100644
--- a/config/stack_config.h.cmake
+++ b/config/stack_config.h.cmake
@@ -19,6 +19,7 @@
#cmakedefine01 DEBUG
/* print debugging information with printf if set to 1 */
+#cmakedefine01 DEBUG_SOCKET
#cmakedefine01 DEBUG_COTP
#cmakedefine01 DEBUG_ISO_SERVER
#cmakedefine01 DEBUG_ISO_CLIENT
@@ -26,6 +27,17 @@
#cmakedefine01 DEBUG_IED_CLIENT
#cmakedefine01 DEBUG_MMS_CLIENT
#cmakedefine01 DEBUG_MMS_SERVER
+#cmakedefine01 DEBUG_GOOSE_SUBSCRIBER
+#cmakedefine01 DEBUG_GOOSE_PUBLISHER
+
+/* 1 ==> server runs in single threaded mode (one dedicated thread for the server)
+ * 0 ==> server runs in multi threaded mode (one thread for each connection and
+ * one server background thread )
+ */
+#cmakedefine01 CONFIG_MMS_SINGLE_THREADED
+
+/* Optimize stack for threadless operation - don't use semaphores */
+#cmakedefine01 CONFIG_MMS_THREADLESS_STACK
/* Maximum MMS PDU SIZE - default is 65000 */
#cmakedefine CONFIG_MMS_MAXIMUM_PDU_SIZE @CONFIG_MMS_MAXIMUM_PDU_SIZE@
@@ -52,9 +64,9 @@
#define CONFIG_TCP_READ_TIMEOUT_MS 1000
/* Ethernet interface ID for GOOSE and SV */
-//#define CONFIG_ETHERNET_INTERFACE_ID "eth0"
+#define CONFIG_ETHERNET_INTERFACE_ID "eth0"
//#define CONFIG_ETHERNET_INTERFACE_ID "vboxnet0"
-#define CONFIG_ETHERNET_INTERFACE_ID "en0" // OS X uses enX in place of ethX as ethernet NIC names.
+//#define CONFIG_ETHERNET_INTERFACE_ID "en0" // OS X uses enX in place of ethX as ethernet NIC names.
/* Set to 1 to include GOOSE support in the build. Otherwise set to 0 */
#cmakedefine01 CONFIG_INCLUDE_GOOSE_SUPPORT
@@ -108,6 +120,12 @@
/* The default buffer size of buffered RCBs in bytes */
#cmakedefine CONFIG_REPORTING_DEFAULT_REPORT_BUFFER_SIZE @CONFIG_REPORTING_DEFAULT_REPORT_BUFFER_SIZE@
+/* include support for setting groups */
+#cmakedefine01 CONFIG_IEC61850_SETTING_GROUPS
+
+/* default reservation time of a setting group control block in s */
+#define CONFIG_IEC61850_SG_RESVTMS 100
+
/* default results for MMS identify service */
#define CONFIG_DEFAULT_MMS_VENDOR_NAME "libiec61850.com"
#define CONFIG_DEFAULT_MMS_MODEL_NAME "LIBIEC61850"
@@ -125,6 +143,12 @@
/* Maximum number of open file per MMS connection (for MMS file read service) */
#define CONFIG_MMS_MAX_NUMBER_OF_OPEN_FILES_PER_CONNECTION 5
+#define CONFIG_MMS_MAX_NUMBER_OF_DOMAIN_SPECIFIC_DATA_SETS 10
+
+#define CONFIG_MMS_MAX_NUMBER_OF_ASSOCIATION_SPECIFIC_DATA_SETS 10
+
+#define CONFIG_MMS_MAX_NUMBER_OF_VMD_SPECIFIC_DATA_SETS 10
+
/* Definition of supported services */
#define MMS_DEFAULT_PROFILE 1
diff --git a/demos/beaglebone/static_model.c b/demos/beaglebone/static_model.c
index 0150f871..5c8824c5 100644
--- a/demos/beaglebone/static_model.c
+++ b/demos/beaglebone/static_model.c
@@ -150,15 +150,12 @@ extern DataAttribute iedModel_GenericIO_GGIO1_Ind4_stVal;
extern DataAttribute iedModel_GenericIO_GGIO1_Ind4_q;
extern DataAttribute iedModel_GenericIO_GGIO1_Ind4_t;
-extern DataSet ds_GenericIO_LLN0_Events;
+static DataSetEntry ds_GenericIO_LLN0_Events_fcda0;
+static DataSetEntry ds_GenericIO_LLN0_Events_fcda1;
+static DataSetEntry ds_GenericIO_LLN0_Events_fcda2;
+static DataSetEntry ds_GenericIO_LLN0_Events_fcda3;
-
-extern DataSetEntry ds_GenericIO_LLN0_Events_fcda0;
-extern DataSetEntry ds_GenericIO_LLN0_Events_fcda1;
-extern DataSetEntry ds_GenericIO_LLN0_Events_fcda2;
-extern DataSetEntry ds_GenericIO_LLN0_Events_fcda3;
-
-DataSetEntry ds_GenericIO_LLN0_Events_fcda0 = {
+static DataSetEntry ds_GenericIO_LLN0_Events_fcda0 = {
"beagleGenericIO",
"GGIO1$ST$SPCSO1$stVal",
-1,
@@ -167,7 +164,7 @@ DataSetEntry ds_GenericIO_LLN0_Events_fcda0 = {
&ds_GenericIO_LLN0_Events_fcda1
};
-DataSetEntry ds_GenericIO_LLN0_Events_fcda1 = {
+static DataSetEntry ds_GenericIO_LLN0_Events_fcda1 = {
"beagleGenericIO",
"GGIO1$ST$SPCSO2$stVal",
-1,
@@ -176,7 +173,7 @@ DataSetEntry ds_GenericIO_LLN0_Events_fcda1 = {
&ds_GenericIO_LLN0_Events_fcda2
};
-DataSetEntry ds_GenericIO_LLN0_Events_fcda2 = {
+static DataSetEntry ds_GenericIO_LLN0_Events_fcda2 = {
"beagleGenericIO",
"GGIO1$ST$SPCSO3$stVal",
-1,
@@ -185,7 +182,7 @@ DataSetEntry ds_GenericIO_LLN0_Events_fcda2 = {
&ds_GenericIO_LLN0_Events_fcda3
};
-DataSetEntry ds_GenericIO_LLN0_Events_fcda3 = {
+static DataSetEntry ds_GenericIO_LLN0_Events_fcda3 = {
"beagleGenericIO",
"GGIO1$ST$DPCSO1$stVal",
-1,
@@ -194,12 +191,11 @@ DataSetEntry ds_GenericIO_LLN0_Events_fcda3 = {
NULL
};
-DataSet ds_GenericIO_LLN0_Events = {
+static DataSet ds_GenericIO_LLN0_Events = {
"beagleGenericIO",
"LLN0$Events",
4,
- &ds_GenericIO_LLN0_Events_fcda0,
- NULL
+ &ds_GenericIO_LLN0_Events_fcda0
};
LogicalDevice iedModel_GenericIO = {
@@ -1923,11 +1919,22 @@ DataAttribute iedModel_GenericIO_GGIO1_Ind4_t = {
NULL,
0};
-extern ReportControlBlock iedModel_GenericIO_LLN0_report0;
-extern ReportControlBlock iedModel_GenericIO_LLN0_report1;
-ReportControlBlock iedModel_GenericIO_LLN0_report0 = {&iedModel_GenericIO_LLN0, "EventsRCB01", "Events1", false, "Events", 1, 8, 111, 50, 1000, &iedModel_GenericIO_LLN0_report1};
-ReportControlBlock iedModel_GenericIO_LLN0_report1 = {&iedModel_GenericIO_LLN0, "EventsRCB201", "Events2", false, "Events", 1, 8, 111, 50, 1000, NULL};
+static ReportControlBlock iedModel_GenericIO_LLN0_report0;
+static ReportControlBlock iedModel_GenericIO_LLN0_report1;
+
+static ReportControlBlock iedModel_GenericIO_LLN0_report0 = {&iedModel_GenericIO_LLN0, "EventsRCB", "Events1", false, "Events", 1, 16, 111, 50, 1000, &iedModel_GenericIO_LLN0_report1};
+static ReportControlBlock iedModel_GenericIO_LLN0_report1 = {&iedModel_GenericIO_LLN0, "EventsRCB2", "Events2", false, "Events", 1, 16, 111, 50, 1000, NULL};
+
+
+
+
+
+
+
+
+
+
diff --git a/dotnet/IEC61850forCSharp/Control.cs b/dotnet/IEC61850forCSharp/Control.cs
index 0b3294bc..d064334b 100644
--- a/dotnet/IEC61850forCSharp/Control.cs
+++ b/dotnet/IEC61850forCSharp/Control.cs
@@ -29,8 +29,14 @@ using IEC61850.Common;
namespace IEC61850
{
+ ///
+ /// IEC 61850 common API parts (used by client and server API)
+ ///
namespace Common {
+ ///
+ /// Control model
+ ///
public enum ControlModel {
CONTROL_MODEL_STATUS_ONLY = 0,
CONTROL_MODEL_DIRECT_NORMAL = 1,
@@ -38,39 +44,142 @@ namespace IEC61850
CONTROL_MODEL_DIRECT_ENHANCED = 3,
CONTROL_MODEL_SBO_ENHANCED = 4
}
+
+ ///
+ /// Originator category
+ ///
+ public enum OrCat {
+ /** Not supported - should not be used */
+ NOT_SUPPORTED = 0,
+ /** Control operation issued from an operator using a client located at bay level */
+ BAY_CONTROL = 1,
+ /** Control operation issued from an operator using a client located at station level */
+ STATION_CONTROL = 2,
+ /** Control operation from a remote operator outside the substation (for example network control center) */
+ REMOTE_CONTROL = 3,
+ /** Control operation issued from an automatic function at bay level */
+ AUTOMATIC_BAY = 4,
+ /** Control operation issued from an automatic function at station level */
+ AUTOMATIC_STATION = 5,
+ /** Control operation issued from a automatic function outside of the substation */
+ AUTOMATIC_REMOTE = 6,
+ /** Control operation issued from a maintenance/service tool */
+ MAINTENANCE = 7,
+ /** Status change occurred without control action (for example external trip of a circuit breaker or failure inside the breaker) */
+ PROCESS = 8
+ }
}
namespace Client {
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct LastApplErrorInternal
+ {
+ public int ctlNum;
+ public int error;
+ public int addCause;
+ }
+
+ public class LastApplError
+ {
+ public int ctlNum;
+ public int error;
+ public ControlAddCause addCause;
+
+
+ internal LastApplError (LastApplErrorInternal lastApplError)
+ {
+ this.addCause = (ControlAddCause) lastApplError.addCause;
+ this.error = lastApplError.error;
+ this.ctlNum = lastApplError.ctlNum;
+ }
+ }
+
+ ///
+ /// Control object.
+ ///
public class ControlObject
{
+
+
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
- static extern IntPtr ControlObjectClient_create(string objectReference, IntPtr connection);
+ private static extern LastApplErrorInternal ControlObjectClient_getLastApplError(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
- static extern void ControlObjectClient_destroy(IntPtr self);
+ private static extern IntPtr ControlObjectClient_create(string objectReference, IntPtr connection);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
- static extern int ControlObjectClient_getControlModel(IntPtr self);
+ private static extern void ControlObjectClient_destroy(IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
- static extern bool ControlObjectClient_operate(IntPtr self, IntPtr ctlVal, UInt64 operTime);
+ private static extern int ControlObjectClient_getControlModel(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern bool ControlObjectClient_operate(IntPtr self, IntPtr ctlVal, UInt64 operTime);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern bool ControlObjectClient_select(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern bool ControlObjectClient_selectWithValue(IntPtr self, IntPtr ctlVal);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern bool ControlObjectClient_cancel(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern void ControlObjectClient_setOrigin(IntPtr self, string orIdent, int orCat);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern void ControlObjectClient_enableInterlockCheck(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern void ControlObjectClient_enableSynchroCheck(IntPtr self);
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ private delegate void InternalCommandTerminationHandler(IntPtr parameter,IntPtr controlClient);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern void ControlObjectClient_setCommandTerminationHandler(IntPtr self,
+ InternalCommandTerminationHandler handler, IntPtr handlerParameter);
+
+ public delegate void CommandTerminationHandler (Object parameter, ControlObject controlObject);
private IntPtr controlObject;
+ private CommandTerminationHandler commandTerminationHandler = null;
+ private Object commandTerminationHandlerParameter = null;
+
+ private void MyCommandTerminationHandler (IntPtr paramter, IntPtr controlClient)
+ {
+ if (commandTerminationHandler != null)
+ commandTerminationHandler(commandTerminationHandlerParameter, this);
+ }
+
+
internal ControlObject (string objectReference, IntPtr connection)
{
this.controlObject = ControlObjectClient_create(objectReference, connection);
if (this.controlObject == System.IntPtr.Zero)
throw new IedConnectionException("Control object not found", 0);
+
+ InternalCommandTerminationHandler intCommandTerminationHandler = new InternalCommandTerminationHandler (MyCommandTerminationHandler);
+
+ ControlObjectClient_setCommandTerminationHandler(controlObject, intCommandTerminationHandler, controlObject);
}
~ControlObject ()
{
- ControlObjectClient_destroy(controlObject);
+ if (this.controlObject != System.IntPtr.Zero)
+ ControlObjectClient_destroy(controlObject);
}
+ ///
+ /// Gets the control model.
+ ///
+ ///
+ /// The control model.
+ ///
public ControlModel GetControlModel ()
{
ControlModel controlModel = (ControlModel) ControlObjectClient_getControlModel(controlObject);
@@ -78,11 +187,36 @@ namespace IEC61850
return controlModel;
}
+ ///
+ /// Sets the origin parameter used by control commands.
+ ///
+ ///
+ /// Originator. An arbitrary string identifying the controlling client.
+ ///
+ ///
+ /// Originator category.
+ ///
+ public void SetOrigin (string originator, OrCat originatorCategory)
+ {
+ ControlObjectClient_setOrigin(controlObject, originator, (int) originatorCategory);
+ }
+
+ ///
+ /// Operate the control with the specified control value.
+ ///
+ /// the new value of the control
+ /// true when the operation has been successful, false otherwise
public bool Operate (bool ctlVal)
{
return Operate (ctlVal, 0);
}
+ ///
+ /// Operate the control with the specified control value (time activated control).
+ ///
+ /// the new value of the control
+ /// the time when the operation will be executed
+ /// true when the operation has been successful, false otherwise
public bool Operate (bool ctlVal, UInt64 operTime)
{
MmsValue value = new MmsValue(ctlVal);
@@ -90,11 +224,22 @@ namespace IEC61850
return Operate (value, operTime);
}
+ ///
+ /// Operate the control with the specified control value.
+ ///
+ /// the new value of the control
+ /// true when the operation has been successful, false otherwise
public bool Operate (float ctlVal)
{
return Operate (ctlVal, 0);
}
+ ///
+ /// Operate the control with the specified control value (time activated control).
+ ///
+ /// the new value of the control
+ /// the time when the operation will be executed
+ /// true when the operation has been successful, false otherwise
public bool Operate (float ctlVal, UInt64 operTime)
{
MmsValue value = new MmsValue(ctlVal);
@@ -102,11 +247,22 @@ namespace IEC61850
return Operate (value, operTime);
}
+ ///
+ /// Operate the control with the specified control value.
+ ///
+ /// the new value of the control
+ /// true when the operation has been successful, false otherwise
public bool Operate (int ctlVal)
{
return Operate (ctlVal, 0);
}
+ ///
+ /// Operate the control with the specified control value (time activated control).
+ ///
+ /// the new value of the control
+ /// the time when the operation will be executed
+ /// true when the operation has been successful, false otherwise
public bool Operate (int ctlVal, UInt64 operTime)
{
MmsValue value = new MmsValue(ctlVal);
@@ -114,15 +270,138 @@ namespace IEC61850
return Operate (value, operTime);
}
+ ///
+ /// Operate the control with the specified control value.
+ ///
+ /// the new value of the control
+ /// true when the operation has been successful, false otherwise
public bool Operate (MmsValue ctlVal)
{
return Operate (ctlVal, 0);
}
+ ///
+ /// Operate the control with the specified control value (time activated control).
+ ///
+ /// the new value of the control
+ /// the time when the operation will be executed
+ /// true when the operation has been successful, false otherwise
public bool Operate (MmsValue ctlVal, UInt64 operTime)
{
return ControlObjectClient_operate(controlObject, ctlVal.valueReference, operTime);
}
+
+ ///
+ /// Select the control object.
+ ///
+ /// true when the selection has been successful, false otherwise
+ public bool Select ()
+ {
+ return ControlObjectClient_select(controlObject);
+ }
+
+
+ ///
+ /// Send a select with value command for generic MmsValue instances
+ ///
+ ///
+ /// the value to be checked.
+ ///
+ /// true when the selection has been successful, false otherwise
+ public bool SelectWithValue (MmsValue ctlVal)
+ {
+ return ControlObjectClient_selectWithValue(controlObject, ctlVal.valueReference);
+ }
+
+ ///
+ /// Send a select with value command for boolean controls
+ ///
+ ///
+ /// the value to be checked.
+ ///
+ /// true when the selection has been successful, false otherwise
+ public bool SelectWithValue (bool ctlVal)
+ {
+ return SelectWithValue(new MmsValue(ctlVal));
+ }
+
+ ///
+ /// Send a select with value command for integer controls
+ ///
+ ///
+ /// the value to be checked.
+ ///
+ /// true when the selection has been successful, false otherwise
+ public bool SelectWithValue (int ctlVal)
+ {
+ return SelectWithValue(new MmsValue(ctlVal));
+ }
+
+ ///
+ /// Send a select with value command for float controls
+ ///
+ ///
+ /// the value to be checked.
+ ///
+ /// true when the selection has been successful, false otherwise
+ public bool SelectWithValue (float ctlVal)
+ {
+ return SelectWithValue(new MmsValue(ctlVal));
+ }
+
+ ///
+ /// Cancel a selection or time activated operation
+ ///
+ /// true when the cancelation has been successful, false otherwise
+ public bool Cancel ()
+ {
+ return ControlObjectClient_cancel(controlObject);
+ }
+
+ ///
+ /// Enables the synchro check for operate commands
+ ///
+ public void EnableSynchroCheck ()
+ {
+ ControlObjectClient_enableSynchroCheck(controlObject);
+ }
+
+ ///
+ /// Enables the interlock check for operate and select commands
+ ///
+ public void EnableInterlockCheck ()
+ {
+ ControlObjectClient_enableInterlockCheck(controlObject);
+ }
+
+ ///
+ /// Gets the last received LastApplError (Additional Cause Diagnostics) value.
+ ///
+ ///
+ /// The last appl error.
+ ///
+ public LastApplError GetLastApplError ()
+ {
+ LastApplErrorInternal lastApplError = ControlObjectClient_getLastApplError(controlObject);
+
+ return new LastApplError(lastApplError);
+ }
+
+ ///
+ /// Sets the command termination handler.
+ ///
+ ///
+ /// the handler (delegate) that is invoked when a CommandTerminationMessage is received.
+ ///
+ ///
+ /// Parameter.
+ ///
+ public void SetCommandTerminationHandler (CommandTerminationHandler handler, Object parameter)
+ {
+ this.commandTerminationHandler = handler;
+ this.commandTerminationHandlerParameter = parameter;
+ }
+
}
}
diff --git a/dotnet/IEC61850forCSharp/DataSet.cs b/dotnet/IEC61850forCSharp/DataSet.cs
index 12ec8d60..c0c887e9 100644
--- a/dotnet/IEC61850forCSharp/DataSet.cs
+++ b/dotnet/IEC61850forCSharp/DataSet.cs
@@ -24,10 +24,16 @@ using System;
using System.Runtime.InteropServices;
+using IEC61850.Common;
+
namespace IEC61850
{
namespace Client
{
+ ///
+ /// This class is used to represent a data set. It is used to store the values
+ /// of a data set.
+ ///
public class DataSet
{
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
@@ -51,6 +57,12 @@ namespace IEC61850
this.nativeObject = nativeObject;
}
+ ///
+ /// Gets the object reference of the data set
+ ///
+ ///
+ /// object reference.
+ ///
public string GetReference ()
{
if (reference == null) {
@@ -62,6 +74,15 @@ namespace IEC61850
return reference;
}
+ ///
+ /// Gets the values associated with the data set object
+ ///
+ /// This function will return the locally stored values associated with the data set.
+ /// These are the values received by the last request to the server. A call to this method doesn't
+ /// invoke a request to the server!
+ ///
+ /// The locally stored values of the data set (as MmsValue instance of type MMS_ARRAY)
+ ///
public MmsValue GetValues ()
{
if (values == null) {
@@ -73,6 +94,13 @@ namespace IEC61850
return values;
}
+
+ ///
+ /// Gets the number of elements of the data set
+ ///
+ ///
+ /// the number of elementes (data set members)
+ ///
public int GetSize ()
{
return ClientDataSet_getDataSetSize (nativeObject);
diff --git a/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs b/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs
index 60bd7952..82f133a2 100644
--- a/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs
+++ b/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs
@@ -28,8 +28,14 @@ using System.Collections;
using IEC61850.Common;
+///
+/// IEC 61850 API for the libiec61850 .NET wrapper library
+///
namespace IEC61850
{
+ ///
+ /// IEC 61850 client API.
+ ///
namespace Client
{
@@ -67,6 +73,12 @@ namespace IEC61850
[DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)]
static extern IntPtr IedConnection_create ();
+ [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)]
+ static extern void IedConnection_destroy (IntPtr self);
+
+ [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)]
+ static extern void IedConnection_setConnectTimeout(IntPtr self, UInt32 timeoutInMs);
+
[DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)]
static extern void IedConnection_connect (IntPtr self, out int error, string hostname, int tcpPort);
@@ -88,6 +100,9 @@ namespace IEC61850
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr IedConnection_getDataDirectory (IntPtr self, out int error, string dataReference);
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern IntPtr IedConnection_getDataDirectoryByFC (IntPtr self, out int error, string dataReference, FunctionalConstraint fc);
+
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr IedConnection_getDataDirectoryFC (IntPtr self, out int error, string dataReference);
@@ -100,7 +115,10 @@ namespace IEC61850
[DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)]
static extern IntPtr IedConnection_getLogicalDeviceDirectory (IntPtr self, out int error, string logicalDeviceName);
-
+ [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)]
+ static extern IntPtr IedConnection_getVariableSpecification(IntPtr self, out int error, string objectReference, int fc);
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void InternalConnectionClosedHandler (IntPtr parameter,IntPtr Iedconnection);
public delegate void ConnectionClosedHandler (IedConnection connection);
@@ -124,7 +142,19 @@ namespace IEC61850
static extern IntPtr IedConnection_getMmsConnection (IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
- static extern IntPtr MmsConnection_getIsoConnectionParameters(IntPtr mmsConnection);
+ static extern IntPtr MmsConnection_getIsoConnectionParameters(IntPtr mmsConnection);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern IntPtr IedConnection_getFileDirectory(IntPtr self, out int error, string directoryName);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern void IedConnection_deleteFile(IntPtr self, out int error, string fileName);
+
+ /********************
+ * FileDirectoryEntry
+ *********************/
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern void FileDirectoryEntry_destroy(IntPtr self);
/****************
* LinkedList
@@ -136,7 +166,16 @@ namespace IEC61850
static extern IntPtr LinkedList_getData (IntPtr self);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
- static extern void LinkedList_destroy (IntPtr self);
+ static extern void LinkedList_destroy (IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern void LinkedList_destroyStatic(IntPtr self);
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ private delegate void LinkedListValueDeleteFunction(IntPtr pointer);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern void LinkedList_destroyDeep(IntPtr list, LinkedListValueDeleteFunction valueDeleteFunction);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr LinkedList_create ();
@@ -144,7 +183,7 @@ namespace IEC61850
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void LinkedList_add (IntPtr self, IntPtr data);
- private IntPtr connection;
+ private IntPtr connection = IntPtr.Zero;
private InternalConnectionClosedHandler connectionClosedHandler;
private ConnectionClosedHandler userProvidedHandler = null;
@@ -153,6 +192,12 @@ namespace IEC61850
connection = IedConnection_create ();
}
+ ~IedConnection ()
+ {
+ if (connection != IntPtr.Zero)
+ IedConnection_destroy(connection);
+ }
+
public IsoConnectionParameters GetConnectionParameters ()
{
IntPtr mmsConnection = IedConnection_getMmsConnection(connection);
@@ -162,12 +207,32 @@ namespace IEC61850
return new IsoConnectionParameters(parameters);
}
+ private void FreeHGlobaleDeleteFunction (IntPtr pointer)
+ {
+ Marshal.FreeHGlobal(pointer);
+ }
+
+
+ private UInt32 connectTimeout = 10000;
+
+ public UInt32 ConnectTimeout {
+ get {
+ return connectTimeout;
+ }
+ set {
+ connectTimeout = value;
+ }
+ }
+
+
/// Establish an MMS connection to a server
/// This exception is thrown if there is a connection or service error
public void Connect (string hostname, int tcpPort)
{
int error;
+ IedConnection_setConnectTimeout(connection, connectTimeout);
+
IedConnection_connect (connection, out error, hostname, tcpPort);
if (error != 0)
@@ -199,19 +264,41 @@ namespace IEC61850
if (error != 0)
throw new IedConnectionException ("GetDeviceDirectory failed", error);
- IntPtr element = LinkedList_getNext (linkedList);
-
List newList = new List ();
- while (element != IntPtr.Zero) {
- string ld = Marshal.PtrToStringAnsi (LinkedList_getData (element));
+ if (fileDirectory == false) {
- newList.Add (ld);
+ IntPtr element = LinkedList_getNext (linkedList);
- element = LinkedList_getNext (element);
- }
+ while (element != IntPtr.Zero) {
+ string ld = Marshal.PtrToStringAnsi (LinkedList_getData (element));
- LinkedList_destroy (linkedList);
+ newList.Add (ld);
+
+ element = LinkedList_getNext (element);
+ }
+
+ LinkedList_destroy (linkedList);
+ }
+ else {
+
+ IntPtr element = LinkedList_getNext(linkedList);
+
+ while (element != IntPtr.Zero)
+ {
+ IntPtr elementData = LinkedList_getData(element);
+
+ FileDirectoryEntry entry = new FileDirectoryEntry(elementData);
+
+ newList.Add(entry.GetFileName());
+
+ FileDirectoryEntry_destroy(elementData);
+
+ element = LinkedList_getNext(element);
+ }
+
+ LinkedList_destroyStatic(linkedList);
+ }
return newList;
}
@@ -243,6 +330,12 @@ namespace IEC61850
return newList;
}
+ /// Get the directory of a logical node (LN)
+ /// This function returns the directory contents of a LN. Depending on the provided ACSI class
+ /// The function returns either data object references, or references of other objects like data sets,
+ /// report control blocks, ...
+ /// The object reference of a DO, SDO, or DA.
+ /// the ACSI class of the requested directory elements.
/// This exception is thrown if there is a connection or service error
public List GetLogicalNodeDirectory (string logicalNodeName, ACSIClass acsiClass)
{
@@ -270,6 +363,8 @@ namespace IEC61850
return newList;
}
+ /// Get a list of attributes (with functional constraints) of a DO, SDO, or DA
+ /// The object reference of a DO, SDO, or DA.
/// This exception is thrown if there is a connection or service error
public List GetDataDirectory (string dataReference)
{
@@ -297,6 +392,40 @@ namespace IEC61850
return newList;
}
+ /// Get the list of attributes with the specified FC of a DO, SDO, or DA
+ /// The object reference of a DO, SDO, or DA.
+ /// Functional constraint
+ /// This exception is thrown if there is a connection or service error
+ public List GetDataDirectory (string dataReference, FunctionalConstraint fc)
+ {
+ int error;
+
+ IntPtr linkedList = IedConnection_getDataDirectoryByFC (connection, out error, dataReference, fc);
+
+ if (error != 0)
+ throw new IedConnectionException ("GetDataDirectory failed", error);
+
+ IntPtr element = LinkedList_getNext (linkedList);
+
+ List newList = new List ();
+
+ while (element != IntPtr.Zero) {
+ string dataObject = Marshal.PtrToStringAnsi (LinkedList_getData (element));
+
+ newList.Add (dataObject);
+
+ element = LinkedList_getNext (element);
+ }
+
+ LinkedList_destroy (linkedList);
+
+ return newList;
+ }
+
+ /// Get a list of attributes (with functional constraints) of a DO, SDO, or DA
+ /// This function is similar to the GetDataDirectory except that the returned element names
+ /// have the functional contraint (FC) appended.
+ /// The object reference of a DO, SDO, or DA.
/// This exception is thrown if there is a connection or service error
public List GetDataDirectoryFC (string dataReference)
{
@@ -324,6 +453,23 @@ namespace IEC61850
return newList;
}
+
+ /// Read the variable specification (type description of a DA or FDCO
+ /// The object reference of a DA or FCDO.
+ /// The functional constraint (FC) of the object
+ /// This exception is thrown if there is a connection or service error
+ public MmsVariableSpecification GetVariableSpecification (string objectReference, FunctionalConstraint fc)
+ {
+ int error;
+
+ IntPtr varSpecPtr = IedConnection_getVariableSpecification(connection, out error, objectReference, (int) fc);
+
+ if (error != 0)
+ throw new IedConnectionException ("GetVariableSpecification failed", error);
+
+ return new MmsVariableSpecification(varSpecPtr, true);
+ }
+
private IntPtr readObjectInternal (string objectReference, FunctionalConstraint fc)
{
int error;
@@ -342,6 +488,7 @@ namespace IEC61850
/// Read the value of a data attribute (DA) or functional constraint data object (FCDO).
/// The object reference of a DA or FCDO.
/// The functional constraint (FC) of the object
+ /// the received value as an MmsValue instance
/// This exception is thrown if there is a connection or service error
public MmsValue ReadValue (String objectReference, FunctionalConstraint fc)
{
@@ -353,6 +500,7 @@ namespace IEC61850
/// Read the value of a basic data attribute (BDA) of type boolean.
/// The object reference of a BDA.
/// The functional constraint (FC) of the object
+ /// the received boolean value
/// This exception is thrown if there is a connection or service error
public bool ReadBooleanValue (string objectReference, FunctionalConstraint fc)
{
@@ -423,6 +571,25 @@ namespace IEC61850
}
}
+ /// Read the value of a basic data attribute (BDA) of type bit string.
+ /// The object reference of a BDA.
+ /// The functional constraint (FC) of the object
+ /// This exception is thrown if there is a connection or service error
+ public int ReadBitStringValue (string objectReference, FunctionalConstraint fc)
+ {
+ IntPtr mmsValue = readObjectInternal (objectReference, fc);
+
+ if (MmsValue_getType (mmsValue) == (int)MmsType.MMS_BIT_STRING) {
+ int bitStringValue = (int)MmsValue_getBitStringAsInteger (mmsValue);
+
+ MmsValue_delete (mmsValue);
+ return bitStringValue;
+ } else {
+ MmsValue_delete (mmsValue);
+ throw new IedConnectionException ("Result is not of type bit string", 0);
+ }
+ }
+
/// Read the value of a basic data attribute (BDA) of type timestamp (MMS_UTC_TIME).
/// The object reference of a BDA.
/// The functional constraint (FC) of the object
@@ -457,6 +624,12 @@ namespace IEC61850
throw new IedConnectionException ("Result is not of type integer (MMS_INTEGER)", 0);
}
+ /// Write the value of a data attribute (DA) or functional constraint data object (FCDO).
+ /// This function can be used to write simple or complex variables (setpoints, parameters, descriptive values...)
+ /// of the server.
+ /// The object reference of a BDA.
+ /// The functional constraint (FC) of the object
+ /// MmsValue object representing asimple or complex variable data
/// This exception is thrown if there is a connection or service error
public void WriteValue (string objectReference, FunctionalConstraint fc, MmsValue value)
{
@@ -466,8 +639,111 @@ namespace IEC61850
if (error != 0)
throw new IedConnectionException ("Write value failed", error);
- }
-
+ }
+
+ /// Read the content of a file directory.
+ /// The name of the directory.
+ /// This exception is thrown if there is a connection or service error
+ public List GetFileDirectory(string directoryName)
+ {
+ int error;
+
+ IntPtr fileEntryList = IedConnection_getFileDirectory(connection, out error, directoryName);
+
+ if (error != 0)
+ throw new IedConnectionException("Reading file directory failed", error);
+
+ List fileDirectory = new List();
+
+ IntPtr element = LinkedList_getNext(fileEntryList);
+
+ while (element != IntPtr.Zero)
+ {
+ IntPtr elementData = LinkedList_getData(element);
+
+ FileDirectoryEntry entry = new FileDirectoryEntry(elementData);
+
+ fileDirectory.Add(entry);
+
+ FileDirectoryEntry_destroy(elementData);
+
+ element = LinkedList_getNext(element);
+ }
+
+ LinkedList_destroyStatic(fileEntryList);
+
+ return fileDirectory;
+ }
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ private delegate bool InternalIedClientGetFileHandler(IntPtr parameter, IntPtr buffer, UInt32 bytesRead);
+
+ private bool iedClientGetFileHandler(IntPtr parameter, IntPtr buffer, UInt32 bytesRead)
+ {
+ GCHandle handle = GCHandle.FromIntPtr(parameter);
+
+ GetFileCallback getFileCallback = (GetFileCallback) handle.Target;
+
+ byte[] bytes = new byte[bytesRead];
+
+ Marshal.Copy(buffer, bytes, 0, (int) bytesRead);
+
+ return getFileCallback.handler(getFileCallback.parameter, bytes);
+ }
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern UInt32 IedConnection_getFile(IntPtr self, out int error, string fileName, InternalIedClientGetFileHandler handler,
+ IntPtr handlerParameter);
+
+
+ public delegate bool GetFileHandler(object parameter, byte[] data);
+
+ private class GetFileCallback
+ {
+ public GetFileCallback(GetFileHandler handler, object parameter)
+ {
+ this.handler = handler;
+ this.parameter = parameter;
+ }
+
+ public GetFileHandler handler;
+ public object parameter;
+ }
+
+ ///
+ /// Download a file from the server.
+ ///
+ ///
+ /// File name of the file (full path)
+ ///
+ ///
+ /// Callback handler that is invoked for each chunk of the file received
+ ///
+ ///
+ /// User provided parameter that is passed to the callback handler
+ ///
+ public void GetFile(string fileName, GetFileHandler handler, object parameter)
+ {
+ int error;
+
+ GetFileCallback getFileCallback = new GetFileCallback(handler, parameter);
+
+ GCHandle handle = GCHandle.Alloc(getFileCallback);
+
+ IedConnection_getFile(connection, out error, fileName, new InternalIedClientGetFileHandler(iedClientGetFileHandler),
+ GCHandle.ToIntPtr(handle));
+
+ if (error != 0)
+ throw new IedConnectionException("Error reading file", error);
+
+ handle.Free();
+ }
+
+ ///
+ /// Abort (close) the connection.
+ ///
+ /// This function will send an abort request to the server. This will immediately interrupt the
+ /// connection.
/// This exception is thrown if there is a connection or service error
public void Abort ()
{
@@ -479,6 +755,11 @@ namespace IEC61850
throw new IedConnectionException ("Abort failed", error);
}
+ ///
+ /// Release (close) the connection.
+ ///
+ /// This function will send an release request to the server. The function will block until the
+ /// connection is released or an error occured.
/// This exception is thrown if there is a connection or service error
public void Release ()
{
@@ -490,6 +771,12 @@ namespace IEC61850
throw new IedConnectionException ("Release failed", error);
}
+ ///
+ /// Immediately close the connection.
+ ///
+ /// This function will close the connnection to the server by closing the TCP connection.
+ /// The client will not send an abort or release request as required by the specification!
+ /// This exception is thrown if there is a connection or service error
public void Close ()
{
IedConnection_close(connection);
@@ -501,6 +788,14 @@ namespace IEC61850
userProvidedHandler (this);
}
+ ///
+ /// Install a callback handler that will be invoked if the connection is closed.
+ ///
+ /// The handler is called when the connection is closed no matter if the connection was closed
+ /// by the client or by the server. Any new call to this function will replace the callback handler installed
+ /// by a prior function call.
+ /// The user provided callback handler
+ /// This exception is thrown if there is a connection or service error
public void InstallConnectionClosedHandler (ConnectionClosedHandler handler)
{
connectionClosedHandler = new InternalConnectionClosedHandler (MyConnectionClosedHandler);
@@ -510,6 +805,28 @@ namespace IEC61850
IedConnection_installConnectionClosedHandler (connection, connectionClosedHandler, connection);
}
+ ///
+ /// Read the values of a data set (GetDataSetValues service).
+ ///
+ /// This function will invoke a readDataSetValues service and return a new DataSet value containing the
+ /// received values.
+ /// The object reference of the data set
+
+ /// This exception is thrown if there is a connection or service error
+ public DataSet GetDataSetValues (string dataSetReference)
+ {
+ return ReadDataSetValues(dataSetReference, null);
+ }
+
+ ///
+ /// Read the values of a data set (GetDataSetValues service).
+ ///
+ /// This function will invoke a readDataSetValues service and return a new DataSet value containing the
+ /// received values. If an existing instance of DataSet is provided to the function the existing instance will be
+ /// updated by the new values.
+ /// The object reference of the data set
+ /// The object reference of an existing data set instance or null
+ /// a DataSet instance containing the received values
/// This exception is thrown if there is a connection or service error
public DataSet ReadDataSetValues (string dataSetReference, DataSet dataSet)
{
@@ -531,6 +848,14 @@ namespace IEC61850
return dataSet;
}
+ ///
+ /// Create a new data set.
+ ///
+ /// This function creates a new data set at the server. The data set consists of the members defined
+ /// by the list of object references provided.
+ /// The object reference of the data set
+ /// A list of object references of the data set elements
+ /// This exception is thrown if there is a connection or service error
public void CreateDataSet (string dataSetReference, List dataSetElements)
{
IntPtr linkedList = LinkedList_create ();
@@ -545,13 +870,20 @@ namespace IEC61850
IedConnection_createDataSet (connection, out error, dataSetReference, linkedList);
- LinkedList_destroy (linkedList);
+ LinkedList_destroyDeep(linkedList, new LinkedListValueDeleteFunction(FreeHGlobaleDeleteFunction));
if (error != 0)
throw new IedConnectionException ("Failed to create data set", error);
}
+ ///
+ /// Delete a data set.
+ ///
+ /// This function will delete a data set at the server. This function may fail if the data set is not
+ /// deletable.
+ /// The object reference of the data set
+ /// This exception is thrown if there is a connection or service error
public void DeleteDataSet (string dataSetReference)
{
int error;
@@ -615,7 +947,45 @@ namespace IEC61850
{
return (IedClientError)this.errorCode;
}
- }
+ }
+
+ public class FileDirectoryEntry
+ {
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern IntPtr FileDirectoryEntry_getFileName(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern UInt32 FileDirectoryEntry_getFileSize(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ private static extern UInt64 FileDirectoryEntry_getLastModified(IntPtr self);
+
+ private string fileName;
+ private UInt32 fileSize;
+ private UInt64 lastModified;
+
+ internal FileDirectoryEntry(IntPtr nativeFileDirectoryEntry)
+ {
+ fileName = Marshal.PtrToStringAnsi(FileDirectoryEntry_getFileName(nativeFileDirectoryEntry));
+ fileSize = FileDirectoryEntry_getFileSize(nativeFileDirectoryEntry);
+ lastModified = FileDirectoryEntry_getLastModified(nativeFileDirectoryEntry);
+ }
+
+ public string GetFileName()
+ {
+ return fileName;
+ }
+
+ public UInt32 GetFileSize()
+ {
+ return fileSize;
+ }
+
+ public UInt64 GetLastModified()
+ {
+ return lastModified;
+ }
+ }
public enum IedClientError
{
@@ -680,10 +1050,15 @@ namespace IEC61850
[Flags]
public enum TriggerOptions {
NONE = 0,
+ /** send report when value of data changed */
DATA_CHANGED = 1,
+ /** send report when quality of data changed */
QUALITY_CHANGED = 2,
+ /** send report when data or quality is updated */
DATA_UPDATE = 4,
+ /** periodic transmission of all data set values */
INTEGRITY = 8,
+ /** general interrogation (on client request) */
GI = 16
}
@@ -708,6 +1083,9 @@ namespace IEC61850
QUESTIONABLE = 3
}
+ ///
+ /// The quality of a data object.
+ ///
public class Quality
{
@@ -740,16 +1118,27 @@ namespace IEC61850
public enum ACSIClass
{
+ /** data objects */
ACSI_CLASS_DATA_OBJECT,
+ /** data sets (container for multiple data objects) */
ACSI_CLASS_DATA_SET,
+ /** buffered report control blocks */
ACSI_CLASS_BRCB,
+ /** unbuffered report control blocks */
ACSI_CLASS_URCB,
+ /** log control blocks */
ACSI_CLASS_LCB,
+ /** logs (journals) */
ACSI_CLASS_LOG,
+ /** setting group control blocks */
ACSI_CLASS_SGCB,
+ /** GOOSE control blocks */
ACSI_CLASS_GoCB,
+ /** GSE control blocks */
ACSI_CLASS_GsCB,
+ /** multicast sampled values control blocks */
ACSI_CLASS_MSVCB,
+ /** unicast sampled values control blocks */
ACSI_CLASS_USVCB
}
@@ -785,5 +1174,89 @@ namespace IEC61850
NONE = -1
}
+ public enum ControlAddCause {
+ ADD_CAUSE_UNKNOWN = 0,
+ ADD_CAUSE_NOT_SUPPORTED = 1,
+ ADD_CAUSE_BLOCKED_BY_SWITCHING_HIERARCHY = 2,
+ ADD_CAUSE_SELECT_FAILED = 3,
+ ADD_CAUSE_INVALID_POSITION = 4,
+ ADD_CAUSE_POSITION_REACHED = 5,
+ ADD_CAUSE_PARAMETER_CHANGE_IN_EXECUTION = 6,
+ ADD_CAUSE_STEP_LIMIT = 7,
+ ADD_CAUSE_BLOCKED_BY_MODE = 8,
+ ADD_CAUSE_BLOCKED_BY_PROCESS = 9,
+ ADD_CAUSE_BLOCKED_BY_INTERLOCKING = 10,
+ ADD_CAUSE_BLOCKED_BY_SYNCHROCHECK = 11,
+ ADD_CAUSE_COMMAND_ALREADY_IN_EXECUTION = 12,
+ ADD_CAUSE_BLOCKED_BY_HEALTH = 13,
+ ADD_CAUSE_1_OF_N_CONTROL = 14,
+ ADD_CAUSE_ABORTION_BY_CANCEL = 15,
+ ADD_CAUSE_TIME_LIMIT_OVER = 16,
+ ADD_CAUSE_ABORTION_BY_TRIP = 17,
+ ADD_CAUSE_OBJECT_NOT_SELECTED = 18,
+ ADD_CAUSE_OBJECT_ALREADY_SELECTED = 19,
+ ADD_CAUSE_NO_ACCESS_AUTHORITY = 20,
+ ADD_CAUSE_ENDED_WITH_OVERSHOOT = 21,
+ ADD_CAUSE_ABORTION_DUE_TO_DEVIATION = 22,
+ ADD_CAUSE_ABORTION_BY_COMMUNICATION_LOSS = 23,
+ ADD_CAUSE_ABORTION_BY_COMMAND = 24,
+ ADD_CAUSE_NONE = 25,
+ ADD_CAUSE_INCONSISTENT_PARAMETERS = 26,
+ ADD_CAUSE_LOCKED_BY_OTHER_CLIENT = 27
+ }
+
+ ///
+ /// Object reference. Helper function to handle object reference strings.
+ ///
+ public static class ObjectReference {
+
+ ///
+ /// Get the name part of an object reference with appended FC
+ ///
+ ///
+ /// The element name.
+ ///
+ ///
+ /// Object reference with appended fc.
+ ///
+ public static string getElementName (string objectReferenceWithFc)
+ {
+ int fcPartStartIndex = objectReferenceWithFc.IndexOf('[');
+
+ if (fcPartStartIndex == -1)
+ return objectReferenceWithFc;
+
+ return objectReferenceWithFc.Substring(0, fcPartStartIndex);
+ }
+
+ ///
+ /// Get the FC of an object reference with appended FC.
+ ///
+ ///
+ /// The FC
+ ///
+ ///
+ /// Object reference with FC.
+ ///
+ public static FunctionalConstraint getFC (string objectReferenceWithFc)
+ {
+ int fcPartStartIndex = objectReferenceWithFc.IndexOf('[');
+
+ if (fcPartStartIndex == -1)
+ return FunctionalConstraint.NONE;
+
+ string fcString = objectReferenceWithFc.Substring(fcPartStartIndex + 1 , 2);
+
+ try
+ {
+ return (FunctionalConstraint) Enum.Parse(typeof(FunctionalConstraint), fcString);
+ }
+ catch(ArgumentException)
+ {
+ return FunctionalConstraint.NONE;
+ }
+ }
+ }
+
}
}
diff --git a/dotnet/IEC61850forCSharp/IEC61850forCSharp.csproj b/dotnet/IEC61850forCSharp/IEC61850forCSharp.csproj
index 5c0e30c3..535e22ab 100644
--- a/dotnet/IEC61850forCSharp/IEC61850forCSharp.csproj
+++ b/dotnet/IEC61850forCSharp/IEC61850forCSharp.csproj
@@ -40,6 +40,7 @@
+
\ No newline at end of file
diff --git a/dotnet/IEC61850forCSharp/IsoConnectionParameters.cs b/dotnet/IEC61850forCSharp/IsoConnectionParameters.cs
index 22aa246a..342dbc30 100644
--- a/dotnet/IEC61850forCSharp/IsoConnectionParameters.cs
+++ b/dotnet/IEC61850forCSharp/IsoConnectionParameters.cs
@@ -30,12 +30,26 @@ namespace IEC61850
{
public enum AcseAuthenticationMechanism {
+ /** don't use authentication */
ACSE_AUTH_NONE = 0,
+ /** use password authentication */
ACSE_AUTH_PASSWORD = 1
}
+ ///
+ /// Connection parameters associated with the ISO protocol layers (transport, session, presentation, ACSE)
+ ///
public class IsoConnectionParameters
{
+
+ [StructLayout(LayoutKind.Sequential)]
+ private struct NativeTSelector
+ {
+ public byte size;
+
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst=4)] public byte[] value;
+ }
+
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
private static extern void IsoConnectionParameters_destroy(IntPtr self);
@@ -43,13 +57,13 @@ namespace IEC61850
private static extern void IsoConnectionParameters_setRemoteApTitle(IntPtr self, string apTitle, int aeQualifier);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
- private static extern void IsoConnectionParameters_setRemoteAddresses(IntPtr self, UInt32 pSelector, UInt16 sSelector, UInt16 tSelector);
+ private static extern void IsoConnectionParameters_setRemoteAddresses(IntPtr self, UInt32 pSelector, UInt16 sSelector, NativeTSelector tSelector);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
private static extern void IsoConnectionParameters_setLocalApTitle(IntPtr self, string apTitle, int aeQualifier);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
- private static extern void IsoConnectionParameters_setLocalAddresses(IntPtr self, UInt32 pSelector, UInt16 sSelector, UInt16 tSelector);
+ private static extern void IsoConnectionParameters_setLocalAddresses(IntPtr self, UInt32 pSelector, UInt16 sSelector, NativeTSelector tSelector);
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
private static extern void IsoConnectionParameters_setAcseAuthenticationParameter(IntPtr self, IntPtr acseAuthParameter);
@@ -80,29 +94,97 @@ namespace IEC61850
if (authParameter != IntPtr.Zero)
AcseAuthenticationParameter_destroy(authParameter);
- IsoConnectionParameters_destroy(self);
+ //IsoConnectionParameters_destroy(self);
}
+ ///
+ /// Sets the remote ap title related parameters
+ ///
+ ///
+ /// remote AP title.
+ ///
+ ///
+ /// remote AE qualifier.
+ ///
public void SetRemoteApTitle(string apTitle, int aeQualifier)
{
IsoConnectionParameters_setRemoteApTitle(self, apTitle, aeQualifier);
}
- public void SetRemoteAddresses (UInt32 pSelector, UInt16 sSelector, UInt16 tSelector)
+ ///
+ /// Sets the remote addresses for ISO layers (transport, session, presentation)
+ ///
+ ///
+ /// presentation layer address
+ ///
+ ///
+ /// session layer address
+ ///
+ ///
+ /// ISO COTP transport layer address
+ ///
+ public void SetRemoteAddresses (UInt32 pSelector, UInt16 sSelector, byte[] tSelector)
{
- IsoConnectionParameters_setRemoteAddresses(self, pSelector, sSelector, tSelector);
+ if (tSelector.Length > 4)
+ throw new ArgumentOutOfRangeException("tSelector", "maximum size (4) exceeded");
+
+ NativeTSelector nativeTSelector;
+ nativeTSelector.size = (byte) tSelector.Length;
+ nativeTSelector.value = new byte[4];
+
+ for (int i = 0; i < tSelector.Length; i++)
+ nativeTSelector.value[i] = tSelector[i];
+
+ IsoConnectionParameters_setRemoteAddresses(self, pSelector, sSelector, nativeTSelector);
}
+ ///
+ /// Sets the local ap title related parameters
+ ///
+ ///
+ /// local AP title.
+ ///
+ ///
+ /// local AE qualifier.
+ ///
public void SetLocalApTitle (string apTitle, int aeQualifier)
{
IsoConnectionParameters_setLocalApTitle(self, apTitle, aeQualifier);
}
- public void SetLocalAddresses (UInt32 pSelector, UInt16 sSelector, UInt16 tSelector)
+ ///
+ /// Sets the local addresses for ISO layers (transport, session, presentation)
+ ///
+ ///
+ /// presentation layer address
+ ///
+ ///
+ /// session layer address
+ ///
+ ///
+ /// ISO COTP transport layer address
+ ///
+ public void SetLocalAddresses (UInt32 pSelector, UInt16 sSelector, byte[] tSelector)
{
- IsoConnectionParameters_setLocalAddresses(self, pSelector, sSelector, tSelector);
+ if (tSelector.Length > 4)
+ throw new ArgumentOutOfRangeException("tSelector", "maximum size (4) exceeded");
+
+ NativeTSelector nativeTSelector;
+ nativeTSelector.size = (byte) tSelector.Length;
+ nativeTSelector.value = new byte[4];
+
+ for (int i = 0; i < tSelector.Length; i++)
+ nativeTSelector.value[i] = tSelector[i];
+
+ IsoConnectionParameters_setLocalAddresses(self, pSelector, sSelector, nativeTSelector);
}
+ ///
+ /// Instruct ACSE layer to use password authentication.
+ ///
+ ///
+ /// Password that will be used to authenticate the client
+ ///
public void UsePasswordAuthentication (string password)
{
if (authParameter == IntPtr.Zero) {
diff --git a/dotnet/IEC61850forCSharp/MmsValue.cs b/dotnet/IEC61850forCSharp/MmsValue.cs
index 7d54894a..0ab8c06b 100644
--- a/dotnet/IEC61850forCSharp/MmsValue.cs
+++ b/dotnet/IEC61850forCSharp/MmsValue.cs
@@ -25,12 +25,16 @@ using System;
using System.Runtime.InteropServices;
using System.Collections.Generic;
-using System.Collections;
+using System.Collections;
+using System.Text;
namespace IEC61850
{
- namespace Client
+ namespace Common
{
+ ///
+ /// This class is used to hold MMS data values of different types.
+ ///
public class MmsValue : IEnumerable
{
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
@@ -48,6 +52,18 @@ namespace IEC61850
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern UInt32 MmsValue_getBitStringAsInteger (IntPtr self);
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern void MmsValue_setBitStringFromInteger(IntPtr self, UInt32 intValue);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern int MmsValue_getBitStringSize(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern void MmsValue_setBitStringBit(IntPtr self, int bitPos, bool value);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern bool MmsValue_getBitStringBit(IntPtr self, int bitPos);
+
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern Int32 MmsValue_toInt32 (IntPtr self);
@@ -87,9 +103,37 @@ namespace IEC61850
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr MmsValue_newIntegerFromInt32 (Int32 integer);
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern IntPtr MmsValue_newUnsignedFromUint32(UInt32 integer);
+
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr MmsValue_newIntegerFromInt64 (Int64 integer);
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern IntPtr MmsValue_newBitString(int bitSize);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern IntPtr MmsValue_newVisibleString(string value);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern IntPtr MmsValue_newOctetString(int size, int maxSize);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern void MmsValue_setOctetString(IntPtr self, [Out] byte[] buf, int size);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern UInt16 MmsValue_getOctetStringSize(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern UInt16 MmsValue_getOctetStringMaxSize(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern IntPtr MmsValue_getOctetStringBuffer(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern bool MmsValue_equals(IntPtr self, IntPtr otherValue);
+
+
internal MmsValue (IntPtr value)
{
valueReference = value;
@@ -122,33 +166,165 @@ namespace IEC61850
valueReference = MmsValue_newIntegerFromInt32 (value);
}
+ public MmsValue (UInt32 value)
+ {
+ valueReference = MmsValue_newUnsignedFromUint32(value);
+ }
+
public MmsValue (long value)
{
valueReference = MmsValue_newIntegerFromInt64 (value);
}
+ public MmsValue (string value)
+ {
+ valueReference = MmsValue_newVisibleString(value);
+ }
+
~MmsValue ()
{
if (responsableForDeletion)
MmsValue_delete (valueReference);
}
+ ///
+ /// Create a new MmsValue instance of type MMS_BIT_STRING.
+ ///
+ ///
+ /// the new MmsValue instance
+ ///
+ ///
+ /// the size of the bit string in bits.
+ ///
+ public static MmsValue NewBitString(int bitSize)
+ {
+ IntPtr newValue = MmsValue_newBitString(bitSize);
+
+ return new MmsValue(newValue, true);
+ }
+
+ ///
+ /// Create a new MmsValue instance of type MMS_OCTET_STRING.
+ ///
+ ///
+ /// the new MmsValue instance
+ ///
+ ///
+ /// the maximum size of the octet string in bytes
+ ///
+ ///
+ /// the current size of the octet string in bytes (defaults to 0)
+ ///
+ public static MmsValue NewOctetString (int maxSize, int size = 0)
+ {
+ IntPtr newValue = MmsValue_newOctetString(size, maxSize);
+
+ return new MmsValue(newValue, true);
+ }
+
internal IntPtr valueReference;
private bool responsableForDeletion;
+ ///
+ /// Gets the type of the value
+ ///
+ ///
+ /// The type.
+ ///
public new MmsType GetType ()
{
return (MmsType)MmsValue_getType (valueReference);
}
+ ///
+ /// Gets the size of an array, structure, or bit string
+ ///
+ ///
+ ///
+ /// Return the size of an array of structure (number of elements)
+ /// The value has to be of type MMS_ARRAY, MMS_STRUCTURE, MMS_BIT_STRING ...
+ ///
+ /// the number of elements (array/structure elements, octets, bits depending on type)
+ ///
+ /// This exception is thrown if the value has the wrong type.
public int Size ()
{
if ((GetType () == MmsType.MMS_ARRAY) || (GetType () == MmsType.MMS_STRUCTURE)) {
return MmsValue_getArraySize (valueReference);
- } else
- throw new MmsValueException ("Value is not a complex type");
+ } else if (GetType () == MmsType.MMS_BIT_STRING) {
+ return MmsValue_getBitStringSize(valueReference);
+ }
+ else if (GetType () == MmsType.MMS_OCTET_STRING) {
+ return MmsValue_getOctetStringSize(valueReference);
+ }
+ else
+ throw new MmsValueException ("Operation not supported for this type");
+ }
+
+ ///
+ /// Gets the maximum size of an octet string
+ ///
+ ///
+ /// The maximum size (in bytes) of the octet string
+ ///
+ public int MaxSize ()
+ {
+ if (GetType () == MmsType.MMS_OCTET_STRING) {
+ return MmsValue_getOctetStringMaxSize(valueReference);
+ }
+ else
+ throw new MmsValueException ("Operation not supported for this type");
}
+ ///
+ /// Gets the octet string as byte array
+ ///
+ /// Instance has to be of type MMS_OCTET_STRING.
+ ///
+ ///
+ /// Byte array containing the bytes of the octet string.
+ ///
+ /// This exception is thrown if the value has the wrong type.
+ public byte[] getOctetString ()
+ {
+ if (GetType () == MmsType.MMS_OCTET_STRING) {
+ IntPtr buffer = MmsValue_getOctetStringBuffer(valueReference);
+ int bufferSize = this.Size();
+
+ byte[] octetString = new byte[bufferSize];
+
+ Marshal.Copy(buffer, octetString, 0, bufferSize);
+
+ return octetString;
+ }
+ else
+ throw new MmsValueException ("Operation not supported for this type");
+ }
+
+ public void setOctetString (byte[] octetString)
+ {
+ if (GetType () == MmsType.MMS_OCTET_STRING) {
+
+ if (this.MaxSize() < octetString.Length)
+ throw new MmsValueException("octet string is to large");
+
+ MmsValue_setOctetString(valueReference, octetString, octetString.Length);
+ }
+ else
+ throw new MmsValueException ("Operation not supported for this type");
+ }
+
+ ///
+ /// Get an element of an array or structure
+ ///
+ ///
+ /// the MmsValue element.
+ ///
+ ///
+ /// index of the element starting with 0
+ ///
+ /// This exception is thrown if the value has the wrong type.
+ /// This exception is thrown if the index is out of range.
public MmsValue GetElement (int index)
{
MmsType type = GetType ();
@@ -163,6 +339,17 @@ namespace IEC61850
throw new MmsValueException ("Value is of wrong type");
}
+ ///
+ /// Gets the timestamp value as UTC time in s (UNIX time stamp).
+ ///
+ ///
+ /// Return the value as seconds since epoch (1.1.1970 UTC).
+ /// The value has to be of type MMS_UTC_TIME.
+ ///
+ ///
+ /// The UTC time in seconds (UNIX time stamp).
+ ///
+ /// This exception is thrown if the value has the wrong type.
public UInt32 ToUnixTimestamp ()
{
if (GetType () == MmsType.MMS_UTC_TIME)
@@ -171,6 +358,17 @@ namespace IEC61850
throw new MmsValueException ("Value is not a time type");
}
+ ///
+ /// Gets the timestamp value as UTC time in ms.
+ ///
+ ///
+ /// Return the value as milliseconds since epoch (1.1.1970 UTC).
+ /// The value has to be of type MMS_UTC_TIME.
+ ///
+ ///
+ /// The UTC time in ms.
+ ///
+ /// This exception is thrown if the value has the wrong type.
public ulong GetUtcTimeInMs ()
{
if (GetType () == MmsType.MMS_UTC_TIME) {
@@ -179,13 +377,33 @@ namespace IEC61850
throw new MmsValueException ("Value is not a time type");
}
+ ///
+ /// Convert a millisecond time (milliseconds since epoch) to DataTimeOffset
+ ///
+ ///
+ /// The time as DataTimeOffset
+ ///
+ ///
+ /// the millisecond time
+ ///
public static DateTimeOffset MsTimeToDateTimeOffset (UInt64 msTime)
{
DateTimeOffset retVal = new DateTimeOffset (1970, 1, 1, 0, 0, 0, TimeSpan.Zero);
- return retVal.AddMilliseconds (msTime);
+ return retVal.AddMilliseconds ((double) msTime);
}
+ ///
+ /// Convert MMS_UTC_TIME to DateTimeOffset instance
+ ///
+ ///
+ /// Return the value as DateTimeOffset instance.
+ /// The value has to be of type MMS_UTC_TIME.
+ ///
+ ///
+ /// the value as DataTimeOffset instance
+ ///
+ /// This exception is thrown if the value has the wrong type.
public DateTimeOffset GetUtcTimeAsDateTimeOffset ()
{
if (GetType () == MmsType.MMS_UTC_TIME)
@@ -194,36 +412,123 @@ namespace IEC61850
throw new MmsValueException ("Value is not a time type");
}
+
+ ///
+ /// Return the value as 32 bit signed integer.
+ ///
+ ///
+ /// Return the value as 32 bit signed integer (Int32).
+ /// The value has to be of type MMS_INTEGER.
+ ///
+ ///
+ /// the value if the object as 32 bit signed integer
+ ///
+ /// This exception is thrown if the value has the wrong type.
public Int32 ToInt32 ()
{
if (GetType () != MmsType.MMS_INTEGER)
throw new MmsValueException ("Value type is not integer");
- Int32 retVal = MmsValue_toInt32 (valueReference);
-
- return retVal;
+ return MmsValue_toInt32 (valueReference);
}
+ ///
+ /// Return the value as 64 bit signed integer.
+ ///
+ ///
+ /// Return the value as 64 bit signed integer (Int64).
+ /// The value has to be of type MMS_INTEGER.
+ ///
+ ///
+ /// the value if the object as 64 bit signed integer
+ ///
+ /// This exception is thrown if the value has the wrong type.
public Int64 ToInt64 ()
{
if (GetType () != MmsType.MMS_INTEGER)
throw new MmsValueException ("Value type is not integer");
- Int64 retVal = MmsValue_toInt64 (valueReference);
-
- return retVal;
+ return MmsValue_toInt64 (valueReference);
}
+ ///
+ /// Return the value as 32 bit unsigned integer.
+ ///
+ ///
+ /// Return the value as 32 bit unsigned integer (Int32).
+ /// The value has to be of type MMS_INTEGER.
+ ///
+ ///
+ /// the value if the object as 32 bit unsigned integer
+ ///
+ /// This exception is thrown if the value has the wrong type.
public UInt32 ToUint32 ()
{
if (GetType () != MmsType.MMS_UNSIGNED)
throw new MmsValueException ("Value type is not unsigned");
- UInt32 retVal = MmsValue_toUint32 (valueReference);
+ return MmsValue_toUint32 (valueReference);
+ }
+
+ public UInt32 BitStringToUInt32 ()
+ {
+ if (GetType () != MmsType.MMS_BIT_STRING)
+ throw new MmsValueException("Value type is not bit string");
+
+ return MmsValue_getBitStringAsInteger(valueReference);
+ }
- return retVal;
+ public void BitStringFromUInt32 (UInt32 intValue)
+ {
+ if (GetType () != MmsType.MMS_BIT_STRING)
+ throw new MmsValueException("Value type is not bit string");
+
+ MmsValue_setBitStringFromInteger(valueReference, intValue);
}
+ public void SetBit (int bitPos, bool bitValue)
+ {
+ if (GetType () != MmsType.MMS_BIT_STRING)
+ throw new MmsValueException("Value type is not bit string");
+
+ MmsValue_setBitStringBit(valueReference, bitPos, bitValue);
+ }
+
+ public bool GetBit (int bitPos)
+ {
+ if (GetType () != MmsType.MMS_BIT_STRING)
+ throw new MmsValueException("Value type is not bit string");
+
+ return MmsValue_getBitStringBit(valueReference, bitPos);
+ }
+
+ private string GetBitStringAsString()
+ {
+ if (GetType() != MmsType.MMS_BIT_STRING)
+ throw new MmsValueException("Value type is not bit string");
+
+ int size = Size();
+
+ StringBuilder builder = new StringBuilder(size);
+
+ for (int i = 0; i < size; i++)
+ {
+ if (MmsValue_getBitStringBit(valueReference, i))
+ builder.Append('1');
+ else
+ builder.Append('0');
+ }
+
+ return builder.ToString();
+ }
+
+ ///
+ /// Gets the boolean value
+ ///
+ ///
+ /// The boolean value
+ ///
+ /// This exception is thrown if the value has the wrong type.
public bool GetBoolean ()
{
if (GetType () == MmsType.MMS_BOOLEAN)
@@ -232,6 +537,13 @@ namespace IEC61850
throw new MmsValueException ("Value type is not boolean");
}
+ ///
+ /// Gets the float value of an MMS_FLOAT instance
+ ///
+ ///
+ /// The float value
+ ///
+ /// This exception is thrown if the value has the wrong type.
public float ToFloat ()
{
if (GetType () == MmsType.MMS_FLOAT)
@@ -240,6 +552,13 @@ namespace IEC61850
throw new MmsValueException ("Value type is not float");
}
+ ///
+ /// Gets the double value of an MMS_FLOAT instance
+ ///
+ ///
+ /// The float value
+ ///
+ /// This exception is thrown if the value has the wrong type.
public double ToDouble ()
{
if (GetType () == MmsType.MMS_FLOAT)
@@ -248,6 +567,13 @@ namespace IEC61850
throw new MmsValueException ("Value type is not float");
}
+ public override bool Equals (object obj)
+ {
+ MmsValue otherValue = (MmsValue) obj;
+
+ return MmsValue_equals(this.valueReference, otherValue.valueReference);
+ }
+
// override standard ToString() method
public override string ToString ()
{
@@ -265,6 +591,8 @@ namespace IEC61850
return ToDouble ().ToString ();
case MmsType.MMS_UTC_TIME:
return GetUtcTimeAsDateTimeOffset ().ToString ();
+ case MmsType.MMS_BIT_STRING:
+ return GetBitStringAsString();
default:
return "unknown";
}
@@ -321,21 +649,37 @@ namespace IEC61850
public enum MmsType
{
+ /** array type (multiple elements of the same type) */
MMS_ARRAY = 0,
+ /** structure type (multiple elements of different types) */
MMS_STRUCTURE = 1,
+ /** boolean */
MMS_BOOLEAN = 2,
+ /** bit string */
MMS_BIT_STRING = 3,
+ /** signed integer */
MMS_INTEGER = 4,
+ /** unsigned integer */
MMS_UNSIGNED = 5,
+ /** floating point value (32 or 64 bit) */
MMS_FLOAT = 6,
+ /** octet string */
MMS_OCTET_STRING = 7,
+ /** visible string - ANSI string */
MMS_VISIBLE_STRING = 8,
+ /** Generalized time */
MMS_GENERALIZED_TIME = 9,
+ /** Binary time */
MMS_BINARY_TIME = 10,
+ /** Binary coded decimal (BCD) - not used */
MMS_BCD = 11,
+ /** object ID - not used */
MMS_OBJ_ID = 12,
+ /** Unicode string */
MMS_STRING = 13,
+ /** UTC time */
MMS_UTC_TIME = 14,
+ /** will be returned in case of an error (contains error code) */
MMS_DATA_ACCESS_ERROR = 15
}
diff --git a/dotnet/IEC61850forCSharp/MmsVariableSpecification.cs b/dotnet/IEC61850forCSharp/MmsVariableSpecification.cs
new file mode 100644
index 00000000..159f10e6
--- /dev/null
+++ b/dotnet/IEC61850forCSharp/MmsVariableSpecification.cs
@@ -0,0 +1,201 @@
+/*
+ * MmsVariableSpecification.cs
+ *
+ * Copyright 2014 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.Collections.Generic;
+
+using System.Collections;
+
+namespace IEC61850
+{
+ namespace Common
+ {
+ ///
+ /// MMS variable specification. This class is used to represent an MMS variable type definition.
+ ///
+ public class MmsVariableSpecification : IEnumerable
+ {
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern void MmsVariableSpecification_destroy(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern IntPtr MmsVariableSpecification_getChildValue(IntPtr self, IntPtr value, string childId);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern IntPtr MmsVariableSpecification_getNamedVariableRecursive(IntPtr variable, string nameId);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern int MmsVariableSpecification_getType(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern IntPtr MmsVariableSpecification_getName(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern int MmsVariableSpecification_getSize(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern IntPtr MmsVariableSpecification_getChildSpecificationByIndex(IntPtr self, int index);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern IntPtr MmsVariableSpecification_getArrayElementSpecification(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern int MmsVariableSpecification_getExponentWidth(IntPtr self);
+
+ private IntPtr self;
+ private bool responsableForDeletion;
+
+ internal MmsVariableSpecification (IntPtr self)
+ {
+ this.self = self;
+ this.responsableForDeletion = false;
+ }
+
+ internal MmsVariableSpecification (IntPtr self, bool responsableForDeletion)
+ {
+ this.self = self;
+ this.responsableForDeletion = responsableForDeletion;
+ }
+
+ ~MmsVariableSpecification ()
+ {
+ if (responsableForDeletion)
+ MmsVariableSpecification_destroy(self);
+ }
+
+ ///
+ /// Gets the MmsValue type of the variable
+ ///
+ ///
+ /// The MmsType of the variable
+ ///
+ public new MmsType GetType ()
+ {
+ return (MmsType) MmsVariableSpecification_getType(self);
+ }
+
+ ///
+ /// Gets the type of the array elements.
+ ///
+ ///
+ /// The array element type.
+ ///
+ /// This exception is thrown if the value is not of type MMS_ARRAY
+ public MmsVariableSpecification getArrayElementType ()
+ {
+ if (GetType() == MmsType.MMS_ARRAY) {
+ IntPtr varSpecPtr = MmsVariableSpecification.MmsVariableSpecification_getArrayElementSpecification(self);
+ return new MmsVariableSpecification(varSpecPtr);
+ }
+ else
+ throw new MmsValueException ("specification is of wrong type");
+ }
+
+ ///
+ /// Gets the element specification of a structure element
+ ///
+ ///
+ /// The element of the structure at given index
+ ///
+ ///
+ /// Index.
+ ///
+ public MmsVariableSpecification GetElement (int index)
+ {
+ if (GetType () == MmsType.MMS_STRUCTURE) {
+
+ if ((index >= 0) && (index < Size ())) {
+ IntPtr varSpecPtr = MmsVariableSpecification_getChildSpecificationByIndex(self, index);
+ return new MmsVariableSpecification(varSpecPtr);
+ }
+ else
+ throw new MmsValueException ("Index out of bounds");
+ }
+ else
+ throw new MmsValueException ("specification is of wrong type");
+ }
+
+ ///
+ /// Gets the name of the variable
+ ///
+ ///
+ /// The name.
+ ///
+ public string GetName ()
+ {
+ IntPtr namePtr = MmsVariableSpecification_getName(self);
+
+ return Marshal.PtrToStringAnsi (namePtr);
+ }
+
+ ///
+ /// Get the "size" of the variable (array size, number of structure elements ...)
+ ///
+ public int Size ()
+ {
+ return MmsVariableSpecification_getSize(self);
+ }
+
+ IEnumerator IEnumerable.GetEnumerator ()
+ {
+ return new MmsVariableSpecificationEnumerator (this);
+ }
+
+ private class MmsVariableSpecificationEnumerator : IEnumerator
+ {
+ private MmsVariableSpecification value;
+ private int index = -1;
+
+ public MmsVariableSpecificationEnumerator (MmsVariableSpecification value)
+ {
+ this.value = value;
+ }
+
+ #region IEnumerator Members
+ public void Reset ()
+ {
+ index = -1;
+ }
+
+ public object Current {
+
+ get { return value.GetElement (index);}
+ }
+
+ public bool MoveNext ()
+ {
+ index++;
+
+ if (index >= value.Size ())
+ return false;
+ else
+ return true;
+ }
+
+ #endregion
+ }
+
+ }
+ }
+}
diff --git a/dotnet/IEC61850forCSharp/ReportControlBlock.cs b/dotnet/IEC61850forCSharp/ReportControlBlock.cs
index e86ffae1..de66949d 100644
--- a/dotnet/IEC61850forCSharp/ReportControlBlock.cs
+++ b/dotnet/IEC61850forCSharp/ReportControlBlock.cs
@@ -31,8 +31,19 @@ namespace IEC61850
namespace Client
{
+ ///
+ /// Report handler.
+ ///
public delegate void ReportHandler (Report report, object parameter);
+ ///
+ /// Report control block (RCB) representation.
+ ///
+ ///
+ /// This class is used as a client side representation (copy) of a report control block (RCB).
+ /// Values from the server will only be read when the GetRCBValues method is called.
+ /// Values at the server are only affected when the SetRCBValues method is called.
+ ///
public class ReportControlBlock
{
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
@@ -133,12 +144,11 @@ namespace IEC61850
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern void IedConnection_installReportHandler (IntPtr connection, string rcbReference, string rptId, InternalReportHandler handler,
- IntPtr handlerParameter);
-
+ IntPtr handlerParameter);
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void InternalReportHandler (IntPtr parameter, IntPtr report);
-
-
private IntPtr self;
private IntPtr connection;
private string objectReference;
@@ -183,8 +193,6 @@ namespace IEC61850
private void internalReportHandler (IntPtr parameter, IntPtr report)
{
- Console.WriteLine ("internalReportHandler called " + this);
-
try {
if (this.report == null)
@@ -207,20 +215,42 @@ namespace IEC61850
this.objectReference = objectReference;
}
+ ///
+ /// Installs the report handler.
+ ///
+ ///
+ /// This will install a callback handler (delegate) that is invoked whenever a report
+ /// related this RCB is received. Any call of this method will replace an previously registered
+ /// handler!
+ ///
+ ///
+ /// report handler
+ ///
+ ///
+ /// parameter is passed to the handler when the handler is invoked.
+ ///
public void InstallReportHandler (ReportHandler reportHandler, object parameter)
{
this.reportHandler = new ReportHandler(reportHandler);
- Console.WriteLine("Installed report handler " + this.reportHandler);
-
this.reportHandlerParameter = parameter;
if (reportHandlerInstalled == false) {
- IedConnection_installReportHandler (this.connection, objectReference, this.GetRptId (), new InternalReportHandler(internalReportHandler), IntPtr.Zero);
+
+ string reportId = this.GetRptId ();
+
+// if ((GetRptId() == null) || (GetRptId().Length == 0))
+// reportId =
+
+ IedConnection_installReportHandler (this.connection, objectReference, reportId, new InternalReportHandler(internalReportHandler), IntPtr.Zero);
reportHandlerInstalled = true;
}
}
+ ///
+ /// Read all RCB values from the server
+ ///
+ /// This exception is thrown if there is a connection or service error
public void GetRCBValues ()
{
int error;
@@ -231,84 +261,142 @@ namespace IEC61850
throw new IedConnectionException ("getRCBValues service failed", error);
}
+ ///
+ /// Write changed RCB values to the server.
+ ///
+ ///
+ /// This function will only write the RCB values that were set by one of the setter methods.
+ /// The RCB values are sent by a single MMS write request.
+ ///
+ /// This exception is thrown if there is a connection or service error
public void SetRCBValues ()
{
SetRCBValues (true);
}
+ ///
+ /// Write changed RCB values to the server.
+ ///
+ ///
+ /// This function will only write the RCB values that were set by one of the setter methods.
+ ///
+ /// This exception is thrown if there is a connection or service error
+ ///
+ /// If true the values are sent by single MMS write request. Otherwise the values are all sent by their own MMS write requests.
+ ///
public void SetRCBValues (bool singleRequest)
- {
- UInt32 parametersMask = 0;
+ {
+ UInt32 parametersMask = 0;
- if (flagRptId)
- parametersMask += 1;
+ if (flagRptId)
+ parametersMask += 1;
- if (flagRptEna)
- parametersMask += 2;
+ if (flagRptEna)
+ parametersMask += 2;
- if (flagResv)
- parametersMask += 4;
+ if (flagResv)
+ parametersMask += 4;
- if (flagDataSetReference)
- parametersMask += 8;
+ if (flagDataSetReference)
+ parametersMask += 8;
- if (flagConfRev)
- parametersMask += 16;
+ if (flagConfRev)
+ parametersMask += 16;
- if (flagOptFlds)
- parametersMask += 32;
+ if (flagOptFlds)
+ parametersMask += 32;
- if (flagBufTm)
- parametersMask += 64;
+ if (flagBufTm)
+ parametersMask += 64;
- if (flagSqNum)
- parametersMask += 128;
+ if (flagSqNum)
+ parametersMask += 128;
- if (flagTrgOps)
- parametersMask += 256;
+ if (flagTrgOps)
+ parametersMask += 256;
- if (flagIntgPd)
- parametersMask += 512;
+ if (flagIntgPd)
+ parametersMask += 512;
- if (flagGI)
- parametersMask += 1024;
+ if (flagGI)
+ parametersMask += 1024;
- if (flagPurgeBuf)
- parametersMask += 2048;
+ if (flagPurgeBuf)
+ parametersMask += 2048;
- if (flagEntryId)
- parametersMask += 4096;
+ if (flagEntryId)
+ parametersMask += 4096;
- if (flagResvTms)
- parametersMask += 16384;
+ if (flagResvTms)
+ parametersMask += 16384;
- int error;
+ int error;
- IedConnection_setRCBValues (connection, out error, self, parametersMask, singleRequest);
+ IedConnection_setRCBValues (connection, out error, self, parametersMask, singleRequest);
- if (error != 0)
- throw new IedConnectionException ("setRCBValues service failed", error);
+ if (error != 0)
+ throw new IedConnectionException ("setRCBValues service failed", error);
+
+ if (flagRptId) {
+
+ if (reportHandlerInstalled) {
+ reportHandlerInstalled = false;
+ InstallReportHandler(this.reportHandler, this.reportHandlerParameter);
+ }
+ }
+
+ resetSendFlags();
}
+ ///
+ /// Determines whether this instance is a buffered or unbuffered RCB.
+ ///
+ ///
+ /// true if this instance is a buffered RCB; otherwise, false.
+ ///
public bool IsBuffered ()
{
return ClientReportControlBlock_isBuffered (self);
}
- public UInt64 getEntryTime ()
+ ///
+ /// Gets the entry time of the RCB as ms time
+ ///
+ ///
+ /// The entry time is the timestamp of the last report sent.
+ ///
+ ///
+ /// The entry time as ms timestamp
+ ///
+ public UInt64 GetEntryTime ()
{
return ClientReportControlBlock_getEntryTime (self);
}
+ ///
+ /// Gets the entry time of the RCB as DateTimeOffset
+ ///
+ ///
+ /// The entry time is the timestamp of the last report sent.
+ ///
+ ///
+ /// The entry time as DataTimeOffset
+ ///
public DateTimeOffset GetEntryTimeAsDateTimeOffset ()
{
- UInt64 entryTime = getEntryTime ();
+ UInt64 entryTime = GetEntryTime ();
DateTimeOffset retVal = new DateTimeOffset (1970, 1, 1, 0, 0, 0, TimeSpan.Zero);
return retVal.AddMilliseconds (entryTime);
}
+ ///
+ /// Gets the data set reference of the associated data set
+ ///
+ ///
+ /// The data set reference.
+ ///
public string GetDataSetReference ()
{
IntPtr dataSetRefPtr = ClientReportControlBlock_getDataSetReference (self);
@@ -316,6 +404,12 @@ namespace IEC61850
return Marshal.PtrToStringAnsi (dataSetRefPtr);
}
+ ///
+ /// Sets the data set reference. Use this method to select the associated data set for the RCB
+ ///
+ ///
+ /// The data set reference.
+ ///
public void SetDataSetReference (string dataSetReference)
{
ClientReportControlBlock_setDataSetReference (self, dataSetReference);
@@ -323,6 +417,12 @@ namespace IEC61850
flagDataSetReference = true;
}
+ ///
+ /// Gets the report identifier.
+ ///
+ ///
+ /// The report identifier.
+ ///
public string GetRptId ()
{
IntPtr rptIdPtr = ClientReportControlBlock_getRptId (self);
@@ -330,22 +430,58 @@ namespace IEC61850
return Marshal.PtrToStringAnsi (rptIdPtr);
}
+ ///
+ /// Sets the RptId (report ID) of the RCB
+ ///
+ ///
+ /// The new RptId
+ ///
+ public void SetRptId (string rptId)
+ {
+ ClientReportControlBlock_setRptId(self, rptId);
+ flagRptId = true;
+ }
+
+ ///
+ /// Check if reporting is currently enabled
+ ///
+ ///
+ /// true, if reporting is enabled, false otherwise
+ ///
public bool GetRptEna ()
{
return ClientReportControlBlock_getRptEna (self);
}
+ ///
+ /// Sets report enable flag. Use this to enable reporting
+ ///
+ ///
+ /// true to enable reporting, false to disable
+ ///
public void SetRptEna (bool rptEna)
{
ClientReportControlBlock_setRptEna (self, rptEna);
flagRptEna = true;
}
+ ///
+ /// Gets the buffer time.
+ ///
+ ///
+ /// The buffer time in ms.
+ ///
public UInt32 GetBufTm()
{
return ClientReportControlBlock_getBufTm (self);
}
+ ///
+ /// Sets the buffer time.
+ ///
+ ///
+ /// Buffer time is ms.
+ ///
public void SetBufTm (UInt32 bufTm)
{
ClientReportControlBlock_setBufTm (self, bufTm);
@@ -353,33 +489,80 @@ namespace IEC61850
flagBufTm = true;
}
+ ///
+ /// Gets the GI flag
+ ///
+ ///
+ /// true, if GI flag is set
+ ///
public bool GetGI ()
{
return ClientReportControlBlock_getGI (self);
}
+ ///
+ /// Sets the GI flag. Use this to trigger a GI (general interrogation) command.
+ ///
+ ///
+ /// request general interrogation of true
+ ///
public void SetGI (bool GI)
{
ClientReportControlBlock_setGI (self, GI);
flagGI = true;
}
+ ///
+ /// Check if RCB is reserved by a client
+ ///
+ ///
+ /// true, the RCB is reserver by a client
+ ///
public bool GetResv ()
{
return ClientReportControlBlock_getResv (self);
}
+ ///
+ /// Gets the configuration revision of the RCB
+ ///
+ ///
+ /// The conf rev.
+ ///
+ public UInt32 GetConfRev ()
+ {
+ return ClientReportControlBlock_getConfRev (self);
+ }
+
+ ///
+ /// Sets RESV flag. Use this to reserve (allocate) this RCB.
+ ///
+ ///
+ /// true: reserver this RCB for exclusive use
+ ///
public void SetResv (bool resv)
{
ClientReportControlBlock_setResv (self, resv);
flagResv = true;
}
+ ///
+ /// Gets the trigger options of the RCB
+ ///
+ ///
+ /// trigger options
+ ///
public TriggerOptions GetTrgOps()
{
return (TriggerOptions) ClientReportControlBlock_getTrgOps (self);
}
+ ///
+ /// Sets the trigger options of the RCB.
+ ///
+ ///
+ /// trigger options
+ ///
public void SetTrgOps(TriggerOptions trgOps)
{
ClientReportControlBlock_setTrgOps (self, (int) trgOps);
@@ -387,22 +570,46 @@ namespace IEC61850
flagTrgOps = true;
}
+ ///
+ /// Gets the integrity period
+ ///
+ ///
+ /// integrity period in ms
+ ///
public UInt32 GetIntgPd ()
{
return ClientReportControlBlock_getIntgPd (self);
}
+ ///
+ /// Sets the integrity period
+ ///
+ ///
+ /// integrity period in ms
+ ///
public void SetIntgPd (UInt32 intgPd)
{
ClientReportControlBlock_setIntgPd (self, intgPd);
flagIntgPd = true;
}
+ ///
+ /// Gets the option fields.
+ ///
+ ///
+ /// The option fields
+ ///
public ReportOptions GetOptFlds()
{
return (ReportOptions) ClientReportControlBlock_getOptFlds (self);
}
+ ///
+ /// Sets the option field. Used to enable or disable optional report elements
+ ///
+ ///
+ /// Option field.
+ ///
public void SetOptFlds(ReportOptions optFlds)
{
ClientReportControlBlock_setOptFlds (self, (int)optFlds);
diff --git a/dotnet/IEC61850forCSharp/Reporting.cs b/dotnet/IEC61850forCSharp/Reporting.cs
index 3cdd9d1e..4bade8e5 100644
--- a/dotnet/IEC61850forCSharp/Reporting.cs
+++ b/dotnet/IEC61850forCSharp/Reporting.cs
@@ -23,13 +23,15 @@
using System;
using System.Runtime.InteropServices;
+using IEC61850.Common;
+
namespace IEC61850
{
namespace Client
{
public partial class IedConnection
{
- public ReportControlBlock getReportControlBlock (string rcbObjectReference)
+ public ReportControlBlock GetReportControlBlock (string rcbObjectReference)
{
return new ReportControlBlock (rcbObjectReference, connection);
}
@@ -59,6 +61,9 @@ namespace IEC61850
REASON_UNKNOWN = 6
}
+ ///
+ /// A class to hold the contents of a received report
+ ///
public class Report
{
@@ -74,6 +79,37 @@ namespace IEC61850
[DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
static extern int ClientReport_getReasonForInclusion(IntPtr self, int elementIndex);
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern bool ClientReport_hasSeqNum(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern UInt16 ClientReport_getSeqNum(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern bool ClientReport_hasDataSetName(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern bool ClientReport_hasReasonForInclusion(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern bool ClientReport_hasConfRev(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern UInt32 ClientReport_getConfRev(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern bool ClientReport_hasBufOvfl(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern bool ClientReport_hasDataReference(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern IntPtr ClientReport_getRcbReference(IntPtr self);
+
+ [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)]
+ static extern IntPtr ClientReport_getRptId(IntPtr self);
+
+
private IntPtr self;
private IntPtr dataSetValues = IntPtr.Zero;
@@ -85,11 +121,23 @@ namespace IEC61850
this.self = self;
}
+ ///
+ /// Determines whether the report has a timestamp.
+ ///
+ ///
+ /// true if this report has a timestamp; otherwise, false.
+ ///
public bool HasTimestamp ()
{
return ClientReport_hasTimestamp (self);
}
+ ///
+ /// Gets the timestamp.
+ ///
+ ///
+ /// The timestamp as milliseconds since 1.1.1970 UTC 00:00 or 0 if no timestamp is present.
+ ///
public UInt64 GetTimestamp ()
{
if (HasTimestamp ())
@@ -98,6 +146,52 @@ namespace IEC61850
return 0;
}
+ public bool HasDataSetName ()
+ {
+ return ClientReport_hasDataSetName(self);
+ }
+
+ public bool HasDataReference ()
+ {
+ return ClientReport_hasDataReference(self);
+ }
+
+ public bool HasConfRev ()
+ {
+ return ClientReport_hasConfRev(self);
+ }
+
+ public UInt32 GetConfRev ()
+ {
+ return ClientReport_getConfRev(self);
+ }
+
+ public bool HasBufOvfl ()
+ {
+ return ClientReport_hasBufOvfl(self);
+ }
+
+ public bool HasSeqNum ()
+ {
+ return ClientReport_hasSeqNum(self);
+ }
+
+ public UInt16 GetSeqNum ()
+ {
+ return ClientReport_getSeqNum(self);
+ }
+
+ public bool HasReasonForInclusion ()
+ {
+ return ClientReport_hasReasonForInclusion(self);
+ }
+
+ ///
+ /// Gets the data set values as MMS_ARRAY instance.
+ ///
+ ///
+ /// The data set values.
+ ///
public MmsValue GetDataSetValues ()
{
if (dataSetValues == IntPtr.Zero) {
@@ -112,6 +206,15 @@ namespace IEC61850
return values;
}
+ ///
+ /// Gets the reason for inclusion of data set member with the given index
+ ///
+ ///
+ /// The reason for inclusion.
+ ///
+ ///
+ /// index of the data set member in the data set
+ ///
public ReasonForInclusion GetReasonForInclusion (int index)
{
if (values == null) {
@@ -129,6 +232,23 @@ namespace IEC61850
return (ReasonForInclusion) ClientReport_getReasonForInclusion(self, index);
}
+ public string GetRcbReference ()
+ {
+ IntPtr rcbRef = ClientReport_getRcbReference(self);
+
+ return Marshal.PtrToStringAnsi (rcbRef);
+ }
+
+ public string GetRptId ()
+ {
+ IntPtr rptId = ClientReport_getRptId(self);
+
+ if (rptId == IntPtr.Zero)
+ return GetRcbReference();
+ else
+ return Marshal.PtrToStringAnsi (rptId);
+ }
+
}
}
diff --git a/dotnet/control/ControlExample.cs b/dotnet/control/ControlExample.cs
index 8da9f4cd..1ca2b515 100644
--- a/dotnet/control/ControlExample.cs
+++ b/dotnet/control/ControlExample.cs
@@ -2,12 +2,19 @@ using System;
using System.Collections.Generic;
using IEC61850.Common;
using IEC61850.Client;
+using System.Threading;
namespace control
{
class ControlExample
{
+ private static void commandTerminationHandler (Object parameter, ControlObject control)
+ {
+ LastApplError lastApplError = control.GetLastApplError();
+ Console.WriteLine("HANDLER CALLED! " + lastApplError.addCause);
+ }
+
public static void Main (string[] args)
{
IedConnection con = new IedConnection ();
@@ -25,7 +32,8 @@ namespace control
{
con.Connect(hostname, 102);
- string objectReference = "IEDM1CPUBHKW/DRCC1.DERStr";
+ /* direct control with normal security */
+ string objectReference = "simpleIOGenericIO/GGIO1.SPCSO1";
ControlObject control = con.CreateControlObject(objectReference);
@@ -33,9 +41,27 @@ namespace control
Console.WriteLine(objectReference + " has control model " + controlModel.ToString());
+ if (controlModel != ControlModel.CONTROL_MODEL_STATUS_ONLY)
+ control.Operate(true);
+
if (!control.Operate(true))
Console.WriteLine("operate failed!");
+ /* direct control with enhanced security */
+ objectReference = "simpleIOGenericIO/GGIO1.SPCSO3";
+ control = con.CreateControlObject(objectReference);
+
+ controlModel = control.GetControlModel();
+ Console.WriteLine(objectReference + " has control model " + controlModel.ToString());
+
+ if (controlModel == ControlModel.CONTROL_MODEL_DIRECT_ENHANCED) {
+ control.SetCommandTerminationHandler(commandTerminationHandler, null);
+
+ control.Operate(true);
+
+ Thread.Sleep(1000);
+ }
+
con.Abort();
diff --git a/dotnet/datasets/DataSetExample.cs b/dotnet/datasets/DataSetExample.cs
index f6a11493..bd73cd54 100644
--- a/dotnet/datasets/DataSetExample.cs
+++ b/dotnet/datasets/DataSetExample.cs
@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using IEC61850.Client;
+using IEC61850.Common;
namespace datasets
{
@@ -16,7 +17,7 @@ namespace datasets
if (args.Length > 0)
hostname = args[0];
else
- hostname = "10.0.2.2";
+ hostname = "localhost";
Console.WriteLine("Connect to " + hostname);
@@ -31,7 +32,6 @@ namespace datasets
Console.WriteLine("LD: " + entry);
}
-
// create a new data set
List dataSetElements = new List();
@@ -49,7 +49,6 @@ namespace datasets
Console.WriteLine("DS element: " + entry);
}
-
// read the values of the newly created data set
DataSet dataSet = con.ReadDataSetValues("IEDM1CPUBHKW/LLN0.ds1", null);
diff --git a/dotnet/dotnet.sln b/dotnet/dotnet.sln
index 8265db95..e781ee8a 100644
--- a/dotnet/dotnet.sln
+++ b/dotnet/dotnet.sln
@@ -19,6 +19,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "authenticate", "authenticat
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "tests", "tests\tests.csproj", "{FBDFE530-DBEB-474B-BA54-9AB287DD57B3}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "files", "files\files.csproj", "{77127456-19B9-4D1A-AEF9-40F8D1C5695E}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "example3", "example3\example3.csproj", "{5E5D0FE0-DF44-48D8-A10E-1FB07D34DEA2}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -37,6 +41,14 @@ Global
{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
{59B85486-F48D-4978-BD35-8F5C3A8288D4}.Release|Any CPU.Build.0 = Release|Any CPU
+ {5E5D0FE0-DF44-48D8-A10E-1FB07D34DEA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {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
+ {77127456-19B9-4D1A-AEF9-40F8D1C5695E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {77127456-19B9-4D1A-AEF9-40F8D1C5695E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {77127456-19B9-4D1A-AEF9-40F8D1C5695E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {77127456-19B9-4D1A-AEF9-40F8D1C5695E}.Release|Any CPU.Build.0 = Release|Any CPU
{9E29B4CE-EE5F-4CA6-85F6-5D1FF8B27BF8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9E29B4CE-EE5F-4CA6-85F6-5D1FF8B27BF8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9E29B4CE-EE5F-4CA6-85F6-5D1FF8B27BF8}.Release|Any CPU.ActiveCfg = Release|Any CPU
diff --git a/dotnet/example3/AssemblyInfo.cs b/dotnet/example3/AssemblyInfo.cs
new file mode 100644
index 00000000..8fa9151c
--- /dev/null
+++ b/dotnet/example3/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("example3")]
+[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/example3/Main.cs b/dotnet/example3/Main.cs
new file mode 100644
index 00000000..5f04ce98
--- /dev/null
+++ b/dotnet/example3/Main.cs
@@ -0,0 +1,48 @@
+using System;
+using IEC61850.Client;
+using System.Collections.Generic;
+
+namespace example3
+{
+ class MainClass
+ {
+ public static void Main (string[] args)
+ {
+ IedConnection con = new IedConnection ();
+
+ string hostname;
+
+ if (args.Length > 0)
+ hostname = args[0];
+ else
+ hostname = "localhost";
+
+ Console.WriteLine("Connect to " + hostname);
+
+
+ try
+ {
+ IsoConnectionParameters parameters = con.GetConnectionParameters();
+
+ parameters.SetRemoteAddresses(1,1, new byte[] {0x00, 0x01, 0x02, 0x03});
+
+ con.ConnectTimeout = 10000;
+
+ con.Connect(hostname, 102);
+
+ List serverDirectory = con.GetServerDirectory(false);
+
+ foreach (string entry in serverDirectory)
+ {
+ Console.WriteLine("LD: " + entry);
+ }
+
+ con.Release();
+ }
+ catch (IedConnectionException e)
+ {
+ Console.WriteLine(e.Message);
+ }
+ }
+ }
+}
diff --git a/dotnet/example3/example3.csproj b/dotnet/example3/example3.csproj
new file mode 100644
index 00000000..7a1f9d03
--- /dev/null
+++ b/dotnet/example3/example3.csproj
@@ -0,0 +1,45 @@
+
+
+
+ Debug
+ AnyCPU
+ 10.0.0
+ 2.0
+ {5E5D0FE0-DF44-48D8-A10E-1FB07D34DEA2}
+ Exe
+ example3
+ example3
+
+
+ true
+ full
+ false
+ bin\Debug
+ DEBUG;
+ prompt
+ 4
+ true
+
+
+ none
+ true
+ bin\Release
+ prompt
+ 4
+ true
+
+
+
+
+
+
+
+
+
+
+
+ {C35D624E-5506-4560-8074-1728F1FA1A4D}
+ IEC61850forCSharp
+
+
+
\ No newline at end of file
diff --git a/dotnet/files/AssemblyInfo.cs b/dotnet/files/AssemblyInfo.cs
new file mode 100644
index 00000000..1133bf62
--- /dev/null
+++ b/dotnet/files/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("files")]
+[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/files/FileServicesExample.cs b/dotnet/files/FileServicesExample.cs
new file mode 100644
index 00000000..ccc94a0a
--- /dev/null
+++ b/dotnet/files/FileServicesExample.cs
@@ -0,0 +1,89 @@
+using System;
+using System.Collections.Generic;
+
+using IEC61850.Client;
+using IEC61850.Common;
+using System.IO;
+
+namespace files
+{
+ class MainClass
+ {
+ public static void printFiles (IedConnection con, string prefix, string parent)
+ {
+ List files = con.GetFileDirectory (parent);
+
+ foreach (FileDirectoryEntry file in files) {
+ Console.WriteLine(prefix + file.GetFileName() + "\t" + file.GetFileSize() + "\t" +
+ MmsValue.MsTimeToDateTimeOffset(file.GetLastModified()));
+
+ if (file.GetFileName().EndsWith("/")) {
+ printFiles (con, prefix + " ", parent + file.GetFileName());
+ }
+ }
+
+ }
+
+ static bool getFileHandler (object parameter, byte[] data)
+ {
+ Console.WriteLine("received " + data.Length + " bytes");
+
+ BinaryWriter binWriter = (BinaryWriter) parameter;
+
+ binWriter.Write(data);
+
+ return true;
+ }
+
+
+ public static void Main (string[] args)
+ {
+ IedConnection con = new IedConnection ();
+
+ string hostname;
+
+ if (args.Length > 0)
+ hostname = args[0];
+ else
+ hostname = "10.0.2.2";
+
+ Console.WriteLine("Connect to " + hostname);
+
+ try
+ {
+ con.Connect(hostname, 102);
+
+ Console.WriteLine ("Files in server root directory:");
+ List serverDirectory = con.GetServerDirectory(true);
+
+ foreach (string entry in serverDirectory) {
+ Console.WriteLine(entry);
+ }
+
+ Console.WriteLine();
+
+ Console.WriteLine ("File directory tree at server:");
+ printFiles(con, "", "");
+ Console.WriteLine();
+
+ string filename = "IEDSERVER.BIN";
+
+ Console.WriteLine("Download file " + filename);
+
+ /* Download file from server and write it to a new local file */
+ FileStream fs = new FileStream(filename, FileMode.Create);
+ BinaryWriter w = new BinaryWriter(fs);
+
+ con.GetFile(filename, new IedConnection.GetFileHandler(getFileHandler), w);
+
+ fs.Close();
+
+ con.Abort();
+ }
+ catch (IedConnectionException e)
+ {
+ Console.WriteLine(e.Message);
+ }
+ }
+ }
+}
diff --git a/dotnet/files/files.csproj b/dotnet/files/files.csproj
new file mode 100644
index 00000000..348f8045
--- /dev/null
+++ b/dotnet/files/files.csproj
@@ -0,0 +1,45 @@
+
+
+
+ Debug
+ AnyCPU
+ 10.0.0
+ 2.0
+ {77127456-19B9-4D1A-AEF9-40F8D1C5695E}
+ Exe
+ files
+ files
+
+
+ true
+ full
+ false
+ bin\Debug
+ DEBUG;
+ prompt
+ 4
+ true
+
+
+ none
+ true
+ bin\Release
+ prompt
+ 4
+ true
+
+
+
+
+
+
+
+
+
+
+
+ {C35D624E-5506-4560-8074-1728F1FA1A4D}
+ IEC61850forCSharp
+
+
+
\ No newline at end of file
diff --git a/dotnet/model_browsing/ModelBrowsing.cs b/dotnet/model_browsing/ModelBrowsing.cs
index 71bc1b39..ce4f7fec 100644
--- a/dotnet/model_browsing/ModelBrowsing.cs
+++ b/dotnet/model_browsing/ModelBrowsing.cs
@@ -51,6 +51,27 @@ namespace model_browsing
foreach (string dataObject in dataObjects) {
Console.WriteLine(" DO: " + dataObject);
+
+ List dataDirectory = con.GetDataDirectoryFC(logicalNodeReference + "." + dataObject);
+
+ foreach (string dataDirectoryElement in dataDirectory) {
+
+ string daReference = logicalNodeReference + "." + dataObject + "." + ObjectReference.getElementName(dataDirectoryElement);
+
+ // get the type specification of a variable
+ MmsVariableSpecification specification = con.GetVariableSpecification(daReference, ObjectReference.getFC(dataDirectoryElement));
+
+ Console.WriteLine (" DA/SDO: [" + ObjectReference.getFC(dataDirectoryElement) + "] " +
+ ObjectReference.getElementName(dataDirectoryElement) + " : " + specification.GetType()
+ + "(" + specification.Size() + ")");
+
+ if (specification.GetType() == MmsType.MMS_STRUCTURE) {
+ foreach (MmsVariableSpecification elementSpec in specification) {
+ Console.WriteLine(" " + elementSpec.GetName() + " : " + elementSpec.GetType());
+ }
+ }
+ }
+
}
// discover data sets
diff --git a/dotnet/reporting/ReportingExample.cs b/dotnet/reporting/ReportingExample.cs
index 1f93ad49..dceb88bd 100644
--- a/dotnet/reporting/ReportingExample.cs
+++ b/dotnet/reporting/ReportingExample.cs
@@ -27,6 +27,10 @@ namespace reporting
}
}
+ ReportControlBlock rcb = (ReportControlBlock) parameter;
+
+ Console.WriteLine("Buffered: " + rcb.IsBuffered());
+
}
@@ -48,13 +52,14 @@ namespace reporting
try {
con.Connect (hostname, 102);
- string rcbReference = "simpleIOGenericIO/LLN0.RP.EventsRCB";
+ string rcbReference = "simpleIOGenericIO/LLN0.RP.EventsRCB01";
- ReportControlBlock rcb = con.getReportControlBlock(rcbReference);
+ ReportControlBlock rcb = con.GetReportControlBlock(rcbReference);
rcb.GetRCBValues();
- rcb.InstallReportHandler(reportHandler, null);
+ // note: the second parameter is not required!
+ rcb.InstallReportHandler(reportHandler, rcb);
if (rcb.IsBuffered())
Console.WriteLine ("RCB: " + rcbReference + " is buffered");
diff --git a/dotnet/tests/Test.cs b/dotnet/tests/Test.cs
index 35a78b9f..c5b03c02 100644
--- a/dotnet/tests/Test.cs
+++ b/dotnet/tests/Test.cs
@@ -15,6 +15,65 @@ namespace tests
Assert.AreEqual (10.0f, val.ToFloat ());
}
+
+ [Test ()]
+ public void MmsValueBitString ()
+ {
+ var val = MmsValue.NewBitString(10);
+
+ Assert.AreEqual (MmsType.MMS_BIT_STRING, val.GetType());
+ Assert.AreEqual (10, val.Size());
+
+ val.BitStringFromUInt32(7);
+
+ Assert.AreEqual(7, val.BitStringToUInt32());
+
+ Assert.AreEqual(true, val.GetBit(0));
+ Assert.AreEqual(true, val.GetBit(1));
+ Assert.AreEqual(true, val.GetBit(2));
+ Assert.AreEqual(false, val.GetBit(3));
+
+ Assert.AreEqual(false, val.GetBit(9));
+
+ Assert.AreEqual(false, val.GetBit(10));
+
+ val.SetBit(3, true);
+ Assert.AreEqual(true, val.GetBit(3));
+
+ Assert.AreEqual(15, val.BitStringToUInt32());
+
+ val.SetBit(3, false);
+ Assert.AreEqual(7, val.BitStringToUInt32());
+ }
+
+ [Test()]
+ public void MmsValueOctetString ()
+ {
+ var val = MmsValue.NewOctetString(20);
+
+ Assert.AreEqual (0, val.Size());
+ Assert.AreEqual (20, val.MaxSize());
+
+ byte[] octetString = val.getOctetString();
+
+ Assert.AreEqual (0, octetString.Length);
+
+ octetString = new byte[5];
+ octetString[0] = 0x11;
+ octetString[1] = 0x12;
+ octetString[2] = 0x13;
+ octetString[3] = 0x14;
+ octetString[4] = 0x15;
+
+ val.setOctetString(octetString);
+
+ Assert.AreEqual(5, val.Size());
+
+ byte[] secondOctetString = val.getOctetString();
+
+ Assert.AreEqual(octetString, secondOctetString);
+ }
+
}
}
diff --git a/dotnet/tests/tests.csproj b/dotnet/tests/tests.csproj
index fffb7f87..76e97b72 100644
--- a/dotnet/tests/tests.csproj
+++ b/dotnet/tests/tests.csproj
@@ -21,7 +21,7 @@
false
- full
+ none
true
bin\Release
prompt
@@ -30,7 +30,9 @@
-
+
+ nunit
+
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index 3c52875b..5bc51cf5 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -8,7 +8,9 @@ add_subdirectory(server_example_control)
add_subdirectory(server_example_dynamic)
add_subdirectory(server_example_config_file)
add_subdirectory(server_example_complex_array)
+add_subdirectory(server_example_threadless)
add_subdirectory(server_example_61400_25)
+add_subdirectory(server_example_setting_groups)
add_subdirectory(iec61850_client_example1)
add_subdirectory(iec61850_client_example2)
add_subdirectory(iec61850_client_example3)
diff --git a/examples/Makefile b/examples/Makefile
index e2168aef..1b83d6ac 100644
--- a/examples/Makefile
+++ b/examples/Makefile
@@ -21,6 +21,8 @@ EXAMPLE_DIRS += server_example_config_file
EXAMPLE_DIRS += server_example_dynamic
EXAMPLE_DIRS += server_example_complex_array
EXAMPLE_DIRS += server_example_61400_25
+EXAMPLE_DIRS += server_example_threadless
+EXAMPLE_DIRS += server_example_setting_groups
EXAMPLE_DIRS += goose_subscriber
EXAMPLE_DIRS += goose_publisher
EXAMPLE_DIRS += mms_utility
diff --git a/examples/goose_publisher/goose_publisher_example.c b/examples/goose_publisher/goose_publisher_example.c
index 494fb497..47b0390a 100644
--- a/examples/goose_publisher/goose_publisher_example.c
+++ b/examples/goose_publisher/goose_publisher_example.c
@@ -23,11 +23,23 @@ main(int argc, char** argv)
LinkedList_add(dataSetValues, MmsValue_newBinaryTime(false));
LinkedList_add(dataSetValues, MmsValue_newIntegerFromInt32(5678));
- GoosePublisher publisher = GoosePublisher_create(NULL, "eth0");
+ CommParameters gooseCommParameters;
- GoosePublisher_setGoCbRef(publisher, "Test1/LLN0$GO$gocb1");
+ gooseCommParameters.appId = 1000;
+ gooseCommParameters.dstAddress[0] = 0x01;
+ gooseCommParameters.dstAddress[1] = 0x0c;
+ gooseCommParameters.dstAddress[2] = 0xcd;
+ gooseCommParameters.dstAddress[3] = 0x01;
+ gooseCommParameters.dstAddress[4] = 0x00;
+ gooseCommParameters.dstAddress[5] = 0x01;
+ gooseCommParameters.vlanId = 0;
+ gooseCommParameters.vlanPriority = 4;
+
+ GoosePublisher publisher = GoosePublisher_create(&gooseCommParameters, "eth0");
+
+ GoosePublisher_setGoCbRef(publisher, "simpleIOGenericIO/LLN0$GO$gcbAnalogValues");
GoosePublisher_setConfRev(publisher, 1);
- GoosePublisher_setDataSetRef(publisher, "Test1/LLN0$dataset1");
+ GoosePublisher_setDataSetRef(publisher, "simpleIOGenericIO/LLN0$AnalogValues");
int i = 0;
diff --git a/examples/goose_subscriber/goose_subscriber_example.c b/examples/goose_subscriber/goose_subscriber_example.c
index 09fe5688..00fd888c 100644
--- a/examples/goose_subscriber/goose_subscriber_example.c
+++ b/examples/goose_subscriber/goose_subscriber_example.c
@@ -6,8 +6,8 @@
* Has to be started as root in Linux.
*/
-#include "goose_subscriber.h"
-#include "thread.h"
+#include "goose_receiver.h"
+#include "hal_thread.h"
#include
#include
@@ -28,7 +28,7 @@ gooseListener(GooseSubscriber subscriber, void* parameter)
printf(" stNum: %u sqNum: %u\n", GooseSubscriber_getStNum(subscriber),
GooseSubscriber_getSqNum(subscriber));
printf(" timeToLive: %u\n", GooseSubscriber_getTimeAllowedToLive(subscriber));
- printf(" timestamp: %"PRIu64"\n", GooseSubscriber_getTimestamp(subscriber));
+ printf(" timestamp: %llu\n", GooseSubscriber_getTimestamp(subscriber));
MmsValue* values = GooseSubscriber_getDataSetValues(subscriber);
@@ -50,20 +50,26 @@ main(int argc, char** argv)
MmsValue_setElement(dataSetValues, i, dataSetEntry);
}
- // GooseSubscriber subscriber = GooseSubscriber_create("simpleIOGenericIO/LLN0$GO$gcbEvents", dataSetValues);
+ GooseReceiver receiver = GooseReceiver_create();
- GooseSubscriber subscriber = GooseSubscriber_create("simpleIOGenericIO/LLN0$GO$gcbAnalogValues", NULL);
+ if (argc > 1) {
+ printf("Set interface id: %s\n", argv[1]);
+ GooseReceiver_setInterfaceId(receiver, argv[1]);
+ }
+ else {
+ printf("Using interface eth0\n");
+ GooseReceiver_setInterfaceId(receiver, "eth0");
+ }
- if (argc > 1) {
- printf("Set interface id: %s\n", argv[1]);
- GooseSubscriber_setInterfaceId(subscriber, argv[1]);
- }
+ GooseSubscriber subscriber = GooseSubscriber_create("simpleIOGenericIO/LLN0$GO$gcbAnalogValues", NULL);
GooseSubscriber_setAppId(subscriber, 1000);
GooseSubscriber_setListener(subscriber, gooseListener, NULL);
- GooseSubscriber_subscribe(subscriber);
+ GooseReceiver_addSubscriber(receiver, subscriber);
+
+ GooseReceiver_start(receiver);
signal(SIGINT, sigint_handler);
diff --git a/examples/iec61850_client_example1/client_example1.c b/examples/iec61850_client_example1/client_example1.c
index fcd56d7f..b8429a09 100644
--- a/examples/iec61850_client_example1/client_example1.c
+++ b/examples/iec61850_client_example1/client_example1.c
@@ -9,7 +9,7 @@
#include
#include
-#include "thread.h"
+#include "hal_thread.h"
void
reportCallbackFunction(void* parameter, ClientReport report)
diff --git a/examples/iec61850_client_example2/client_example2.c b/examples/iec61850_client_example2/client_example2.c
index c6d6cf26..d199d0ab 100644
--- a/examples/iec61850_client_example2/client_example2.c
+++ b/examples/iec61850_client_example2/client_example2.c
@@ -25,6 +25,8 @@ printDataDirectory(char* doRef, IedConnection con, int spaces)
LinkedList dataAttributes = IedConnection_getDataDirectory(con, &error, doRef);
+ //LinkedList dataAttributes = IedConnection_getDataDirectoryByFC(con, &error, doRef, MX);
+
if (dataAttributes != NULL) {
LinkedList dataAttribute = LinkedList_getNext(dataAttributes);
@@ -70,7 +72,10 @@ main(int argc, char** argv)
printf("Get logical device list...\n");
LinkedList deviceList = IedConnection_getLogicalDeviceList(con, &error);
- printf("error: %i\n", error);
+ if (error != IED_ERROR_OK) {
+ printf("Failed to read device list (error code: %i)\n", error);
+ goto cleanup_and_exit;
+ }
LinkedList device = LinkedList_getNext(deviceList);
@@ -191,6 +196,7 @@ main(int argc, char** argv)
printf("Connection failed!\n");
}
+cleanup_and_exit:
IedConnection_destroy(con);
}
diff --git a/examples/iec61850_client_example3/client_example3.c b/examples/iec61850_client_example3/client_example3.c
index 93ab88df..6e8e0533 100644
--- a/examples/iec61850_client_example3/client_example3.c
+++ b/examples/iec61850_client_example3/client_example3.c
@@ -5,10 +5,27 @@
*/
#include "iec61850_client.h"
+#include "hal_thread.h"
#include
#include
+static void commandTerminationHandler(void *parameter, ControlObjectClient connection)
+{
+
+
+ LastApplError lastApplError = ControlObjectClient_getLastApplError(connection);
+
+ // if lastApplError.error != 0 this indicates a CommandTermination-
+ if (lastApplError.error != 0) {
+ printf("Received CommandTermination-.\n");
+ printf(" LastApplError: %i\n", lastApplError.error);
+ printf(" addCause: %i\n", lastApplError.addCause);
+ }
+ else
+ printf("Received CommandTermination+.\n");
+}
+
int main(int argc, char** argv) {
char* hostname;
@@ -57,6 +74,7 @@ int main(int argc, char** argv) {
if (error == IED_ERROR_OK) {
bool state = MmsValue_getBoolean(stVal);
+ MmsValue_delete(stVal);
printf("New status of simpleIOGenericIO/GGIO1.SPCSO1.stVal: %i\n", state);
}
@@ -91,6 +109,101 @@ int main(int argc, char** argv) {
ControlObjectClient_destroy(control);
+ /****************************************
+ * Direct control with enhanced security
+ ****************************************/
+
+ control = ControlObjectClient_create("simpleIOGenericIO/GGIO1.SPCSO3", con);
+
+ ControlObjectClient_setCommandTerminationHandler(control, commandTerminationHandler, NULL);
+
+ ctlVal = MmsValue_newBoolean(true);
+
+ if (ControlObjectClient_operate(control, ctlVal, 0 /* operate now */)) {
+ printf("simpleIOGenericIO/GGIO1.SPCSO3 operated successfully\n");
+ }
+ else {
+ printf("failed to operate simpleIOGenericIO/GGIO1.SPCSO3\n");
+ }
+
+ MmsValue_delete(ctlVal);
+
+ /* Wait for command termination message */
+ Thread_sleep(1000);
+
+ ControlObjectClient_destroy(control);
+
+ /* Check if status value has changed */
+
+ stVal = IedConnection_readObject(con, &error, "simpleIOGenericIO/GGIO1.SPCSO3.stVal", ST);
+
+ if (error == IED_ERROR_OK) {
+ bool state = MmsValue_getBoolean(stVal);
+
+ printf("New status of simpleIOGenericIO/GGIO1.SPCSO3.stVal: %i\n", state);
+
+ MmsValue_delete(stVal);
+ }
+ else {
+ printf("Reading status for simpleIOGenericIO/GGIO1.SPCSO3 failed!\n");
+ }
+
+ /***********************************************
+ * Select before operate with enhanced security
+ ***********************************************/
+
+ control = ControlObjectClient_create("simpleIOGenericIO/GGIO1.SPCSO4", con);
+
+ ControlObjectClient_setCommandTerminationHandler(control, commandTerminationHandler, NULL);
+
+ ctlVal = MmsValue_newBoolean(true);
+
+ if (ControlObjectClient_selectWithValue(control, ctlVal)) {
+
+ if (ControlObjectClient_operate(control, ctlVal, 0 /* operate now */)) {
+ printf("simpleIOGenericIO/GGIO1.SPCSO4 operated successfully\n");
+ }
+ else {
+ printf("failed to operate simpleIOGenericIO/GGIO1.SPCSO4!\n");
+ }
+
+ }
+ else {
+ printf("failed to select simpleIOGenericIO/GGIO1.SPCSO4!\n");
+ }
+
+ MmsValue_delete(ctlVal);
+
+ /* Wait for command termination message */
+ Thread_sleep(1000);
+
+ ControlObjectClient_destroy(control);
+
+
+ /*********************************************************************
+ * Direct control with enhanced security (expect CommandTermination-)
+ *********************************************************************/
+
+ control = ControlObjectClient_create("simpleIOGenericIO/GGIO1.SPCSO9", con);
+
+ ControlObjectClient_setCommandTerminationHandler(control, commandTerminationHandler, NULL);
+
+ ctlVal = MmsValue_newBoolean(true);
+
+ if (ControlObjectClient_operate(control, ctlVal, 0 /* operate now */)) {
+ printf("simpleIOGenericIO/GGIO1.SPCSO9 operated successfully\n");
+ }
+ else {
+ printf("failed to operate simpleIOGenericIO/GGIO1.SPCSO9\n");
+ }
+
+ MmsValue_delete(ctlVal);
+
+ /* Wait for command termination message */
+ Thread_sleep(1000);
+
+ ControlObjectClient_destroy(control);
+
IedConnection_close(con);
}
diff --git a/examples/iec61850_client_example4/client_example4.c b/examples/iec61850_client_example4/client_example4.c
index 12cec16d..1b1d4619 100644
--- a/examples/iec61850_client_example4/client_example4.c
+++ b/examples/iec61850_client_example4/client_example4.c
@@ -11,7 +11,7 @@
#include
#include
-#include "thread.h"
+#include "hal_thread.h"
static void
printDataSetValues(MmsValue* dataSet)
diff --git a/examples/iec61850_client_example5/client_example5.c b/examples/iec61850_client_example5/client_example5.c
index 4f43805a..f49c0aba 100644
--- a/examples/iec61850_client_example5/client_example5.c
+++ b/examples/iec61850_client_example5/client_example5.c
@@ -11,7 +11,7 @@
#include
#include
-#include "thread.h"
+#include "hal_thread.h"
int main(int argc, char** argv) {
@@ -47,9 +47,12 @@ int main(int argc, char** argv) {
// IsoConnectionParameters_setRemoteApTitle(parameters, NULL, 0);
// IsoConnectionParameters_setLocalApTitle(parameters, NULL, 0);
+ TSelector localTSelector = { 3, { 0x00, 0x01, 0x02 } };
+ TSelector remoteTSelector = { 2, { 0x00, 0x01 } };
+
/* change parameters for presentation, session and transport layers */
- IsoConnectionParameters_setRemoteAddresses(parameters, 0x12345678, 12 , 13);
- IsoConnectionParameters_setLocalAddresses(parameters, 0x87654321, 1234 , 2345);
+ IsoConnectionParameters_setRemoteAddresses(parameters, 0x12345678, 12, localTSelector);
+ IsoConnectionParameters_setLocalAddresses(parameters, 0x87654321, 1234 , remoteTSelector);
char* password = "top secret";
@@ -61,6 +64,8 @@ int main(int argc, char** argv) {
IsoConnectionParameters_setAcseAuthenticationParameter(parameters, auth);
+ IedConnection_setConnectTimeout(con, 10000);
+
/* call connect when all parameters are set */
IedConnection_connect(con, &error, hostname, tcpPort);
diff --git a/examples/iec61850_client_example_files/client_example_files.c b/examples/iec61850_client_example_files/client_example_files.c
index 36efa3fb..0b3f5f38 100644
--- a/examples/iec61850_client_example_files/client_example_files.c
+++ b/examples/iec61850_client_example_files/client_example_files.c
@@ -15,7 +15,7 @@
#include
#include
-#include "thread.h"
+#include "hal_thread.h"
#define MAX_BUFFER_SIZE 2000000
diff --git a/examples/iec61850_client_example_reporting/client_example_reporting.c b/examples/iec61850_client_example_reporting/client_example_reporting.c
index e234b3c2..1c6f7a86 100644
--- a/examples/iec61850_client_example_reporting/client_example_reporting.c
+++ b/examples/iec61850_client_example_reporting/client_example_reporting.c
@@ -11,7 +11,7 @@
#include
#include
-#include "thread.h"
+#include "hal_thread.h"
static int running = 0;
@@ -105,7 +105,7 @@ int main(int argc, char** argv) {
/* Read RCB values */
ClientReportControlBlock rcb =
- IedConnection_getRCBValues(con, &error, "simpleIOGenericIO/LLN0.RP.EventsRCB", NULL);
+ IedConnection_getRCBValues(con, &error, "simpleIOGenericIO/LLN0.RP.EventsRCB01", NULL);
if (error != IED_ERROR_OK) {
printf("getRCBValues service error!\n");
@@ -131,7 +131,7 @@ int main(int argc, char** argv) {
Thread_sleep(1000);
- IedConnection_triggerGIReport(con, &error, "simpleIOGenericIO/LLN0.RP.EventsRCB");
+ IedConnection_triggerGIReport(con, &error, "simpleIOGenericIO/LLN0.RP.EventsRCB01");
if (error != IED_ERROR_OK) {
printf("Error triggering a GI report (code: %i)\n", error);
diff --git a/examples/mms_client_example1/mms_client_example1.c b/examples/mms_client_example1/mms_client_example1.c
index ece6535b..d8ad47c6 100644
--- a/examples/mms_client_example1/mms_client_example1.c
+++ b/examples/mms_client_example1/mms_client_example1.c
@@ -27,7 +27,7 @@
#include
#include
#include "mms_client_connection.h"
-#include "thread.h"
+#include "hal_thread.h"
int main(int argc, char** argv) {
diff --git a/examples/server_example1/server_example1.c b/examples/server_example1/server_example1.c
index 7d3e14fb..14a0b2a1 100644
--- a/examples/server_example1/server_example1.c
+++ b/examples/server_example1/server_example1.c
@@ -22,7 +22,7 @@
*/
#include "iec61850_server.h"
-#include "thread.h"
+#include "hal_thread.h"
#include
#include
#include
diff --git a/examples/server_example1/static_model.c b/examples/server_example1/static_model.c
index c3ac50db..3abfe08a 100644
--- a/examples/server_example1/static_model.c
+++ b/examples/server_example1/static_model.c
@@ -4,7 +4,7 @@
* automatically generated from sampleModel_with_dataset.icd
*/
#include
-#include "model.h"
+#include "iec61850_model.h"
extern IedModel iedModel;
static void initializeValues();
@@ -148,7 +148,7 @@ extern DataSetEntry ds_Device1_LLN0_dataset1_fcda1;
extern DataSetEntry ds_Device1_LLN0_dataset1_fcda2;
DataSetEntry ds_Device1_LLN0_dataset1_fcda0 = {
- "SampleIEDDevice1",
+ "Device1",
"LLN0$ST$Mod$q",
-1,
NULL,
@@ -157,7 +157,7 @@ DataSetEntry ds_Device1_LLN0_dataset1_fcda0 = {
};
DataSetEntry ds_Device1_LLN0_dataset1_fcda1 = {
- "SampleIEDDevice1",
+ "Device1",
"MMXU1$ST$Mod$q",
-1,
NULL,
@@ -166,7 +166,7 @@ DataSetEntry ds_Device1_LLN0_dataset1_fcda1 = {
};
DataSetEntry ds_Device1_LLN0_dataset1_fcda2 = {
- "SampleIEDDevice1",
+ "Device1",
"MMXU1$CF$Mod$ctlModel",
-1,
NULL,
@@ -175,7 +175,7 @@ DataSetEntry ds_Device1_LLN0_dataset1_fcda2 = {
};
DataSet ds_Device1_LLN0_dataset1 = {
- "SampleIEDDevice1",
+ "Device1",
"LLN0$dataset1",
3,
&ds_Device1_LLN0_dataset1_fcda0,
@@ -184,7 +184,7 @@ DataSet ds_Device1_LLN0_dataset1 = {
LogicalDevice iedModel_Device1 = {
LogicalDeviceModelType,
- "SampleIEDDevice1",
+ "Device1",
(ModelNode*) &iedModel,
NULL,
(ModelNode*) &iedModel_Device1_LLN0
@@ -1718,31 +1718,9 @@ DataAttribute iedModel_Device1_MMXU2_TotW_t = {
NULL,
0};
-
extern ReportControlBlock iedModel_Device1_LLN0_report0;
-ReportControlBlock iedModel_Device1_LLN0_report0 = {&iedModel_Device1_LLN0, "LLN0_Events_BuffRep", "LLN0$RP$brcbEV1", true, "dataset1", 1, 9, 239, 50, 900000, NULL};
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ReportControlBlock iedModel_Device1_LLN0_report0 = {&iedModel_Device1_LLN0, "LLN0_Events_BuffRep01", "LLN0$RP$brcbEV1", true, "dataset1", 1, 9, 239, 50, 900000, NULL};
@@ -1753,6 +1731,7 @@ IedModel iedModel = {
&ds_Device1_LLN0_dataset1,
&iedModel_Device1_LLN0_report0,
NULL,
+ NULL,
initializeValues
};
diff --git a/examples/server_example1/static_model.h b/examples/server_example1/static_model.h
index 94afedd8..208787e3 100644
--- a/examples/server_example1/static_model.h
+++ b/examples/server_example1/static_model.h
@@ -8,7 +8,7 @@
#define STATIC_MODEL_H_
#include
-#include "model.h"
+#include "iec61850_model.h"
extern IedModel iedModel;
extern LogicalDevice iedModel_Device1;
diff --git a/examples/server_example2/server_example2.c b/examples/server_example2/server_example2.c
index 20fe7a6e..e4d95e90 100644
--- a/examples/server_example2/server_example2.c
+++ b/examples/server_example2/server_example2.c
@@ -22,7 +22,7 @@
*/
#include "iec61850_server.h"
-#include "thread.h"
+#include "hal_thread.h"
#include
#include
#include
diff --git a/examples/server_example2/static_model.c b/examples/server_example2/static_model.c
index 6eeed2f0..fbc3cfa7 100644
--- a/examples/server_example2/static_model.c
+++ b/examples/server_example2/static_model.c
@@ -1,10 +1,10 @@
/*
* static_model.c
*
- * automatically generated from complexModel.scd
+ * automatically generated from complexModel.icd
*/
#include
-#include "model.h"
+#include "iec61850_model.h"
extern IedModel iedModel;
static void initializeValues();
@@ -314,7 +314,7 @@ extern DataSetEntry ds_Inverter_LLN0_dataset1_fcda3;
extern DataSetEntry ds_Inverter_LLN0_dataset1_fcda4;
DataSetEntry ds_Inverter_LLN0_dataset1_fcda0 = {
- "ied1Inverter",
+ "Inverter",
"LLN0$ST$Mod$q",
-1,
NULL,
@@ -323,7 +323,7 @@ DataSetEntry ds_Inverter_LLN0_dataset1_fcda0 = {
};
DataSetEntry ds_Inverter_LLN0_dataset1_fcda1 = {
- "ied1Battery",
+ "Battery",
"LLN0$ST$Mod$q",
-1,
NULL,
@@ -332,7 +332,7 @@ DataSetEntry ds_Inverter_LLN0_dataset1_fcda1 = {
};
DataSetEntry ds_Inverter_LLN0_dataset1_fcda2 = {
- "ied1Inverter",
+ "Inverter",
"MMXU1$ST$Mod$q",
-1,
NULL,
@@ -341,7 +341,7 @@ DataSetEntry ds_Inverter_LLN0_dataset1_fcda2 = {
};
DataSetEntry ds_Inverter_LLN0_dataset1_fcda3 = {
- "ied1Inverter",
+ "Inverter",
"MMXU1$CF$Mod$ctlModel",
-1,
NULL,
@@ -350,7 +350,7 @@ DataSetEntry ds_Inverter_LLN0_dataset1_fcda3 = {
};
DataSetEntry ds_Inverter_LLN0_dataset1_fcda4 = {
- "ied1Inverter",
+ "Inverter",
"MMXU1$MX$TotW$mag",
-1,
NULL,
@@ -359,7 +359,7 @@ DataSetEntry ds_Inverter_LLN0_dataset1_fcda4 = {
};
DataSet ds_Inverter_LLN0_dataset1 = {
- "ied1Inverter",
+ "Inverter",
"LLN0$dataset1",
5,
&ds_Inverter_LLN0_dataset1_fcda0,
@@ -368,7 +368,7 @@ DataSet ds_Inverter_LLN0_dataset1 = {
LogicalDevice iedModel_Inverter = {
LogicalDeviceModelType,
- "ied1Inverter",
+ "Inverter",
(ModelNode*) &iedModel,
(ModelNode*) &iedModel_Battery,
(ModelNode*) &iedModel_Inverter_LLN0
@@ -2480,7 +2480,7 @@ DataAttribute iedModel_Inverter_MMXU1_W_phsC_t = {
LogicalDevice iedModel_Battery = {
LogicalDeviceModelType,
- "ied1Battery",
+ "Battery",
(ModelNode*) &iedModel,
(ModelNode*) &iedModel_Physical_Measurements,
(ModelNode*) &iedModel_Battery_LLN0
@@ -3512,7 +3512,7 @@ DataAttribute iedModel_Battery_ZBTC1_ChaA_t = {
LogicalDevice iedModel_Physical_Measurements = {
LogicalDeviceModelType,
- "ied1Physical_Measurements",
+ "Physical_Measurements",
(ModelNode*) &iedModel,
NULL,
(ModelNode*) &iedModel_Physical_Measurements_LLN0
@@ -3870,47 +3870,9 @@ DataAttribute iedModel_Physical_Measurements_LPHD1_Proxy_t = {
NULL,
0};
-
extern ReportControlBlock iedModel_Inverter_LLN0_report0;
-ReportControlBlock iedModel_Inverter_LLN0_report0 = {&iedModel_Inverter_LLN0, "rcb1", "ID", false, "dataset1", 0, 3, 32, 0, 0, NULL};
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ReportControlBlock iedModel_Inverter_LLN0_report0 = {&iedModel_Inverter_LLN0, "rcb101", "ID", false, "dataset1", 0, 3, 32, 0, 0, NULL};
@@ -3921,6 +3883,7 @@ IedModel iedModel = {
&ds_Inverter_LLN0_dataset1,
&iedModel_Inverter_LLN0_report0,
NULL,
+ NULL,
initializeValues
};
diff --git a/examples/server_example2/static_model.h b/examples/server_example2/static_model.h
index 609fc245..34623f80 100644
--- a/examples/server_example2/static_model.h
+++ b/examples/server_example2/static_model.h
@@ -1,14 +1,14 @@
/*
* static_model.h
*
- * automatically generated from complexModel.scd
+ * automatically generated from complexModel.icd
*/
#ifndef STATIC_MODEL_H_
#define STATIC_MODEL_H_
#include
-#include "model.h"
+#include "iec61850_model.h"
extern IedModel iedModel;
extern LogicalDevice iedModel_Inverter;
diff --git a/examples/server_example3/server_example3.c b/examples/server_example3/server_example3.c
index e7659369..0953e409 100644
--- a/examples/server_example3/server_example3.c
+++ b/examples/server_example3/server_example3.c
@@ -6,7 +6,7 @@
*/
#include "iec61850_server.h"
-#include "thread.h"
+#include "hal_thread.h"
#include
#include
#include
@@ -66,6 +66,16 @@ controlHandlerForBinaryOutput(void* parameter, MmsValue* value, bool test)
return true;
}
+
+static void
+connectionHandler (IedServer self, ClientConnection connection, bool connected, void* parameter)
+{
+ if (connected)
+ printf("Connection opened\n");
+ else
+ printf("Connection closed\n");
+}
+
int
main(int argc, char** argv)
{
@@ -89,6 +99,8 @@ main(int argc, char** argv)
(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, 102);
@@ -135,4 +147,5 @@ main(int argc, char** argv)
/* Cleanup - free all resources */
IedServer_destroy(iedServer);
+
} /* main() */
diff --git a/examples/server_example3/static_model.c b/examples/server_example3/static_model.c
index ced6aaeb..90017480 100644
--- a/examples/server_example3/static_model.c
+++ b/examples/server_example3/static_model.c
@@ -4,7 +4,7 @@
* automatically generated from simpleIO_direct_control.icd
*/
#include
-#include "model.h"
+#include "iec61850_model.h"
extern IedModel iedModel;
static void initializeValues();
@@ -160,7 +160,7 @@ extern DataSetEntry ds_GenericIO_LLN0_Events_fcda2;
extern DataSetEntry ds_GenericIO_LLN0_Events_fcda3;
DataSetEntry ds_GenericIO_LLN0_Events_fcda0 = {
- "simpleIOGenericIO",
+ "GenericIO",
"GGIO1$ST$SPCSO1$stVal",
-1,
NULL,
@@ -169,7 +169,7 @@ DataSetEntry ds_GenericIO_LLN0_Events_fcda0 = {
};
DataSetEntry ds_GenericIO_LLN0_Events_fcda1 = {
- "simpleIOGenericIO",
+ "GenericIO",
"GGIO1$ST$SPCSO2$stVal",
-1,
NULL,
@@ -178,7 +178,7 @@ DataSetEntry ds_GenericIO_LLN0_Events_fcda1 = {
};
DataSetEntry ds_GenericIO_LLN0_Events_fcda2 = {
- "simpleIOGenericIO",
+ "GenericIO",
"GGIO1$ST$SPCSO3$stVal",
-1,
NULL,
@@ -187,7 +187,7 @@ DataSetEntry ds_GenericIO_LLN0_Events_fcda2 = {
};
DataSetEntry ds_GenericIO_LLN0_Events_fcda3 = {
- "simpleIOGenericIO",
+ "GenericIO",
"GGIO1$ST$SPCSO4$stVal",
-1,
NULL,
@@ -196,7 +196,7 @@ DataSetEntry ds_GenericIO_LLN0_Events_fcda3 = {
};
DataSet ds_GenericIO_LLN0_Events = {
- "simpleIOGenericIO",
+ "GenericIO",
"LLN0$Events",
4,
&ds_GenericIO_LLN0_Events_fcda0,
@@ -209,7 +209,7 @@ extern DataSetEntry ds_GenericIO_LLN0_Events2_fcda2;
extern DataSetEntry ds_GenericIO_LLN0_Events2_fcda3;
DataSetEntry ds_GenericIO_LLN0_Events2_fcda0 = {
- "simpleIOGenericIO",
+ "GenericIO",
"GGIO1$ST$SPCSO1",
-1,
NULL,
@@ -218,7 +218,7 @@ DataSetEntry ds_GenericIO_LLN0_Events2_fcda0 = {
};
DataSetEntry ds_GenericIO_LLN0_Events2_fcda1 = {
- "simpleIOGenericIO",
+ "GenericIO",
"GGIO1$ST$SPCSO2",
-1,
NULL,
@@ -227,7 +227,7 @@ DataSetEntry ds_GenericIO_LLN0_Events2_fcda1 = {
};
DataSetEntry ds_GenericIO_LLN0_Events2_fcda2 = {
- "simpleIOGenericIO",
+ "GenericIO",
"GGIO1$ST$SPCSO3",
-1,
NULL,
@@ -236,7 +236,7 @@ DataSetEntry ds_GenericIO_LLN0_Events2_fcda2 = {
};
DataSetEntry ds_GenericIO_LLN0_Events2_fcda3 = {
- "simpleIOGenericIO",
+ "GenericIO",
"GGIO1$ST$SPCSO4",
-1,
NULL,
@@ -245,7 +245,7 @@ DataSetEntry ds_GenericIO_LLN0_Events2_fcda3 = {
};
DataSet ds_GenericIO_LLN0_Events2 = {
- "simpleIOGenericIO",
+ "GenericIO",
"LLN0$Events2",
4,
&ds_GenericIO_LLN0_Events2_fcda0,
@@ -254,7 +254,7 @@ DataSet ds_GenericIO_LLN0_Events2 = {
LogicalDevice iedModel_GenericIO = {
LogicalDeviceModelType,
- "simpleIOGenericIO",
+ "GenericIO",
(ModelNode*) &iedModel,
NULL,
(ModelNode*) &iedModel_GenericIO_LLN0
@@ -1973,13 +1973,12 @@ DataAttribute iedModel_GenericIO_GGIO1_Ind4_t = {
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;
-ReportControlBlock iedModel_GenericIO_LLN0_report0 = {&iedModel_GenericIO_LLN0, "EventsRCB", "Events1", false, "Events", 1, 8, 111, 50, 1000, &iedModel_GenericIO_LLN0_report1};
+ReportControlBlock iedModel_GenericIO_LLN0_report0 = {&iedModel_GenericIO_LLN0, "EventsRCB01", "Events1", false, "Events", 1, 8, 111, 50, 1000, &iedModel_GenericIO_LLN0_report1};
ReportControlBlock iedModel_GenericIO_LLN0_report1 = {&iedModel_GenericIO_LLN0, "EventsIndexed01", "Events2", false, "Events", 1, 8, 111, 50, 1000, &iedModel_GenericIO_LLN0_report2};
ReportControlBlock iedModel_GenericIO_LLN0_report2 = {&iedModel_GenericIO_LLN0, "EventsIndexed02", "Events2", false, "Events", 1, 8, 111, 50, 1000, &iedModel_GenericIO_LLN0_report3};
ReportControlBlock iedModel_GenericIO_LLN0_report3 = {&iedModel_GenericIO_LLN0, "EventsIndexed03", "Events2", false, "Events", 1, 8, 111, 50, 1000, NULL};
@@ -1987,21 +1986,13 @@ ReportControlBlock iedModel_GenericIO_LLN0_report3 = {&iedModel_GenericIO_LLN0,
-
-
-
-
-
-
-
-
-
IedModel iedModel = {
"simpleIO",
&iedModel_GenericIO,
&ds_GenericIO_LLN0_Events,
&iedModel_GenericIO_LLN0_report0,
NULL,
+ NULL,
initializeValues
};
diff --git a/examples/server_example3/static_model.h b/examples/server_example3/static_model.h
index 6883b430..b5670e9f 100644
--- a/examples/server_example3/static_model.h
+++ b/examples/server_example3/static_model.h
@@ -8,7 +8,7 @@
#define STATIC_MODEL_H_
#include
-#include "model.h"
+#include "iec61850_model.h"
extern IedModel iedModel;
extern LogicalDevice iedModel_GenericIO;
diff --git a/examples/server_example4/server_example4.c b/examples/server_example4/server_example4.c
index e09ffee9..166515e1 100644
--- a/examples/server_example4/server_example4.c
+++ b/examples/server_example4/server_example4.c
@@ -16,7 +16,7 @@
#include "iec61850_server.h"
#include "static_model.h"
-#include "thread.h"
+#include "hal_thread.h"
#include
#include
#include
diff --git a/examples/server_example4/static_model.c b/examples/server_example4/static_model.c
index 4cb637a6..08974481 100644
--- a/examples/server_example4/static_model.c
+++ b/examples/server_example4/static_model.c
@@ -4,7 +4,7 @@
* automatically generated from simpleIO_direct_control.icd
*/
#include
-#include "model.h"
+#include "iec61850_model.h"
extern IedModel iedModel;
static void initializeValues();
@@ -158,7 +158,7 @@ extern DataSetEntry ds_GenericIO_LLN0_Events_fcda2;
extern DataSetEntry ds_GenericIO_LLN0_Events_fcda3;
DataSetEntry ds_GenericIO_LLN0_Events_fcda0 = {
- "simpleIOGenericIO",
+ "GenericIO",
"GGIO1$ST$SPCSO1$stVal",
-1,
NULL,
@@ -167,7 +167,7 @@ DataSetEntry ds_GenericIO_LLN0_Events_fcda0 = {
};
DataSetEntry ds_GenericIO_LLN0_Events_fcda1 = {
- "simpleIOGenericIO",
+ "GenericIO",
"GGIO1$ST$SPCSO2$stVal",
-1,
NULL,
@@ -176,7 +176,7 @@ DataSetEntry ds_GenericIO_LLN0_Events_fcda1 = {
};
DataSetEntry ds_GenericIO_LLN0_Events_fcda2 = {
- "simpleIOGenericIO",
+ "GenericIO",
"GGIO1$ST$SPCSO3$stVal",
-1,
NULL,
@@ -185,7 +185,7 @@ DataSetEntry ds_GenericIO_LLN0_Events_fcda2 = {
};
DataSetEntry ds_GenericIO_LLN0_Events_fcda3 = {
- "simpleIOGenericIO",
+ "GenericIO",
"GGIO1$ST$SPCSO4$stVal",
-1,
NULL,
@@ -194,7 +194,7 @@ DataSetEntry ds_GenericIO_LLN0_Events_fcda3 = {
};
DataSet ds_GenericIO_LLN0_Events = {
- "simpleIOGenericIO",
+ "GenericIO",
"LLN0$Events",
4,
&ds_GenericIO_LLN0_Events_fcda0,
@@ -203,7 +203,7 @@ DataSet ds_GenericIO_LLN0_Events = {
LogicalDevice iedModel_GenericIO = {
LogicalDeviceModelType,
- "simpleIOGenericIO",
+ "GenericIO",
(ModelNode*) &iedModel,
NULL,
(ModelNode*) &iedModel_GenericIO_LLN0
@@ -1909,19 +1909,9 @@ DataAttribute iedModel_GenericIO_GGIO1_Ind4_t = {
NULL,
0};
-
extern ReportControlBlock iedModel_GenericIO_LLN0_report0;
-ReportControlBlock iedModel_GenericIO_LLN0_report0 = {&iedModel_GenericIO_LLN0, "EventsRCB", "Events", false, "Events", 1, 8, 111, 50, 1000, NULL};
-
-
-
-
-
-
-
-
-
+ReportControlBlock iedModel_GenericIO_LLN0_report0 = {&iedModel_GenericIO_LLN0, "EventsRCB01", "Events", false, "Events", 1, 8, 111, 50, 1000, NULL};
@@ -1932,6 +1922,7 @@ IedModel iedModel = {
&ds_GenericIO_LLN0_Events,
&iedModel_GenericIO_LLN0_report0,
NULL,
+ NULL,
initializeValues
};
diff --git a/examples/server_example4/static_model.h b/examples/server_example4/static_model.h
index 4f352309..58dd28b5 100644
--- a/examples/server_example4/static_model.h
+++ b/examples/server_example4/static_model.h
@@ -8,7 +8,7 @@
#define STATIC_MODEL_H_
#include
-#include "model.h"
+#include "iec61850_model.h"
extern IedModel iedModel;
extern LogicalDevice iedModel_GenericIO;
diff --git a/examples/server_example5/server_example5.c b/examples/server_example5/server_example5.c
index 2f31f96b..58931db2 100644
--- a/examples/server_example5/server_example5.c
+++ b/examples/server_example5/server_example5.c
@@ -22,7 +22,7 @@
*/
#include "iec61850_server.h"
-#include "thread.h"
+#include "hal_thread.h"
#include
#include
#include
diff --git a/examples/server_example5/static_model.c b/examples/server_example5/static_model.c
index 4cb637a6..08974481 100644
--- a/examples/server_example5/static_model.c
+++ b/examples/server_example5/static_model.c
@@ -4,7 +4,7 @@
* automatically generated from simpleIO_direct_control.icd
*/
#include
-#include "model.h"
+#include "iec61850_model.h"
extern IedModel iedModel;
static void initializeValues();
@@ -158,7 +158,7 @@ extern DataSetEntry ds_GenericIO_LLN0_Events_fcda2;
extern DataSetEntry ds_GenericIO_LLN0_Events_fcda3;
DataSetEntry ds_GenericIO_LLN0_Events_fcda0 = {
- "simpleIOGenericIO",
+ "GenericIO",
"GGIO1$ST$SPCSO1$stVal",
-1,
NULL,
@@ -167,7 +167,7 @@ DataSetEntry ds_GenericIO_LLN0_Events_fcda0 = {
};
DataSetEntry ds_GenericIO_LLN0_Events_fcda1 = {
- "simpleIOGenericIO",
+ "GenericIO",
"GGIO1$ST$SPCSO2$stVal",
-1,
NULL,
@@ -176,7 +176,7 @@ DataSetEntry ds_GenericIO_LLN0_Events_fcda1 = {
};
DataSetEntry ds_GenericIO_LLN0_Events_fcda2 = {
- "simpleIOGenericIO",
+ "GenericIO",
"GGIO1$ST$SPCSO3$stVal",
-1,
NULL,
@@ -185,7 +185,7 @@ DataSetEntry ds_GenericIO_LLN0_Events_fcda2 = {
};
DataSetEntry ds_GenericIO_LLN0_Events_fcda3 = {
- "simpleIOGenericIO",
+ "GenericIO",
"GGIO1$ST$SPCSO4$stVal",
-1,
NULL,
@@ -194,7 +194,7 @@ DataSetEntry ds_GenericIO_LLN0_Events_fcda3 = {
};
DataSet ds_GenericIO_LLN0_Events = {
- "simpleIOGenericIO",
+ "GenericIO",
"LLN0$Events",
4,
&ds_GenericIO_LLN0_Events_fcda0,
@@ -203,7 +203,7 @@ DataSet ds_GenericIO_LLN0_Events = {
LogicalDevice iedModel_GenericIO = {
LogicalDeviceModelType,
- "simpleIOGenericIO",
+ "GenericIO",
(ModelNode*) &iedModel,
NULL,
(ModelNode*) &iedModel_GenericIO_LLN0
@@ -1909,19 +1909,9 @@ DataAttribute iedModel_GenericIO_GGIO1_Ind4_t = {
NULL,
0};
-
extern ReportControlBlock iedModel_GenericIO_LLN0_report0;
-ReportControlBlock iedModel_GenericIO_LLN0_report0 = {&iedModel_GenericIO_LLN0, "EventsRCB", "Events", false, "Events", 1, 8, 111, 50, 1000, NULL};
-
-
-
-
-
-
-
-
-
+ReportControlBlock iedModel_GenericIO_LLN0_report0 = {&iedModel_GenericIO_LLN0, "EventsRCB01", "Events", false, "Events", 1, 8, 111, 50, 1000, NULL};
@@ -1932,6 +1922,7 @@ IedModel iedModel = {
&ds_GenericIO_LLN0_Events,
&iedModel_GenericIO_LLN0_report0,
NULL,
+ NULL,
initializeValues
};
diff --git a/examples/server_example5/static_model.h b/examples/server_example5/static_model.h
index 4f352309..58dd28b5 100644
--- a/examples/server_example5/static_model.h
+++ b/examples/server_example5/static_model.h
@@ -8,7 +8,7 @@
#define STATIC_MODEL_H_
#include
-#include "model.h"
+#include "iec61850_model.h"
extern IedModel iedModel;
extern LogicalDevice iedModel_GenericIO;
diff --git a/examples/server_example_61400_25/server_example_61400_25.c b/examples/server_example_61400_25/server_example_61400_25.c
index c86e153b..890b5a3d 100644
--- a/examples/server_example_61400_25/server_example_61400_25.c
+++ b/examples/server_example_61400_25/server_example_61400_25.c
@@ -22,7 +22,7 @@
*/
#include "iec61850_server.h"
-#include "thread.h"
+#include "hal_thread.h"
#include
#include
#include
diff --git a/examples/server_example_61400_25/static_model.c b/examples/server_example_61400_25/static_model.c
index 1a8e22de..d40302fc 100644
--- a/examples/server_example_61400_25/static_model.c
+++ b/examples/server_example_61400_25/static_model.c
@@ -4,7 +4,7 @@
* automatically generated from wtur.icd
*/
#include
-#include "model.h"
+#include "iec61850_model.h"
extern IedModel iedModel;
static void initializeValues();
@@ -344,7 +344,7 @@ extern DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmAcs;
LogicalDevice iedModel_WTG = {
LogicalDeviceModelType,
- "WINDWTG",
+ "WTG",
(ModelNode*) &iedModel,
NULL,
(ModelNode*) &iedModel_WTG_LLN0
@@ -4466,22 +4466,13 @@ DataAttribute iedModel_WTG_WTUR1_SetTurOp_cmAcs = {
-
-
-
-
-
-
-
-
-
-
IedModel iedModel = {
"WIND",
&iedModel_WTG,
NULL,
NULL,
NULL,
+ NULL,
initializeValues
};
diff --git a/examples/server_example_61400_25/static_model.h b/examples/server_example_61400_25/static_model.h
index 171dba6f..c19af1c4 100644
--- a/examples/server_example_61400_25/static_model.h
+++ b/examples/server_example_61400_25/static_model.h
@@ -8,7 +8,7 @@
#define STATIC_MODEL_H_
#include
-#include "model.h"
+#include "iec61850_model.h"
extern IedModel iedModel;
extern LogicalDevice iedModel_WTG;
diff --git a/examples/server_example_complex_array/server_example_ca.c b/examples/server_example_complex_array/server_example_ca.c
index bad2b47e..5db5a755 100644
--- a/examples/server_example_complex_array/server_example_ca.c
+++ b/examples/server_example_complex_array/server_example_ca.c
@@ -5,7 +5,7 @@
*/
#include "iec61850_server.h"
-#include "thread.h"
+#include "hal_thread.h"
#include
#include
#include
diff --git a/examples/server_example_complex_array/static_model.c b/examples/server_example_complex_array/static_model.c
index 07b6e111..979e8d35 100644
--- a/examples/server_example_complex_array/static_model.c
+++ b/examples/server_example_complex_array/static_model.c
@@ -4,7 +4,7 @@
* automatically generated from mhai_array.icd
*/
#include
-#include "model.h"
+#include "iec61850_model.h"
extern IedModel iedModel;
static void initializeValues();
@@ -58,7 +58,7 @@ extern DataAttribute iedModel_ComplexArray_MHAI1_HA_frequency;
LogicalDevice iedModel_ComplexArray = {
LogicalDeviceModelType,
- "testComplexArray",
+ "ComplexArray",
(ModelNode*) &iedModel,
NULL,
(ModelNode*) &iedModel_ComplexArray_LLN0
@@ -589,12 +589,14 @@ DataAttribute iedModel_ComplexArray_MHAI1_HA_frequency = {
+
IedModel iedModel = {
"test",
&iedModel_ComplexArray,
NULL,
NULL,
NULL,
+ NULL,
initializeValues
};
diff --git a/examples/server_example_complex_array/static_model.h b/examples/server_example_complex_array/static_model.h
index bad70b71..0999d581 100644
--- a/examples/server_example_complex_array/static_model.h
+++ b/examples/server_example_complex_array/static_model.h
@@ -8,7 +8,7 @@
#define STATIC_MODEL_H_
#include
-#include "model.h"
+#include "iec61850_model.h"
extern IedModel iedModel;
extern LogicalDevice iedModel_ComplexArray;
diff --git a/examples/server_example_config_file/server_example_config_file.c b/examples/server_example_config_file/server_example_config_file.c
index 11320ccc..924707bc 100644
--- a/examples/server_example_config_file/server_example_config_file.c
+++ b/examples/server_example_config_file/server_example_config_file.c
@@ -15,13 +15,13 @@
*/
#include "iec61850_server.h"
-#include "thread.h"
+#include "hal_thread.h"
#include
#include
#include
-#include "filesystem.h"
-#include "config_file_parser.h"
+#include "hal_filesystem.h"
+#include "iec61850_config_file_parser.h"
static int running = 0;
diff --git a/examples/server_example_config_file/vmd-filestore/model.cfg b/examples/server_example_config_file/vmd-filestore/model.cfg
index 4b7698a3..d0507a1f 100644
--- a/examples/server_example_config_file/vmd-filestore/model.cfg
+++ b/examples/server_example_config_file/vmd-filestore/model.cfg
@@ -1,6 +1,7 @@
-MODEL{
-LD(simpleIOGenericIO){
+MODEL(simpleIO){
+LD(GenericIO){
LN(LLN0){
+SG(1 2)
DO(Mod 0){
DA(q 0 23 0 2 0);
DA(t 0 22 0 0 0);
@@ -35,8 +36,8 @@ DE(GGIO1$MX$AnIn2);
DE(GGIO1$MX$AnIn3);
DE(GGIO1$MX$AnIn4);
}
-RC(EventsRCB Events 0 Events 1 8 111 50 1000);
-RC(AnalogValuesRCB AnalogValues 0 AnalogValues 1 8 111 50 1000);
+RC(EventsRCB01 - 0 Events 1 8 111 50 1000);
+RC(AnalogValuesRCB01 AnalogValues 0 AnalogValues 1 8 111 50 1000);
GC(gcbEvents events Events 2 0){
PA(4 111 1000 010ccd010001);
}
diff --git a/examples/server_example_control/server_example_control.c b/examples/server_example_control/server_example_control.c
index 202606ac..72fc6bc2 100644
--- a/examples/server_example_control/server_example_control.c
+++ b/examples/server_example_control/server_example_control.c
@@ -5,7 +5,7 @@
*/
#include "iec61850_server.h"
-#include "thread.h"
+#include "hal_thread.h"
#include
#include
#include
@@ -44,23 +44,31 @@ checkHandler(void* parameter, MmsValue* ctlVal, bool test, bool interlockCheck,
if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO4)
return CONTROL_ACCEPTED;
+ if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO9)
+ return CONTROL_ACCEPTED;
+
return CONTROL_OBJECT_UNDEFINED;
}
-void
+static ControlHandlerResult
controlHandlerForBinaryOutput(void* parameter, MmsValue* value, bool test)
{
if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO1)
IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO1_stVal, value);
- if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO2)
+ else if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO2)
IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO2_stVal, value);
- if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO3)
+ else if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO3)
IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO3_stVal, value);
- if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO4)
+ else if (parameter == IEDMODEL_GenericIO_GGIO1_SPCSO4)
IedServer_updateAttributeValue(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO4_stVal, value);
+
+ else
+ return CONTROL_RESULT_FAILED;
+
+ return CONTROL_RESULT_OK;
}
int
@@ -91,7 +99,16 @@ main(int argc, char** argv)
/* this is optional - performs operative checks */
IedServer_setPerformCheckHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO4, checkHandler,
- IEDMODEL_GenericIO_GGIO1_SPCSO4);
+ IEDMODEL_GenericIO_GGIO1_SPCSO4);
+
+
+ IedServer_setControlHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO9,
+ (ControlHandler) controlHandlerForBinaryOutput,
+ IEDMODEL_GenericIO_GGIO1_SPCSO9);
+
+ /* this is optional - performs operative checks */
+ IedServer_setPerformCheckHandler(iedServer, IEDMODEL_GenericIO_GGIO1_SPCSO9, checkHandler,
+ IEDMODEL_GenericIO_GGIO1_SPCSO9);
/* MMS server will be instructed to start listening to client connections. */
IedServer_start(iedServer, 102);
diff --git a/examples/server_example_control/simpleIO_control_tests.icd b/examples/server_example_control/simpleIO_control_tests.icd
index 63c13eae..6bfd88cd 100644
--- a/examples/server_example_control/simpleIO_control_tests.icd
+++ b/examples/server_example_control/simpleIO_control_tests.icd
@@ -93,6 +93,11 @@
sbo-with-enhanced-security
+
+
+ direct-with-enhanced-security
+
+
@@ -127,6 +132,7 @@
+
diff --git a/examples/server_example_control/static_model.c b/examples/server_example_control/static_model.c
index f9040c3e..50e3df5d 100644
--- a/examples/server_example_control/static_model.c
+++ b/examples/server_example_control/static_model.c
@@ -4,7 +4,7 @@
* automatically generated from simpleIO_control_tests.icd
*/
#include
-#include "model.h"
+#include "iec61850_model.h"
extern IedModel iedModel;
static void initializeValues();
@@ -277,6 +277,28 @@ extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_stVal;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_q;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_t;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_ctlModel;
+extern DataObject iedModel_GenericIO_GGIO1_SPCSO9;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_ctlVal;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_origin;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_origin_orCat;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_origin_orIdent;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_ctlNum;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_T;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_Test;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_Check;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel_ctlVal;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel_origin;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel_origin_orCat;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel_origin_orIdent;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel_ctlNum;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel_T;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel_Test;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_stVal;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_q;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_t;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_ctlModel;
extern DataObject iedModel_GenericIO_GGIO1_Ind1;
extern DataAttribute iedModel_GenericIO_GGIO1_Ind1_stVal;
extern DataAttribute iedModel_GenericIO_GGIO1_Ind1_q;
@@ -298,7 +320,7 @@ extern DataAttribute iedModel_GenericIO_GGIO1_Ind4_t;
LogicalDevice iedModel_GenericIO = {
LogicalDeviceModelType,
- "simpleIOGenericIO",
+ "GenericIO",
(ModelNode*) &iedModel,
NULL,
(ModelNode*) &iedModel_GenericIO_LLN0
@@ -3195,7 +3217,7 @@ DataObject iedModel_GenericIO_GGIO1_SPCSO8 = {
DataObjectModelType,
"SPCSO8",
(ModelNode*) &iedModel_GenericIO_GGIO1,
- (ModelNode*) &iedModel_GenericIO_GGIO1_Ind1,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9,
(ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO8_SBOw,
0
};
@@ -3681,6 +3703,288 @@ DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_ctlModel = {
NULL,
0};
+DataObject iedModel_GenericIO_GGIO1_SPCSO9 = {
+ DataObjectModelType,
+ "SPCSO9",
+ (ModelNode*) &iedModel_GenericIO_GGIO1,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_Ind1,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Oper,
+ 0
+};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper = {
+ DataAttributeModelType,
+ "Oper",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Cancel,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Oper_ctlVal,
+ 0,
+ CO,
+ CONSTRUCTED,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_ctlVal = {
+ DataAttributeModelType,
+ "ctlVal",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Oper,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Oper_origin,
+ NULL,
+ 0,
+ CO,
+ BOOLEAN,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_origin = {
+ DataAttributeModelType,
+ "origin",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Oper,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Oper_ctlNum,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Oper_origin_orCat,
+ 0,
+ CO,
+ CONSTRUCTED,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_origin_orCat = {
+ DataAttributeModelType,
+ "orCat",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Oper_origin,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Oper_origin_orIdent,
+ NULL,
+ 0,
+ CO,
+ ENUMERATED,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_origin_orIdent = {
+ DataAttributeModelType,
+ "orIdent",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Oper_origin,
+ NULL,
+ NULL,
+ 0,
+ CO,
+ OCTET_STRING_64,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_ctlNum = {
+ DataAttributeModelType,
+ "ctlNum",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Oper,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Oper_T,
+ NULL,
+ 0,
+ CO,
+ INT8U,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_T = {
+ DataAttributeModelType,
+ "T",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Oper,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Oper_Test,
+ NULL,
+ 0,
+ CO,
+ TIMESTAMP,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_Test = {
+ DataAttributeModelType,
+ "Test",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Oper,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Oper_Check,
+ NULL,
+ 0,
+ CO,
+ BOOLEAN,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_Check = {
+ DataAttributeModelType,
+ "Check",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Oper,
+ NULL,
+ NULL,
+ 0,
+ CO,
+ CHECK,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel = {
+ DataAttributeModelType,
+ "Cancel",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_stVal,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Cancel_ctlVal,
+ 0,
+ CO,
+ CONSTRUCTED,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel_ctlVal = {
+ DataAttributeModelType,
+ "ctlVal",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Cancel,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Cancel_origin,
+ NULL,
+ 0,
+ CO,
+ BOOLEAN,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel_origin = {
+ DataAttributeModelType,
+ "origin",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Cancel,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Cancel_ctlNum,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Cancel_origin_orCat,
+ 0,
+ CO,
+ CONSTRUCTED,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel_origin_orCat = {
+ DataAttributeModelType,
+ "orCat",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Cancel_origin,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Cancel_origin_orIdent,
+ NULL,
+ 0,
+ CO,
+ ENUMERATED,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel_origin_orIdent = {
+ DataAttributeModelType,
+ "orIdent",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Cancel_origin,
+ NULL,
+ NULL,
+ 0,
+ CO,
+ OCTET_STRING_64,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel_ctlNum = {
+ DataAttributeModelType,
+ "ctlNum",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Cancel,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Cancel_T,
+ NULL,
+ 0,
+ CO,
+ INT8U,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel_T = {
+ DataAttributeModelType,
+ "T",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Cancel,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Cancel_Test,
+ NULL,
+ 0,
+ CO,
+ TIMESTAMP,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel_Test = {
+ DataAttributeModelType,
+ "Test",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_Cancel,
+ NULL,
+ NULL,
+ 0,
+ CO,
+ BOOLEAN,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_stVal = {
+ DataAttributeModelType,
+ "stVal",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_q,
+ NULL,
+ 0,
+ ST,
+ BOOLEAN,
+ 0 + TRG_OPT_DATA_CHANGED,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_q = {
+ DataAttributeModelType,
+ "q",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_t,
+ NULL,
+ 0,
+ ST,
+ QUALITY,
+ 0 + TRG_OPT_QUALITY_CHANGED,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_t = {
+ DataAttributeModelType,
+ "t",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9,
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9_ctlModel,
+ NULL,
+ 0,
+ ST,
+ TIMESTAMP,
+ 0,
+ NULL,
+ 0};
+
+DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_ctlModel = {
+ DataAttributeModelType,
+ "ctlModel",
+ (ModelNode*) &iedModel_GenericIO_GGIO1_SPCSO9,
+ NULL,
+ NULL,
+ 0,
+ CF,
+ ENUMERATED,
+ 0,
+ NULL,
+ 0};
+
DataObject iedModel_GenericIO_GGIO1_Ind1 = {
DataObjectModelType,
"Ind1",
@@ -3878,22 +4182,13 @@ DataAttribute iedModel_GenericIO_GGIO1_Ind4_t = {
-
-
-
-
-
-
-
-
-
-
IedModel iedModel = {
"simpleIO",
&iedModel_GenericIO,
NULL,
NULL,
NULL,
+ NULL,
initializeValues
};
@@ -3920,4 +4215,6 @@ iedModel_GenericIO_GGIO1_SPCSO6_ctlModel.mmsValue = MmsValue_newIntegerFromInt32
iedModel_GenericIO_GGIO1_SPCSO7_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(3);
iedModel_GenericIO_GGIO1_SPCSO8_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(4);
+
+iedModel_GenericIO_GGIO1_SPCSO9_ctlModel.mmsValue = MmsValue_newIntegerFromInt32(3);
}
diff --git a/examples/server_example_control/static_model.h b/examples/server_example_control/static_model.h
index e93a2bc3..67c3967f 100644
--- a/examples/server_example_control/static_model.h
+++ b/examples/server_example_control/static_model.h
@@ -8,7 +8,7 @@
#define STATIC_MODEL_H_
#include
-#include "model.h"
+#include "iec61850_model.h"
extern IedModel iedModel;
extern LogicalDevice iedModel_GenericIO;
@@ -280,6 +280,28 @@ extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_stVal;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_q;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_t;
extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO8_ctlModel;
+extern DataObject iedModel_GenericIO_GGIO1_SPCSO9;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_ctlVal;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_origin;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_origin_orCat;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_origin_orIdent;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_ctlNum;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_T;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_Test;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Oper_Check;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel_ctlVal;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel_origin;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel_origin_orCat;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel_origin_orIdent;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel_ctlNum;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel_T;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_Cancel_Test;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_stVal;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_q;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_t;
+extern DataAttribute iedModel_GenericIO_GGIO1_SPCSO9_ctlModel;
extern DataObject iedModel_GenericIO_GGIO1_Ind1;
extern DataAttribute iedModel_GenericIO_GGIO1_Ind1_stVal;
extern DataAttribute iedModel_GenericIO_GGIO1_Ind1_q;
@@ -568,6 +590,28 @@ extern DataAttribute iedModel_GenericIO_GGIO1_Ind4_t;
#define IEDMODEL_GenericIO_GGIO1_SPCSO8_q (&iedModel_GenericIO_GGIO1_SPCSO8_q)
#define IEDMODEL_GenericIO_GGIO1_SPCSO8_t (&iedModel_GenericIO_GGIO1_SPCSO8_t)
#define IEDMODEL_GenericIO_GGIO1_SPCSO8_ctlModel (&iedModel_GenericIO_GGIO1_SPCSO8_ctlModel)
+#define IEDMODEL_GenericIO_GGIO1_SPCSO9 (&iedModel_GenericIO_GGIO1_SPCSO9)
+#define IEDMODEL_GenericIO_GGIO1_SPCSO9_Oper (&iedModel_GenericIO_GGIO1_SPCSO9_Oper)
+#define IEDMODEL_GenericIO_GGIO1_SPCSO9_Oper_ctlVal (&iedModel_GenericIO_GGIO1_SPCSO9_Oper_ctlVal)
+#define IEDMODEL_GenericIO_GGIO1_SPCSO9_Oper_origin (&iedModel_GenericIO_GGIO1_SPCSO9_Oper_origin)
+#define IEDMODEL_GenericIO_GGIO1_SPCSO9_Oper_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO9_Oper_origin_orCat)
+#define IEDMODEL_GenericIO_GGIO1_SPCSO9_Oper_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO9_Oper_origin_orIdent)
+#define IEDMODEL_GenericIO_GGIO1_SPCSO9_Oper_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO9_Oper_ctlNum)
+#define IEDMODEL_GenericIO_GGIO1_SPCSO9_Oper_T (&iedModel_GenericIO_GGIO1_SPCSO9_Oper_T)
+#define IEDMODEL_GenericIO_GGIO1_SPCSO9_Oper_Test (&iedModel_GenericIO_GGIO1_SPCSO9_Oper_Test)
+#define IEDMODEL_GenericIO_GGIO1_SPCSO9_Oper_Check (&iedModel_GenericIO_GGIO1_SPCSO9_Oper_Check)
+#define IEDMODEL_GenericIO_GGIO1_SPCSO9_Cancel (&iedModel_GenericIO_GGIO1_SPCSO9_Cancel)
+#define IEDMODEL_GenericIO_GGIO1_SPCSO9_Cancel_ctlVal (&iedModel_GenericIO_GGIO1_SPCSO9_Cancel_ctlVal)
+#define IEDMODEL_GenericIO_GGIO1_SPCSO9_Cancel_origin (&iedModel_GenericIO_GGIO1_SPCSO9_Cancel_origin)
+#define IEDMODEL_GenericIO_GGIO1_SPCSO9_Cancel_origin_orCat (&iedModel_GenericIO_GGIO1_SPCSO9_Cancel_origin_orCat)
+#define IEDMODEL_GenericIO_GGIO1_SPCSO9_Cancel_origin_orIdent (&iedModel_GenericIO_GGIO1_SPCSO9_Cancel_origin_orIdent)
+#define IEDMODEL_GenericIO_GGIO1_SPCSO9_Cancel_ctlNum (&iedModel_GenericIO_GGIO1_SPCSO9_Cancel_ctlNum)
+#define IEDMODEL_GenericIO_GGIO1_SPCSO9_Cancel_T (&iedModel_GenericIO_GGIO1_SPCSO9_Cancel_T)
+#define IEDMODEL_GenericIO_GGIO1_SPCSO9_Cancel_Test (&iedModel_GenericIO_GGIO1_SPCSO9_Cancel_Test)
+#define IEDMODEL_GenericIO_GGIO1_SPCSO9_stVal (&iedModel_GenericIO_GGIO1_SPCSO9_stVal)
+#define IEDMODEL_GenericIO_GGIO1_SPCSO9_q (&iedModel_GenericIO_GGIO1_SPCSO9_q)
+#define IEDMODEL_GenericIO_GGIO1_SPCSO9_t (&iedModel_GenericIO_GGIO1_SPCSO9_t)
+#define IEDMODEL_GenericIO_GGIO1_SPCSO9_ctlModel (&iedModel_GenericIO_GGIO1_SPCSO9_ctlModel)
#define IEDMODEL_GenericIO_GGIO1_Ind1 (&iedModel_GenericIO_GGIO1_Ind1)
#define IEDMODEL_GenericIO_GGIO1_Ind1_stVal (&iedModel_GenericIO_GGIO1_Ind1_stVal)
#define IEDMODEL_GenericIO_GGIO1_Ind1_q (&iedModel_GenericIO_GGIO1_Ind1_q)
diff --git a/examples/server_example_dynamic/server_example_dynamic.c b/examples/server_example_dynamic/server_example_dynamic.c
index 361acd0f..49dccbc1 100644
--- a/examples/server_example_dynamic/server_example_dynamic.c
+++ b/examples/server_example_dynamic/server_example_dynamic.c
@@ -6,7 +6,7 @@
*/
#include "iec61850_server.h"
-#include "thread.h"
+#include "hal_thread.h"
#include
#include
#include
@@ -40,6 +40,8 @@ int main(int argc, char** argv) {
DataObject* lln0_mod = CDC_ENS_create("Mod", (ModelNode*) lln0, 0);
DataObject* lln0_health = CDC_ENS_create("Health", (ModelNode*) lln0, 0);
+ SettingGroupControlBlock_create(lln0, 1, 1);
+
/* Add a temperature sensor LN */
LogicalNode* ttmp1 = LogicalNode_create("TTMP1", lDevice1);
DataObject* ttmp1_tmpsv = CDC_SAV_create("TmpSv", (ModelNode*) ttmp1, 0, false);
diff --git a/examples/server_example_goose/server_example_goose.c b/examples/server_example_goose/server_example_goose.c
index 7df535ce..f014c42b 100644
--- a/examples/server_example_goose/server_example_goose.c
+++ b/examples/server_example_goose/server_example_goose.c
@@ -7,7 +7,7 @@
*/
#include "iec61850_server.h"
-#include "thread.h" /* for Thread_sleep() */
+#include "hal_thread.h" /* for Thread_sleep() */
#include
#include
#include
diff --git a/examples/server_example_goose/simpleIO_direct_control_goose.icd b/examples/server_example_goose/simpleIO_direct_control_goose.icd
index 81357b14..5f68fa01 100644
--- a/examples/server_example_goose/simpleIO_direct_control_goose.icd
+++ b/examples/server_example_goose/simpleIO_direct_control_goose.icd
@@ -17,7 +17,7 @@
- 111
+ 1
4
01-0c-cd-01-00-01
1000
@@ -25,7 +25,7 @@
- 111
+ 1
4
01-0c-cd-01-00-01
1000
diff --git a/examples/server_example_goose/static_model.c b/examples/server_example_goose/static_model.c
index 1295dfe1..2beaeac0 100644
--- a/examples/server_example_goose/static_model.c
+++ b/examples/server_example_goose/static_model.c
@@ -4,7 +4,7 @@
* automatically generated from simpleIO_direct_control_goose.icd
*/
#include
-#include "model.h"
+#include "iec61850_model.h"
extern IedModel iedModel;
static void initializeValues();
@@ -159,7 +159,7 @@ extern DataSetEntry ds_GenericIO_LLN0_Events_fcda2;
extern DataSetEntry ds_GenericIO_LLN0_Events_fcda3;
DataSetEntry ds_GenericIO_LLN0_Events_fcda0 = {
- "simpleIOGenericIO",
+ "GenericIO",
"GGIO1$ST$SPCSO1$stVal",
-1,
NULL,
@@ -168,7 +168,7 @@ DataSetEntry ds_GenericIO_LLN0_Events_fcda0 = {
};
DataSetEntry ds_GenericIO_LLN0_Events_fcda1 = {
- "simpleIOGenericIO",
+ "GenericIO",
"GGIO1$ST$SPCSO2$stVal",
-1,
NULL,
@@ -177,7 +177,7 @@ DataSetEntry ds_GenericIO_LLN0_Events_fcda1 = {
};
DataSetEntry ds_GenericIO_LLN0_Events_fcda2 = {
- "simpleIOGenericIO",
+ "GenericIO",
"GGIO1$ST$SPCSO3$stVal",
-1,
NULL,
@@ -186,7 +186,7 @@ DataSetEntry ds_GenericIO_LLN0_Events_fcda2 = {
};
DataSetEntry ds_GenericIO_LLN0_Events_fcda3 = {
- "simpleIOGenericIO",
+ "GenericIO",
"GGIO1$ST$SPCSO4$stVal",
-1,
NULL,
@@ -195,7 +195,7 @@ DataSetEntry ds_GenericIO_LLN0_Events_fcda3 = {
};
DataSet ds_GenericIO_LLN0_Events = {
- "simpleIOGenericIO",
+ "GenericIO",
"LLN0$Events",
4,
&ds_GenericIO_LLN0_Events_fcda0,
@@ -208,7 +208,7 @@ extern DataSetEntry ds_GenericIO_LLN0_AnalogValues_fcda2;
extern DataSetEntry ds_GenericIO_LLN0_AnalogValues_fcda3;
DataSetEntry ds_GenericIO_LLN0_AnalogValues_fcda0 = {
- "simpleIOGenericIO",
+ "GenericIO",
"GGIO1$MX$AnIn1",
-1,
NULL,
@@ -217,7 +217,7 @@ DataSetEntry ds_GenericIO_LLN0_AnalogValues_fcda0 = {
};
DataSetEntry ds_GenericIO_LLN0_AnalogValues_fcda1 = {
- "simpleIOGenericIO",
+ "GenericIO",
"GGIO1$MX$AnIn2",
-1,
NULL,
@@ -226,7 +226,7 @@ DataSetEntry ds_GenericIO_LLN0_AnalogValues_fcda1 = {
};
DataSetEntry ds_GenericIO_LLN0_AnalogValues_fcda2 = {
- "simpleIOGenericIO",
+ "GenericIO",
"GGIO1$MX$AnIn3",
-1,
NULL,
@@ -235,7 +235,7 @@ DataSetEntry ds_GenericIO_LLN0_AnalogValues_fcda2 = {
};
DataSetEntry ds_GenericIO_LLN0_AnalogValues_fcda3 = {
- "simpleIOGenericIO",
+ "GenericIO",
"GGIO1$MX$AnIn4",
-1,
NULL,
@@ -244,7 +244,7 @@ DataSetEntry ds_GenericIO_LLN0_AnalogValues_fcda3 = {
};
DataSet ds_GenericIO_LLN0_AnalogValues = {
- "simpleIOGenericIO",
+ "GenericIO",
"LLN0$AnalogValues",
4,
&ds_GenericIO_LLN0_AnalogValues_fcda0,
@@ -253,7 +253,7 @@ DataSet ds_GenericIO_LLN0_AnalogValues = {
LogicalDevice iedModel_GenericIO = {
LogicalDeviceModelType,
- "simpleIOGenericIO",
+ "GenericIO",
(ModelNode*) &iedModel,
NULL,
(ModelNode*) &iedModel_GenericIO_LLN0
@@ -1970,7 +1970,7 @@ extern GSEControlBlock iedModel_GenericIO_LLN0_gse1;
static PhyComAddress iedModel_GenericIO_LLN0_gse0_address = {
4,
- 111,
+ 1,
1000,
{0x1, 0xc, 0xcd, 0x1, 0x0, 0x1}
};
@@ -1979,7 +1979,7 @@ GSEControlBlock iedModel_GenericIO_LLN0_gse0 = {&iedModel_GenericIO_LLN0, "gcbEv
static PhyComAddress iedModel_GenericIO_LLN0_gse1_address = {
4,
- 111,
+ 1,
1000,
{0x1, 0xc, 0xcd, 0x1, 0x0, 0x1}
};
@@ -1987,12 +1987,14 @@ static PhyComAddress iedModel_GenericIO_LLN0_gse1_address = {
GSEControlBlock iedModel_GenericIO_LLN0_gse1 = {&iedModel_GenericIO_LLN0, "gcbAnalogValues", "analog", "AnalogValues", 2, false,&iedModel_GenericIO_LLN0_gse1_address, NULL};
+
IedModel iedModel = {
"simpleIO",
&iedModel_GenericIO,
&ds_GenericIO_LLN0_Events,
&iedModel_GenericIO_LLN0_report0,
&iedModel_GenericIO_LLN0_gse0,
+ NULL,
initializeValues
};
diff --git a/examples/server_example_goose/static_model.h b/examples/server_example_goose/static_model.h
index 5a4bb9b2..5e827db7 100644
--- a/examples/server_example_goose/static_model.h
+++ b/examples/server_example_goose/static_model.h
@@ -8,7 +8,7 @@
#define STATIC_MODEL_H_
#include
-#include "model.h"
+#include "iec61850_model.h"
extern IedModel iedModel;
extern LogicalDevice iedModel_GenericIO;
diff --git a/make/stack_includes.mk b/make/stack_includes.mk
index 6d89ad10..28e1291c 100644
--- a/make/stack_includes.mk
+++ b/make/stack_includes.mk
@@ -1,24 +1,9 @@
INCLUDES = -I$(LIBIEC_HOME)/config
-INCLUDES += -I$(LIBIEC_HOME)/src/common
-INCLUDES += -I$(LIBIEC_HOME)/src/mms/iso_presentation
-INCLUDES += -I$(LIBIEC_HOME)/src/mms/iso_session
-INCLUDES += -I$(LIBIEC_HOME)/src/mms/iso_cotp
-INCLUDES += -I$(LIBIEC_HOME)/src/mms/iso_acse
-INCLUDES += -I$(LIBIEC_HOME)/src/mms/iso_mms/common
-INCLUDES += -I$(LIBIEC_HOME)/src/mms/iso_mms/client
-INCLUDES += -I$(LIBIEC_HOME)/src/mms/iso_mms/server
-INCLUDES += -I$(LIBIEC_HOME)/src/mms/iso_client
-INCLUDES += -I$(LIBIEC_HOME)/src/mms/iso_common
-INCLUDES += -I$(LIBIEC_HOME)/src/mms/iso_server
+INCLUDES += -I$(LIBIEC_HOME)/src/common/inc
+INCLUDES += -I$(LIBIEC_HOME)/src/mms/inc
+INCLUDES += -I$(LIBIEC_HOME)/src/mms/inc_private
INCLUDES += -I$(LIBIEC_HOME)/src/mms/asn1
-INCLUDES += -I$(LIBIEC_HOME)/src/iedcommon
-INCLUDES += -I$(LIBIEC_HOME)/src/iedserver/mms_mapping
-INCLUDES += -I$(LIBIEC_HOME)/src/iedserver/model
-INCLUDES += -I$(LIBIEC_HOME)/src/iedserver
-INCLUDES += -I$(LIBIEC_HOME)/src/iedclient
-INCLUDES += -I$(LIBIEC_HOME)/src/hal
-INCLUDES += -I$(LIBIEC_HOME)/src/hal/thread
-INCLUDES += -I$(LIBIEC_HOME)/src/hal/socket
-INCLUDES += -I$(LIBIEC_HOME)/src/hal/filesystem
-INCLUDES += -I$(LIBIEC_HOME)/src/hal/time
+INCLUDES += -I$(LIBIEC_HOME)/src/iec61850/inc
+INCLUDES += -I$(LIBIEC_HOME)/src/iec61850/inc_private
+INCLUDES += -I$(LIBIEC_HOME)/src/hal/inc
INCLUDES += -I$(LIBIEC_HOME)/src/goose
diff --git a/make/target_system.mk b/make/target_system.mk
index 161acd90..c7edf351 100644
--- a/make/target_system.mk
+++ b/make/target_system.mk
@@ -4,7 +4,7 @@ MIPSEL_TOOLCHAIN_PREFIX=mipsel-openwrt-linux-
# ARM_TOOLCHAIN_PREFIX=arm-linux-gnueabihf-
#ARM_TOOLCHAIN_PREFIX=arm-linux-gnueabi-
#ARM_TOOLCHAIN_PREFIX=arm-poky-linux-gnueabi-
-ARM_TOOLCHAIN_PREFIX=arm-linux-
+ARM_TOOLCHAIN_PREFIX=arm-linux-gnueabi-
UCLINUX_ARM_TOOLCHAIN_PREFIX=arm-uclinux-elf-
MINGW_TOOLCHAIN_PREFIX=i586-mingw32msvc-
#MINGW_TOOLCHAIN_PREFIX=x86_64-w64-mingw32-
@@ -126,7 +126,7 @@ LIB_OBJS_DIR = $(LIBIEC_HOME)/build
endif
CFLAGS += -g
-CFLAGS += -Os
+#CFLAGS += -Os
DYNLIB_LDFLAGS=-lpthread
endif
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 19d94212..46dbfae8 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -5,12 +5,12 @@ set (lib_common_SRCS
./common/map.c
./common/linked_list.c
./common/byte_buffer.c
+./common/lib_memory.c
./common/string_utilities.c
./common/buffer_chain.c
./common/conversions.c
./common/mem_alloc_linked_list.c
./common/simple_allocator.c
-./common/byte_stream.c
./mms/iso_server/iso_connection.c
./mms/iso_server/iso_server.c
./mms/iso_acse/acse.c
@@ -52,24 +52,25 @@ set (lib_common_SRCS
./mms/asn1/asn1_ber_primitive_value.c
./mms/asn1/ber_encoder.c
./mms/asn1/ber_integer.c
-./mms/iso_client/impl/iso_client_connection.c
+./mms/iso_client/iso_client_connection.c
./mms/iso_common/iso_connection_parameters.c
./mms/iso_session/iso_session.c
-./iedclient/impl/client_control.c
-./iedclient/impl/client_report_control.c
-./iedclient/impl/client_report.c
-./iedclient/impl/ied_connection.c
-./iedcommon/iec61850_common.c
-./iedserver/impl/ied_server.c
-./iedserver/impl/client_connection.c
-./iedserver/model/model.c
-./iedserver/model/dynamic_model.c
-./iedserver/model/cdc.c
-./iedserver/model/config_file_parser.c
-./iedserver/mms_mapping/control.c
-./iedserver/mms_mapping/mms_mapping.c
-./iedserver/mms_mapping/reporting.c
-./iedserver/mms_mapping/mms_goose.c
+./iec61850/client/client_control.c
+./iec61850/client/client_report_control.c
+./iec61850/client/client_goose_control.c
+./iec61850/client/client_report.c
+./iec61850/client/ied_connection.c
+./iec61850/common/iec61850_common.c
+./iec61850/server/impl/ied_server.c
+./iec61850/server/impl/client_connection.c
+./iec61850/server/model/model.c
+./iec61850/server/model/dynamic_model.c
+./iec61850/server/model/cdc.c
+./iec61850/server/model/config_file_parser.c
+./iec61850/server/mms_mapping/control.c
+./iec61850/server/mms_mapping/mms_mapping.c
+./iec61850/server/mms_mapping/reporting.c
+./iec61850/server/mms_mapping/mms_goose.c
)
@@ -168,6 +169,7 @@ set (lib_asn1c_SRCS
set (lib_goose_SRCS
./goose/goose_subscriber.c
+./goose/goose_receiver.c
./goose/goose_publisher.c
)
@@ -274,8 +276,6 @@ set_target_properties(iec61850-shared PROPERTIES
)
-
-
GENERATE_EXPORT_HEADER(iec61850-shared
BASE_NAME iec61850-shared
EXPORT_MACRO_NAME iec61850-shared_EXPORT
@@ -286,12 +286,21 @@ GENERATE_EXPORT_HEADER(iec61850-shared
add_library (iec61850 STATIC ${library_SRCS})
IF(UNIX)
-target_link_libraries (iec61850
- -lpthread
- -lm
-)
+ IF (CONFIG_SYSTEM_HAS_CLOCK_GETTIME)
+ target_link_libraries (iec61850
+ -lpthread
+ -lm
+ -lrt
+ )
+ ELSE ()
+ target_link_libraries (iec61850
+ -lpthread
+ -lm
+ )
+ ENDIF (CONFIG_SYSTEM_HAS_CLOCK_GETTIME)
ENDIF(UNIX)
+
iF(WITH_WPCAP)
target_link_libraries(iec61850
${CMAKE_CURRENT_SOURCE_DIR}/../third_party/winpcap/lib/wpcap.lib
@@ -318,6 +327,8 @@ if(MSVC)
endif()
ENDIF(WITH_WPCAP)
+
+
install (TARGETS iec61850 iec61850-shared
RUNTIME DESTINATION bin
ARCHIVE DESTINATION lib
diff --git a/src/common/buffer_chain.c b/src/common/buffer_chain.c
index 39253be2..96043140 100644
--- a/src/common/buffer_chain.c
+++ b/src/common/buffer_chain.c
@@ -42,7 +42,7 @@ BufferChain_destroy(BufferChain self)
while (currentChainElement != NULL) {
BufferChain nextChainElement = currentChainElement->nextPart;
- free(currentChainElement);
+ GLOBAL_FREEMEM(currentChainElement);
currentChainElement = nextChainElement;
}
}
diff --git a/src/common/byte_buffer.c b/src/common/byte_buffer.c
index 96949611..9c1a4f9d 100644
--- a/src/common/byte_buffer.c
+++ b/src/common/byte_buffer.c
@@ -28,10 +28,10 @@ ByteBuffer*
ByteBuffer_create(ByteBuffer* self, int maxSize)
{
if (self == NULL) {
- self = (ByteBuffer*) calloc(1, sizeof(ByteBuffer));
+ self = (ByteBuffer*) GLOBAL_CALLOC(1, sizeof(ByteBuffer));
}
- self->buffer = (uint8_t*) calloc(maxSize, sizeof(uint8_t));
+ self->buffer = (uint8_t*) GLOBAL_CALLOC(maxSize, sizeof(uint8_t));
self->maxSize = maxSize;
self->size = 0;
@@ -41,8 +41,8 @@ ByteBuffer_create(ByteBuffer* self, int maxSize)
void
ByteBuffer_destroy(ByteBuffer* self)
{
- free(self->buffer);
- free(self);
+ GLOBAL_FREEMEM(self->buffer);
+ GLOBAL_FREEMEM(self);
}
void
@@ -105,6 +105,7 @@ ByteBuffer_setSize(ByteBuffer* self, int size)
return self->size;
}
+#if 0
void
ByteBuffer_print(ByteBuffer* self, char* message)
{
@@ -119,3 +120,4 @@ ByteBuffer_print(ByteBuffer* self, char* message)
}
printf("\n");
}
+#endif
diff --git a/src/common/lib_memory.c b/src/common/lib_memory.c
new file mode 100644
index 00000000..d279b6c0
--- /dev/null
+++ b/src/common/lib_memory.c
@@ -0,0 +1,83 @@
+/*
+ * lib_memory.c
+ *
+ * Copyright 2014 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.
+ */
+
+#include "lib_memory.h"
+
+static MemoryExceptionHandler exceptionHandler = NULL;
+static void* exceptionHandlerParameter = NULL;
+
+static void
+noMemoryAvailableHandler(void)
+{
+ if (exceptionHandler != NULL)
+ exceptionHandler(exceptionHandlerParameter);
+}
+
+void
+Memory_installExceptionHandler(MemoryExceptionHandler handler, void* parameter)
+{
+ exceptionHandler = handler;
+ exceptionHandlerParameter = parameter;
+}
+
+void*
+Memory_malloc(size_t size)
+{
+ void* memory = malloc(size);
+
+ if (memory == NULL)
+ noMemoryAvailableHandler();
+
+ return memory;
+}
+
+
+void*
+Memory_calloc(size_t nmemb, size_t size)
+{
+ void* memory = calloc(nmemb, size);
+
+ if (memory == NULL)
+ noMemoryAvailableHandler();
+
+ return memory;
+}
+
+
+void *
+Memory_realloc(void *ptr, size_t size)
+{
+ void* memory = realloc(ptr, size);
+
+ if (memory == NULL)
+ noMemoryAvailableHandler();
+
+ return memory;
+}
+
+void
+Memory_free(void* memb)
+{
+ free(memb);
+}
+
diff --git a/src/common/linked_list.c b/src/common/linked_list.c
index 93dd0436..a487b097 100644
--- a/src/common/linked_list.c
+++ b/src/common/linked_list.c
@@ -1,7 +1,7 @@
/*
* linked_list.c
*
- * Copyright 2013 Michael Zillgith
+ * Copyright 2013, 2014 Michael Zillgith
*
* This file is part of libIEC61850.
*
@@ -38,7 +38,7 @@ LinkedList_create()
{
LinkedList newList;
- newList = (LinkedList) malloc(sizeof(struct sLinkedList));
+ newList = (LinkedList) GLOBAL_MALLOC(sizeof(struct sLinkedList));
newList->data = NULL;
newList->next = NULL;
@@ -57,9 +57,11 @@ LinkedList_destroyDeep(LinkedList list, LinkedListValueDeleteFunction valueDelet
do {
currentElement = nextElement;
nextElement = currentElement->next;
+
if (currentElement->data != NULL)
valueDeleteFunction(currentElement->data);
- free(currentElement);
+
+ GLOBAL_FREEMEM(currentElement);
}
while (nextElement != NULL);
}
@@ -67,7 +69,7 @@ LinkedList_destroyDeep(LinkedList list, LinkedListValueDeleteFunction valueDelet
void
LinkedList_destroy(LinkedList list)
{
- LinkedList_destroyDeep(list, free);
+ LinkedList_destroyDeep(list, Memory_free);
}
/**
@@ -82,7 +84,7 @@ LinkedList_destroyStatic(LinkedList list)
do {
currentElement = nextElement;
nextElement = currentElement->next;
- free(currentElement);
+ GLOBAL_FREEMEM(currentElement);
}
while (nextElement != NULL);
}
@@ -123,7 +125,7 @@ LinkedList_remove(LinkedList list, void* data)
while (currentElement != NULL) {
if (currentElement->data == data) {
lastElement->next = currentElement->next;
- free(currentElement);
+ GLOBAL_FREEMEM(currentElement);
return true;
}
diff --git a/src/common/map.c b/src/common/map.c
index c1fe97b2..d0ab9e33 100644
--- a/src/common/map.c
+++ b/src/common/map.c
@@ -42,7 +42,7 @@ comparePointerKeys(void* key1, void* key2)
Map
Map_create()
{
- Map map = (Map) calloc(1, sizeof(struct sMap));
+ Map map = (Map) GLOBAL_CALLOC(1, sizeof(struct sMap));
map->entries = LinkedList_create();
map->compareKeys = comparePointerKeys;
return map;
@@ -57,7 +57,7 @@ Map_size(Map map)
void*
Map_addEntry(Map map, void* key, void* value)
{
- MapEntry* entry = (MapEntry*) malloc(sizeof(MapEntry));
+ MapEntry* entry = (MapEntry*) GLOBAL_MALLOC(sizeof(MapEntry));
entry->key = key;
entry->value = value;
LinkedList_add(map->entries, entry);
@@ -81,9 +81,9 @@ Map_removeEntry(Map map, void* key, bool deleteKey)
value = entry->value;
if (deleteKey == true)
- free(entry->key);
- free(entry);
- free(element);
+ GLOBAL_FREEMEM(entry->key);
+ GLOBAL_FREEMEM(entry);
+ GLOBAL_FREEMEM(element);
break;
}
@@ -117,12 +117,12 @@ Map_delete(Map map, bool deleteKey)
while ((element = LinkedList_getNext(element)) != NULL) {
MapEntry* entry = (MapEntry*) element->data;
if (deleteKey == true)
- free(entry->key);
- free(entry->value);
+ GLOBAL_FREEMEM(entry->key);
+ GLOBAL_FREEMEM(entry->value);
}
LinkedList_destroy(map->entries);
- free(map);
+ GLOBAL_FREEMEM(map);
}
void
@@ -133,12 +133,12 @@ Map_deleteStatic(Map map, bool deleteKey)
if (deleteKey == true) {
while ((element = LinkedList_getNext(element)) != NULL) {
MapEntry* entry = (MapEntry*) element->data;
- free(entry->key);
+ GLOBAL_FREEMEM(entry->key);
}
}
LinkedList_destroy(map->entries);
- free(map);
+ GLOBAL_FREEMEM(map);
}
void
@@ -150,10 +150,10 @@ Map_deleteDeep(Map map, bool deleteKey, void
while ((element = LinkedList_getNext(element)) != NULL) {
MapEntry* entry = (MapEntry*) element->data;
if (deleteKey == true)
- free(entry->key);
+ GLOBAL_FREEMEM(entry->key);
valueDeleteFunction(entry->value);
}
LinkedList_destroy(map->entries);
- free(map);
+ GLOBAL_FREEMEM(map);
}
diff --git a/src/common/simple_allocator.c b/src/common/simple_allocator.c
index 6e0fac08..6592f746 100644
--- a/src/common/simple_allocator.c
+++ b/src/common/simple_allocator.c
@@ -1,7 +1,7 @@
/*
* simple_allocator.c
*
- * Copyright 2013 Michael Zillgith
+ * Copyright 2013, 2014 Michael Zillgith
*
* This file is part of libIEC61850.
*
@@ -33,9 +33,20 @@ MemoryAllocator_init(MemoryAllocator* self, char* memoryBlock, int size)
self->size = size;
}
+static int
+getAlignedSize(int size)
+{
+ if ((size % sizeof(void*)) > 0)
+ return sizeof(void*) * ((size + sizeof(void*)) / sizeof(void*));
+ else
+ return size;
+}
+
char*
MemoryAllocator_allocate(MemoryAllocator* self, int size)
{
+ size = getAlignedSize(size);
+
if (((self->currentPtr - self->memoryBlock) + size) <= self->size) {
char* ptr = self->currentPtr;
self->currentPtr += size;
diff --git a/src/common/string_utilities.c b/src/common/string_utilities.c
index 98dfd29b..702f9453 100644
--- a/src/common/string_utilities.c
+++ b/src/common/string_utilities.c
@@ -28,7 +28,7 @@ copySubString(char* startPos, char* endPos)
{
int newStringLength = endPos - startPos;
- char* newString = (char*) malloc(newStringLength) + 1;
+ char* newString = (char*) GLOBAL_MALLOC(newStringLength) + 1;
memcpy(newString, startPos, newStringLength);
@@ -42,7 +42,7 @@ copyString(const char* string)
{
int newStringLength = strlen(string) + 1;
- char* newString = (char*) malloc(newStringLength);
+ char* newString = (char*) GLOBAL_MALLOC(newStringLength);
memcpy(newString, string, newStringLength);
@@ -50,7 +50,7 @@ copyString(const char* string)
}
char*
-copyStringToBuffer(char* string, char* buffer)
+copyStringToBuffer(const char* string, char* buffer)
{
int newStringLength = strlen(string) + 1;
@@ -63,7 +63,7 @@ copyStringToBuffer(char* string, char* buffer)
char*
createStringFromBuffer(uint8_t* buf, int size)
{
- char* newStr = (char*) malloc(size + 1);
+ char* newStr = (char*) GLOBAL_MALLOC(size + 1);
memcpy(newStr, buf, size);
newStr[size] = 0;
@@ -110,7 +110,7 @@ createString(int count, ...)
}
va_end(ap);
- newStr = (char*) malloc(newStringLength + 1);
+ newStr = (char*) GLOBAL_MALLOC(newStringLength + 1);
currentPos = newStr;
diff --git a/src/doxygen.config b/src/doxygen.config
index 81704c69..84558522 100644
--- a/src/doxygen.config
+++ b/src/doxygen.config
@@ -16,9 +16,9 @@
DOXYFILE_ENCODING = UTF-8
-PROJECT_NAME = "libIEC61850 0.7.8"
+PROJECT_NAME = "libIEC61850"
-PROJECT_NUMBER =
+PROJECT_NUMBER = 0.8.2
PROJECT_BRIEF = "Open-source IEC 61850 MMS/GOOSE server and client library"
@@ -207,29 +207,31 @@ WARN_LOGFILE =
# directories like "/usr/src/myproject". Separate the files or directories
# with spaces.
-INPUT = "iedclient/iec61850_client.h"
-INPUT += "mms/iso_mms/common/mms_value.h"
-INPUT += "common/linked_list.h"
+INPUT = "iec61850/inc/iec61850_client.h"
+INPUT += "mms/inc/mms_value.h"
+INPUT += "common/inc/linked_list.h"
INPUT += "doxygen/mainpage.doxygen"
-INPUT += "iedserver/iec61850_server.h"
-INPUT += "iedcommon/iec61850_common.h"
-INPUT += "iedserver/model/model.h"
-INPUT += "iedserver/model/dynamic_model.h"
-INPUT += "iedserver/model/config_file_parser.h"
-INPUT += "iedserver/model/cdc.h"
+INPUT += "iec61850/inc/iec61850_server.h"
+INPUT += "iec61850/inc/iec61850_common.h"
+INPUT += "iec61850/inc/iec61850_model.h"
+INPUT += "iec61850/inc/iec61850_dynamic_model.h"
+INPUT += "iec61850/inc/iec61850_config_file_parser.h"
+INPUT += "iec61850/inc/iec61850_cdc.h"
INPUT += "goose/goose_subscriber.h"
-INPUT += "mms/iso_mms/server/mms_device_model.h"
-INPUT += "mms/iso_mms/common/mms_types.h"
-INPUT += "mms/iso_mms/server/mms_server.h"
-INPUT += "mms/iso_server/iso_server.h"
-INPUT += "mms/iso_mms/server/mms_named_variable_list.h"
-INPUT += "mms/iso_mms/client/mms_client_connection.h"
-INPUT += "mms/iso_client/iso_connection_parameters.h"
-INPUT += "hal/socket/socket.h"
-INPUT += "hal/thread/thread.h"
-INPUT += "hal/ethernet/ethernet.h"
-INPUT += "hal/filesystem/filesystem.h"
-INPUT += "hal/hal.h"
+INPUT += "mms/inc/mms_device_model.h"
+INPUT += "mms/inc/mms_types.h"
+INPUT += "mms/inc/mms_server.h"
+INPUT += "mms/inc/iso_server.h"
+INPUT += "mms/inc/mms_named_variable_list.h"
+INPUT += "mms/inc/mms_type_spec.h"
+INPUT += "mms/inc/mms_types.h"
+INPUT += "mms/inc/mms_client_connection.h"
+INPUT += "mms/inc/iso_connection_parameters.h"
+INPUT += "hal/inc/hal_socket.h"
+INPUT += "hal/inc/hal_thread.h"
+INPUT += "hal/inc/hal_ethernet.h"
+INPUT += "hal/inc/hal_filesystem.h"
+INPUT += "hal/inc/hal_time.h"
INPUT_ENCODING = UTF-8
diff --git a/src/goose/goose_publisher.c b/src/goose/goose_publisher.c
index a4090c9c..371fde2e 100644
--- a/src/goose/goose_publisher.c
+++ b/src/goose/goose_publisher.c
@@ -24,11 +24,15 @@
#include "libiec61850_platform_includes.h"
#include "stack_config.h"
#include "goose_publisher.h"
-#include "ethernet.h"
+#include "hal_ethernet.h"
#include "ber_encoder.h"
#include "mms_server_internal.h"
#include "mms_value_internal.h"
+#ifndef DEBUG_GOOSE_PUBLISHER
+#define DEBUG_GOOSE_PUBLISHER 0
+#endif
+
#define GOOSE_MAX_MESSAGE_SIZE 1518
static void
@@ -36,7 +40,7 @@ prepareGooseBuffer(GoosePublisher self, CommParameters* parameters, char* interf
struct sGoosePublisher {
uint8_t* buffer;
- uint16_t appId;
+ //uint16_t appId;
EthernetSocket ethernetSocket;
int lengthField;
int payloadStart;
@@ -45,9 +49,9 @@ struct sGoosePublisher {
char* goCBRef;
char* dataSetRef;
- uint16_t minTime;
- uint16_t maxTime;
- bool fixedOffs;
+ //uint16_t minTime;
+ //uint16_t maxTime;
+ //bool fixedOffs;
uint32_t confRev;
uint32_t stNum;
@@ -63,7 +67,7 @@ struct sGoosePublisher {
GoosePublisher
GoosePublisher_create(CommParameters* parameters, char* interfaceID)
{
- GoosePublisher self = (GoosePublisher) calloc(1, sizeof(struct sGoosePublisher));
+ GoosePublisher self = (GoosePublisher) GLOBAL_CALLOC(1, sizeof(struct sGoosePublisher));
prepareGooseBuffer(self, parameters, interfaceID);
@@ -82,16 +86,16 @@ GoosePublisher_destroy(GoosePublisher self)
MmsValue_delete(self->timestamp);
if (self->goID != NULL)
- free(self->goID);
+ GLOBAL_FREEMEM(self->goID);
if (self->goCBRef != NULL)
- free(self->goCBRef);
+ GLOBAL_FREEMEM(self->goCBRef);
if (self->dataSetRef != NULL)
- free(self->dataSetRef);
+ GLOBAL_FREEMEM(self->dataSetRef);
- free(self->buffer);
- free(self);
+ GLOBAL_FREEMEM(self->buffer);
+ GLOBAL_FREEMEM(self);
}
void
@@ -190,7 +194,7 @@ prepareGooseBuffer(GoosePublisher self, CommParameters* parameters, char* interf
else
self->ethernetSocket = Ethernet_createSocket(CONFIG_ETHERNET_INTERFACE_ID, dstAddr);
- self->buffer = (uint8_t*) malloc(GOOSE_MAX_MESSAGE_SIZE);
+ self->buffer = (uint8_t*) GLOBAL_MALLOC(GOOSE_MAX_MESSAGE_SIZE);
memcpy(self->buffer, dstAddr, 6);
memcpy(self->buffer + 6, srcAddr, 6);
@@ -246,6 +250,8 @@ createGoosePayload(GoosePublisher self, LinkedList dataSetValues, uint8_t* buffe
if (self->goID != NULL)
goosePduLength += BerEncoder_determineEncodedStringSize(self->goID);
+ else
+ goosePduLength += BerEncoder_determineEncodedStringSize(self->goCBRef);
uint32_t timeAllowedToLive = self->timeAllowedToLive;
@@ -303,6 +309,8 @@ createGoosePayload(GoosePublisher self, LinkedList dataSetValues, uint8_t* buffe
/* Encode goID */
if (self->goID != NULL)
bufPos = BerEncoder_encodeStringWithTag(0x83, self->goID, buffer, bufPos);
+ else
+ bufPos = BerEncoder_encodeStringWithTag(0x83, self->goCBRef, buffer, bufPos);
/* Encode t */
bufPos = BerEncoder_encodeOctetString(0x84, self->timestamp->value.utcTime, 8, buffer, bufPos);
@@ -363,6 +371,9 @@ GoosePublisher_publish(GoosePublisher self, LinkedList dataSet)
self->buffer[lengthIndex] = gooseLength / 256;
self->buffer[lengthIndex + 1] = gooseLength & 0xff;
+ if (DEBUG_GOOSE_PUBLISHER)
+ printf("GOOSE_PUBLISHER: send GOOSE message\n");
+
Ethernet_sendPacket(self->ethernetSocket, self->buffer, self->payloadStart + payloadLength);
return 0;
diff --git a/src/goose/goose_receiver.c b/src/goose/goose_receiver.c
new file mode 100644
index 00000000..0b5e39d6
--- /dev/null
+++ b/src/goose/goose_receiver.c
@@ -0,0 +1,778 @@
+/*
+ * goose_receiver.c
+ *
+ * Copyright 2014 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.
+ */
+
+#include "libiec61850_platform_includes.h"
+
+#include "stack_config.h"
+#include "goose_subscriber.h"
+#include "hal_ethernet.h"
+#include "hal_thread.h"
+
+#include "ber_decode.h"
+
+#include "mms_value.h"
+#include "mms_value_internal.h"
+#include "linked_list.h"
+
+#include "goose_receiver.h"
+#include "goose_receiver_internal.h"
+
+#ifndef DEBUG_GOOSE_SUBSCRIBER
+#define DEBUG_GOOSE_SUBSCRIBER 0
+#endif
+
+#define ETH_BUFFER_LENGTH 1518
+
+#define ETH_P_GOOSE 0x88b8
+
+struct sGooseReceiver {
+ bool running;
+ char* interfaceId;
+ uint8_t* buffer;
+ EthernetSocket ethSocket;
+ LinkedList subscriberList;
+};
+
+
+GooseReceiver
+GooseReceiver_create()
+{
+ GooseReceiver self = (GooseReceiver) GLOBAL_MALLOC(sizeof(struct sGooseReceiver));
+
+ if (self != NULL) {
+ self->running = false;
+ self->interfaceId = NULL;
+ self->buffer = (uint8_t*) GLOBAL_MALLOC(ETH_BUFFER_LENGTH);
+ self->ethSocket = NULL;
+ self->subscriberList = LinkedList_create();
+ }
+
+ return self;
+}
+
+void
+GooseReceiver_addSubscriber(GooseReceiver self, GooseSubscriber subscriber)
+{
+ LinkedList_add(self->subscriberList, (void*) subscriber);
+}
+
+void
+GooseReceiver_removeSubscriber(GooseReceiver self, GooseSubscriber subscriber)
+{
+ LinkedList_remove(self->subscriberList, (void*) subscriber);
+}
+
+
+void
+GooseReceiver_setInterfaceId(GooseReceiver self, const char* interfaceId)
+{
+ if (self->interfaceId != NULL)
+ GLOBAL_FREEMEM(self->interfaceId);
+
+ self->interfaceId = copyString(interfaceId);
+}
+
+
+void
+GooseReceiver_setBackupListener(GooseReceiver self)
+{
+}
+
+static void
+createNewStringFromBufferElement(MmsValue* value, uint8_t* bufferSrc, int elementLength)
+{
+ value->value.visibleString.buf = (char*) GLOBAL_MALLOC(elementLength + 1);
+ memcpy(value->value.visibleString.buf, bufferSrc, elementLength);
+ value->value.visibleString.buf[elementLength] = 0;
+ value->value.visibleString.size = elementLength;
+}
+
+static int
+parseAllData(uint8_t* buffer, int allDataLength, MmsValue* dataSetValues)
+{
+ int bufPos = 0;
+ int elementLength = 0;
+
+ int elementIndex = 0;
+
+ int maxIndex = MmsValue_getArraySize(dataSetValues) - 1;
+
+ while (bufPos < allDataLength) {
+ uint8_t tag = buffer[bufPos++];
+
+ if (elementIndex > maxIndex) {
+ if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Malformed message: too much elements!\n");
+ return 0;
+ }
+
+ MmsValue* value = MmsValue_getElement(dataSetValues, elementIndex);
+
+ bufPos = BerDecoder_decodeLength(buffer, &elementLength, bufPos, allDataLength);
+
+ if (bufPos + elementLength > allDataLength) {
+ if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Malformed message: sub element is too large!\n");
+ return 0;
+ }
+
+ switch (tag) {
+ case 0x80: /* reserved for access result */
+ printf("GOOSE_SUBSCRIBER: found reserved value (tag 0x80)!\n");
+ break;
+ case 0xa1: /* array */
+ if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: found array\n");
+ if (MmsValue_getType(value) == MMS_ARRAY) {
+ if (!parseAllData(buffer + bufPos, elementLength, value))
+ return -1;
+ }
+ break;
+ case 0xa2: /* structure */
+ if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: found structure\n");
+ if (MmsValue_getType(value) == MMS_STRUCTURE) {
+ if (!parseAllData(buffer + bufPos, elementLength, value))
+ return -1;
+ }
+ break;
+ case 0x83: /* boolean */
+ if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: found boolean\n");
+
+ if (MmsValue_getType(value) == MMS_BOOLEAN) {
+ MmsValue_setBoolean(value, BerDecoder_decodeBoolean(buffer, bufPos));
+ }
+ else
+ if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: message contains value of wrong type!\n");
+
+ break;
+
+ case 0x84: /* BIT STRING */
+ if (MmsValue_getType(value) == MMS_BIT_STRING) {
+ int padding = buffer[bufPos];
+ int bitStringLength = (8 * (elementLength - 1)) - padding;
+ if (bitStringLength == value->value.bitString.size) {
+ memcpy(value->value.bitString.buf, buffer + bufPos + 1,
+ elementLength - 1);
+ }
+ else
+ if (DEBUG_GOOSE_SUBSCRIBER)
+ printf("bit-string is of wrong size");
+ }
+ break;
+ case 0x85: /* integer */
+ if (MmsValue_getType(value) == MMS_INTEGER) {
+ if (elementLength <= value->value.integer->maxSize) {
+ value->value.integer->size = elementLength;
+ memcpy(value->value.integer->octets, buffer + bufPos, elementLength);
+ }
+ }
+ break;
+ case 0x86: /* unsigned integer */
+ if (MmsValue_getType(value) == MMS_UNSIGNED) {
+ if (elementLength <= value->value.integer->maxSize) {
+ value->value.integer->size = elementLength;
+ memcpy(value->value.integer->octets, buffer + bufPos, elementLength);
+ }
+ }
+ break;
+ case 0x87: /* Float */
+ if (MmsValue_getType(value) == MMS_FLOAT) {
+ if (elementLength == 9) {
+ MmsValue_setDouble(value, BerDecoder_decodeDouble(buffer, bufPos));
+ }
+ else if (elementLength == 5) {
+ MmsValue_setFloat(value, BerDecoder_decodeFloat(buffer, bufPos));
+ }
+ }
+ break;
+
+ case 0x89: /* octet string */
+ if (MmsValue_getType(value) == MMS_OCTET_STRING) {
+ if (elementLength <= value->value.octetString.maxSize) {
+ value->value.octetString.size = elementLength;
+ memcpy(value->value.octetString.buf, buffer + bufPos, elementLength);
+ }
+ }
+ break;
+ case 0x8a: /* visible string */
+ if (MmsValue_getType(value) == MMS_VISIBLE_STRING) {
+
+ if (value->value.visibleString.buf != NULL) {
+ if ((int32_t) value->value.visibleString.size >= elementLength) {
+ memcpy(value->value.visibleString.buf, buffer + bufPos, elementLength);
+ value->value.visibleString.buf[elementLength] = 0;
+ }
+ else {
+ GLOBAL_FREEMEM(value->value.visibleString.buf);
+
+ createNewStringFromBufferElement(value, buffer + bufPos, elementLength);
+ }
+ }
+ else
+ createNewStringFromBufferElement(value, buffer + bufPos, elementLength);
+
+ }
+ break;
+ case 0x8c: /* binary time */
+ if (MmsValue_getType(value) == MMS_BINARY_TIME) {
+ if ((elementLength == 4) || (elementLength == 6)) {
+ memcpy(value->value.binaryTime.buf, buffer + bufPos, elementLength);
+ }
+ }
+ break;
+ case 0x91: /* Utctime */
+ if (elementLength == 8) {
+ if (MmsValue_getType(value) == MMS_UTC_TIME) {
+ MmsValue_setUtcTimeByBuffer(value, buffer + bufPos);
+ }
+ else
+ if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: message contains value of wrong type!\n");
+ }
+ else
+ if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: UTCTime element is of wrong size!\n");
+ break;
+ default:
+ if (DEBUG_GOOSE_SUBSCRIBER)
+ printf("GOOSE_SUBSCRIBER: found unkown tag %02x\n", tag);
+ break;
+ }
+
+ bufPos += elementLength;
+
+ elementIndex++;
+ }
+
+ return 1;
+}
+
+static MmsValue*
+parseAllDataUnknownValue(GooseSubscriber self, uint8_t* buffer, int allDataLength, bool isStructure)
+{
+ int bufPos = 0;
+ int elementLength = 0;
+
+ int elementIndex = 0;
+
+ MmsValue* dataSetValues = NULL;
+
+ while (bufPos < allDataLength) {
+ uint8_t tag = buffer[bufPos++];
+
+ bufPos = BerDecoder_decodeLength(buffer, &elementLength, bufPos, allDataLength);
+
+ if (bufPos + elementLength > allDataLength) {
+ if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Malformed message: sub element is too large!\n");
+ goto exit_with_error;
+ }
+
+ switch (tag) {
+ case 0x80: /* reserved for access result */
+ break;
+ case 0xa1: /* array */
+ break;
+ case 0xa2: /* structure */
+ break;
+ case 0x83: /* boolean */
+ break;
+ case 0x84: /* BIT STRING */
+ break;
+ case 0x85: /* integer */
+ break;
+ case 0x86: /* unsigned integer */
+ break;
+ case 0x87: /* Float */
+ break;
+ case 0x89: /* octet string */
+ break;
+ case 0x8a: /* visible string */
+ break;
+ case 0x8c: /* binary time */
+ break;
+ case 0x91: /* Utctime */
+ break;
+ default:
+ if (DEBUG_GOOSE_SUBSCRIBER)
+ printf("GOOSE_SUBSCRIBER: found unkown tag %02x\n", tag);
+ goto exit_with_error;
+ }
+
+ bufPos += elementLength;
+
+ elementIndex++;
+ }
+
+ if (isStructure)
+ dataSetValues = MmsValue_createEmptyStructure(elementIndex);
+ else
+ dataSetValues = MmsValue_createEmtpyArray(elementIndex);
+
+ elementIndex = 0;
+ bufPos = 0;
+
+ while (bufPos < allDataLength) {
+ uint8_t tag = buffer[bufPos++];
+
+ bufPos = BerDecoder_decodeLength(buffer, &elementLength, bufPos, allDataLength);
+
+ if (bufPos + elementLength > allDataLength) {
+ if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Malformed message: sub element is too large!\n");
+ goto exit_with_error;
+ }
+
+ MmsValue* value = NULL;
+
+ switch (tag) {
+ case 0xa1: /* array */
+ if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: found array\n");
+
+ value = parseAllDataUnknownValue(self, buffer + bufPos, elementLength, false);
+
+ if (value == NULL)
+ goto exit_with_error;
+
+ break;
+ case 0xa2: /* structure */
+ if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: found structure\n");
+
+ value = parseAllDataUnknownValue(self, buffer + bufPos, elementLength, true);
+
+ if (value == NULL)
+ goto exit_with_error;
+
+ break;
+ case 0x83: /* boolean */
+ if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: found boolean\n");
+ value = MmsValue_newBoolean(BerDecoder_decodeBoolean(buffer, bufPos));
+
+ break;
+
+ case 0x84: /* BIT STRING */
+ {
+ int padding = buffer[bufPos];
+ int bitStringLength = (8 * (elementLength - 1)) - padding;
+ value = MmsValue_newBitString(bitStringLength);
+ memcpy(value->value.bitString.buf, buffer + bufPos + 1, elementLength - 1);
+
+ }
+ break;
+ case 0x85: /* integer */
+ value = MmsValue_newInteger(elementLength * 8);
+ memcpy(value->value.integer->octets, buffer + bufPos, elementLength);
+ break;
+ case 0x86: /* unsigned integer */
+ value = MmsValue_newUnsigned(elementLength * 8);
+ memcpy(value->value.integer->octets, buffer + bufPos, elementLength);
+ break;
+ case 0x87: /* Float */
+ if (elementLength == 9)
+ value = MmsValue_newDouble(BerDecoder_decodeDouble(buffer, bufPos));
+ else if (elementLength == 5)
+ value = MmsValue_newFloat(BerDecoder_decodeFloat(buffer, bufPos));
+ break;
+
+ case 0x89: /* octet string */
+ value = MmsValue_newOctetString(elementLength, elementLength);
+ memcpy(value->value.octetString.buf, buffer + bufPos, elementLength);
+ break;
+ case 0x8a: /* visible string */
+ value = MmsValue_newVisibleStringFromByteArray(buffer + bufPos, elementLength);
+ break;
+ case 0x8c: /* binary time */
+ if (elementLength == 4)
+ value = MmsValue_newBinaryTime(true);
+ else if (elementLength == 6)
+ value = MmsValue_newBinaryTime(false);
+
+ if ((elementLength == 4) || (elementLength == 6))
+ memcpy(value->value.binaryTime.buf, buffer + bufPos, elementLength);
+
+ break;
+ case 0x91: /* Utctime */
+ if (elementLength == 8) {
+ value = MmsValue_newUtcTime(0);
+ MmsValue_setUtcTimeByBuffer(value, buffer + bufPos);
+ }
+ else
+ if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: UTCTime element is of wrong size!\n");
+ break;
+ default:
+ if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: found unkown tag %02x\n", tag);
+ goto exit_with_error;
+ }
+
+ bufPos += elementLength;
+
+ if (value != NULL) {
+ MmsValue_setElement(dataSetValues, elementIndex, value);
+ elementIndex++;
+ }
+ }
+
+ self->dataSetValuesSelfAllocated = true;
+
+ return dataSetValues;
+
+exit_with_error:
+
+ if (dataSetValues != NULL)
+ MmsValue_delete(dataSetValues);
+
+ return NULL;
+}
+
+
+static int
+parseGoosePayload(GooseReceiver self, uint8_t* buffer, int apduLength)
+{
+ int bufPos = 0;
+ uint32_t timeAllowedToLive = 0;
+ uint32_t stNum = 0;
+ uint32_t sqNum = 0;
+ uint32_t confRev;
+ bool simulation = false;
+ bool ndsCom = false;
+ GooseSubscriber matchingSubscriber = NULL;
+ uint8_t* timestampBufPos = NULL;
+ uint8_t* dataSetBufferAddress = NULL;
+ int dataSetBufferLength = 0;
+
+ uint32_t numberOfDatSetEntries = 0;
+
+ if (buffer[bufPos++] == 0x61) {
+ int gooseLength;
+ bufPos = BerDecoder_decodeLength(buffer, &gooseLength, bufPos, apduLength);
+
+ int gooseEnd = bufPos + gooseLength;
+
+ while (bufPos < gooseEnd) {
+ int elementLength;
+
+ uint8_t tag = buffer[bufPos++];
+ bufPos = BerDecoder_decodeLength(buffer, &elementLength, bufPos, apduLength);
+
+ if (bufPos + elementLength > apduLength) {
+ if (DEBUG_GOOSE_SUBSCRIBER)
+ printf("GOOSE_SUBSCRIBER: Malformed message: sub element is too large!\n");
+
+ goto exit_with_fault;
+ }
+
+ if (bufPos == -1)
+ goto exit_with_fault;
+
+ switch(tag) {
+ case 0x80: /* gocbRef */
+ if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Found gocbRef\n");
+
+ {
+ LinkedList element = LinkedList_getNext(self->subscriberList);
+
+ while (element != NULL) {
+ GooseSubscriber subscriber = (GooseSubscriber) LinkedList_getData(element);
+
+ if (subscriber->goCBRefLen == elementLength) {
+ if (memcmp(subscriber->goCBRef, buffer + bufPos, elementLength) == 0) {
+ if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: gocbRef is matching!\n");
+ matchingSubscriber = subscriber;
+ break;
+ }
+ }
+
+ element = LinkedList_getNext(element);
+ }
+
+ if (matchingSubscriber == NULL)
+ return 0;
+ }
+
+ break;
+
+ case 0x81: /* timeAllowedToLive */
+
+ timeAllowedToLive = BerDecoder_decodeUint32(buffer, elementLength, bufPos);
+
+ if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Found timeAllowedToLive %u\n", timeAllowedToLive);
+
+ break;
+
+ case 0x82:
+ if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Found dataSet\n");
+ break;
+
+ case 0x83:
+ if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Found goId\n");
+ break;
+
+ case 0x84:
+ timestampBufPos = buffer + bufPos;
+ if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Found timestamp\n");
+ break;
+
+ case 0x85:
+ stNum = BerDecoder_decodeUint32(buffer, elementLength, bufPos);
+ if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Found stNum: %u\n", stNum);
+ break;
+
+ case 0x86:
+ sqNum = BerDecoder_decodeUint32(buffer, elementLength, bufPos);
+ if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Found sqNum: %u\n", sqNum);
+ break;
+
+ case 0x87:
+ simulation = BerDecoder_decodeBoolean(buffer, bufPos);
+ if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Found simulation: %i\n", simulation);
+ break;
+
+ case 0x88:
+ confRev = BerDecoder_decodeUint32(buffer, elementLength, bufPos);
+ if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Found confRev: %u\n", confRev);
+ break;
+
+ case 0x89:
+ ndsCom = BerDecoder_decodeBoolean(buffer, bufPos);
+ if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Found ndsCom: %i\n", ndsCom);
+ break;
+
+ case 0x8a:
+ numberOfDatSetEntries = BerDecoder_decodeUint32(buffer, elementLength, bufPos);
+ if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Found number of entries: %u\n", numberOfDatSetEntries);
+ break;
+
+ case 0xab:
+ if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Found all data with length: %i\n", elementLength);
+ dataSetBufferAddress = buffer + bufPos;
+ dataSetBufferLength = elementLength;
+ break;
+
+ default:
+ if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Unknown tag %02x\n", tag);
+ break;
+ }
+
+ bufPos += elementLength;
+ }
+
+ if (matchingSubscriber != NULL) {
+
+ matchingSubscriber->timeAllowedToLive = timeAllowedToLive;
+ matchingSubscriber->confRev = confRev;
+ matchingSubscriber->ndsCom = ndsCom;
+ matchingSubscriber->simulation = simulation;
+ MmsValue_setUtcTimeByBuffer(matchingSubscriber->timestamp, timestampBufPos);
+
+ if (matchingSubscriber->dataSetValues == NULL)
+ matchingSubscriber->dataSetValues = parseAllDataUnknownValue(matchingSubscriber, dataSetBufferAddress, dataSetBufferLength, false);
+ else
+ parseAllData(dataSetBufferAddress, dataSetBufferLength, matchingSubscriber->dataSetValues);
+
+ bool isValid = true;
+
+ if (matchingSubscriber->stNum == stNum) {
+ if (matchingSubscriber->sqNum >= sqNum) {
+ isValid = false;
+ }
+ }
+
+ matchingSubscriber->stateValid = isValid;
+
+ matchingSubscriber->stNum = stNum;
+ matchingSubscriber->sqNum = sqNum;
+
+ matchingSubscriber->invalidityTime = Hal_getTimeInMs() + timeAllowedToLive;
+
+ if (matchingSubscriber->listener != NULL)
+ matchingSubscriber->listener(matchingSubscriber, matchingSubscriber->listenerParameter);
+
+ return 1;
+ }
+
+ return 0;
+ }
+
+exit_with_fault:
+ if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: Invalid goose payload\n");
+ return -1;
+}
+
+
+static void
+parseGooseMessage(GooseReceiver self, int numbytes)
+{
+ int bufPos;
+ bool subscriberFound = false;
+ uint8_t* buffer = self->buffer;
+
+ if (numbytes < 22) return;
+
+ /* skip ethernet addresses */
+ bufPos = 12;
+ int headerLength = 14;
+
+ /* check for VLAN tag */
+ if ((buffer[bufPos] == 0x81) && (buffer[bufPos + 1] == 0x00)) {
+ bufPos += 4; /* skip VLAN tag */
+ headerLength += 4;
+ }
+
+ /* check for GOOSE Ethertype */
+ if (buffer[bufPos++] != 0x88)
+ return;
+ if (buffer[bufPos++] != 0xb8)
+ return;
+
+ uint16_t appId;
+
+ appId = buffer[bufPos++] * 0x100;
+ appId += buffer[bufPos++];
+
+ uint16_t length;
+
+ length = buffer[bufPos++] * 0x100;
+ length += buffer[bufPos++];
+
+ /* skip reserved fields */
+ bufPos += 4;
+
+ int apduLength = length - 8;
+
+ if (numbytes != length + headerLength) {
+ if (DEBUG)
+ printf("GOOSE_SUBSCRIBER: Invalid PDU size\n");
+ return;
+ }
+
+ if (DEBUG_GOOSE_SUBSCRIBER) {
+ printf("GOOSE_SUBSCRIBER: GOOSE message:\nGOOSE_SUBSCRIBER: ----------------\n");
+ printf("GOOSE_SUBSCRIBER: APPID: %u\n", appId);
+ printf("GOOSE_SUBSCRIBER: LENGTH: %u\n", length);
+ printf("GOOSE_SUBSCRIBER: APDU length: %i\n", apduLength);
+ }
+
+
+ // check if there is an interested subscriber
+ LinkedList element = LinkedList_getNext(self->subscriberList);
+
+ while (element != NULL) {
+ GooseSubscriber subscriber = (GooseSubscriber) LinkedList_getData(element);
+
+ if (subscriber->appId == appId) {
+ subscriberFound = true;
+ break;
+ }
+
+ element = LinkedList_getNext(element);
+ }
+
+ if (subscriberFound)
+ parseGoosePayload(self, buffer + bufPos, apduLength);
+ else {
+ if (DEBUG_GOOSE_SUBSCRIBER)
+ printf("GOOSE_SUBSCRIBER: GOOSE message ignored due to unknown APPID value\n");
+ }
+}
+
+
+static void
+gooseReceiverLoop(void* threadParameter)
+{
+ GooseReceiver self = (GooseReceiver) threadParameter;
+
+ GooseReceiver_startThreadless(self);
+
+ while (self->running) {
+
+ GooseReceiver_tick(self);
+
+ Thread_sleep(1);
+ }
+
+ GooseReceiver_stopThreadless(self);
+}
+
+
+// start GOOSE receiver in a separate thread
+void
+GooseReceiver_start(GooseReceiver self)
+{
+ Thread thread = Thread_create((ThreadExecutionFunction) gooseReceiverLoop, (void*) self, true);
+
+ if (thread != NULL) {
+ if (DEBUG_GOOSE_SUBSCRIBER)
+ printf("GOOSE_SUBSCRIBER: GOOSE receiver started for interface %s\n", self->interfaceId);
+
+ Thread_start(thread);
+ }
+ else {
+ if (DEBUG_GOOSE_SUBSCRIBER)
+ printf("GOOSE_SUBSCRIBER: Starting GOOSE receiver failed for interface %s\n", self->interfaceId);
+ }
+
+}
+
+void
+GooseReceiver_stop(GooseReceiver self)
+{
+ self->running = false;
+}
+
+void
+GooseReceiver_destroy(GooseReceiver self)
+{
+ LinkedList_destroyDeep(self->subscriberList,
+ (LinkedListValueDeleteFunction) GooseSubscriber_destroy);
+
+ GLOBAL_FREEMEM(self->buffer);
+ GLOBAL_FREEMEM(self);
+}
+
+/***************************************
+ * Functions for non-threaded operation
+ ***************************************/
+void
+GooseReceiver_startThreadless(GooseReceiver self)
+{
+
+ if (self->interfaceId == NULL)
+ self->ethSocket = Ethernet_createSocket(CONFIG_ETHERNET_INTERFACE_ID, NULL);
+ else
+ self->ethSocket = Ethernet_createSocket(self->interfaceId, NULL);
+
+ Ethernet_setProtocolFilter(self->ethSocket, ETH_P_GOOSE);
+
+ self->running = true;
+}
+
+void
+GooseReceiver_stopThreadless(GooseReceiver self)
+{
+ Ethernet_destroySocket(self->ethSocket);
+
+ self->running = false;
+}
+
+// call after reception of ethernet frame and periodically to to house keeping tasks
+void
+GooseReceiver_tick(GooseReceiver self)
+{
+ int packetSize = Ethernet_receivePacket(self->ethSocket, self->buffer, ETH_BUFFER_LENGTH);
+
+ if (packetSize > 0)
+ parseGooseMessage(self, packetSize);
+}
diff --git a/src/goose/goose_receiver.h b/src/goose/goose_receiver.h
new file mode 100644
index 00000000..c57f1d72
--- /dev/null
+++ b/src/goose/goose_receiver.h
@@ -0,0 +1,70 @@
+/*
+ * goose_receiver.h
+ *
+ * Copyright 2014 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.
+ */
+
+#ifndef GOOSE_RECEIVER_H_
+#define GOOSE_RECEIVER_H_
+
+#include
+
+typedef struct sGooseReceiver* GooseReceiver;
+
+GooseReceiver
+GooseReceiver_create(void);
+
+void
+GooseReceiver_setInterfaceId(GooseReceiver self, const char* interfaceId);
+
+void
+GooseReceiver_addSubscriber(GooseReceiver self, GooseSubscriber subscriber);
+
+void
+GooseReceiver_removeSubscriber(GooseReceiver self, GooseSubscriber subscriber);
+
+// call backup listener if message is not handled by a subscriber
+void
+GooseReceiver_setBackupListener(GooseReceiver self);
+
+// start GOOSE receiver in a separate thread
+void
+GooseReceiver_start(GooseReceiver self);
+
+void
+GooseReceiver_stop(GooseReceiver self);
+
+void
+GooseReceiver_destroy(GooseReceiver self);
+
+/***************************************
+ * Functions for non-threaded operation
+ ***************************************/
+void
+GooseReceiver_startThreadless(GooseReceiver self);
+
+void
+GooseReceiver_stopThreadless(GooseReceiver self);
+
+// call after reception of ethernet frame and periodically to to house keeping tasks
+void
+GooseReceiver_tick(GooseReceiver self);
+
+#endif /* GOOSE_RECEIVER_H_ */
diff --git a/src/goose/goose_receiver_internal.h b/src/goose/goose_receiver_internal.h
new file mode 100644
index 00000000..e595da00
--- /dev/null
+++ b/src/goose/goose_receiver_internal.h
@@ -0,0 +1,62 @@
+/*
+ * goose_receiver_internal.h
+ *
+ * Copyright 2014 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.
+ */
+
+#ifndef GOOSE_RECEIVER_INTERNAL_H_
+#define GOOSE_RECEIVER_INTERNAL_H_
+
+
+#define ETH_BUFFER_LENGTH 1518
+
+#define ETH_P_GOOSE 0x88b8
+
+#ifndef DEBUG_GOOSE_SUBSCRIBER
+#define DEBUG_GOOSE_SUBSCRIBER 0
+#endif
+
+
+struct sGooseSubscriber {
+ char* goCBRef;
+ int goCBRefLen;
+ uint32_t timeAllowedToLive;
+ uint32_t stNum;
+ uint32_t sqNum;
+ uint32_t confRev;
+ MmsValue* timestamp;
+ bool simulation;
+ bool ndsCom;
+
+ uint64_t invalidityTime;
+ bool stateValid;
+
+ int32_t appId; /* APPID or -1 if APPID should be ignored */
+
+ MmsValue* dataSetValues;
+ bool dataSetValuesSelfAllocated;
+
+ GooseListener listener;
+ void* listenerParameter;
+};
+
+
+
+#endif /* GOOSE_RECEIVER_INTERNAL_H_ */
diff --git a/src/goose/goose_subscriber.c b/src/goose/goose_subscriber.c
index ff615087..f1d1e8ea 100644
--- a/src/goose/goose_subscriber.c
+++ b/src/goose/goose_subscriber.c
@@ -25,622 +25,20 @@
#include "stack_config.h"
#include "goose_subscriber.h"
-#include "ethernet.h"
-#include "thread.h"
+#include "hal_ethernet.h"
+#include "hal_thread.h"
#include "ber_decode.h"
#include "mms_value.h"
#include "mms_value_internal.h"
-#define ETH_BUFFER_LENGTH 1518
-
-#define ETH_P_GOOSE 0x88b8
-
-struct sGooseSubscriber {
- char* goCBRef;
- int goCBRefLen;
- uint32_t timeAllowedToLive;
- uint32_t stNum;
- uint32_t sqNum;
- uint32_t confRev;
- MmsValue* timestamp;
- bool simulation;
- bool ndsCom;
-
- int32_t appId; /* APPID or -1 if APPID should be ignored */
-
- MmsValue* dataSetValues;
- bool dataSetValuesSelfAllocated;
-
- GooseListener listener;
- void* listenerParameter;
- bool running;
- Thread receiver;
- char* interfaceId;
-};
-
-static void
-createNewStringFromBufferElement(MmsValue* value, uint8_t* bufferSrc, int elementLength)
-{
- value->value.visibleString.buf = (char*) malloc(elementLength + 1);
- memcpy(value->value.visibleString.buf, bufferSrc, elementLength);
- value->value.visibleString.buf[elementLength] = 0;
- value->value.visibleString.size = elementLength;
-}
-
-static int
-parseAllData(uint8_t* buffer, int allDataLength, MmsValue* dataSetValues)
-{
- int bufPos = 0;
- int elementLength = 0;
-
- int elementIndex = 0;
-
- int maxIndex = MmsValue_getArraySize(dataSetValues) - 1;
-
- while (bufPos < allDataLength) {
- uint8_t tag = buffer[bufPos++];
-
- if (elementIndex > maxIndex) {
- if (DEBUG) printf("Malformed message: too much elements!\n");
- return 0;
- }
-
- MmsValue* value = MmsValue_getElement(dataSetValues, elementIndex);
-
- bufPos = BerDecoder_decodeLength(buffer, &elementLength, bufPos, allDataLength);
-
- if (bufPos + elementLength > allDataLength) {
- if (DEBUG) printf("Malformed message: sub element is to large!\n");
- return 0;
- }
-
- switch (tag) {
- case 0x80: /* reserved for access result */
- printf(" found reserved value (tag 0x80)!\n");
- break;
- case 0xa1: /* array */
- if (DEBUG) printf(" found array\n");
- if (MmsValue_getType(value) == MMS_ARRAY) {
- if (!parseAllData(buffer + bufPos, elementLength, value))
- return -1;
- }
- break;
- case 0xa2: /* structure */
- if (DEBUG) printf(" found structure\n");
- if (MmsValue_getType(value) == MMS_STRUCTURE) {
- if (!parseAllData(buffer + bufPos, elementLength, value))
- return -1;
- }
- break;
- case 0x83: /* boolean */
- if (DEBUG) printf(" found boolean\n");
-
- if (MmsValue_getType(value) == MMS_BOOLEAN) {
- MmsValue_setBoolean(value, BerDecoder_decodeBoolean(buffer, bufPos));
- }
- else
- if (DEBUG) printf(" message contains value of wrong type!\n");
-
- break;
-
- case 0x84: /* BIT STRING */
- if (MmsValue_getType(value) == MMS_BIT_STRING) {
- int padding = buffer[bufPos];
- int bitStringLength = (8 * (elementLength - 1)) - padding;
- if (bitStringLength == value->value.bitString.size) {
- memcpy(value->value.bitString.buf, buffer + bufPos + 1,
- elementLength - 1);
- }
- else
- printf("bit-string is of wrong size");
- }
- break;
- case 0x85: /* integer */
- if (MmsValue_getType(value) == MMS_INTEGER) {
- if (elementLength <= value->value.integer->maxSize) {
- value->value.integer->size = elementLength;
- memcpy(value->value.integer->octets, buffer + bufPos, elementLength);
- }
- }
- break;
- case 0x86: /* unsigned integer */
- if (MmsValue_getType(value) == MMS_UNSIGNED) {
- if (elementLength <= value->value.integer->maxSize) {
- value->value.integer->size = elementLength;
- memcpy(value->value.integer->octets, buffer + bufPos, elementLength);
- }
- }
- break;
- case 0x87: /* Float */
- if (MmsValue_getType(value) == MMS_FLOAT) {
- if (elementLength == 9) {
- MmsValue_setDouble(value, BerDecoder_decodeDouble(buffer, bufPos));
- }
- else if (elementLength == 5) {
- MmsValue_setFloat(value, BerDecoder_decodeFloat(buffer, bufPos));
- }
- }
- break;
-
- case 0x89: /* octet string */
- if (MmsValue_getType(value) == MMS_OCTET_STRING) {
- if (elementLength <= value->value.octetString.maxSize) {
- value->value.octetString.size = elementLength;
- memcpy(value->value.octetString.buf, buffer + bufPos, elementLength);
- }
- }
- break;
- case 0x8a: /* visible string */
- if (MmsValue_getType(value) == MMS_VISIBLE_STRING) {
-
- if (value->value.visibleString.buf != NULL) {
- if ((int32_t) value->value.visibleString.size >= elementLength) {
- memcpy(value->value.visibleString.buf, buffer + bufPos, elementLength);
- value->value.visibleString.buf[elementLength] = 0;
- }
- else {
- free(value->value.visibleString.buf);
-
- createNewStringFromBufferElement(value, buffer + bufPos, elementLength);
- }
- }
- else
- createNewStringFromBufferElement(value, buffer + bufPos, elementLength);
-
- }
- break;
- case 0x8c: /* binary time */
- if (MmsValue_getType(value) == MMS_BINARY_TIME) {
- if ((elementLength == 4) || (elementLength == 6)) {
- memcpy(value->value.binaryTime.buf, buffer + bufPos, elementLength);
- }
- }
- break;
- case 0x91: /* Utctime */
- if (elementLength == 8) {
- if (MmsValue_getType(value) == MMS_UTC_TIME) {
- MmsValue_setUtcTimeByBuffer(value, buffer + bufPos);
- }
- else
- if (DEBUG) printf(" message contains value of wrong type!\n");
- }
- else
- if (DEBUG) printf(" UTCTime element is of wrong size!\n");
- break;
- default:
- printf(" found unkown tag %02x\n", tag);
- break;
- }
-
- bufPos += elementLength;
-
- elementIndex++;
- }
-
- return 1;
-}
-
-static MmsValue*
-parseAllDataUnknownValue(GooseSubscriber self, uint8_t* buffer, int allDataLength, bool isStructure)
-{
- int bufPos = 0;
- int elementLength = 0;
-
- int elementIndex = 0;
-
- MmsValue* dataSetValues = NULL;
-
- while (bufPos < allDataLength) {
- uint8_t tag = buffer[bufPos++];
-
- bufPos = BerDecoder_decodeLength(buffer, &elementLength, bufPos, allDataLength);
-
- if (bufPos + elementLength > allDataLength) {
- if (DEBUG) printf("Malformed message: sub element is to large!\n");
- goto exit_with_error;
- }
-
- switch (tag) {
- case 0x80: /* reserved for access result */
- break;
- case 0xa1: /* array */
- break;
- case 0xa2: /* structure */
- break;
- case 0x83: /* boolean */
- break;
- case 0x84: /* BIT STRING */
- break;
- case 0x85: /* integer */
- break;
- case 0x86: /* unsigned integer */
- break;
- case 0x87: /* Float */
- break;
- case 0x89: /* octet string */
- break;
- case 0x8a: /* visible string */
- break;
- case 0x8c: /* binary time */
- break;
- case 0x91: /* Utctime */
- break;
- default:
- printf(" found unkown tag %02x\n", tag);
- goto exit_with_error;
- }
-
- bufPos += elementLength;
-
- elementIndex++;
- }
-
- if (isStructure)
- dataSetValues = MmsValue_createEmptyStructure(elementIndex);
- else
- dataSetValues = MmsValue_createEmtpyArray(elementIndex);
-
- elementIndex = 0;
- bufPos = 0;
-
- while (bufPos < allDataLength) {
- uint8_t tag = buffer[bufPos++];
-
- bufPos = BerDecoder_decodeLength(buffer, &elementLength, bufPos, allDataLength);
-
- if (bufPos + elementLength > allDataLength) {
- if (DEBUG) printf("Malformed message: sub element is too large!\n");
- goto exit_with_error;
- }
-
- MmsValue* value = NULL;
-
- switch (tag) {
- case 0xa1: /* array */
- if (DEBUG) printf(" found array\n");
-
- value = parseAllDataUnknownValue(self, buffer + bufPos, elementLength, false);
-
- if (value == NULL)
- goto exit_with_error;
-
- break;
- case 0xa2: /* structure */
- if (DEBUG) printf(" found structure\n");
-
- value = parseAllDataUnknownValue(self, buffer + bufPos, elementLength, true);
-
- if (value == NULL)
- goto exit_with_error;
-
- break;
- case 0x83: /* boolean */
- if (DEBUG) printf(" found boolean\n");
- value = MmsValue_newBoolean(BerDecoder_decodeBoolean(buffer, bufPos));
-
- break;
-
- case 0x84: /* BIT STRING */
- {
- int padding = buffer[bufPos];
- int bitStringLength = (8 * (elementLength - 1)) - padding;
- value = MmsValue_newBitString(bitStringLength);
- memcpy(value->value.bitString.buf, buffer + bufPos + 1, elementLength - 1);
-
- }
- break;
- case 0x85: /* integer */
- value = MmsValue_newInteger(elementLength * 8);
- memcpy(value->value.integer->octets, buffer + bufPos, elementLength);
- break;
- case 0x86: /* unsigned integer */
- value = MmsValue_newUnsigned(elementLength * 8);
- memcpy(value->value.integer->octets, buffer + bufPos, elementLength);
- break;
- case 0x87: /* Float */
- if (elementLength == 9)
- value = MmsValue_newDouble(BerDecoder_decodeDouble(buffer, bufPos));
- else if (elementLength == 5)
- value = MmsValue_newFloat(BerDecoder_decodeFloat(buffer, bufPos));
- break;
-
- case 0x89: /* octet string */
- value = MmsValue_newOctetString(elementLength, elementLength);
- memcpy(value->value.octetString.buf, buffer + bufPos, elementLength);
- break;
- case 0x8a: /* visible string */
- value = MmsValue_newVisibleStringFromByteArray(buffer + bufPos, elementLength);
- break;
- case 0x8c: /* binary time */
- if (elementLength == 4)
- value = MmsValue_newBinaryTime(true);
- else if (elementLength == 6)
- value = MmsValue_newBinaryTime(false);
-
- if ((elementLength == 4) || (elementLength == 6))
- memcpy(value->value.binaryTime.buf, buffer + bufPos, elementLength);
-
- break;
- case 0x91: /* Utctime */
- if (elementLength == 8) {
- value = MmsValue_newUtcTime(0);
- MmsValue_setUtcTimeByBuffer(value, buffer + bufPos);
- }
- else
- if (DEBUG) printf(" UTCTime element is of wrong size!\n");
- break;
- default:
- if (DEBUG) printf(" found unkown tag %02x\n", tag);
- goto exit_with_error;
- }
-
- bufPos += elementLength;
-
- if (value != NULL) {
- MmsValue_setElement(dataSetValues, elementIndex, value);
- elementIndex++;
- }
- }
-
- self->dataSetValuesSelfAllocated = true;
-
- return dataSetValues;
-
-exit_with_error:
-
- if (dataSetValues != NULL)
- MmsValue_delete(dataSetValues);
-
- return NULL;
-}
-
-
-static int
-parseGoosePayload(uint8_t* buffer, int apduLength, GooseSubscriber self)
-{
- int bufPos = 0;
- uint32_t timeAllowedToLive = 0;
- uint32_t stNum = 0;
- uint32_t sqNum = 0;
- uint32_t confRev;
- bool simulation = false;
- bool ndsCom = false;
- bool isMatching = false;
-
- uint32_t numberOfDatSetEntries = 0;
-
- if (buffer[bufPos++] == 0x61) {
- int gooseLength;
- bufPos = BerDecoder_decodeLength(buffer, &gooseLength, bufPos, apduLength);
-
- int gooseEnd = bufPos + gooseLength;
-
- while (bufPos < gooseEnd) {
- int elementLength;
-
- uint8_t tag = buffer[bufPos++];
- bufPos = BerDecoder_decodeLength(buffer, &elementLength, bufPos, apduLength);
-
- if (bufPos + elementLength > apduLength) {
- if (DEBUG) printf("Malformed message: sub element is to large!\n");
- goto exit_with_fault;
- }
-
- if (bufPos == -1)
- goto exit_with_fault;
-
- switch(tag) {
- case 0x80: /* gocbRef */
- if (DEBUG) printf(" Found gocbRef\n");
-
- if (self->goCBRefLen == elementLength) {
- if (memcmp(self->goCBRef, buffer + bufPos, elementLength) == 0) {
- if (DEBUG) printf(" gocbRef is matching!\n");
- isMatching = true;
- }
- else return 0;
- }
- else
- return 0;
-
- break;
-
- case 0x81: /* timeAllowedToLive */
-
- timeAllowedToLive = BerDecoder_decodeUint32(buffer, elementLength, bufPos);
-
- if (DEBUG) printf(" Found timeAllowedToLive %u\n", timeAllowedToLive);
-
- break;
-
- case 0x82:
- if (DEBUG) printf(" Found dataSet\n");
- break;
-
- case 0x83:
- if (DEBUG) printf(" Found goId\n");
- break;
-
- case 0x84:
- MmsValue_setUtcTimeByBuffer(self->timestamp, buffer + bufPos);
- if (DEBUG) printf(" Found timestamp t: %" PRIu64 "\n", MmsValue_getUtcTimeInMs(self->timestamp));
- break;
-
- case 0x85:
- stNum = BerDecoder_decodeUint32(buffer, elementLength, bufPos);
- if (DEBUG) printf(" Found stNum: %u\n", stNum);
- break;
-
- case 0x86:
- sqNum = BerDecoder_decodeUint32(buffer, elementLength, bufPos);
- if (DEBUG) printf(" Found sqNum: %u\n", sqNum);
- break;
-
- case 0x87:
- simulation = BerDecoder_decodeBoolean(buffer, bufPos);
- if (DEBUG) printf(" Found simulation: %i\n", simulation);
- break;
-
- case 0x88:
- confRev = BerDecoder_decodeUint32(buffer, elementLength, bufPos);
- if (DEBUG) printf(" Found confRev: %u\n", confRev);
- break;
-
- case 0x89:
- ndsCom = BerDecoder_decodeBoolean(buffer, bufPos);
- if (DEBUG) printf(" Found ndsCom: %i\n", ndsCom);
- break;
-
- case 0x8a:
- numberOfDatSetEntries = BerDecoder_decodeUint32(buffer, elementLength, bufPos);
- if (DEBUG) printf(" Found number of entries: %u\n", numberOfDatSetEntries);
- break;
-
- case 0xab:
- if (DEBUG) printf(" Found all data with length: %i\n", elementLength);
-
- if (self->dataSetValues == NULL)
- self->dataSetValues = parseAllDataUnknownValue(self, buffer + bufPos, elementLength, false);
- else
- parseAllData(buffer + bufPos, elementLength, self->dataSetValues);
- break;
-
- default:
- if (DEBUG) printf(" Unknown tag %02x\n", tag);
- break;
- }
-
- bufPos += elementLength;
- }
-
- if (isMatching) {
- self->stNum = stNum;
- self->sqNum = sqNum;
- self->timeAllowedToLive = timeAllowedToLive;
- self->confRev = confRev;
- self->ndsCom = ndsCom;
- self->simulation = simulation;
-
- return 1;
- }
-
- return 0;
- }
-
-exit_with_fault:
- if (DEBUG) printf("Invalid goose payload\n");
- return -1;
-}
-
-static int
-parseGooseMessage(uint8_t* buffer, int numbytes, GooseSubscriber subscriber)
-{
- int bufPos;
-
- if (numbytes < 22) return -1;
-
- /* skip ethernet addresses */
- bufPos = 12;
- int headerLength = 14;
-
- /* check for VLAN tag */
- if ((buffer[bufPos] == 0x81) && (buffer[bufPos + 1] == 0x00)) {
- bufPos += 4; /* skip VLAN tag */
- headerLength += 4;
- }
-
- /* check for GOOSE Ethertype */
- if (buffer[bufPos++] != 0x88)
- return -1;
- if (buffer[bufPos++] != 0xb8)
- return -1;
-
- uint16_t appId;
-
- appId = buffer[bufPos++] * 0x100;
- appId += buffer[bufPos++];
-
- uint16_t length;
-
- length = buffer[bufPos++] * 0x100;
- length += buffer[bufPos++];
-
- /* skip reserved fields */
- bufPos += 4;
-
- int apduLength = length - 8;
-
- if (numbytes != length + headerLength) {
- if (DEBUG)
- printf("Invalid PDU size\n");
- return -1;
- }
-
- if (DEBUG) {
- printf("GOOSE message:\n----------------\n");
- printf(" APPID: %u\n", appId);
- printf(" LENGTH: %u\n", length);
- printf(" APDU length: %i\n", apduLength);
- }
-
- if (subscriber->appId >= 0) {
- if (appId != (uint16_t) subscriber->appId) {
- if (DEBUG)
- printf("GOOSE message ignored due to wrong APPID value\n");
-
- return 0;
- }
- }
-
- return parseGoosePayload(buffer + bufPos, apduLength, subscriber);
-}
-
-static void
-gooseSubscriberLoop(void* threadParameter)
-{
- GooseSubscriber self = (GooseSubscriber) threadParameter;
-
- uint8_t* buffer = (uint8_t*) malloc(ETH_BUFFER_LENGTH);
-
- EthernetSocket socket;
-
- if (self->interfaceId == NULL)
- socket = Ethernet_createSocket(CONFIG_ETHERNET_INTERFACE_ID, NULL);
- else
- socket = Ethernet_createSocket(self->interfaceId, NULL);
-
- Ethernet_setProtocolFilter(socket, ETH_P_GOOSE);
-
- int running = 1;
-
- while (running) {
-
- int packetSize = Ethernet_receivePacket(socket, buffer, ETH_BUFFER_LENGTH);
-
- if (packetSize > 0) {
- if (parseGooseMessage(buffer, packetSize, self) == 1) {
- if (self->listener != NULL) {
- self->listener(self, self->listenerParameter);
- }
- }
- }
-
- Thread_sleep(1);
-
- running = self->running;
- }
-
- free(buffer);
-
- Ethernet_destroySocket(socket);
-}
+#include "goose_receiver_internal.h"
GooseSubscriber
GooseSubscriber_create(char* goCbRef, MmsValue* dataSetValues)
{
- GooseSubscriber self = (GooseSubscriber) calloc(1, sizeof(struct sGooseSubscriber));
+ GooseSubscriber self = (GooseSubscriber) GLOBAL_CALLOC(1, sizeof(struct sGooseSubscriber));
self->goCBRef = copyString(goCbRef);
self->goCBRefLen = strlen(goCbRef);
@@ -650,59 +48,40 @@ GooseSubscriber_create(char* goCbRef, MmsValue* dataSetValues)
if (dataSetValues != NULL)
self->dataSetValuesSelfAllocated = false;
- self->running = false;
-
self->appId = -1;
return self;
}
-void
-GooseSubscriber_setAppId(GooseSubscriber self, uint16_t appId)
+bool
+GooseSubscriber_isValid(GooseSubscriber self)
{
- self->appId = (int32_t) appId;
-}
+ if (self->stateValid == false)
+ return false;
-void
-GooseSubscriber_setInterfaceId(GooseSubscriber self, char* interfaceId)
-{
- self->interfaceId = copyString(interfaceId);
-}
+ if (Hal_getTimeInMs() > self->invalidityTime)
+ return false;
-void
-GooseSubscriber_subscribe(GooseSubscriber self)
-{
- Thread thread = Thread_create((ThreadExecutionFunction) gooseSubscriberLoop, self, false);
- self->receiver = thread;
- self->running = true;
- Thread_start(thread);
+ return true;
}
void
-GooseSubscriber_unsubscribe(GooseSubscriber self)
+GooseSubscriber_setAppId(GooseSubscriber self, uint16_t appId)
{
- if (self->running) {
- self->running = false;
- Thread_destroy(self->receiver);
- }
+ self->appId = (int32_t) appId;
}
void
GooseSubscriber_destroy(GooseSubscriber self)
{
- GooseSubscriber_unsubscribe(self);
-
- free(self->goCBRef);
+ GLOBAL_FREEMEM(self->goCBRef);
MmsValue_delete(self->timestamp);
if (self->dataSetValuesSelfAllocated)
MmsValue_delete(self->dataSetValues);
- if (self->interfaceId != NULL)
- free(self->interfaceId);
-
- free(self);
+ GLOBAL_FREEMEM(self);
}
void
diff --git a/src/goose/goose_subscriber.h b/src/goose/goose_subscriber.h
index ade78e48..f9f09742 100644
--- a/src/goose/goose_subscriber.h
+++ b/src/goose/goose_subscriber.h
@@ -1,7 +1,7 @@
/*
* goose_subscriber.h
*
- * Copyright 2013 Michael Zillgith
+ * Copyright 2013, 2014 Michael Zillgith
*
* This file is part of libIEC61850.
*
@@ -70,6 +70,9 @@ typedef void (*GooseListener)(GooseSubscriber subscriber, void* parameter);
GooseSubscriber
GooseSubscriber_create(char* goCbRef, MmsValue* dataSetValues);
+//char*
+//GooseSubscriber_getGoCbRef(GooseSubscriber self);
+
/**
* \brief set the APPID used by the subscriber to filter relevant messages.
*
@@ -82,30 +85,23 @@ void
GooseSubscriber_setAppId(GooseSubscriber self, uint16_t appId);
/**
- * \brief set the ethernet interface that should be used.
+ * \brief Check if subscriber state is valid
*
- * \param self GooseSubscriber instance to operate on.
- * \param interfaceId the id of the interface (e.g. a network device name like eth0
- * for linux or a numerical index for windows)
- */
-void
-GooseSubscriber_setInterfaceId(GooseSubscriber self, char* interfaceId);
-
-/**
- * \brief Start listening to GOOSE messages
+ * A GOOSE subscriber is valid if TimeAllowedToLive timeout is not elapsed and GOOSE
+ * message were received with correct state and sequence ID.
*
- * \param self GooseSubscriber instance to operate on.
*/
-void
-GooseSubscriber_subscribe(GooseSubscriber self);
+bool
+GooseSubscriber_isValid(GooseSubscriber self);
+
+//uint16_t
+//GooseSubscriber_getAppId(GooseSubscriber self);
-/**
- * \brief Stop listening to GOOSE messages
- *
- * \param self GooseSubscriber instance to operate on.
- */
void
-GooseSubscriber_unsubscribe(GooseSubscriber self);
+GooseSubscriber_setGoId(GooseSubscriber self, const char* goId);
+
+//char*
+//GooseSubscriber_getGoId(GooseSubscriber self);
void
GooseSubscriber_destroy(GooseSubscriber self);
@@ -138,6 +134,17 @@ GooseSubscriber_getTimeAllowedToLive(GooseSubscriber self);
uint64_t
GooseSubscriber_getTimestamp(GooseSubscriber self);
+/**
+ * \brief get the data set values received with the last report
+ *
+ * Note: To prevent data corruption. The MmsValue instance received should
+ * only be used inside of the callback function, when the GOOSE receiver is
+ * running in a separate thread.
+ *
+ * \param self GooseSubscriber instance to operate on.
+ *
+ * \return MmsValue instance of the report data set
+ */
MmsValue*
GooseSubscriber_getDataSetValues(GooseSubscriber self);
diff --git a/src/hal/ethernet/bsd/ethernet_bsd.c b/src/hal/ethernet/bsd/ethernet_bsd.c
index b9c8fe3c..b1eaf296 100644
--- a/src/hal/ethernet/bsd/ethernet_bsd.c
+++ b/src/hal/ethernet/bsd/ethernet_bsd.c
@@ -36,7 +36,8 @@
#include
#include
-#include "ethernet.h"
+#include "libiec61850_platform_includes.h"
+#include "hal_ethernet.h"
struct sEthernetSocket {
int bpf; // BPF device handle.
@@ -181,7 +182,7 @@ EthernetSocket Ethernet_createSocket(char* interfaceId, uint8_t* destAddress)
*/
};
- EthernetSocket self = calloc(1, sizeof(struct sEthernetSocket));
+ EthernetSocket self = GLOBAL_CALLOC(1, sizeof(struct sEthernetSocket));
if (!self)
{
printf("Could not allocate socket descriptor!\n");
@@ -189,7 +190,7 @@ EthernetSocket Ethernet_createSocket(char* interfaceId, uint8_t* destAddress)
}
// Copy default BPF filter program into descriptor.
- self->bpfProgram.bf_insns = calloc(1, sizeof(destAddrFiltCode));
+ self->bpfProgram.bf_insns = GLOBAL_CALLOC(1, sizeof(destAddrFiltCode));
if (!self->bpfProgram.bf_insns)
{
printf("Could not allocate memory for BPF filter program!\n");
@@ -212,8 +213,8 @@ EthernetSocket Ethernet_createSocket(char* interfaceId, uint8_t* destAddress)
if (self->bpf == -1)
{
printf("Error opening BPF file handle!\n");
- free(self->bpfProgram.bf_insns);
- free(self);
+ GLOBAL_FREEMEM(self->bpfProgram.bf_insns);
+ GLOBAL_FREEMEM(self);
return NULL;
}
@@ -223,8 +224,8 @@ EthernetSocket Ethernet_createSocket(char* interfaceId, uint8_t* destAddress)
if (fcntl(self->bpf, F_SETFL, &optval) == -1)
{
printf("Unable to change to non-blocking mode!\n");
- free(self->bpfProgram.bf_insns);
- free(self);
+ GLOBAL_FREEMEM(self->bpfProgram.bf_insns);
+ GLOBAL_FREEMEM(self);
return NULL;
}
@@ -233,8 +234,8 @@ EthernetSocket Ethernet_createSocket(char* interfaceId, uint8_t* destAddress)
if (ioctl(self->bpf, BIOCSETIF, &ifr))
{
printf("Unable to select interface %s!\n", interfaceId);
- free(self->bpfProgram.bf_insns);
- free(self);
+ GLOBAL_FREEMEM(self->bpfProgram.bf_insns);
+ GLOBAL_FREEMEM(self);
return NULL;
}
@@ -242,8 +243,8 @@ EthernetSocket Ethernet_createSocket(char* interfaceId, uint8_t* destAddress)
if (ioctl(self->bpf, BIOCIMMEDIATE, &self->bpfBufferSize) == -1)
{
printf("Unable to activate immediate mode!\n");
- free(self->bpfProgram.bf_insns);
- free(self);
+ GLOBAL_FREEMEM(self->bpfProgram.bf_insns);
+ GLOBAL_FREEMEM(self);
return NULL;
}
@@ -251,18 +252,18 @@ EthernetSocket Ethernet_createSocket(char* interfaceId, uint8_t* destAddress)
if (ioctl(self->bpf, BIOCGBLEN, &self->bpfBufferSize) == -1)
{
printf("Unable to get BPF buffer lenght!\n");
- free(self->bpfProgram.bf_insns);
- free(self);
+ GLOBAL_FREEMEM(self->bpfProgram.bf_insns);
+ GLOBAL_FREEMEM(self);
return NULL;
}
// Allocate a buffer for the message reception.
- self->bpfBuffer = calloc(1, self->bpfBufferSize);
+ self->bpfBuffer = GLOBAL_CALLOC(1, self->bpfBufferSize);
if (!self->bpfBuffer)
{
printf("Unable to allocate BPF RX buffer!\n");
- free(self->bpfProgram.bf_insns);
- free(self);
+ GLOBAL_FREEMEM(self->bpfProgram.bf_insns);
+ GLOBAL_FREEMEM(self);
return NULL;
}
self->bpfPositon = self->bpfBuffer;
@@ -273,9 +274,9 @@ EthernetSocket Ethernet_createSocket(char* interfaceId, uint8_t* destAddress)
if (ioctl(self->bpf, BIOCPROMISC, &optval) == -1)
{
printf("Unable to activate promiscous mode!\n");
- free(self->bpfProgram.bf_insns);
- free(self->bpfBuffer);
- free(self);
+ GLOBAL_FREEMEM(self->bpfProgram.bf_insns);
+ GLOBAL_FREEMEM(self->bpfBuffer);
+ GLOBAL_FREEMEM(self);
return NULL;
}
@@ -313,7 +314,7 @@ int Ethernet_receivePacket(EthernetSocket self, uint8_t* buffer, int bufferSize)
struct bpf_hdr *header = (struct bpf_hdr *)(self->bpfPositon);
// Check if the target buffer is big enough to hold the received ethernet frame.
- if (bufferSize >= header->bh_caplen)
+ if ((unsigned int) bufferSize >= header->bh_caplen)
{
// Copy the frame to the target buffer.
memcpy(buffer, self->bpfPositon + header->bh_hdrlen, header->bh_caplen);
@@ -346,7 +347,14 @@ void Ethernet_destroySocket(EthernetSocket self)
close(self->bpf);
// Free all dynamic resources used by the ethernet socket.
- free(self->bpfBuffer);
- free(self->bpfProgram.bf_insns);
- free(self);
+ GLOBAL_FREEMEM(self->bpfBuffer);
+ GLOBAL_FREEMEM(self->bpfProgram.bf_insns);
+ GLOBAL_FREEMEM(self);
}
+
+bool
+Ethernet_isSupported()
+{
+ return true;
+}
+
diff --git a/src/hal/ethernet/linux/ethernet_linux.c b/src/hal/ethernet/linux/ethernet_linux.c
index f9dfadf5..82e65e95 100644
--- a/src/hal/ethernet/linux/ethernet_linux.c
+++ b/src/hal/ethernet/linux/ethernet_linux.c
@@ -35,7 +35,8 @@
#include
#include
-#include "ethernet.h"
+#include "libiec61850_platform_includes.h"
+#include "hal_ethernet.h"
struct sEthernetSocket {
int rawSocket;
@@ -101,13 +102,13 @@ Ethernet_getInterfaceMACAddress(char* interfaceId, uint8_t* addr)
EthernetSocket
Ethernet_createSocket(char* interfaceId, uint8_t* destAddress)
{
- EthernetSocket ethernetSocket = calloc(1, sizeof(struct sEthernetSocket));
+ EthernetSocket ethernetSocket = GLOBAL_CALLOC(1, sizeof(struct sEthernetSocket));
ethernetSocket->rawSocket = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (ethernetSocket->rawSocket == -1) {
printf("Error creating raw socket!\n");
- free(ethernetSocket);
+ GLOBAL_FREEMEM(ethernetSocket);
return NULL;
}
@@ -163,6 +164,12 @@ void
Ethernet_destroySocket(EthernetSocket ethSocket)
{
close(ethSocket->rawSocket);
- free(ethSocket);
+ GLOBAL_FREEMEM(ethSocket);
+}
+
+bool
+Ethernet_isSupported()
+{
+ return true;
}
diff --git a/src/hal/ethernet/win32/ethernet_win32.c b/src/hal/ethernet/win32/ethernet_win32.c
index 05eb67f1..7095382a 100644
--- a/src/hal/ethernet/win32/ethernet_win32.c
+++ b/src/hal/ethernet/win32/ethernet_win32.c
@@ -23,12 +23,16 @@
#include "stack_config.h"
-#if CONFIG_INCLUDE_ETHERNET_WINDOWS == 1
-
#include
#include
#include
#include
+
+#include "hal_ethernet.h"
+
+#if (CONFIG_INCLUDE_ETHERNET_WINDOWS == 1)
+
+
#include
#include
@@ -38,8 +42,6 @@
#pragma comment (lib, "IPHLPAPI.lib")
#endif
-#include "ethernet.h"
-
#define HAVE_REMOTE
#include "pcap.h"
@@ -89,7 +91,7 @@ static pgetadaptersaddresses GetAdaptersAddresses;
static bool dllLoaded = false;
static void
-loadDLLs()
+loadDLLs(void)
{
HINSTANCE hDll = LoadLibrary("iphlpapi.dll");
@@ -103,7 +105,7 @@ loadDLLs()
"GetAdaptersAddresses");
if (GetAdaptersAddresses == NULL)
- printf("Error loading GetAdaptersAddresses from iphlpapi.dll (%d)\n", GetLastError());
+ printf("Error loading GetAdaptersAddresses from iphlpapi.dll (%d)\n", (int) GetLastError());
}
#endif /* __MINGW64_VERSION_MAJOR */
@@ -155,7 +157,7 @@ getInterfaceName(int interfaceIndex)
return interfaceName;
}
-void
+static void
getAdapterMacAddress(char* pcapAdapterName, uint8_t* macAddress)
{
PIP_ADAPTER_ADDRESSES pAddresses = NULL;
@@ -224,7 +226,7 @@ Ethernet_getInterfaceMACAddress(char* interfaceId, uint8_t* addr)
long interfaceIndex = strtol(interfaceId, &endPtr, 10);
- if (*endPtr != NULL) {
+ if (endPtr != NULL) {
printf("Ethernet_getInterfaceMACAddress: invalid interface number %s\n", interfaceId);
return;
}
@@ -315,4 +317,50 @@ Ethernet_receivePacket(EthernetSocket self, uint8_t* buffer, int bufferSize)
}
}
-#endif
+bool
+Ethernet_isSupported()
+{
+ return true;
+}
+
+#else
+
+bool
+Ethernet_isSupported()
+{
+ return false;
+}
+
+void
+Ethernet_getInterfaceMACAddress(char* interfaceId, uint8_t* addr)
+{
+}
+
+EthernetSocket
+Ethernet_createSocket(char* interfaceId, uint8_t* destAddress)
+{
+ return NULL;
+}
+
+void
+Ethernet_destroySocket(EthernetSocket ethSocket)
+{
+}
+
+void
+Ethernet_sendPacket(EthernetSocket ethSocket, uint8_t* buffer, int packetSize)
+{
+}
+
+void
+Ethernet_setProtocolFilter(EthernetSocket ethSocket, uint16_t etherType)
+{
+}
+
+int
+Ethernet_receivePacket(EthernetSocket self, uint8_t* buffer, int bufferSize)
+{
+ return 0;
+}
+
+#endif /* (CONFIG_INCLUDE_ETHERNET_WINDOWS == 1) */
diff --git a/src/hal/filesystem/linux/file_provider_linux.c b/src/hal/filesystem/linux/file_provider_linux.c
index a5a88f45..91bf3d3e 100644
--- a/src/hal/filesystem/linux/file_provider_linux.c
+++ b/src/hal/filesystem/linux/file_provider_linux.c
@@ -32,7 +32,9 @@
#include
#include
-#include "filesystem.h"
+#include "libiec61850_platform_includes.h"
+
+#include "hal_filesystem.h"
#include "stack_config.h"
@@ -154,7 +156,7 @@ FileSystem_openDirectory(char* directoryName)
DirectoryHandle handle = NULL;
if (dirHandle != NULL) {
- handle = malloc(sizeof(struct sDirectoryHandle));
+ handle = GLOBAL_MALLOC(sizeof(struct sDirectoryHandle));
handle->handle = dirHandle;
}
@@ -190,7 +192,7 @@ void
FileSystem_closeDirectory(DirectoryHandle directory)
{
closedir(directory->handle);
- free(directory);
+ GLOBAL_FREEMEM(directory);
}
#if 0
diff --git a/src/hal/filesystem/win32/file_provider_win32.c b/src/hal/filesystem/win32/file_provider_win32.c
index c0b6a182..01250219 100644
--- a/src/hal/filesystem/win32/file_provider_win32.c
+++ b/src/hal/filesystem/win32/file_provider_win32.c
@@ -30,8 +30,9 @@
#include
#include
-#include "filesystem.h"
+#include "hal_filesystem.h"
+#include "libiec61850_platform_includes.h"
#include "stack_config.h"
#include
@@ -131,7 +132,7 @@ FileSystem_openDirectory(char* directoryName)
createFullPathFromFileName(fullPath, directoryName);
- DirectoryHandle dirHandle = (DirectoryHandle) calloc(1, sizeof(struct sDirectoryHandle));
+ DirectoryHandle dirHandle = (DirectoryHandle) GLOBAL_CALLOC(1, sizeof(struct sDirectoryHandle));
strcat(fullPath, "\\*");
@@ -141,7 +142,7 @@ FileSystem_openDirectory(char* directoryName)
dirHandle->available = true;
if (dirHandle->handle == INVALID_HANDLE_VALUE) {
- free(dirHandle);
+ GLOBAL_FREEMEM(dirHandle);
return NULL;
}
else
@@ -226,27 +227,6 @@ void
FileSystem_closeDirectory(DirectoryHandle directory)
{
FindClose(directory->handle);
- free(directory);
+ GLOBAL_FREEMEM(directory);
}
-#if 0
-int
-main(int argc, char** argv)
-{
- DirectoryHandle directory = FileSystem_openDirectory("/");
-
- if (directory != NULL) {
- char* fileName = FileSystem_readDirectory(directory);
-
-
- while (fileName != NULL) {
- printf("FILE: (%s)\n", fileName);
- fileName = FileSystem_readDirectory(directory);
- }
-
- FileSystem_closeDirectory(directory);
- }
- else
- printf("Error opening directory!\n");
-}
-#endif
diff --git a/src/hal/socket/bsd/socket_bsd.c b/src/hal/socket/bsd/socket_bsd.c
index 770b0039..09457212 100644
--- a/src/hal/socket/bsd/socket_bsd.c
+++ b/src/hal/socket/bsd/socket_bsd.c
@@ -1,7 +1,7 @@
/*
* socket_bsd.c
*
- * Copyright 2013 Michael Zillgith, contributed to the project by Michael Clausen (School of engineering Valais).
+ * Copyright 2013, 2014 Michael Zillgith, contributions by Michael Clausen (School of engineering Valais).
*
* This file is part of libIEC61850.
*
@@ -21,7 +21,7 @@
* See COPYING file for the complete license text.
*/
-#include "socket.h"
+#include "hal_socket.h"
#include
#include
#include
@@ -38,7 +38,7 @@
#include // required for TCP keepalive
-#include "thread.h"
+#include "hal_thread.h"
#include "libiec61850_platform_includes.h"
@@ -48,6 +48,7 @@
struct sSocket {
int fd;
+ uint32_t connectTimeout;
};
struct sServerSocket {
@@ -55,6 +56,58 @@ struct sServerSocket {
int backLog;
};
+struct sHandleSet {
+ fd_set handles;
+ int maxHandle;
+};
+
+HandleSet
+Handleset_new(void)
+{
+ HandleSet result = (HandleSet) GLOBAL_MALLOC(sizeof(struct sHandleSet));
+
+ if (result != NULL) {
+ FD_ZERO(&result->handles);
+ result->maxHandle = -1;
+ }
+ return result;
+}
+
+void
+Handleset_addSocket(HandleSet self, const Socket sock)
+{
+ if (self != NULL && sock != NULL && sock->fd != -1) {
+ FD_SET(sock->fd, &self->handles);
+ if (sock->fd > self->maxHandle) {
+ self->maxHandle = sock->fd;
+ }
+ }
+}
+
+int
+Handleset_waitReady(HandleSet self, unsigned int timeoutMs)
+{
+ int result;
+
+ if (self != NULL && self->maxHandle >= 0) {
+ struct timeval timeout;
+
+ timeout.tv_sec = timeoutMs / 1000;
+ timeout.tv_usec = (timeoutMs % 1000) * 1000;
+ result = select(self->maxHandle + 1, &self->handles, NULL, NULL, &timeout);
+ } else {
+ result = -1;
+ }
+
+ return result;
+}
+
+void
+Handleset_destroy(HandleSet self)
+{
+ GLOBAL_FREEMEM(self);
+}
+
static void
activateKeepAlive(int sd)
{
@@ -79,7 +132,7 @@ activateKeepAlive(int sd)
}
static bool
-prepareServerAddress(char* address, int port, struct sockaddr_in* sockaddr)
+prepareServerAddress(const char* address, int port, struct sockaddr_in* sockaddr)
{
memset((char *) sockaddr , 0, sizeof(struct sockaddr_in));
@@ -101,17 +154,15 @@ prepareServerAddress(char* address, int port, struct sockaddr_in* sockaddr)
return true;
}
-#if 0
static void
setSocketNonBlocking(Socket self)
{
int flags = fcntl(self->fd, F_GETFL, 0);
fcntl(self->fd, F_SETFL, flags | O_NONBLOCK);
}
-#endif
ServerSocket
-TcpServerSocket_create(char* address, int port)
+TcpServerSocket_create(const char* address, int port)
{
ServerSocket serverSocket = NULL;
@@ -129,7 +180,7 @@ TcpServerSocket_create(char* address, int port)
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &optionReuseAddr, sizeof(int));
if (bind(fd, (struct sockaddr *) &serverAddress, sizeof(serverAddress)) >= 0) {
- serverSocket = malloc(sizeof(struct sServerSocket));
+ serverSocket = GLOBAL_MALLOC(sizeof(struct sServerSocket));
serverSocket->fd = fd;
serverSocket->backLog = 0;
}
@@ -141,6 +192,8 @@ TcpServerSocket_create(char* address, int port)
#if CONFIG_ACTIVATE_TCP_KEEPALIVE == 1
activateKeepAlive(fd);
#endif
+
+ setSocketNonBlocking((Socket) serverSocket);
}
return serverSocket;
@@ -201,21 +254,28 @@ ServerSocket_destroy(ServerSocket self)
Thread_sleep(10);
- free(self);
+ GLOBAL_FREEMEM(self);
}
Socket
TcpSocket_create()
{
- Socket self = malloc(sizeof(struct sSocket));
+ Socket self = GLOBAL_MALLOC(sizeof(struct sSocket));
self->fd = -1;
return self;
}
-int
-Socket_connect(Socket self, char* address, int port)
+void
+Socket_setConnectTimeout(Socket self, uint32_t timeoutInMs)
+{
+ self->connectTimeout = timeoutInMs;
+}
+
+
+bool
+Socket_connect(Socket self, const char* address, int port)
{
struct sockaddr_in serverAddress;
@@ -223,7 +283,7 @@ Socket_connect(Socket self, char* address, int port)
printf("Socket_connect: %s:%i\n", address, port);
if (!prepareServerAddress(address, port, &serverAddress))
- return 0;
+ return false;
self->fd = socket(AF_INET, SOCK_STREAM, 0);
@@ -231,10 +291,25 @@ Socket_connect(Socket self, char* address, int port)
activateKeepAlive(self->fd);
#endif
- if (connect(self->fd, (struct sockaddr *) &serverAddress, sizeof(serverAddress)) < 0)
- return 0;
+ fd_set fdSet;
+ FD_ZERO(&fdSet);
+ FD_SET(self->fd, &fdSet);
+
+ fcntl(self->fd, F_SETFL, O_NONBLOCK);
+
+ if (connect(self->fd, (struct sockaddr *) &serverAddress, sizeof(serverAddress)) < 0) {
+ if (errno != EINPROGRESS)
+ return false;
+ }
+
+ struct timeval timeout;
+ timeout.tv_sec = self->connectTimeout / 1000;
+ timeout.tv_usec = (self->connectTimeout % 1000) * 1000;
+
+ if (select(self->fd + 1, NULL, &fdSet, NULL, &timeout) < 0)
+ return false;
else
- return 1;
+ return true;
}
char*
@@ -265,7 +340,7 @@ Socket_getPeerAddress(Socket self)
else
return NULL ;
- char* clientConnection = malloc(strlen(addrString) + 9);
+ char* clientConnection = GLOBAL_MALLOC(strlen(addrString) + 9);
if (isIPv6)
@@ -284,7 +359,10 @@ Socket_read(Socket self, uint8_t* buf, int size)
if (self->fd == -1)
return -1;
- int read_bytes = read(self->fd, buf, size);
+ int read_bytes = recv(self->fd, buf, size, MSG_DONTWAIT);
+
+ if (read_bytes == 0)
+ return -1;
if (read_bytes == -1) {
int error = errno;
@@ -300,9 +378,8 @@ Socket_read(Socket self, uint8_t* buf, int size)
return -1;
}
}
- else {
- return read_bytes;
- }
+
+ return read_bytes;
}
int
@@ -326,5 +403,5 @@ Socket_destroy(Socket self)
Thread_sleep(10);
- free(self);
+ GLOBAL_FREEMEM(self);
}
diff --git a/src/hal/socket/linux/socket_linux.c b/src/hal/socket/linux/socket_linux.c
index be6f838e..87c22a5b 100644
--- a/src/hal/socket/linux/socket_linux.c
+++ b/src/hal/socket/linux/socket_linux.c
@@ -1,7 +1,7 @@
/*
* socket_linux.c
*
- * Copyright 2013 Michael Zillgith
+ * Copyright 2013, 2014 Michael Zillgith
*
* This file is part of libIEC61850.
*
@@ -21,7 +21,7 @@
* See COPYING file for the complete license text.
*/
-#include "socket.h"
+#include "hal_socket.h"
#include
#include
#include
@@ -38,7 +38,7 @@
#include // required for TCP keepalive
-#include "thread.h"
+#include "hal_thread.h"
#include "libiec61850_platform_includes.h"
@@ -48,6 +48,7 @@
struct sSocket {
int fd;
+ uint32_t connectTimeout;
};
struct sServerSocket {
@@ -55,6 +56,58 @@ struct sServerSocket {
int backLog;
};
+struct sHandleSet {
+ fd_set handles;
+ int maxHandle;
+};
+
+HandleSet
+Handleset_new(void)
+{
+ HandleSet result = (HandleSet) GLOBAL_MALLOC(sizeof(struct sHandleSet));
+
+ if (result != NULL) {
+ FD_ZERO(&result->handles);
+ result->maxHandle = -1;
+ }
+ return result;
+}
+
+void
+Handleset_addSocket(HandleSet self, const Socket sock)
+{
+ if (self != NULL && sock != NULL && sock->fd != -1) {
+ FD_SET(sock->fd, &self->handles);
+ if (sock->fd > self->maxHandle) {
+ self->maxHandle = sock->fd;
+ }
+ }
+}
+
+int
+Handleset_waitReady(HandleSet self, unsigned int timeoutMs)
+{
+ int result;
+
+ if (self != NULL && self->maxHandle >= 0) {
+ struct timeval timeout;
+
+ timeout.tv_sec = timeoutMs / 1000;
+ timeout.tv_usec = (timeoutMs % 1000) * 1000;
+ result = select(self->maxHandle + 1, &self->handles, NULL, NULL, &timeout);
+ } else {
+ result = -1;
+ }
+
+ return result;
+}
+
+void
+Handleset_destroy(HandleSet self)
+{
+ GLOBAL_FREEMEM(self);
+}
+
static void
activateKeepAlive(int sd)
{
@@ -80,7 +133,7 @@ activateKeepAlive(int sd)
}
static bool
-prepareServerAddress(char* address, int port, struct sockaddr_in* sockaddr)
+prepareServerAddress(const char* address, int port, struct sockaddr_in* sockaddr)
{
memset((char *) sockaddr , 0, sizeof(struct sockaddr_in));
@@ -102,17 +155,23 @@ prepareServerAddress(char* address, int port, struct sockaddr_in* sockaddr)
return true;
}
-#if 0
static void
setSocketNonBlocking(Socket self)
{
int flags = fcntl(self->fd, F_GETFL, 0);
fcntl(self->fd, F_SETFL, flags | O_NONBLOCK);
}
-#endif
+
+static void
+activateTcpNoDelay(Socket self)
+{
+ /* activate TCP_NODELAY option - packets will be sent immediately */
+ int flag = 1;
+ setsockopt(self->fd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int));
+}
ServerSocket
-TcpServerSocket_create(char* address, int port)
+TcpServerSocket_create(const char* address, int port)
{
ServerSocket serverSocket = NULL;
@@ -130,9 +189,11 @@ TcpServerSocket_create(char* address, int port)
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &optionReuseAddr, sizeof(int));
if (bind(fd, (struct sockaddr *) &serverAddress, sizeof(serverAddress)) >= 0) {
- serverSocket = malloc(sizeof(struct sServerSocket));
+ serverSocket = GLOBAL_MALLOC(sizeof(struct sServerSocket));
serverSocket->fd = fd;
serverSocket->backLog = 0;
+
+ setSocketNonBlocking((Socket) serverSocket);
}
else {
close(fd);
@@ -153,6 +214,8 @@ ServerSocket_listen(ServerSocket self)
listen(self->fd, self->backLog);
}
+
+/* CHANGED TO MAKE NON-BLOCKING --> RETURNS NULL IF NO CONNECTION IS PENDING */
Socket
ServerSocket_accept(ServerSocket self)
{
@@ -165,6 +228,8 @@ ServerSocket_accept(ServerSocket self)
if (fd >= 0) {
conSocket = TcpSocket_create();
conSocket->fd = fd;
+
+ activateTcpNoDelay(conSocket);
}
return conSocket;
@@ -202,21 +267,30 @@ ServerSocket_destroy(ServerSocket self)
Thread_sleep(10);
- free(self);
+ GLOBAL_FREEMEM(self);
}
Socket
TcpSocket_create()
{
- Socket self = malloc(sizeof(struct sSocket));
+ Socket self = GLOBAL_MALLOC(sizeof(struct sSocket));
self->fd = -1;
+ self->connectTimeout = 5000;
return self;
}
-int
-Socket_connect(Socket self, char* address, int port)
+
+void
+Socket_setConnectTimeout(Socket self, uint32_t timeoutInMs)
+{
+ self->connectTimeout = timeoutInMs;
+}
+
+
+bool
+Socket_connect(Socket self, const char* address, int port)
{
struct sockaddr_in serverAddress;
@@ -224,18 +298,36 @@ Socket_connect(Socket self, char* address, int port)
printf("Socket_connect: %s:%i\n", address, port);
if (!prepareServerAddress(address, port, &serverAddress))
- return 0;
+ return false;
self->fd = socket(AF_INET, SOCK_STREAM, 0);
+ fd_set fdSet;
+ FD_ZERO(&fdSet);
+ FD_SET(self->fd, &fdSet);
+
+ activateTcpNoDelay(self);
+
#if CONFIG_ACTIVATE_TCP_KEEPALIVE == 1
activateKeepAlive(self->fd);
#endif
- if (connect(self->fd, (struct sockaddr *) &serverAddress, sizeof(serverAddress)) < 0)
- return 0;
+ fcntl(self->fd, F_SETFL, O_NONBLOCK);
+
+ if (connect(self->fd, (struct sockaddr *) &serverAddress, sizeof(serverAddress)) < 0) {
+ if (errno != EINPROGRESS)
+ return false;
+ }
+
+ struct timeval timeout;
+ timeout.tv_sec = self->connectTimeout / 1000;
+ timeout.tv_usec = (self->connectTimeout % 1000) * 1000;
+
+ if (select(self->fd + 1, NULL, &fdSet, NULL, &timeout) < 0)
+ return false;
else
- return 1;
+ return true;
+
}
char*
@@ -266,7 +358,7 @@ Socket_getPeerAddress(Socket self)
else
return NULL ;
- char* clientConnection = malloc(strlen(addrString) + 9);
+ char* clientConnection = GLOBAL_MALLOC(strlen(addrString) + 9);
if (isIPv6)
@@ -285,7 +377,10 @@ Socket_read(Socket self, uint8_t* buf, int size)
if (self->fd == -1)
return -1;
- int read_bytes = read(self->fd, buf, size);
+ int read_bytes = recv(self->fd, buf, size, MSG_DONTWAIT);
+
+ if (read_bytes == 0)
+ return -1;
if (read_bytes == -1) {
int error = errno;
@@ -301,9 +396,8 @@ Socket_read(Socket self, uint8_t* buf, int size)
return -1;
}
}
- else {
- return read_bytes;
- }
+
+ return read_bytes;
}
int
@@ -327,5 +421,5 @@ Socket_destroy(Socket self)
Thread_sleep(10);
- free(self);
+ GLOBAL_FREEMEM(self);
}
diff --git a/src/hal/socket/win32/socket_win32.c b/src/hal/socket/win32/socket_win32.c
index 11430107..789de3b7 100644
--- a/src/hal/socket/win32/socket_win32.c
+++ b/src/hal/socket/win32/socket_win32.c
@@ -1,7 +1,7 @@
/*
* socket_win32.c
*
- * Copyright 2013 Michael Zillgith
+ * Copyright 2013, 2014 Michael Zillgith
*
* This file is part of libIEC61850.
*
@@ -29,7 +29,8 @@
#pragma comment (lib, "Ws2_32.lib")
-#include "socket.h"
+#include "libiec61850_platform_includes.h"
+#include "hal_socket.h"
#include "stack_config.h"
@@ -45,6 +46,7 @@ struct tcp_keepalive {
struct sSocket {
SOCKET fd;
+ uint32_t connectTimeout;
};
struct sServerSocket {
@@ -52,6 +54,58 @@ struct sServerSocket {
int backLog;
};
+struct sHandleSet {
+ fd_set handles;
+ int maxHandle;
+};
+
+HandleSet
+Handleset_new(void)
+{
+ HandleSet result = (HandleSet) GLOBAL_MALLOC(sizeof(struct sHandleSet));
+
+ if (result != NULL) {
+ FD_ZERO(&result->handles);
+ result->maxHandle = -1;
+ }
+ return result;
+}
+
+void
+Handleset_addSocket(HandleSet self, const Socket sock)
+{
+ if (self != NULL && sock != NULL && sock->fd != -1) {
+ FD_SET(sock->fd, &self->handles);
+ if (sock->fd > self->maxHandle) {
+ self->maxHandle = sock->fd;
+ }
+ }
+}
+
+int
+Handleset_waitReady(HandleSet self, unsigned int timeoutMs)
+{
+ int result;
+
+ if (self != NULL && self->maxHandle >= 0) {
+ struct timeval timeout;
+
+ timeout.tv_sec = timeoutMs / 1000;
+ timeout.tv_usec = (timeoutMs % 1000) * 1000;
+ result = select(self->maxHandle + 1, &self->handles, NULL, NULL, &timeout);
+ } else {
+ result = -1;
+ }
+
+ return result;
+}
+
+void
+Handleset_destroy(HandleSet self)
+{
+ GLOBAL_FREEMEM(self);
+}
+
static void
activateKeepAlive(SOCKET s)
{
@@ -65,13 +119,30 @@ activateKeepAlive(SOCKET s)
if (WSAIoctl(s, SIO_KEEPALIVE_VALS, &keepalive, sizeof(keepalive),
NULL, 0, &retVal, NULL, NULL) == SOCKET_ERROR)
{
- printf("WSAIotcl(SIO_KEEPALIVE_VALS) failed; %d\n",
- WSAGetLastError());
+ if (DEBUG_SOCKET)
+ printf("WIN32_SOCKET: WSAIotcl(SIO_KEEPALIVE_VALS) failed: %d\n",
+ WSAGetLastError());
}
}
+static void
+setSocketNonBlocking(Socket self)
+{
+ unsigned long mode = 1;
+ if (ioctlsocket(self->fd, FIONBIO, &mode) != 0) {
+ if (DEBUG_SOCKET)
+ printf("WIN32_SOCKET: failed to set socket non-blocking!\n");
+ }
+
+ /* activate TCP_NODELAY */
+
+ int tcpNoDelay = 1;
+
+ setsockopt(self->fd, IPPROTO_TCP, TCP_NODELAY, (const char*)&tcpNoDelay, sizeof(int));
+}
+
static bool
-prepareServerAddress(char* address, int port, struct sockaddr_in* sockaddr)
+prepareServerAddress(const char* address, int port, struct sockaddr_in* sockaddr)
{
memset((char *) sockaddr , 0, sizeof(struct sockaddr_in));
@@ -94,7 +165,7 @@ prepareServerAddress(char* address, int port, struct sockaddr_in* sockaddr)
}
ServerSocket
-TcpServerSocket_create(char* address, int port)
+TcpServerSocket_create(const char* address, int port)
{
ServerSocket serverSocket = NULL;
int ec;
@@ -102,7 +173,8 @@ TcpServerSocket_create(char* address, int port)
SOCKET listen_socket = INVALID_SOCKET;
if ((ec = WSAStartup(MAKEWORD(2,0), &wsa)) != 0) {
- printf("winsock error: code %i\n");
+ if (DEBUG_SOCKET)
+ printf("WIN32_SOCKET: winsock error: code %i\n", ec);
return NULL;
}
@@ -118,7 +190,8 @@ TcpServerSocket_create(char* address, int port)
#endif
if (listen_socket == INVALID_SOCKET) {
- printf("socket failed with error: %i\n", WSAGetLastError());
+ if (DEBUG_SOCKET)
+ printf("WIN32_SOCKET: socket failed with error: %i\n", WSAGetLastError());
WSACleanup();
return NULL;
}
@@ -129,17 +202,20 @@ TcpServerSocket_create(char* address, int port)
ec = bind(listen_socket, (struct sockaddr*)&server_addr, sizeof(server_addr));
if (ec == SOCKET_ERROR) {
- printf("bind failed with error:%i\n", WSAGetLastError());
+ if (DEBUG_SOCKET)
+ printf("WIN32_SOCKET: bind failed with error:%i\n", WSAGetLastError());
closesocket(listen_socket);
WSACleanup();
return NULL;
}
- serverSocket = (ServerSocket) malloc(sizeof(struct sServerSocket));
+ serverSocket = (ServerSocket) GLOBAL_MALLOC(sizeof(struct sServerSocket));
serverSocket->fd = listen_socket;
serverSocket->backLog = 10;
+ setSocketNonBlocking((Socket) serverSocket);
+
return serverSocket;
}
@@ -161,6 +237,8 @@ ServerSocket_accept(ServerSocket self)
if (fd >= 0) {
conSocket = TcpSocket_create();
conSocket->fd = fd;
+
+ setSocketNonBlocking(conSocket);
}
return conSocket;
@@ -183,27 +261,34 @@ ServerSocket_destroy(ServerSocket self)
Socket
TcpSocket_create()
{
- Socket self = (Socket) malloc(sizeof(struct sSocket));
+ Socket self = (Socket) GLOBAL_MALLOC(sizeof(struct sSocket));
- self->fd = -1;
+ self->fd = INVALID_SOCKET;
return self;
}
-int
-Socket_connect(Socket self, char* address, int port)
+void
+Socket_setConnectTimeout(Socket self, uint32_t timeoutInMs)
+{
+ self->connectTimeout = timeoutInMs;
+}
+
+bool
+Socket_connect(Socket self, const char* address, int port)
{
- struct hostent *server;
struct sockaddr_in serverAddress;
WSADATA wsa;
+ int ec;
- if (WSAStartup(MAKEWORD(2,0), &wsa) != 0) {
- printf("winsock error: code %i\n");
- return 0;
+ if ((ec = WSAStartup(MAKEWORD(2,0), &wsa)) != 0) {
+ if (DEBUG_SOCKET)
+ printf("WIN32_SOCKET: winsock error: code %i\n", ec);
+ return false;
}
if (!prepareServerAddress(address, port, &serverAddress))
- return 0;
+ return false;
self->fd = socket(AF_INET, SOCK_STREAM, 0);
@@ -211,12 +296,35 @@ Socket_connect(Socket self, char* address, int port)
activateKeepAlive(self->fd);
#endif
- if (connect(self->fd, (struct sockaddr *) &serverAddress,sizeof(serverAddress)) < 0) {
- printf("Socket failed connecting!\n");
- return 0;
- }
- else
- return 1;
+ setSocketNonBlocking(self);
+
+ fd_set fdSet;
+ FD_ZERO(&fdSet);
+ FD_SET(self->fd, &fdSet);
+
+// if (connect(self->fd, (struct sockaddr *) &serverAddress,sizeof(serverAddress)) < 0) {
+// if (DEBUG_SOCKET)
+// printf("WIN32_SOCKET: Socket failed connecting!\n");
+// return false;
+// }
+// else {
+//
+// return true;
+// }
+
+ if (connect(self->fd, (struct sockaddr *) &serverAddress, sizeof(serverAddress)) == SOCKET_ERROR) {
+ if (WSAGetLastError() != WSAEWOULDBLOCK)
+ return false;
+ }
+
+ struct timeval timeout;
+ timeout.tv_sec = self->connectTimeout / 1000;
+ timeout.tv_usec = (self->connectTimeout % 1000) * 1000;
+
+ if (select(self->fd + 1, NULL, &fdSet, NULL, &timeout) == SOCKET_ERROR)
+ return false;
+ else
+ return true;
}
char*
@@ -252,7 +360,7 @@ Socket_getPeerAddress(Socket self)
else
return NULL;
- char* clientConnection = (char*) malloc(strlen(addrString) + 9);
+ char* clientConnection = (char*) GLOBAL_MALLOC(strlen(addrString) + 9);
if (isIPv6)
sprintf(clientConnection, "[%s]:%i", addrString, port);
@@ -265,7 +373,19 @@ Socket_getPeerAddress(Socket self)
int
Socket_read(Socket self, uint8_t* buf, int size)
{
- return recv(self->fd, (char*) buf, size, 0);
+ int bytes_read = recv(self->fd, (char*) buf, size, 0);
+
+ if (bytes_read == 0) // peer has closed socket
+ return -1;
+
+ if (bytes_read == SOCKET_ERROR) {
+ if (WSAGetLastError() == WSAEWOULDBLOCK)
+ return 0;
+ else
+ return -1;
+ }
+
+ return bytes_read;
}
int
@@ -277,7 +397,7 @@ Socket_write(Socket self, uint8_t* buf, int size)
void
Socket_destroy(Socket self)
{
- if (self->fd != -1) {
+ if (self->fd != INVALID_SOCKET) {
closesocket(self->fd);
}
diff --git a/src/hal/thread/linux/thread_linux.c b/src/hal/thread/linux/thread_linux.c
index a2b13343..cf8ec73e 100644
--- a/src/hal/thread/linux/thread_linux.c
+++ b/src/hal/thread/linux/thread_linux.c
@@ -26,7 +26,9 @@
#include
#include
#include
-#include "thread.h"
+#include "hal_thread.h"
+
+#include "libiec61850_platform_includes.h"
struct sThread {
ThreadExecutionFunction function;
@@ -39,7 +41,7 @@ struct sThread {
Semaphore
Semaphore_create(int initialValue)
{
- Semaphore self = malloc(sizeof(sem_t));
+ Semaphore self = GLOBAL_MALLOC(sizeof(sem_t));
sem_init((sem_t*) self, 0, initialValue);
@@ -63,18 +65,20 @@ void
Semaphore_destroy(Semaphore self)
{
sem_destroy((sem_t*) self);
- free(self);
+ GLOBAL_FREEMEM(self);
}
Thread
Thread_create(ThreadExecutionFunction function, void* parameter, bool autodestroy)
{
- Thread thread = malloc(sizeof(struct sThread));
+ Thread thread = (Thread) GLOBAL_MALLOC(sizeof(struct sThread));
- thread->parameter = parameter;
- thread->function = function;
- thread->state = 0;
- thread->autodestroy = autodestroy;
+ if (thread != NULL) {
+ thread->parameter = parameter;
+ thread->function = function;
+ thread->state = 0;
+ thread->autodestroy = autodestroy;
+ }
return thread;
}
@@ -86,9 +90,9 @@ destroyAutomaticThread(void* parameter)
thread->function(thread->parameter);
- free(thread);
+ GLOBAL_FREEMEM(thread);
- return NULL;
+ pthread_exit(NULL);
}
void
@@ -111,7 +115,7 @@ Thread_destroy(Thread thread)
pthread_join(thread->pthread, NULL);
}
- free(thread);
+ GLOBAL_FREEMEM(thread);
}
void
diff --git a/src/hal/thread/win32/thread_win32.c b/src/hal/thread/win32/thread_win32.c
index 81018585..02498ff1 100644
--- a/src/hal/thread/win32/thread_win32.c
+++ b/src/hal/thread/win32/thread_win32.c
@@ -23,7 +23,8 @@
#include
#include
-#include "thread.h"
+#include "libiec61850_platform_includes.h"
+#include "hal_thread.h"
struct sThread {
ThreadExecutionFunction function;
@@ -59,7 +60,7 @@ Thread
Thread_create(ThreadExecutionFunction function, void* parameter, bool autodestroy)
{
DWORD threadId;
- Thread thread = (Thread) malloc(sizeof(struct sThread));
+ Thread thread = (Thread) GLOBAL_MALLOC(sizeof(struct sThread));
thread->parameter = parameter;
thread->function = function;
@@ -89,7 +90,7 @@ Thread_destroy(Thread thread)
CloseHandle(thread->handle);
- free(thread);
+ GLOBAL_FREEMEM(thread);
}
void
diff --git a/src/mms/asn1/asn1_ber_primitive_value.c b/src/mms/asn1/asn1_ber_primitive_value.c
index 4d4d7e5a..d08e885b 100644
--- a/src/mms/asn1/asn1_ber_primitive_value.c
+++ b/src/mms/asn1/asn1_ber_primitive_value.c
@@ -28,11 +28,11 @@
Asn1PrimitiveValue*
Asn1PrimitiveValue_create(int size)
{
- Asn1PrimitiveValue* self = (Asn1PrimitiveValue*) malloc(sizeof(Asn1PrimitiveValue));
+ Asn1PrimitiveValue* self = (Asn1PrimitiveValue*) GLOBAL_MALLOC(sizeof(Asn1PrimitiveValue));
self->size = size;
self->maxSize = size;
- self->octets = (uint8_t*) calloc(1, size);
+ self->octets = (uint8_t*) GLOBAL_CALLOC(1, size);
return self;
}
@@ -40,22 +40,22 @@ Asn1PrimitiveValue_create(int size)
//Asn1PrimitiveValue*
//Asn1PrimitiveValue_createFromBuffer(uint8_t buffer, int bufferSize)
//{
-// Asn1PrimitiveValue* self = malloc(sizeof(Asn1PrimitiveValue));
+// Asn1PrimitiveValue* self = GLOBAL_MALLOC(sizeof(Asn1PrimitiveValue));
// self->size = bufferSize;
// self->maxSize = bufferSize;
-// self->octets = malloc(1, bufferSize);
+// self->octets = GLOBAL_MALLOC(1, bufferSize);
//
//}
Asn1PrimitiveValue*
Asn1PrimitiveValue_clone(Asn1PrimitiveValue* self)
{
- Asn1PrimitiveValue* clone = (Asn1PrimitiveValue*) malloc(sizeof(Asn1PrimitiveValue));
+ Asn1PrimitiveValue* clone = (Asn1PrimitiveValue*) GLOBAL_MALLOC(sizeof(Asn1PrimitiveValue));
clone->size = self->size;
clone->maxSize = self->maxSize;
- clone->octets = (uint8_t*) malloc(self->maxSize);
+ clone->octets = (uint8_t*) GLOBAL_MALLOC(self->maxSize);
memcpy(clone->octets, self->octets, clone->maxSize);
@@ -90,6 +90,6 @@ Asn1PrimitiveValue_getMaxSize(Asn1PrimitiveValue* self)
void
Asn1PrimitiveValue_destroy(Asn1PrimitiveValue* self)
{
- free(self->octets);
- free(self);
+ GLOBAL_FREEMEM(self->octets);
+ GLOBAL_FREEMEM(self);
}
diff --git a/src/mms/asn1/ber_decode.c b/src/mms/asn1/ber_decode.c
index 18f2fa52..bbd2231f 100644
--- a/src/mms/asn1/ber_decode.c
+++ b/src/mms/asn1/ber_decode.c
@@ -62,7 +62,7 @@ BerDecoder_decodeLength(uint8_t* buffer, int* length, int bufPos, int maxBufPos)
char*
BerDecoder_decodeString(uint8_t* buffer, int strlen, int bufPos, int maxBufPos)
{
- char* string = (char*) malloc(strlen + 1);
+ char* string = (char*) GLOBAL_MALLOC(strlen + 1);
memcpy(string, buffer + bufPos, strlen);
string[strlen] = 0;
diff --git a/src/mms/asn1/ber_encoder.c b/src/mms/asn1/ber_encoder.c
index c0bf2aef..f22f9e2b 100644
--- a/src/mms/asn1/ber_encoder.c
+++ b/src/mms/asn1/ber_encoder.c
@@ -70,7 +70,7 @@ BerEncoder_encodeBoolean(uint8_t tag, bool value, uint8_t* buffer, int bufPos)
}
int
-BerEncoder_encodeStringWithTag(uint8_t tag, char* string, uint8_t* buffer, int bufPos)
+BerEncoder_encodeStringWithTag(uint8_t tag, const char* string, uint8_t* buffer, int bufPos)
{
buffer[bufPos++] = tag;
@@ -341,7 +341,7 @@ BerEncoder_determineLengthSize(uint32_t length)
}
int
-BerEncoder_determineEncodedStringSize(char* string)
+BerEncoder_determineEncodedStringSize(const char* string)
{
if (string != NULL) {
int size = 1;
@@ -359,13 +359,13 @@ BerEncoder_determineEncodedStringSize(char* string)
}
int
-BerEncoder_encodeOIDToBuffer(char* oidString, uint8_t* buffer, int maxBufLen)
+BerEncoder_encodeOIDToBuffer(const char* oidString, uint8_t* buffer, int maxBufLen)
{
int encodedBytes = 0;
int x = atoi(oidString);
- char* separator = strchr(oidString, '.');
+ const char* separator = strchr(oidString, '.');
if (separator == NULL) return 0;
diff --git a/src/mms/iso_client/iso_client_connection.c b/src/mms/iso_client/iso_client_connection.c
new file mode 100644
index 00000000..b279f08f
--- /dev/null
+++ b/src/mms/iso_client/iso_client_connection.c
@@ -0,0 +1,589 @@
+/*
+ * iso_client_connection.c
+ *
+ * Client side representation of the ISO stack (COTP, session, presentation, ACSE)
+ *
+ * Copyright 2013 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.
+ */
+
+#include "libiec61850_platform_includes.h"
+
+#include "stack_config.h"
+
+#include "hal_socket.h"
+#include "hal_thread.h"
+#include "cotp.h"
+#include "iso_session.h"
+#include "iso_presentation.h"
+#include "iso_client_connection.h"
+#include "acse.h"
+
+#ifndef DEBUG_ISO_CLIENT
+#ifdef DEBUG
+#define DEBUG_ISO_CLIENT 1
+#else
+#define DEBUG_ISO_CLIENT 0
+#endif /*DEBUG */
+#endif /* DEBUG_ISO_SERVER */
+
+#define STATE_IDLE 0
+#define STATE_ASSOCIATED 1
+#define STATE_ERROR 2
+
+#define TPKT_RFC1006_HEADER_SIZE 4
+
+#define ISO_CLIENT_BUFFER_SIZE CONFIG_MMS_MAXIMUM_PDU_SIZE + 100
+
+struct sIsoClientConnection
+{
+ IsoIndicationCallback callback;
+ void* callbackParameter;
+ volatile int state;
+ Socket socket;
+ CotpConnection* cotpConnection;
+ IsoPresentation* presentation;
+ IsoSession* session;
+ AcseConnection acseConnection;
+
+ uint8_t* sendBuffer; /* ISO/MMS send buffer */
+ uint8_t* receiveBuf; /* ISO/MMS receive buffer */
+ ByteBuffer* receiveBuffer;
+
+ ByteBuffer* transmitPayloadBuffer;
+ Semaphore transmitBufferMutex;
+
+ ByteBuffer* receivePayloadBuffer;
+ Semaphore receiveBufferMutex;
+
+ uint8_t* cotpReadBuf;
+ uint8_t* cotpWriteBuf;
+
+ ByteBuffer* cotpReadBuffer;
+ ByteBuffer* cotpWriteBuffer;
+
+ volatile bool handlingThreadRunning;
+ volatile bool stopHandlingThread;
+ volatile bool destroyHandlingThread;
+ volatile bool startHandlingThread;
+
+ Thread thread;
+};
+
+static void
+connectionHandlingThread(IsoClientConnection self)
+{
+ IsoSessionIndication sessionIndication;
+
+ self->handlingThreadRunning = true;
+ self->stopHandlingThread = false;
+
+ if (DEBUG_ISO_CLIENT)
+ printf("ISO_CLIENT_CONNECTION: new connection %p\n", self);
+
+ /* Wait until lower layer association is finished */
+ Semaphore_wait(self->receiveBufferMutex);
+
+ CotpConnection_resetPayload(self->cotpConnection);
+
+ while (true) {
+
+ TpktState packetState;
+
+ while ((packetState = CotpConnection_readToTpktBuffer(self->cotpConnection)) == TPKT_WAITING)
+ {
+ Thread_sleep(1);
+
+ if (self->stopHandlingThread) {
+ packetState = TPKT_ERROR;
+ break;
+ }
+ }
+
+ if (packetState == TPKT_ERROR)
+ break;
+
+ CotpIndication cotpIndication = CotpConnection_parseIncomingMessage(self->cotpConnection);
+
+ if (cotpIndication == COTP_MORE_FRAGMENTS_FOLLOW)
+ continue;
+
+ if (cotpIndication != COTP_DATA_INDICATION)
+ break;
+
+ if (DEBUG_ISO_CLIENT)
+ printf("ISO_CLIENT_CONNECTION: parse message\n");
+
+ sessionIndication =
+ IsoSession_parseMessage(self->session,
+ CotpConnection_getPayload(self->cotpConnection));
+
+ if (sessionIndication != SESSION_DATA) {
+ if (DEBUG_ISO_CLIENT)
+ printf("ISO_CLIENT_CONNECTION: Invalid session message\n");
+ break;
+ }
+
+ if (!IsoPresentation_parseUserData(self->presentation, IsoSession_getUserData(self->session))) {
+ if (DEBUG_ISO_CLIENT)
+ printf("ISO_CLIENT_CONNECTION: Invalid presentation message\n");
+ break;
+ }
+
+ self->callback(ISO_IND_DATA, self->callbackParameter,
+ &(self->presentation->nextPayload));
+
+ /* wait for user to release the buffer */
+ Semaphore_wait(self->receiveBufferMutex);
+
+ CotpConnection_resetPayload(self->cotpConnection);
+ }
+
+ self->callback(ISO_IND_CLOSED, self->callbackParameter, NULL);
+
+ self->state = STATE_IDLE;
+
+ Socket_destroy(self->socket);
+
+ if (DEBUG_ISO_CLIENT)
+ printf("ISO_CLIENT_CONNECTION: exit connection %p\n", self);
+
+ /* release buffer to enable resuse of client connection */
+ Semaphore_post(self->receiveBufferMutex);
+
+ self->handlingThreadRunning = false;
+}
+
+
+static void*
+connectionThreadFunction(void* parameter)
+{
+ IsoClientConnection self = (IsoClientConnection) parameter;
+
+ while (self->destroyHandlingThread == false) {
+
+ if (self->startHandlingThread) {
+ self->startHandlingThread = false;
+ connectionHandlingThread(self);
+ }
+
+ Thread_sleep(1);
+ }
+
+ self->destroyHandlingThread = false;
+
+ return NULL;
+}
+
+
+IsoClientConnection
+IsoClientConnection_create(IsoIndicationCallback callback, void* callbackParameter)
+{
+ IsoClientConnection self = (IsoClientConnection) GLOBAL_CALLOC(1, sizeof(struct sIsoClientConnection));
+
+ if (self == NULL)
+ return NULL;
+
+ self->callback = callback;
+ self->callbackParameter = callbackParameter;
+ self->state = STATE_IDLE;
+
+ self->sendBuffer = (uint8_t*) GLOBAL_MALLOC(ISO_CLIENT_BUFFER_SIZE);
+
+ self->transmitPayloadBuffer = (ByteBuffer*) GLOBAL_CALLOC(1, sizeof(ByteBuffer));
+ self->transmitPayloadBuffer->buffer = self->sendBuffer;
+ self->transmitPayloadBuffer->maxSize = ISO_CLIENT_BUFFER_SIZE;
+
+ self->receivePayloadBuffer = (ByteBuffer*) GLOBAL_CALLOC(1, sizeof(ByteBuffer));
+
+ self->transmitBufferMutex = Semaphore_create(1);
+
+ self->receiveBufferMutex = Semaphore_create(1);
+
+ self->receiveBuf = (uint8_t*) GLOBAL_MALLOC(ISO_CLIENT_BUFFER_SIZE);
+ self->receiveBuffer = (ByteBuffer*) GLOBAL_CALLOC(1, sizeof(ByteBuffer));
+ ByteBuffer_wrap(self->receiveBuffer, self->receiveBuf, 0, ISO_CLIENT_BUFFER_SIZE);
+
+ self->presentation = (IsoPresentation*) GLOBAL_CALLOC(1, sizeof(IsoPresentation));
+
+ self->session = (IsoSession*) GLOBAL_CALLOC(1, sizeof(IsoSession));
+
+ self->cotpReadBuf = (uint8_t*) GLOBAL_MALLOC(CONFIG_COTP_MAX_TPDU_SIZE + TPKT_RFC1006_HEADER_SIZE);
+ self->cotpWriteBuf = (uint8_t*) GLOBAL_MALLOC(CONFIG_COTP_MAX_TPDU_SIZE + TPKT_RFC1006_HEADER_SIZE);
+
+ self->cotpReadBuffer = (ByteBuffer*) GLOBAL_CALLOC(1, sizeof(ByteBuffer));
+ ByteBuffer_wrap(self->cotpReadBuffer, self->cotpReadBuf, 0, CONFIG_COTP_MAX_TPDU_SIZE + TPKT_RFC1006_HEADER_SIZE);
+
+ self->cotpWriteBuffer = (ByteBuffer*) GLOBAL_CALLOC(1, sizeof(ByteBuffer));
+ ByteBuffer_wrap(self->cotpWriteBuffer, self->cotpWriteBuf, 0, CONFIG_COTP_MAX_TPDU_SIZE + TPKT_RFC1006_HEADER_SIZE);
+
+ self->cotpConnection = (CotpConnection*) GLOBAL_CALLOC(1, sizeof(CotpConnection));
+
+ return self;
+}
+
+void
+IsoClientConnection_associate(IsoClientConnection self, IsoConnectionParameters params,
+ ByteBuffer* payload, uint32_t connectTimeoutInMs)
+{
+ self->socket = TcpSocket_create();
+
+ Socket_setConnectTimeout(self->socket, connectTimeoutInMs);
+
+ if (!Socket_connect(self->socket, params->hostname, params->tcpPort))
+ goto returnError;
+
+ /* COTP (ISO transport) handshake */
+ CotpConnection_init(self->cotpConnection, self->socket, self->receiveBuffer, self->cotpReadBuffer, self->cotpWriteBuffer);
+ CotpIndication cotpIndication =
+ CotpConnection_sendConnectionRequestMessage(self->cotpConnection, params);
+
+ TpktState packetState;
+
+ uint64_t timeout = Hal_getTimeInMs() + CONFIG_TCP_READ_TIMEOUT_MS;
+
+ while (((packetState = CotpConnection_readToTpktBuffer(self->cotpConnection)) == TPKT_WAITING)
+ && (Hal_getTimeInMs() < timeout))
+ {
+ Thread_sleep(1);
+ }
+
+ if (packetState != TPKT_PACKET_COMPLETE)
+ goto returnError;
+
+ cotpIndication = CotpConnection_parseIncomingMessage(self->cotpConnection);
+
+ if (cotpIndication != COTP_CONNECT_INDICATION)
+ goto returnError;
+
+ /* Upper layers handshake */
+ struct sBufferChain sAcsePayload;
+ BufferChain acsePayload = &sAcsePayload;
+ acsePayload->buffer = payload->buffer;
+ acsePayload->partLength = payload->size;
+ acsePayload->length = payload->size;
+ acsePayload->nextPart = NULL;
+
+ AcseConnection_init(&(self->acseConnection), NULL, NULL);
+
+ AcseAuthenticationParameter authParameter = NULL;
+
+ if (params != NULL)
+ authParameter = params->acseAuthParameter;
+
+ struct sBufferChain sAcseBuffer;
+ BufferChain acseBuffer = &sAcseBuffer;
+
+ acseBuffer->buffer = self->sendBuffer + payload->size;
+ acseBuffer->partMaxLength = ISO_CLIENT_BUFFER_SIZE - acsePayload->length;
+
+ AcseConnection_createAssociateRequestMessage(&(self->acseConnection), params, acseBuffer, acsePayload,
+ authParameter);
+
+ struct sBufferChain sPresentationBuffer;
+ BufferChain presentationBuffer = &sPresentationBuffer;
+
+ presentationBuffer->buffer = self->sendBuffer + acseBuffer->length;
+ presentationBuffer->partMaxLength = ISO_CLIENT_BUFFER_SIZE - acseBuffer->length;
+
+ IsoPresentation_init(self->presentation);
+ IsoPresentation_createConnectPdu(self->presentation, params, presentationBuffer, acseBuffer);
+
+ struct sBufferChain sSessionBuffer;
+ BufferChain sessionBuffer = &sSessionBuffer;
+ sessionBuffer->buffer = self->sendBuffer + presentationBuffer->length;
+
+ IsoSession_init(self->session);
+ IsoSession_createConnectSpdu(self->session, params, sessionBuffer,
+ presentationBuffer);
+
+ CotpConnection_sendDataMessage(self->cotpConnection, sessionBuffer);
+
+ Semaphore_post(self->transmitBufferMutex);
+
+ while ((packetState = CotpConnection_readToTpktBuffer(self->cotpConnection)) == TPKT_WAITING)
+ {
+ Thread_sleep(1);
+ }
+
+ cotpIndication = CotpConnection_parseIncomingMessage(self->cotpConnection);
+
+ if (cotpIndication != COTP_DATA_INDICATION)
+ goto returnError;
+
+ IsoSessionIndication sessionIndication;
+
+ sessionIndication =
+ IsoSession_parseMessage(self->session, CotpConnection_getPayload(self->cotpConnection));
+
+ if (sessionIndication != SESSION_CONNECT) {
+ if (DEBUG_ISO_CLIENT)
+ printf("IsoClientConnection_associate: no session connect indication\n");
+ goto returnError;
+ }
+
+ if (!IsoPresentation_parseAcceptMessage(self->presentation, IsoSession_getUserData(self->session))) {
+ if (DEBUG_ISO_CLIENT)
+ printf("IsoClientConnection_associate: no presentation ok indication\n");
+ goto returnError;
+ }
+
+ AcseIndication acseIndication;
+
+ acseIndication = AcseConnection_parseMessage(&(self->acseConnection), &self->presentation->nextPayload);
+
+ if (acseIndication != ACSE_ASSOCIATE) {
+ if (DEBUG_ISO_CLIENT)
+ printf("IsoClientConnection_associate: no ACSE_ASSOCIATE indication\n");
+ goto returnError;
+ }
+
+
+ ByteBuffer_wrap(self->receivePayloadBuffer, self->acseConnection.userDataBuffer,
+ self->acseConnection.userDataBufferSize, self->acseConnection.userDataBufferSize);
+
+ Semaphore_wait(self->receiveBufferMutex);
+
+ self->callback(ISO_IND_ASSOCIATION_SUCCESS, self->callbackParameter, self->receivePayloadBuffer);
+
+ /* wait for upper layer to release buffer */
+ Semaphore_wait(self->receiveBufferMutex);
+
+ self->state = STATE_ASSOCIATED;
+
+ if (self->thread == NULL) {
+ self->thread = Thread_create(connectionThreadFunction, self, false);
+ Thread_start(self->thread);
+ }
+
+ self->startHandlingThread = true;
+
+ while (self->handlingThreadRunning == false)
+ Thread_sleep(1);
+
+ return;
+
+returnError:
+ self->callback(ISO_IND_ASSOCIATION_FAILED, self->callbackParameter, NULL);
+
+ self->state = STATE_ERROR;
+
+ Socket_destroy(self->socket);
+ self->socket = NULL;
+
+ Semaphore_post(self->transmitBufferMutex); //TODO check
+
+ return;
+}
+
+void
+IsoClientConnection_sendMessage(IsoClientConnection self, ByteBuffer* payloadBuffer)
+{
+
+ struct sBufferChain payloadBCMemory;
+ BufferChain payload = &payloadBCMemory;
+
+ BufferChain_init(payload, payloadBuffer->size, payloadBuffer->size, NULL, payloadBuffer->buffer);
+
+ struct sBufferChain presentationBCMemory;
+ BufferChain presentationBuffer = &presentationBCMemory;
+
+ presentationBuffer->buffer = self->sendBuffer + payload->length;
+ presentationBuffer->partMaxLength = ISO_CLIENT_BUFFER_SIZE;
+
+ IsoPresentation_createUserData(self->presentation, presentationBuffer, payload);
+
+ struct sBufferChain sessionBufferBCMemory;
+ BufferChain sessionBuffer = &sessionBufferBCMemory;
+
+ IsoSession_createDataSpdu(self->session, sessionBuffer, presentationBuffer);
+
+ CotpIndication indication = CotpConnection_sendDataMessage(self->cotpConnection, sessionBuffer);
+
+ /* release transmit buffer for use by API client */
+ Semaphore_post(self->transmitBufferMutex);
+
+ if (indication != COTP_OK)
+ if (DEBUG_ISO_CLIENT)
+ printf("ISO_CLIENT: IsoClientConnection_sendMessage: send message failed!\n");
+}
+
+void
+IsoClientConnection_close(IsoClientConnection self)
+{
+ if (DEBUG_ISO_CLIENT)
+ printf("ISO_CLIENT: IsoClientConnection_close\n");
+
+ if (self->handlingThreadRunning) {
+ self->stopHandlingThread = true;
+ while (self->handlingThreadRunning)
+ Thread_sleep(1);
+ }
+
+ self->state = STATE_IDLE;
+}
+
+
+void
+IsoClientConnection_destroy(IsoClientConnection self)
+{
+ if (DEBUG_ISO_CLIENT)
+ printf("ISO_CLIENT: IsoClientConnection_destroy\n");
+
+ if (self->state == STATE_ASSOCIATED) {
+
+ if (DEBUG_ISO_CLIENT)
+ printf("ISO_CLIENT: call IsoClientConnection_close\n");
+
+ IsoClientConnection_close(self);
+ }
+
+ /* stop handling thread */
+ self->destroyHandlingThread = true;
+
+ if (self->thread != NULL) {
+ while (self->destroyHandlingThread)
+ Thread_sleep(1);
+
+ Thread_destroy(self->thread);
+ }
+
+ if (self->receiveBuf != NULL)
+ GLOBAL_FREEMEM(self->receiveBuf);
+ if (self->receiveBuffer != NULL)
+ GLOBAL_FREEMEM(self->receiveBuffer);
+ if (self->cotpConnection != NULL)
+ GLOBAL_FREEMEM(self->cotpConnection);
+
+ if (self->cotpReadBuffer != NULL)
+ GLOBAL_FREEMEM(self->cotpReadBuffer);
+
+ if (self->cotpReadBuf != NULL)
+ GLOBAL_FREEMEM(self->cotpReadBuf);
+
+ if (self->cotpWriteBuffer != NULL)
+ GLOBAL_FREEMEM(self->cotpWriteBuffer);
+
+ if (self->cotpWriteBuf != NULL)
+ GLOBAL_FREEMEM(self->cotpWriteBuf);
+
+ if (self->session != NULL)
+ GLOBAL_FREEMEM(self->session);
+ if (self->presentation != NULL)
+ GLOBAL_FREEMEM(self->presentation);
+
+ GLOBAL_FREEMEM(self->transmitPayloadBuffer);
+ GLOBAL_FREEMEM(self->receivePayloadBuffer);
+
+ Semaphore_destroy(self->receiveBufferMutex);
+ Semaphore_destroy(self->transmitBufferMutex);
+
+ GLOBAL_FREEMEM(self->sendBuffer);
+ GLOBAL_FREEMEM(self);
+}
+
+void
+IsoClientConnection_abort(IsoClientConnection self)
+{
+ //TODO block other messages from being sent
+ IsoClientConnection_allocateTransmitBuffer(self);
+
+ struct sBufferChain sAcseBuffer;
+ BufferChain acseBuffer = &sAcseBuffer;
+ acseBuffer->partMaxLength = ISO_CLIENT_BUFFER_SIZE;
+ acseBuffer->buffer = self->sendBuffer;
+ acseBuffer->nextPart = NULL;
+
+ AcseConnection_createAbortMessage(NULL, acseBuffer, false);
+
+ struct sBufferChain sPresentationBuffer;
+ BufferChain presentationBuffer = &sPresentationBuffer;
+ presentationBuffer->partMaxLength = ISO_CLIENT_BUFFER_SIZE - acseBuffer->length;
+ presentationBuffer->buffer = self->sendBuffer + acseBuffer->length;
+ presentationBuffer->nextPart = acseBuffer;
+
+ IsoPresentation_createAbortUserMessage(self->presentation, presentationBuffer, acseBuffer);
+
+ struct sBufferChain sSessionBuffer;
+ BufferChain sessionBuffer = &sSessionBuffer;
+ sessionBuffer->partMaxLength = ISO_CLIENT_BUFFER_SIZE - presentationBuffer->length;
+ sessionBuffer->buffer = self->sendBuffer + presentationBuffer->length;
+ sessionBuffer->nextPart = presentationBuffer;
+
+ IsoSession_createAbortSpdu(self->session, sessionBuffer, presentationBuffer);
+
+ CotpConnection_sendDataMessage(self->cotpConnection, sessionBuffer);
+
+ Semaphore_post(self->transmitBufferMutex);
+
+ uint64_t timeout = Hal_getTimeInMs() + CONFIG_TCP_READ_TIMEOUT_MS;
+
+ while ((self->handlingThreadRunning == true) && (Hal_getTimeInMs() < timeout));
+}
+
+void
+IsoClientConnection_release(IsoClientConnection self)
+{
+ //TODO block other messages from being sent
+ IsoClientConnection_allocateTransmitBuffer(self);
+
+ struct sBufferChain sAcseBuffer;
+ BufferChain acseBuffer = &sAcseBuffer;
+ acseBuffer->partMaxLength = ISO_CLIENT_BUFFER_SIZE;
+ acseBuffer->buffer = self->sendBuffer;
+ acseBuffer->nextPart = NULL;
+
+ AcseConnection_createReleaseRequestMessage(NULL, acseBuffer);
+
+ struct sBufferChain sPresentationBuffer;
+ BufferChain presentationBuffer = &sPresentationBuffer;
+ presentationBuffer->partMaxLength = ISO_CLIENT_BUFFER_SIZE - acseBuffer->length;
+ presentationBuffer->buffer = self->sendBuffer + acseBuffer->length;
+ presentationBuffer->nextPart = acseBuffer;
+
+ IsoPresentation_createUserDataACSE(self->presentation, presentationBuffer, acseBuffer);
+
+ struct sBufferChain sSessionBuffer;
+ BufferChain sessionBuffer = &sSessionBuffer;
+ sessionBuffer->partMaxLength = ISO_CLIENT_BUFFER_SIZE - presentationBuffer->length;
+ sessionBuffer->buffer = self->sendBuffer + presentationBuffer->length;
+ sessionBuffer->nextPart = presentationBuffer;
+
+ IsoSession_createFinishSpdu(NULL, sessionBuffer, presentationBuffer);
+
+ CotpConnection_sendDataMessage(self->cotpConnection, sessionBuffer);
+
+ Semaphore_post(self->transmitBufferMutex);
+}
+
+
+ByteBuffer*
+IsoClientConnection_allocateTransmitBuffer(IsoClientConnection self)
+{
+ Semaphore_wait(self->transmitBufferMutex);
+ self->transmitPayloadBuffer->size = 0;
+ self->transmitPayloadBuffer->maxSize = ISO_CLIENT_BUFFER_SIZE;
+ return self->transmitPayloadBuffer;
+}
+
+void
+IsoClientConnection_releaseReceiveBuffer(IsoClientConnection self)
+{
+ Semaphore_post(self->receiveBufferMutex);
+}
diff --git a/src/mms/iso_common/iso_connection_parameters.c b/src/mms/iso_common/iso_connection_parameters.c
index 2e71477a..8f4b2d2e 100644
--- a/src/mms/iso_common/iso_connection_parameters.c
+++ b/src/mms/iso_common/iso_connection_parameters.c
@@ -35,7 +35,7 @@ AcseAuthenticationParameter
AcseAuthenticationParameter_create()
{
AcseAuthenticationParameter self = (AcseAuthenticationParameter)
- calloc(1, sizeof(struct sAcseAuthenticationParameter));
+ GLOBAL_CALLOC(1, sizeof(struct sAcseAuthenticationParameter));
return self;
}
@@ -45,9 +45,9 @@ AcseAuthenticationParameter_destroy(AcseAuthenticationParameter self)
{
if (self->mechanism == ACSE_AUTH_PASSWORD)
if (self->value.password.octetString != NULL)
- free(self->value.password.octetString);
+ GLOBAL_FREEMEM(self->value.password.octetString);
- free(self);
+ GLOBAL_FREEMEM(self);
}
void
@@ -67,7 +67,7 @@ AcseAuthenticationParameter_setAuthMechanism(AcseAuthenticationParameter self, A
IsoConnectionParameters
IsoConnectionParameters_create()
{
- IsoConnectionParameters self = (IsoConnectionParameters) calloc(1, sizeof(struct sIsoConnectionParameters));
+ IsoConnectionParameters self = (IsoConnectionParameters) GLOBAL_CALLOC(1, sizeof(struct sIsoConnectionParameters));
return self;
}
@@ -75,7 +75,7 @@ IsoConnectionParameters_create()
void
IsoConnectionParameters_destroy(IsoConnectionParameters self)
{
- free(self);
+ GLOBAL_FREEMEM(self);
}
void
@@ -86,14 +86,14 @@ IsoConnectionParameters_setAcseAuthenticationParameter(IsoConnectionParameters s
}
void
-IsoConnectionParameters_setTcpParameters(IsoConnectionParameters self, char* hostname, int tcpPort)
+IsoConnectionParameters_setTcpParameters(IsoConnectionParameters self, const char* hostname, int tcpPort)
{
self->hostname = hostname;
self->tcpPort = tcpPort;
}
void
-IsoConnectionParameters_setRemoteApTitle(IsoConnectionParameters self, char* apTitle, int aeQualifier)
+IsoConnectionParameters_setRemoteApTitle(IsoConnectionParameters self, const char* apTitle, int aeQualifier)
{
if (apTitle == NULL)
self->remoteApTitleLen = 0;
@@ -104,7 +104,7 @@ IsoConnectionParameters_setRemoteApTitle(IsoConnectionParameters self, char* apT
}
void
-IsoConnectionParameters_setRemoteAddresses(IsoConnectionParameters self, uint32_t pSelector, uint16_t sSelector, uint16_t tSelector)
+IsoConnectionParameters_setRemoteAddresses(IsoConnectionParameters self, uint32_t pSelector, uint16_t sSelector, TSelector tSelector)
{
self->remotePSelector = pSelector;
self->remoteSSelector = sSelector;
@@ -124,7 +124,7 @@ IsoConnectionParameters_setLocalApTitle(IsoConnectionParameters self, char* apTi
}
void
-IsoConnectionParameters_setLocalAddresses(IsoConnectionParameters self, uint32_t pSelector, uint16_t sSelector, uint16_t tSelector)
+IsoConnectionParameters_setLocalAddresses(IsoConnectionParameters self, uint32_t pSelector, uint16_t sSelector, TSelector tSelector)
{
self->localPSelector = pSelector;
self->localSSelector = sSelector;
diff --git a/src/mms/iso_cotp/cotp.c b/src/mms/iso_cotp/cotp.c
index 80e80a59..83089f01 100644
--- a/src/mms/iso_cotp/cotp.c
+++ b/src/mms/iso_cotp/cotp.c
@@ -3,10 +3,9 @@
*
* ISO 8073 Connection Oriented Transport Protocol over TCP (RFC1006)
*
- * Partial implementation of the ISO 8073 COTP protocol for MMS.
+ * Partial implementation of the ISO 8073 COTP (ISO TP0) protocol for MMS.
*
- *
- * Copyright 2013 Michael Zillgith
+ * Copyright 2013, 2014 Michael Zillgith
*
* This file is part of libIEC61850.
*
@@ -28,11 +27,10 @@
#include "stack_config.h"
#include "cotp.h"
-#include "byte_stream.h"
#include "byte_buffer.h"
#include "buffer_chain.h"
-#define COTP_RFC1006_HEADER_SIZE 4
+#define TPKT_RFC1006_HEADER_SIZE 4
#define COTP_DATA_HEADER_SIZE 3
@@ -46,8 +44,20 @@
#define DEBUG_COTP 0
#endif
-static int
-addPayloadToBuffer(CotpConnection* self, int rfc1006Length);
+static bool
+addPayloadToBuffer(CotpConnection* self, uint8_t* buffer, int payloadLength);
+
+static inline uint16_t
+getUint16(uint8_t* buffer)
+{
+ return (buffer[0] * 0x100) + buffer[1];
+}
+
+static inline uint8_t
+getUint8(uint8_t* buffer)
+{
+ return buffer[0];
+}
static void
writeOptions(CotpConnection* self)
@@ -56,28 +66,32 @@ writeOptions(CotpConnection* self)
uint8_t* buffer = self->writeBuffer->buffer;
int bufPos = self->writeBuffer->size;
- if (self->options.tpdu_size != 0) {
+ if (self->options.tpduSize != 0) {
if (DEBUG_COTP)
printf("COTP: send TPDU size: %i\n", CotpConnection_getTpduSize(self));
buffer[bufPos++] = 0xc0;
buffer[bufPos++] = 0x01;
- buffer[bufPos++] = self->options.tpdu_size;
+ buffer[bufPos++] = self->options.tpduSize;
}
- if (self->options.tsap_id_dst != -1) {
+ if (self->options.tSelDst.size != 0) {
buffer[bufPos++] = 0xc2;
- buffer[bufPos++] = 0x02;
- buffer[bufPos++] = (uint8_t) (self->options.tsap_id_dst / 0x100);
- buffer[bufPos++] = (uint8_t) (self->options.tsap_id_dst & 0xff);
+ buffer[bufPos++] = (uint8_t) self->options.tSelDst.size;
+
+ int i;
+ for (i = 0; i < self->options.tSelDst.size; i++)
+ buffer[bufPos++] = (uint8_t) self->options.tSelDst.value[i];
}
- if (self->options.tsap_id_src != -1) {
+ if (self->options.tSelSrc.size != 0) {
buffer[bufPos++] = 0xc1;
- buffer[bufPos++] = 0x02;
- buffer[bufPos++] = (uint8_t) (self->options.tsap_id_src / 0x100);
- buffer[bufPos++] = (uint8_t) (self->options.tsap_id_src & 0xff);
+ buffer[bufPos++] = (uint8_t) self->options.tSelSrc.size;
+
+ int i;
+ for (i = 0; i < self->options.tSelSrc.size; i++)
+ buffer[bufPos++] = (uint8_t) self->options.tSelSrc.value[i];
}
self->writeBuffer->size = bufPos;
@@ -87,12 +101,16 @@ static int
getOptionsLength(CotpConnection* self)
{
int optionsLength = 0;
- if (self->options.tpdu_size != 0)
+
+ if (self->options.tpduSize != 0)
optionsLength += 3;
- if (self->options.tsap_id_dst != -1)
- optionsLength += 4;
- if (self->options.tsap_id_src != -1)
- optionsLength += 4;
+
+ if (self->options.tSelDst.size != 0)
+ optionsLength += (2 + self->options.tSelDst.size);
+
+ if (self->options.tSelSrc.size != 0)
+ optionsLength += (2 + self->options.tSelSrc.size);
+
return optionsLength;
}
@@ -225,12 +243,12 @@ CotpConnection_sendDataMessage(CotpConnection* self, BufferChain payload)
printf("COTP: Send COTP fragment %i bufpos: %i\n", fragments, currentBufPos);
if (!sendBuffer(self))
- return ERROR;
+ return COTP_ERROR;
fragments--;
}
- return OK;
+ return COTP_OK;
}
static void
@@ -238,7 +256,7 @@ allocateWriteBuffer(CotpConnection* self)
{
if (self->writeBuffer == NULL )
self->writeBuffer = ByteBuffer_create(NULL,
- CotpConnection_getTpduSize(self) + COTP_RFC1006_HEADER_SIZE);
+ CotpConnection_getTpduSize(self) + TPKT_RFC1006_HEADER_SIZE);
}
/* client side */
@@ -247,17 +265,22 @@ CotpConnection_sendConnectionRequestMessage(CotpConnection* self, IsoConnectionP
{
allocateWriteBuffer(self);
- const int CON_REQUEST_SIZE = 22;
+ self->options.tSelDst = isoParameters->remoteTSelector;
+ self->options.tSelSrc = isoParameters->localTSelector;
- if(self->writeBuffer->maxSize < CON_REQUEST_SIZE)
- return ERROR;
+ int cotpRequestSize = getOptionsLength(self) + 6;
+
+ int conRequestSize = cotpRequestSize + 5;
+
+ if(self->writeBuffer->maxSize < conRequestSize)
+ return COTP_ERROR;
uint8_t* buffer = self->writeBuffer->buffer;
- writeRfc1006Header(self, CON_REQUEST_SIZE);
+ writeRfc1006Header(self, conRequestSize);
/* LI */
- buffer[4] = 17;
+ buffer[4] = (uint8_t) cotpRequestSize;
/* TPDU CODE */
buffer[5] = 0xe0;
@@ -275,15 +298,12 @@ CotpConnection_sendConnectionRequestMessage(CotpConnection* self, IsoConnectionP
self->writeBuffer->size = 11;
- self->options.tsap_id_dst = isoParameters->remoteTSelector;
- self->options.tsap_id_src = 0;
-
writeOptions(self);
if (sendBuffer(self))
- return OK;
+ return COTP_OK;
else
- return ERROR;
+ return COTP_ERROR;
}
CotpIndication
@@ -301,127 +321,134 @@ CotpConnection_sendConnectionResponseMessage(CotpConnection* self)
writeOptions(self);
if (sendBuffer(self))
- return OK;
+ return COTP_OK;
else
- return ERROR;
+ return COTP_ERROR;
}
-static int
-parseOptions(CotpConnection* self, int opt_len)
+static bool
+parseOptions(CotpConnection* self, uint8_t* buffer, int bufLen)
{
- int read_bytes = 0;
- uint8_t option_type, option_len, uint8_value;
- uint16_t uint16_value;
- int i;
- Socket sock = self->socket;
-
- while (read_bytes < opt_len) {
- if (ByteStream_readUint8(sock, &option_type) == -1)
- goto cpo_error;
- if (ByteStream_readUint8(sock, &option_len) == -1)
- goto cpo_error;
+ int bufPos = 0;
+
+ while (bufPos < bufLen) {
+ uint8_t optionType = buffer[bufPos++];
+ uint8_t optionLen = buffer[bufPos++];
- read_bytes += 2;
+ if (optionLen > (bufLen - bufPos)) {
+ if (DEBUG_COTP)
+ printf("COTP: option to long optionLen:%i bufPos:%i bufLen:%i\n", optionLen, bufPos, bufLen);
+ goto cpo_error;
+ }
if (DEBUG_COTP)
- printf("COTP: option: %02x len: %02x\n", option_type, option_len);
+ printf("COTP: option: %02x len: %02x\n", optionType, optionLen);
- switch (option_type) {
+ switch (optionType) {
case 0xc0:
- {
- if (ByteStream_readUint8(sock, &uint8_value) == -1)
- goto cpo_error;
- read_bytes++;
+ if (optionLen == 1) {
+ int requestedTpduSize = (1 << buffer[bufPos++]);
- int requestedTpduSize = (1 << uint8_value);
+ CotpConnection_setTpduSize(self, requestedTpduSize);
if (DEBUG_COTP)
printf("COTP: requested TPDU size: %i\n", requestedTpduSize);
-
- CotpConnection_setTpduSize(self, requestedTpduSize);
}
+ else
+ goto cpo_error;
break;
- case 0xc1:
- if (option_len == 2) {
- if (ByteStream_readUint16(sock, &uint16_value) == -1)
- goto cpo_error;
- read_bytes += 2;
- self->options.tsap_id_src = (int32_t) uint16_value;
- } else
+
+ case 0xc1: /* remote T-selector */
+ if (optionLen < 5) {
+ self->options.tSelSrc.size = optionLen;
+
+ int i;
+ for (i = 0; i < optionLen; i++)
+ self->options.tSelSrc.value[i] = buffer[bufPos++];
+ }
+ else
goto cpo_error;
break;
- case 0xc2:
- if (option_len == 2) {
- if (ByteStream_readUint16(sock, &uint16_value) == -1)
- goto cpo_error;
- self->options.tsap_id_dst = (int32_t) uint16_value;
- read_bytes += 2;
- } else
+
+ case 0xc2: /* local T-selector */
+ if (optionLen < 5) {
+ self->options.tSelDst.size = optionLen;
+
+ int i;
+ for (i = 0; i < optionLen; i++)
+ self->options.tSelDst.value[i] = buffer[bufPos++];
+ }
+ else
goto cpo_error;
break;
+
case 0xc6: /* additional option selection */
- if (option_len == 1) {
- ByteStream_readUint8(sock, &uint8_value); /* ignore value */
- read_bytes++;
- }
+ if (optionLen == 1)
+ bufPos++; /* ignore value */
else
goto cpo_error;
break;
- default:
+ default:
if (DEBUG_COTP)
- printf("COTP: Unknown option %02x\n", option_type);
+ printf("COTP: Unknown option %02x\n", optionType);
- for (i = 0; i < opt_len; i++) {
- if (ByteStream_readUint8(sock, &uint8_value) == -1)
- goto cpo_error;
- }
-
- read_bytes += opt_len;
+ bufPos += optionLen; /* ignore value */
break;
}
}
- return 1;
+ return true;
- cpo_error:
+cpo_error:
if (DEBUG_COTP)
printf("COTP: cotp_parse_options: error parsing options!\n");
- return -1;
+ return false;
}
void
CotpConnection_init(CotpConnection* self, Socket socket,
- ByteBuffer* payloadBuffer)
+ ByteBuffer* payloadBuffer, ByteBuffer* readBuffer, ByteBuffer* writeBuffer)
{
self->state = 0;
self->socket = socket;
self->srcRef = -1;
self->dstRef = -1;
self->protocolClass = -1;
- self->options.tpdu_size = 0;
- self->options.tsap_id_src = -1;
- self->options.tsap_id_dst = -1;
+ self->options.tpduSize = 0;
+
+ TSelector tsel;
+ tsel.size = 2;
+ tsel.value[0] = 0;
+ tsel.value[1] = 1;
+
+ self->options.tSelSrc = tsel;
+ self->options.tSelDst = tsel;
self->payload = payloadBuffer;
/* default TPDU size is maximum size */
CotpConnection_setTpduSize(self, COTP_MAX_TPDU_SIZE);
- self->writeBuffer = NULL;
+ self->writeBuffer = writeBuffer;
+ self->readBuffer = readBuffer;
+ self->packetSize = 0;
}
-void
-CotpConnection_destroy(CotpConnection* self)
-{
- if (self->writeBuffer != NULL)
- ByteBuffer_destroy(self->writeBuffer);
-}
+//void
+//CotpConnection_destroy(CotpConnection* self)
+//{
+// if (self->writeBuffer != NULL)
+// ByteBuffer_destroy(self->writeBuffer);
+//
+// if (self->readBuffer != NULL)
+// ByteBuffer_destroy(self->readBuffer);
+//}
int /* in byte */
CotpConnection_getTpduSize(CotpConnection* self)
{
- return (1 << self->options.tpdu_size);
+ return (1 << self->options.tpduSize);
}
void
@@ -438,7 +465,7 @@ CotpConnection_setTpduSize(CotpConnection* self, int tpduSize /* in byte */)
if ((1 << newTpduSize) > tpduSize)
newTpduSize--;
- self->options.tpdu_size = newTpduSize;
+ self->options.tpduSize = newTpduSize;
}
ByteBuffer*
@@ -469,183 +496,202 @@ CotpConnection_getDstRef(CotpConnection* self)
+--+------+---------+---------+---+---+------+-------+---------+
*/
-static int
-parseConnectRequestTpdu(CotpConnection* self, uint8_t len)
+
+static bool
+parseConnectRequestTpdu(CotpConnection* self, uint8_t* buffer, uint8_t len)
{
- uint16_t dstRef;
- uint16_t srcRef;
- uint8_t protocolClass;
- Socket sock = self->socket;
+ if (len < 6)
+ return false;
- if (ByteStream_readUint16(sock, &dstRef) != 2)
- return -1;
- else
- self->dstRef = dstRef;
+ self->dstRef = getUint16(buffer);
+ self->srcRef = getUint16(buffer + 2);
+ self->protocolClass = getUint8(buffer + 4);
- if (ByteStream_readUint16(sock, &srcRef) != 2)
- return -1;
- else
- self->srcRef = srcRef;
+ return parseOptions(self, buffer + 5, len - 6);
+}
- if (ByteStream_readUint8(sock, &protocolClass) != 1)
- return -1;
- else
- self->protocolClass = protocolClass;
+static bool
+parseConnectConfirmTpdu(CotpConnection* self, uint8_t* buffer, uint8_t len)
+{
+ if (len < 6)
+ return false;
+
+ self->srcRef = getUint16(buffer);
+ self->dstRef = getUint16(buffer + 2);
+ self->protocolClass = getUint8(buffer + 4);
- return parseOptions(self, len - 6);
+ return parseOptions(self, buffer + 5, len - 6);
}
-static int
-parseConnectConfirmTpdu(CotpConnection* self, uint8_t len)
+static bool
+parseDataTpdu(CotpConnection* self, uint8_t* buffer, uint8_t len)
{
- uint16_t dstRef;
- uint16_t srcRef;
- uint8_t protocolClass;
- Socket sock = self->socket;
-
- if (ByteStream_readUint16(sock, &dstRef) != 2)
- return -1;
- else
- self->srcRef = dstRef;
+ if (len != 2)
+ return false;
- if (ByteStream_readUint16(sock, &srcRef) != 2)
- return -1;
- else
- self->dstRef = srcRef;
+ uint8_t flowControl = getUint8(buffer);
- if (ByteStream_readUint8(sock, &protocolClass) != 1)
- return -1;
+ if (flowControl & 0x80)
+ self->isLastDataUnit = true;
else
- self->protocolClass = protocolClass;
+ self->isLastDataUnit = false;
- return parseOptions(self, len - 6);
+ return true;
}
-static int
-parseDataTpdu(CotpConnection* self, uint8_t len)
+static bool
+addPayloadToBuffer(CotpConnection* self, uint8_t* buffer, int payloadLength)
{
- uint8_t flowControl;
+ if (DEBUG_COTP)
+ printf("COTP: add to payload buffer (cur size: %i, len: %i)\n", self->payload->size, payloadLength);
- if (len != 2)
- return -1;
+ if ((self->payload->size + payloadLength) > self->payload->maxSize)
+ return false;
- if (ByteStream_readUint8(self->socket, &flowControl) != 1)
- return -1;
- else {
- if (flowControl & 0x80)
- self->isLastDataUnit = true;
- else
- self->isLastDataUnit = false;
- }
+ memcpy(self->payload->buffer + self->payload->size, buffer, payloadLength);
- return 1;
+ self->payload->size += payloadLength;
+
+ return true;
}
static CotpIndication
-parseRFC1006Header(CotpConnection* self, uint16_t* rfc1006_length)
+parseCotpMessage(CotpConnection* self)
{
- Socket sock = self->socket;
- uint8_t b;
+ uint8_t* buffer = self->readBuffer->buffer + 4;
+ int tpduLength = self->readBuffer->size - 4;
+
+ uint8_t len;
+ uint8_t tpduType;
- if (ByteStream_readUint8(sock, &b) == -1)
- return ERROR;
- if (b != 3)
- return ERROR;
+ len = buffer[0];
+ assert(len <= tpduLength);
- if (ByteStream_readUint8(sock, &b) == -1)
- return ERROR;
- if (b != 0)
- return ERROR;
+ tpduType = buffer[1];
- if (ByteStream_readUint16(sock, rfc1006_length) == -1)
- return ERROR;
+ switch (tpduType) {
+ case 0xe0:
+ if (parseConnectRequestTpdu(self, buffer + 2, len))
+ return COTP_CONNECT_INDICATION;
+ else
+ return COTP_ERROR;
+ case 0xd0:
+ if (parseConnectConfirmTpdu(self, buffer + 2, len))
+ return COTP_CONNECT_INDICATION;
+ else
+ return COTP_ERROR;
+ case 0xf0:
+ if (parseDataTpdu(self, buffer + 2, len)) {
+
+ if (addPayloadToBuffer(self, buffer + 3, tpduLength - 3) != 1)
+ return COTP_ERROR;
+
+ if (self->isLastDataUnit)
+ return COTP_DATA_INDICATION;
+ else
+ return COTP_MORE_FRAGMENTS_FOLLOW;
+ }
+ else
+ return COTP_ERROR;
+ default:
+ return COTP_ERROR;
+ }
- return OK;
}
+CotpIndication
+CotpConnection_parseIncomingMessage(CotpConnection* self)
+{
+ CotpIndication indication = parseCotpMessage(self);
-static CotpIndication parseIncomingMessage(CotpConnection* self);
+ self->readBuffer->size = 0;
+ self->packetSize = 0;
-static int
-addPayloadToBuffer(CotpConnection* self, int rfc1006Length)
+ return indication;
+}
+
+void
+CotpConnection_resetPayload(CotpConnection* self)
+{
+ self->payload->size = 0;
+}
+
+TpktState
+CotpConnection_readToTpktBuffer(CotpConnection* self)
{
- int payloadLength = rfc1006Length - 7;
+ uint8_t* buffer = self->readBuffer->buffer;
+ int bufferSize = self->readBuffer->maxSize;
+ int bufPos = self->readBuffer->size;
- if ((self->payload->size + payloadLength) > self->payload->maxSize)
- return 0;
+ assert (bufferSize > 4);
- int readLength = ByteStream_readOctets(self->socket,
- self->payload->buffer + self->payload->size,
- payloadLength);
+ int readBytes;
- if (readLength != payloadLength) {
- if (DEBUG_COTP)
- printf("COTP: read %i bytes should have been %i\n", readLength, payloadLength);
- return 0;
- }
- else {
- self->payload->size += payloadLength;
+ if (bufPos < 4) {
- if (self->isLastDataUnit == false) {
- if (parseIncomingMessage(self) == DATA_INDICATION)
- return 1;
- else
- return 0;
+ readBytes = Socket_read(self->socket, buffer + bufPos, 4 - bufPos);
+
+ if (readBytes < 0)
+ goto exit_closed;
+
+ if (DEBUG_COTP) {
+ if (readBytes > 0)
+ printf("TPKT: read %i bytes from socket\n", readBytes);
}
- else
- return 1;
- }
-}
-static CotpIndication
-parseIncomingMessage(CotpConnection* self)
-{
- uint8_t len;
- uint8_t tpduType;
- uint16_t rfc1006Length;
- Socket sock = self->socket;
+ bufPos += readBytes;
- if (parseRFC1006Header(self, &rfc1006Length) == ERROR)
- return ERROR;
+ if (bufPos == 4) {
+ if ((buffer[0] == 3) && (buffer[1] == 0)) {
+ self->packetSize = (buffer[2] * 0x100) + buffer[3];
- if (ByteStream_readUint8(sock, &len) != 1) {
- return ERROR;
- }
+ if (DEBUG_COTP)
+ printf("TPKT: header complete (msg size = %i)\n", self->packetSize);
- if (ByteStream_readUint8(sock, &tpduType) == 1) {
- switch (tpduType) {
- case 0xe0:
- if (parseConnectRequestTpdu(self, len) == 1)
- return CONNECT_INDICATION;
- else
- return ERROR;
- case 0xd0:
- self->isLastDataUnit = true;
- if (parseConnectConfirmTpdu(self, len) == 1)
- return CONNECT_INDICATION;
- else
- return ERROR;
- case 0xf0:
- if (parseDataTpdu(self, len) == 1) {
- if (addPayloadToBuffer(self, rfc1006Length) == 1)
- return DATA_INDICATION;
- else
- return ERROR;
+ if (self->packetSize > bufferSize) {
+ if (DEBUG_COTP) printf("TPKT: packet too large\n");
+ goto exit_error;
+ }
+ }
+ else {
+ if (DEBUG_COTP) printf("TPKT: failed to decode TPKT header.\n");
+ goto exit_error;
}
- else
- return ERROR;
- default:
- return ERROR;
}
+ else
+ goto exit_waiting;
}
- else
- return ERROR;
-}
-CotpIndication
-CotpConnection_parseIncomingMessage(CotpConnection* self)
-{
- self->payload->size = 0;
+ readBytes = Socket_read(self->socket, buffer + bufPos, self->packetSize - bufPos);
+
+ if (readBytes < 0)
+ goto exit_closed;
+
+ bufPos += readBytes;
+
+ if (bufPos < self->packetSize)
+ goto exit_waiting;
- return parseIncomingMessage(self);
+ if (DEBUG_COTP) printf("TPKT: message complete (size = %i)\n", self->packetSize);
+
+ self->readBuffer->size = bufPos;
+ return TPKT_PACKET_COMPLETE;
+
+exit_closed:
+ if (DEBUG_COTP) printf("TPKT: socket closed or socket error\n");
+ return TPKT_ERROR;
+
+exit_error:
+ if (DEBUG_COTP) printf("TPKT: Error parsing message\n");
+ return TPKT_ERROR;
+
+exit_waiting:
+
+ if (DEBUG_COTP)
+ if (bufPos != 0)
+ printf("TPKT: waiting (read %i of %i)\n", bufPos, self->packetSize);
+
+ self->readBuffer->size = bufPos;
+ return TPKT_WAITING;
}
+
diff --git a/src/mms/iso_mms/asn1c/GeneralizedTime.c b/src/mms/iso_mms/asn1c/GeneralizedTime.c
index 80341811..cf974496 100644
--- a/src/mms/iso_mms/asn1c/GeneralizedTime.c
+++ b/src/mms/iso_mms/asn1c/GeneralizedTime.c
@@ -14,6 +14,23 @@
#include
#endif /* __CYGWIN__ */
+#ifdef __IAR_SYSTEMS_ICC__
+
+static struct tm *localtime_r(const time_t *tloc, struct tm *result) {
+ struct tm *tm;
+ if((tm = localtime(tloc)))
+ return memcpy(result, tm, sizeof(struct tm));
+ return 0;
+}
+
+static struct tm *gmtime_r(const time_t *tloc, struct tm *result) {
+ struct tm *tm;
+ if((tm = gmtime(tloc)))
+ return memcpy(result, tm, sizeof(struct tm));
+ return 0;
+}
+#endif /* __IAR_SYSTEMS_ICC__ */
+
#if defined(WIN32)
#pragma message( "PLEASE STOP AND READ!")
#pragma message( " localtime_r is implemented via localtime(), which may be not thread-safe.")
diff --git a/src/mms/iso_mms/asn1c/INTEGER.c b/src/mms/iso_mms/asn1c/INTEGER.c
index 53a64285..c1d074f5 100644
--- a/src/mms/iso_mms/asn1c/INTEGER.c
+++ b/src/mms/iso_mms/asn1c/INTEGER.c
@@ -6,7 +6,7 @@
#include
#include
#include /* Encoder and decoder of a primitive type */
-#include
+//#include
/*
* INTEGER basic type description.
@@ -95,8 +95,6 @@ INTEGER_encode_der(asn_TYPE_descriptor_t *td, void *sptr,
return der_encode_primitive(td, sptr, tag_mode, tag, cb, app_key);
}
-static const asn_INTEGER_enum_map_t *INTEGER_map_enum2value(asn_INTEGER_specifics_t *specs, const char *lstart, const char *lstop);
-
#if 0
/*
* INTEGER specific human-readable output.
@@ -220,6 +218,7 @@ INTEGER_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel,
}
#endif
+#if 0
struct e2v_key {
const char *start;
const char *stop;
@@ -245,6 +244,7 @@ INTEGER__compar_enum2value(const void *kp, const void *am) {
return name[0] ? -1 : 0;
}
+
static const asn_INTEGER_enum_map_t *
INTEGER_map_enum2value(asn_INTEGER_specifics_t *specs, const char *lstart, const char *lstop) {
asn_INTEGER_enum_map_t *el_found;
@@ -282,7 +282,9 @@ INTEGER_map_enum2value(asn_INTEGER_specifics_t *specs, const char *lstart, const
}
return el_found;
}
+#endif
+#if 0
static int
INTEGER__compar_value2enum(const void *kp, const void *am) {
long a = *(const long *)kp;
@@ -301,7 +303,9 @@ INTEGER_map_value2enum(asn_INTEGER_specifics_t *specs, long value) {
count, sizeof(specs->value2enum[0]),
INTEGER__compar_value2enum);
}
+#endif
+#if 0
static int
INTEGER_st_prealloc(INTEGER_t *st, int min_size) {
void *p = MALLOC(min_size + 1);
@@ -315,6 +319,7 @@ INTEGER_st_prealloc(INTEGER_t *st, int min_size) {
return -1;
}
}
+#endif
#if 0
/*
@@ -737,7 +742,7 @@ asn_INTEGER2long(const INTEGER_t *iptr, long *lptr) {
/* Sanity checking */
if(!iptr || !iptr->buf || !lptr) {
- errno = EINVAL;
+ //errno = EINVAL;
return -1;
}
@@ -766,7 +771,7 @@ asn_INTEGER2long(const INTEGER_t *iptr, long *lptr) {
size = end - b;
if(size > sizeof(long)) {
/* Still cannot fit the long */
- errno = ERANGE;
+ //errno = ERANGE;
return -1;
}
}
@@ -799,7 +804,7 @@ asn_long2INTEGER(INTEGER_t *st, long value) {
int add;
if(!st) {
- errno = EINVAL;
+ //errno = EINVAL;
return -1;
}
diff --git a/src/mms/iso_mms/asn1c/NativeEnumerated.c b/src/mms/iso_mms/asn1c/NativeEnumerated.c
index 76269a35..76aab81b 100644
--- a/src/mms/iso_mms/asn1c/NativeEnumerated.c
+++ b/src/mms/iso_mms/asn1c/NativeEnumerated.c
@@ -27,7 +27,8 @@ asn_TYPE_descriptor_t asn_DEF_NativeEnumerated = {
NativeInteger_decode_ber,
NativeInteger_encode_der,
NULL,
- NativeEnumerated_encode_xer,
+ NULL,
+ //NativeEnumerated_encode_xer,
NativeEnumerated_decode_uper,
NativeEnumerated_encode_uper,
0, /* Use generic outmost tag fetcher */
@@ -40,6 +41,7 @@ asn_TYPE_descriptor_t asn_DEF_NativeEnumerated = {
0 /* No specifics */
};
+#if 0
asn_enc_rval_t
NativeEnumerated_encode_xer(asn_TYPE_descriptor_t *td, void *sptr,
int ilevel, enum xer_encoder_flags_e flags,
@@ -69,6 +71,7 @@ NativeEnumerated_encode_xer(asn_TYPE_descriptor_t *td, void *sptr,
_ASN_ENCODE_FAILED;
}
}
+#endif
asn_dec_rval_t
NativeEnumerated_decode_uper(asn_codec_ctx_t *opt_codec_ctx,
diff --git a/src/mms/iso_mms/asn1c/asn_internal.h b/src/mms/iso_mms/asn1c/asn_internal.h
index fc5ee818..2ba232bc 100644
--- a/src/mms/iso_mms/asn1c/asn_internal.h
+++ b/src/mms/iso_mms/asn1c/asn_internal.h
@@ -11,6 +11,9 @@
#include "asn_application.h" /* Application-visible API */
+//#include "libiec61850_platform_includes.h"
+#include "lib_memory.h"
+
#ifndef __NO_ASSERT_H__ /* Include assert.h only for internal use. */
#include /* for assert() macro */
#endif
@@ -23,10 +26,23 @@ extern "C" {
#define ASN1C_ENVIRONMENT_VERSION 920 /* Compile-time version */
int get_asn1c_environment_version(void); /* Run-time version */
+#if 0
+#ifndef CALLOC
#define CALLOC(nmemb, size) calloc(nmemb, size)
+#endif
+
+#ifndef MALLOC
#define MALLOC(size) malloc(size)
+#endif
+
+#ifndef REALLOC
#define REALLOC(oldptr, size) realloc(oldptr, size)
+#endif
+
+#ifndef FREEMEM
#define FREEMEM(ptr) free(ptr)
+#endif
+#endif
/*
* A macro for debugging the ASN.1 internals.
diff --git a/src/mms/iso_mms/asn1c/asn_system.h b/src/mms/iso_mms/asn1c/asn_system.h
index 61c41512..0fdb37fa 100644
--- a/src/mms/iso_mms/asn1c/asn_system.h
+++ b/src/mms/iso_mms/asn1c/asn_system.h
@@ -1,110 +1,119 @@
-/*-
- * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved.
- * Redistribution and modifications are permitted subject to BSD license.
- */
-/*
- * Miscellaneous system-dependent types.
- */
-#ifndef _ASN_SYSTEM_H_
-#define _ASN_SYSTEM_H_
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include /* For snprintf(3) */
-#include /* For *alloc(3) */
-#include /* For memcpy(3) */
-#include /* For size_t */
-#include /* For va_start */
-#include /* for offsetof and ptrdiff_t */
-
-#ifdef _WIN32
-#ifndef WIN32
-#define WIN32
-#endif
-#endif
-
-#ifdef WIN32
-
-#include
-#include
-#define snprintf _snprintf
-#define vsnprintf _vsnprintf
-
-#ifdef _MSC_VER /* MSVS.Net */
-#ifndef __cplusplus
-#define inline __inline
-#endif
-#define ssize_t SSIZE_T
-//typedef char int8_t;
-//typedef short int16_t;
-//typedef int int32_t;
-//typedef unsigned char uint8_t;
-//typedef unsigned short uint16_t;
-//typedef unsigned int uint32_t;
-#define WIN32_LEAN_AND_MEAN
-#include
-#include
-#define isnan _isnan
-#define finite _finite
-#define copysign _copysign
-#define ilogb _logb
-#endif /* _MSC_VER */
-
-#else /* !WIN32 */
-
-#if defined(__vxworks)
-#include
-#else /* !defined(__vxworks) */
-
-#include /* C99 specifies this file */
-/*
- * 1. Earlier FreeBSD version didn't have ,
- * but was present.
- * 2. Sun Solaris requires for alloca(3),
- * but does not have .
- */
-#if (!defined(__FreeBSD__) || !defined(_SYS_INTTYPES_H_))
-#if defined(sun)
-#include /* For alloca(3) */
-#include /* for finite(3) */
-#elif defined(__hpux)
-#ifdef __GNUC__
-#include /* For alloca(3) */
-#else /* !__GNUC__ */
-#define inline
-#endif /* __GNUC__ */
-#else
-#include /* SUSv2+ and C99 specify this file, for uintXX_t */
-#endif /* defined(sun) */
-#endif
-
-#endif /* defined(__vxworks) */
-
-#endif /* WIN32 */
-
-#if __GNUC__ >= 3
-#ifndef GCC_PRINTFLIKE
-#define GCC_PRINTFLIKE(fmt,var) __attribute__((format(printf,fmt,var)))
-#endif
-#else
-#ifndef GCC_PRINTFLIKE
-#define GCC_PRINTFLIKE(fmt,var) /* nothing */
-#endif
-#endif
-
-#ifndef offsetof /* If not defined by */
-#define offsetof(s, m) ((ptrdiff_t)&(((s *)0)->m) - (ptrdiff_t)((s *)0))
-#endif /* offsetof */
-
-#ifndef MIN /* Suitable for comparing primitive types (integers) */
-#if defined(__GNUC__)
-#define MIN(a,b) ({ __typeof a _a = a; __typeof b _b = b; \
- ((_a)<(_b)?(_a):(_b)); })
-#else /* !__GNUC__ */
-#define MIN(a,b) ((a)<(b)?(a):(b)) /* Unsafe variant */
-#endif /* __GNUC__ */
-#endif /* MIN */
-
-#endif /* _ASN_SYSTEM_H_ */
+/*-
+ * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+/*
+ * Miscellaneous system-dependent types.
+ */
+#ifndef _ASN_SYSTEM_H_
+#define _ASN_SYSTEM_H_
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include /* For snprintf(3) */
+#include /* For *alloc(3) */
+#include /* For memcpy(3) */
+
+#include "stack_config.h"
+#if CONFIG_INCLUDE_PLATFORM_SPECIFIC_HEADERS
+#include "libiec61850_platform_specific.h"
+#else
+#include /* For size_t */
+#endif
+
+#include /* For va_start */
+#include /* for offsetof and ptrdiff_t */
+
+
+
+#ifdef _WIN32
+#ifndef WIN32
+#define WIN32
+#endif
+#endif
+
+#ifdef WIN32
+
+#include
+#include
+#define snprintf _snprintf
+#define vsnprintf _vsnprintf
+
+#ifdef _MSC_VER /* MSVS.Net */
+#ifndef __cplusplus
+#define inline __inline
+#endif
+#define ssize_t SSIZE_T
+//typedef char int8_t;
+//typedef short int16_t;
+//typedef int int32_t;
+//typedef unsigned char uint8_t;
+//typedef unsigned short uint16_t;
+//typedef unsigned int uint32_t;
+#define WIN32_LEAN_AND_MEAN
+#include
+#include
+#define isnan _isnan
+#define finite _finite
+#define copysign _copysign
+#define ilogb _logb
+#endif /* _MSC_VER */
+
+#else /* !WIN32 */
+
+#if defined(__vxworks)
+#include
+#else /* !defined(__vxworks) */
+
+#include /* C99 specifies this file */
+/*
+ * 1. Earlier FreeBSD version didn't have ,
+ * but was present.
+ * 2. Sun Solaris requires for alloca(3),
+ * but does not have .
+ */
+#if (!defined(__FreeBSD__) || !defined(_SYS_INTTYPES_H_))
+#if defined(sun)
+#include /* For alloca(3) */
+#include /* for finite(3) */
+#elif defined(__hpux)
+#ifdef __GNUC__
+#include /* For alloca(3) */
+#else /* !__GNUC__ */
+#define inline
+#endif /* __GNUC__ */
+#else
+#include /* SUSv2+ and C99 specify this file, for uintXX_t */
+#endif /* defined(sun) */
+#endif
+
+#endif /* defined(__vxworks) */
+
+#endif /* WIN32 */
+
+#if __GNUC__ >= 3
+#ifndef GCC_PRINTFLIKE
+#define GCC_PRINTFLIKE(fmt,var) __attribute__((format(printf,fmt,var)))
+#endif
+#else
+#ifndef GCC_PRINTFLIKE
+#define GCC_PRINTFLIKE(fmt,var) /* nothing */
+#endif
+#endif
+
+#ifndef offsetof /* If not defined by */
+#define offsetof(s, m) ((ptrdiff_t)&(((s *)0)->m) - (ptrdiff_t)((s *)0))
+#endif /* offsetof */
+
+#ifndef MIN /* Suitable for comparing primitive types (integers) */
+#if defined(__GNUC__)
+#define MIN(a,b) ({ __typeof a _a = a; __typeof b _b = b; \
+ ((_a)<(_b)?(_a):(_b)); })
+#else /* !__GNUC__ */
+#define MIN(a,b) ((a)<(b)?(a):(b)) /* Unsafe variant */
+#endif /* __GNUC__ */
+#endif /* MIN */
+
+#endif /* _ASN_SYSTEM_H_ */
diff --git a/src/mms/iso_mms/asn1c/der_encoder.c b/src/mms/iso_mms/asn1c/der_encoder.c
index 6c859e1b..cc2000e0 100644
--- a/src/mms/iso_mms/asn1c/der_encoder.c
+++ b/src/mms/iso_mms/asn1c/der_encoder.c
@@ -80,20 +80,18 @@ der_write_tags(asn_TYPE_descriptor_t *sd,
ber_tlv_tag_t tag, /* EXPLICIT or IMPLICIT tag */
asn_app_consume_bytes_f *cb,
void *app_key) {
- ber_tlv_tag_t *tags; /* Copy of tags stream */
+ ber_tlv_tag_t tag_mem[5]; /* Copy of tags stream */
+ ber_tlv_tag_t* tags;
int tags_count; /* Number of tags */
size_t overall_length;
- ssize_t *lens;
+ ssize_t lens[5];
int i;
- ASN_DEBUG("Writing tags (%s, tm=%d, tc=%d, tag=%s, mtc=%d)",
- sd->name, tag_mode, sd->tags_count,
- ber_tlv_tag_string(tag),
- tag_mode
- ?(sd->tags_count+1
- -((tag_mode == -1) && sd->tags_count))
- :sd->tags_count
- );
+ if (sd->tags_count > 4) {
+ printf("TO MUCH TAGS");
+ errno = ENOMEM;
+ return -1;
+ }
if(tag_mode) {
/*
@@ -102,11 +100,9 @@ der_write_tags(asn_TYPE_descriptor_t *sd,
* and initialize it appropriately.
*/
int stag_offset;
- tags = (ber_tlv_tag_t *)alloca((sd->tags_count + 1) * sizeof(ber_tlv_tag_t));
- if(!tags) { /* Can fail on !x86 */
- errno = ENOMEM;
- return -1;
- }
+
+ tags = tag_mem;
+
tags_count = sd->tags_count
+ 1 /* EXPLICIT or IMPLICIT tag is given */
- ((tag_mode == -1) && sd->tags_count);
@@ -124,12 +120,6 @@ der_write_tags(asn_TYPE_descriptor_t *sd,
if(tags_count == 0)
return 0;
- lens = (ssize_t *)alloca(tags_count * sizeof(lens[0]));
- if(!lens) {
- errno = ENOMEM;
- return -1;
- }
-
/*
* Array of tags is initialized.
* Now, compute the size of the TLV pairs, from right to left.
diff --git a/src/mms/iso_mms/asn1c/xer_encoder.h b/src/mms/iso_mms/asn1c/xer_encoder.h
index 055e73c0..1cb546a3 100644
--- a/src/mms/iso_mms/asn1c/xer_encoder.h
+++ b/src/mms/iso_mms/asn1c/xer_encoder.h
@@ -1,59 +1,59 @@
-/*-
- * Copyright (c) 2004 Lev Walkin . All rights reserved.
- * Redistribution and modifications are permitted subject to BSD license.
- */
-#ifndef _XER_ENCODER_H_
-#define _XER_ENCODER_H_
-
-#include
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct asn_TYPE_descriptor_s; /* Forward declaration */
-
-/* Flags used by the xer_encode() and (*xer_type_encoder_f), defined below */
-enum xer_encoder_flags_e {
- /* Mode of encoding */
- XER_F_BASIC = 0x01, /* BASIC-XER (pretty-printing) */
- XER_F_CANONICAL = 0x02 /* Canonical XER (strict rules) */
-};
-
-/*
- * The XER encoder of any type. May be invoked by the application.
- */
-asn_enc_rval_t xer_encode(struct asn_TYPE_descriptor_s *type_descriptor,
- void *struct_ptr, /* Structure to be encoded */
- enum xer_encoder_flags_e xer_flags,
- asn_app_consume_bytes_f *consume_bytes_cb,
- void *app_key /* Arbitrary callback argument */
- );
-
-/*
- * The variant of the above function which dumps the BASIC-XER (XER_F_BASIC)
- * output into the chosen file pointer.
- * RETURN VALUES:
- * 0: The structure is printed.
- * -1: Problem printing the structure.
- * WARNING: No sensible errno value is returned.
- */
-int xer_fprint(FILE *stream, struct asn_TYPE_descriptor_s *td, void *sptr);
-
-/*
- * Type of the generic XER encoder.
- */
-typedef asn_enc_rval_t (xer_type_encoder_f)(
- struct asn_TYPE_descriptor_s *type_descriptor,
- void *struct_ptr, /* Structure to be encoded */
- int ilevel, /* Level of indentation */
- enum xer_encoder_flags_e xer_flags,
- asn_app_consume_bytes_f *consume_bytes_cb, /* Callback */
- void *app_key /* Arbitrary callback argument */
- );
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _XER_ENCODER_H_ */
+/*-
+ * Copyright (c) 2004 Lev Walkin . All rights reserved.
+ * Redistribution and modifications are permitted subject to BSD license.
+ */
+#ifndef _XER_ENCODER_H_
+#define _XER_ENCODER_H_
+
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct asn_TYPE_descriptor_s; /* Forward declaration */
+
+/* Flags used by the xer_encode() and (*xer_type_encoder_f), defined below */
+enum xer_encoder_flags_e {
+ /* Mode of encoding */
+ XER_F_BASIC = 0x01, /* BASIC-XER (pretty-printing) */
+ XER_F_CANONICAL = 0x02 /* Canonical XER (strict rules) */
+};
+
+/*
+ * The XER encoder of any type. May be invoked by the application.
+ */
+asn_enc_rval_t xer_encode(struct asn_TYPE_descriptor_s *type_descriptor,
+ void *struct_ptr, /* Structure to be encoded */
+ enum xer_encoder_flags_e xer_flags,
+ asn_app_consume_bytes_f *consume_bytes_cb,
+ void *app_key /* Arbitrary callback argument */
+ );
+
+/*
+ * The variant of the above function which dumps the BASIC-XER (XER_F_BASIC)
+ * output into the chosen file pointer.
+ * RETURN VALUES:
+ * 0: The structure is printed.
+ * -1: Problem printing the structure.
+ * WARNING: No sensible errno value is returned.
+ */
+int xer_fprint(FILE *stream, struct asn_TYPE_descriptor_s *td, void *sptr);
+
+/*
+ * Type of the generic XER encoder.
+ */
+typedef asn_enc_rval_t (xer_type_encoder_f)(
+ struct asn_TYPE_descriptor_s *type_descriptor,
+ void *struct_ptr, /* Structure to be encoded */
+ int ilevel, /* Level of indentation */
+ enum xer_encoder_flags_e xer_flags,
+ asn_app_consume_bytes_f *consume_bytes_cb, /* Callback */
+ void *app_key /* Arbitrary callback argument */
+ );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _XER_ENCODER_H_ */
diff --git a/src/mms/iso_mms/client/mms_client_common.c b/src/mms/iso_mms/client/mms_client_common.c
index e0f02925..f06072e6 100644
--- a/src/mms/iso_mms/client/mms_client_common.c
+++ b/src/mms/iso_mms/client/mms_client_common.c
@@ -49,7 +49,7 @@ mmsClient_getInvokeId(ConfirmedResponsePdu_t* confirmedResponse)
MmsPdu_t*
mmsClient_createConfirmedRequestPdu(uint32_t invokeId)
{
- MmsPdu_t* mmsPdu = (MmsPdu_t*) calloc(1, sizeof(MmsPdu_t));
+ MmsPdu_t* mmsPdu = (MmsPdu_t*) GLOBAL_CALLOC(1, sizeof(MmsPdu_t));
mmsPdu->present = MmsPdu_PR_confirmedRequestPdu;
asn_long2INTEGER(&(mmsPdu->choice.confirmedRequestPdu.invokeID), invokeId);
diff --git a/src/mms/iso_mms/client/mms_client_connection.c b/src/mms/iso_mms/client/mms_client_connection.c
index c41c7dae..793d50d7 100644
--- a/src/mms/iso_mms/client/mms_client_connection.c
+++ b/src/mms/iso_mms/client/mms_client_connection.c
@@ -1,7 +1,7 @@
/*
* mms_client_connection.c
*
- * Copyright 2013 Michael Zillgith
+ * Copyright 2013, 2014 Michael Zillgith
*
* This file is part of libIEC61850.
*
@@ -36,6 +36,7 @@
#include
#define CONFIG_MMS_CONNECTION_DEFAULT_TIMEOUT 5000
+#define CONFIG_MMS_CONNECTION_DEFAULT_CONNECT_TIMEOUT 10000
#define OUTSTANDING_CALLS 10
static void
@@ -45,7 +46,7 @@ handleUnconfirmedMmsPdu(MmsConnection self, ByteBuffer* message)
MmsPdu_t* mmsPdu = 0; /* allow asn1c to allocate structure */
if (DEBUG_MMS_CLIENT)
- printf("MMS_CLIENT: report handler revd size:%i\n", ByteBuffer_getSize(message));
+ printf("MMS_CLIENT: report handler rcvd size:%i\n", ByteBuffer_getSize(message));
asn_dec_rval_t rval = ber_decode(NULL, &asn_DEF_MmsPdu,
(void**) &mmsPdu, ByteBuffer_getBuffer(message), ByteBuffer_getSize(message));
@@ -58,7 +59,7 @@ handleUnconfirmedMmsPdu(MmsConnection self, ByteBuffer* message)
if (mmsPdu->choice.unconfirmedPDU.unconfirmedService.present ==
UnconfirmedService_PR_informationReport)
- {
+ {
char* domainId = NULL;
InformationReport_t* report =
@@ -84,18 +85,15 @@ handleUnconfirmedMmsPdu(MmsConnection self, ByteBuffer* message)
self->reportHandler(self->reportHandlerParameter, domainId, variableListName, values, true);
- free(variableListName);
+ GLOBAL_FREEMEM(variableListName);
}
else {
// Ignore domain and association specific information reports (not used by IEC 61850)
}
}
- else if (report->variableAccessSpecification.present ==
- VariableAccessSpecification_PR_listOfVariable)
- {
- //TODO add code to handle reports with more than one variable
-
+ else if (report->variableAccessSpecification.present == VariableAccessSpecification_PR_listOfVariable)
+ {
int listSize = report->listOfAccessResult.list.count;
int variableSpecSize = report->variableAccessSpecification.choice.listOfVariable.list.count;
@@ -111,12 +109,11 @@ handleUnconfirmedMmsPdu(MmsConnection self, ByteBuffer* message)
int i;
for (i = 0; i < variableSpecSize; i++) {
if (report->variableAccessSpecification.choice.listOfVariable.list.array[i]->variableSpecification.present
- ==
- VariableSpecification_PR_name)
- {
+ == VariableSpecification_PR_name)
+ {
if (report->variableAccessSpecification.choice.listOfVariable.list.array[i]
- ->variableSpecification.choice.name.present == ObjectName_PR_vmdspecific) {
-
+ ->variableSpecification.choice.name.present == ObjectName_PR_vmdspecific)
+ {
int nameSize =
report->variableAccessSpecification.choice.listOfVariable.list.array[i]
->variableSpecification.choice.name.choice.vmdspecific.size;
@@ -130,14 +127,20 @@ handleUnconfirmedMmsPdu(MmsConnection self, ByteBuffer* message)
memcpy(variableListName, buffer, nameSize);
variableListName[nameSize] = 0;
+ MmsValue* value = values;
+
+ if (variableSpecSize != 1)
+ value = MmsValue_getElement(values, i);
+
self->reportHandler(self->reportHandlerParameter, domainId, variableListName,
- values, false);
+ value, false);
// report handler should have deleted the MmsValue!
- values = NULL;
+ if (variableSpecSize != 1)
+ MmsValue_setElement(values, i, NULL);
+ else
+ values = NULL;
}
- else
- MmsValue_delete(values);
}
else if (report->variableAccessSpecification.choice.listOfVariable.list.array[i]
->variableSpecification.choice.name.present == ObjectName_PR_domainspecific) {
@@ -167,22 +170,25 @@ handleUnconfirmedMmsPdu(MmsConnection self, ByteBuffer* message)
memcpy(itemNameStr, itemNamebuffer, itemNameSize);
itemNameStr[itemNameSize] = 0;
+ MmsValue* value = values;
+
+ if (variableSpecSize != 1)
+ value = MmsValue_getElement(values, i);
+
self->reportHandler(self->reportHandlerParameter, domainNameStr, itemNameStr,
- values, false);
+ value, false);
// report handler should have deleted the MmsValue!
- values = NULL;
+ if (variableSpecSize != 1)
+ MmsValue_setElement(values, i, NULL);
+ else
+ values = NULL;
+
}
- else
- MmsValue_delete(values);
}
-
}
-
}
- //TODO handle CommandTermination request!
-
if (values != NULL)
MmsValue_delete(values);
}
@@ -615,7 +621,7 @@ mmsIsoCallback(IsoIndication indication, void* parameter, ByteBuffer* payload)
}
self->lastResponse = payload;
- return;
+ IsoClientConnection_releaseReceiveBuffer(self->isoClient);
}
else if (tag == 0xa3) { /* unconfirmed PDU */
handleUnconfirmedMmsPdu(self, payload);
@@ -627,7 +633,8 @@ mmsIsoCallback(IsoIndication indication, void* parameter, ByteBuffer* payload)
self->concludeState = CONCLUDE_STATE_REQUESTED;
- /* block all new user requests */
+ /* TODO block all new user requests */
+
IsoClientConnection_releaseReceiveBuffer(self->isoClient);
}
else if (tag == 0x8c) { /* conclude response PDU */
@@ -742,7 +749,7 @@ mmsIsoCallback(IsoIndication indication, void* parameter, ByteBuffer* payload)
MmsConnection
MmsConnection_create()
{
- MmsConnection self = (MmsConnection) calloc(1, sizeof(struct sMmsConnection));
+ MmsConnection self = (MmsConnection) GLOBAL_CALLOC(1, sizeof(struct sMmsConnection));
self->parameters.dataStructureNestingLevel = -1;
self->parameters.maxServOutstandingCalled = -1;
@@ -759,16 +766,23 @@ MmsConnection_create()
self->lastResponseError = MMS_ERROR_NONE;
- self->outstandingCalls = (uint32_t*) calloc(OUTSTANDING_CALLS, sizeof(uint32_t));
+ self->outstandingCalls = (uint32_t*) GLOBAL_CALLOC(OUTSTANDING_CALLS, sizeof(uint32_t));
self->isoParameters = IsoConnectionParameters_create();
/* Load default values for connection parameters */
- IsoConnectionParameters_setLocalAddresses(self->isoParameters, 1, 1, 1);
+ TSelector selector1 = { 2, { 0, 0 } };
+ TSelector selector2 = { 2, { 0, 0 } };
+
+ IsoConnectionParameters_setLocalAddresses(self->isoParameters, 1, 1, selector1);
IsoConnectionParameters_setLocalApTitle(self->isoParameters, "1.1.1.999", 12);
- IsoConnectionParameters_setRemoteAddresses(self->isoParameters, 1, 1, 1);
+ IsoConnectionParameters_setRemoteAddresses(self->isoParameters, 1, 1, selector2);
IsoConnectionParameters_setRemoteApTitle(self->isoParameters, "1.1.1.999.1", 12);
+ self->connectTimeout = CONFIG_MMS_CONNECTION_DEFAULT_CONNECT_TIMEOUT;
+
+ self->isoClient = IsoClientConnection_create((IsoIndicationCallback) mmsIsoCallback, (void*) self);
+
return self;
}
@@ -785,9 +799,9 @@ MmsConnection_destroy(MmsConnection self)
Semaphore_destroy(self->lastResponseLock);
Semaphore_destroy(self->outstandingCallsLock);
- free(self->outstandingCalls);
+ GLOBAL_FREEMEM(self->outstandingCalls);
- free(self);
+ GLOBAL_FREEMEM(self);
}
void
@@ -803,6 +817,12 @@ MmsConnection_setRequestTimeout(MmsConnection self, uint32_t timeoutInMs)
self->requestTimeout = timeoutInMs;
}
+void
+MmsConnection_setConnectTimeout(MmsConnection self, uint32_t timeoutInMs)
+{
+ self->connectTimeout = timeoutInMs;
+}
+
void
MmsConnection_setLocalDetail(MmsConnection self, int32_t localDetail)
{
@@ -842,10 +862,8 @@ waitForConnectResponse(MmsConnection self)
}
bool
-MmsConnection_connect(MmsConnection self, MmsError* mmsError, char* serverName, int serverPort)
+MmsConnection_connect(MmsConnection self, MmsError* mmsError, const char* serverName, int serverPort)
{
- self->isoClient = IsoClientConnection_create((IsoIndicationCallback) mmsIsoCallback, (void*) self);
-
IsoConnectionParameters_setTcpParameters(self->isoParameters, serverName, serverPort);
if (self->parameters.maxPduSize == -1)
@@ -857,7 +875,8 @@ MmsConnection_connect(MmsConnection self, MmsError* mmsError, char* serverName,
self->connectionState = MMS_CON_WAITING;
- IsoClientConnection_associate(self->isoClient, self->isoParameters, payload);
+ IsoClientConnection_associate(self->isoClient, self->isoParameters, payload,
+ self->connectTimeout);
waitForConnectResponse(self);
@@ -890,12 +909,26 @@ MmsConnection_connect(MmsConnection self, MmsError* mmsError, char* serverName,
}
}
+void
+MmsConnection_close(MmsConnection self)
+{
+ self->connectionLostHandler = NULL;
+
+ if (self->associationState == MMS_STATE_CONNECTED)
+ IsoClientConnection_close(self->isoClient);
+}
+
void
MmsConnection_abort(MmsConnection self, MmsError* mmsError)
{
*mmsError = MMS_ERROR_NONE;
- IsoClientConnection_abort(self->isoClient);
+ self->connectionLostHandler = NULL;
+
+ if (self->associationState == MMS_STATE_CONNECTED)
+ IsoClientConnection_abort(self->isoClient);
+
+ //TODO wait for connection to be closed
}
static void
@@ -960,6 +993,8 @@ MmsConnection_conclude(MmsConnection self, MmsError* mmsError)
if (self->concludeState == CONCLUDE_STATE_REJECTED)
*mmsError = MMS_ERROR_CONCLUDE_REJECTED;
}
+
+ self->connectionLostHandler = NULL;
}
void
@@ -975,10 +1010,10 @@ mmsClient_getNameListSingleRequest(
LinkedList* nameList,
MmsConnection self,
MmsError* mmsError,
- char* domainId,
+ const char* domainId,
MmsObjectClass objectClass,
bool associationSpecific,
- char* continueAfter)
+ const char* continueAfter)
{
*mmsError = MMS_ERROR_NONE;
@@ -1016,7 +1051,7 @@ mmsClient_getNameListSingleRequest(
static LinkedList /* */
mmsClient_getNameList(MmsConnection self, MmsError *mmsError,
- char* domainId,
+ const char* domainId,
MmsObjectClass objectClass,
bool associationSpecific)
{
@@ -1055,13 +1090,13 @@ MmsConnection_getDomainNames(MmsConnection self, MmsError* mmsError)
}
LinkedList /* */
-MmsConnection_getDomainVariableNames(MmsConnection self, MmsError* mmsError, char* domainId)
+MmsConnection_getDomainVariableNames(MmsConnection self, MmsError* mmsError, const char* domainId)
{
return mmsClient_getNameList(self, mmsError, domainId, MMS_NAMED_VARIABLE, false);
}
LinkedList /* */
-MmsConnection_getDomainVariableListNames(MmsConnection self, MmsError* mmsError, char* domainId)
+MmsConnection_getDomainVariableListNames(MmsConnection self, MmsError* mmsError, const char* domainId)
{
return mmsClient_getNameList(self, mmsError, domainId, MMS_NAMED_VARIABLE_LIST, false);
}
@@ -1074,7 +1109,7 @@ MmsConnection_getVariableListNamesAssociationSpecific(MmsConnection self, MmsErr
MmsValue*
MmsConnection_readVariable(MmsConnection self, MmsError* mmsError,
- char* domainId, char* itemId)
+ const char* domainId, const char* itemId)
{
ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
@@ -1103,7 +1138,7 @@ MmsConnection_readVariable(MmsConnection self, MmsError* mmsError,
MmsValue*
MmsConnection_readArrayElements(MmsConnection self, MmsError* mmsError,
- char* domainId, char* itemId,
+ const char* domainId, const char* itemId,
uint32_t startIndex, uint32_t numberOfElements)
{
ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
@@ -1134,7 +1169,7 @@ MmsConnection_readArrayElements(MmsConnection self, MmsError* mmsError,
MmsValue*
MmsConnection_readMultipleVariables(MmsConnection self, MmsError* mmsError,
- char* domainId, LinkedList /**/items)
+ const char* domainId, LinkedList /**/items)
{
ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
@@ -1163,7 +1198,7 @@ MmsConnection_readMultipleVariables(MmsConnection self, MmsError* mmsError,
MmsValue*
MmsConnection_readNamedVariableListValues(MmsConnection self, MmsError* mmsError,
- char* domainId, char* listName,
+ const char* domainId, const char* listName,
bool specWithResult)
{
ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
@@ -1197,7 +1232,7 @@ MmsConnection_readNamedVariableListValues(MmsConnection self, MmsError* mmsError
MmsValue*
MmsConnection_readNamedVariableListValuesAssociationSpecific(
MmsConnection self, MmsError* mmsError,
- char* listName,
+ const char* listName,
bool specWithResult)
{
ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
@@ -1228,7 +1263,7 @@ MmsConnection_readNamedVariableListValuesAssociationSpecific(
LinkedList /* */
MmsConnection_readNamedVariableListDirectory(MmsConnection self, MmsError* mmsError,
- char* domainId, char* listName, bool* deletable)
+ const char* domainId, const char* listName, bool* deletable)
{
ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
@@ -1259,7 +1294,7 @@ MmsConnection_readNamedVariableListDirectory(MmsConnection self, MmsError* mmsEr
LinkedList /* */
MmsConnection_readNamedVariableListDirectoryAssociationSpecific(MmsConnection self, MmsError* mmsError,
- char* listName, bool* deletable)
+ const char* listName, bool* deletable)
{
ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
@@ -1290,7 +1325,7 @@ MmsConnection_readNamedVariableListDirectoryAssociationSpecific(MmsConnection se
void
MmsConnection_defineNamedVariableList(MmsConnection self, MmsError* mmsError,
- char* domainId, char* listName, LinkedList variableSpecs)
+ const char* domainId, const char* listName, LinkedList variableSpecs)
{
ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
@@ -1317,7 +1352,7 @@ MmsConnection_defineNamedVariableList(MmsConnection self, MmsError* mmsError,
void
MmsConnection_defineNamedVariableListAssociationSpecific(MmsConnection self,
- MmsError* mmsError, char* listName, LinkedList variableSpecs)
+ MmsError* mmsError, const char* listName, LinkedList variableSpecs)
{
ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
@@ -1344,7 +1379,7 @@ MmsConnection_defineNamedVariableListAssociationSpecific(MmsConnection self,
void
MmsConnection_deleteNamedVariableList(MmsConnection self, MmsError* mmsError,
- char* domainId, char* listName)
+ const char* domainId, const char* listName)
{
ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
@@ -1370,7 +1405,7 @@ MmsConnection_deleteNamedVariableList(MmsConnection self, MmsError* mmsError,
void
MmsConnection_deleteAssociationSpecificNamedVariableList(MmsConnection self,
- MmsError* mmsError, char* listName)
+ MmsError* mmsError, const char* listName)
{
ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
@@ -1397,7 +1432,7 @@ MmsConnection_deleteAssociationSpecificNamedVariableList(MmsConnection self,
MmsVariableSpecification*
MmsConnection_getVariableAccessAttributes(MmsConnection self, MmsError* mmsError,
- char* domainId, char* itemId)
+ const char* domainId, const char* itemId)
{
ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
@@ -1483,7 +1518,7 @@ MmsConnection_getServerStatus(MmsConnection self, MmsError* mmsError, int* vmdLo
int32_t
-MmsConnection_fileOpen(MmsConnection self, MmsError* mmsError, char* filename, uint32_t initialPosition,
+MmsConnection_fileOpen(MmsConnection self, MmsError* mmsError, const char* filename, uint32_t initialPosition,
uint32_t* fileSize, uint64_t* lastModified)
{
ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
@@ -1538,7 +1573,7 @@ MmsConnection_fileClose(MmsConnection self, MmsError* mmsError, int32_t frsmId)
}
void
-MmsConnection_fileDelete(MmsConnection self, MmsError* mmsError, char* fileName)
+MmsConnection_fileDelete(MmsConnection self, MmsError* mmsError, const char* fileName)
{
ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
@@ -1594,7 +1629,7 @@ MmsConnection_fileRead(MmsConnection self, MmsError* mmsError, int32_t frsmId, M
bool
-MmsConnection_getFileDirectory(MmsConnection self, MmsError* mmsError, char* fileSpecification, char* continueAfter,
+MmsConnection_getFileDirectory(MmsConnection self, MmsError* mmsError, const char* fileSpecification, const char* continueAfter,
MmsFileDirectoryHandler handler, void* handlerParameter)
{
ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
@@ -1625,7 +1660,7 @@ MmsConnection_getFileDirectory(MmsConnection self, MmsError* mmsError, char* fil
}
void
-MmsConnection_fileRename(MmsConnection self, MmsError* mmsError, char* currentFileName, char* newFileName)
+MmsConnection_fileRename(MmsConnection self, MmsError* mmsError, const char* currentFileName, const char* newFileName)
{
ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
@@ -1651,7 +1686,7 @@ MmsConnection_fileRename(MmsConnection self, MmsError* mmsError, char* currentFi
void
MmsConnection_writeVariable(MmsConnection self, MmsError* mmsError,
- char* domainId, char* itemId,
+ const char* domainId, const char* itemId,
MmsValue* value)
{
ByteBuffer* payload = IsoClientConnection_allocateTransmitBuffer(self->isoClient);
@@ -1676,7 +1711,7 @@ MmsConnection_writeVariable(MmsConnection self, MmsError* mmsError,
}
void
-MmsConnection_writeMultipleVariables(MmsConnection self, MmsError* mmsError, char* domainId,
+MmsConnection_writeMultipleVariables(MmsConnection self, MmsError* mmsError, const char* domainId,
LinkedList /**/items,
LinkedList /* */values,
/* OUTPUT */LinkedList* /* */accessResults)
@@ -1711,22 +1746,22 @@ void
MmsServerIdentity_destroy(MmsServerIdentity* self)
{
if (self->modelName != NULL)
- free(self->modelName);
+ GLOBAL_FREEMEM(self->modelName);
if (self->vendorName != NULL)
- free(self->vendorName);
+ GLOBAL_FREEMEM(self->vendorName);
if (self->revision != NULL)
- free(self->revision);
+ GLOBAL_FREEMEM(self->revision);
- free(self);
+ GLOBAL_FREEMEM(self);
}
MmsVariableAccessSpecification*
MmsVariableAccessSpecification_create(char* domainId, char* itemId)
{
MmsVariableAccessSpecification* self = (MmsVariableAccessSpecification*)
- malloc(sizeof(MmsVariableAccessSpecification));
+ GLOBAL_MALLOC(sizeof(MmsVariableAccessSpecification));
self->domainId = domainId;
self->itemId = itemId;
@@ -1741,7 +1776,7 @@ MmsVariableAccessSpecification_createAlternateAccess(char* domainId, char* itemI
char* componentName)
{
MmsVariableAccessSpecification* self = (MmsVariableAccessSpecification*)
- malloc(sizeof(MmsVariableAccessSpecification));
+ GLOBAL_MALLOC(sizeof(MmsVariableAccessSpecification));
self->domainId = domainId;
self->itemId = itemId;
@@ -1755,14 +1790,14 @@ void
MmsVariableAccessSpecification_destroy(MmsVariableAccessSpecification* self)
{
if (self->domainId != NULL)
- free(self->domainId);
+ GLOBAL_FREEMEM((void*) self->domainId);
if (self->itemId != NULL)
- free(self->itemId);
+ GLOBAL_FREEMEM((void*) self->itemId);
if (self->componentName != NULL)
- free(self->componentName);
+ GLOBAL_FREEMEM((void*) self->componentName);
- free(self);
+ GLOBAL_FREEMEM(self);
}
diff --git a/src/mms/iso_mms/client/mms_client_files.c b/src/mms/iso_mms/client/mms_client_files.c
index 1b46d32f..a66590e3 100644
--- a/src/mms/iso_mms/client/mms_client_files.c
+++ b/src/mms/iso_mms/client/mms_client_files.c
@@ -33,7 +33,7 @@
#include "conversions.h"
void
-mmsClient_createFileOpenRequest(uint32_t invokeId, ByteBuffer* request, char* fileName, uint32_t initialPosition)
+mmsClient_createFileOpenRequest(uint32_t invokeId, ByteBuffer* request, const char* fileName, uint32_t initialPosition)
{
uint32_t invokeIdSize = BerEncoder_UInt32determineEncodedSize(invokeId);
@@ -66,7 +66,7 @@ mmsClient_createFileOpenRequest(uint32_t invokeId, ByteBuffer* request, char* fi
}
void
-mmsClient_createFileDeleteRequest(uint32_t invokeId, ByteBuffer* request, char* fileName)
+mmsClient_createFileDeleteRequest(uint32_t invokeId, ByteBuffer* request, const char* fileName)
{
uint32_t invokeIdSize = BerEncoder_UInt32determineEncodedSize(invokeId);
@@ -122,7 +122,7 @@ mmsClient_createFileReadRequest(uint32_t invokeId, ByteBuffer* request, int32_t
}
static int
-encodeFileSpecification(uint8_t tag, char* fileSpecification, uint8_t* buffer, int bufPos)
+encodeFileSpecification(uint8_t tag, const char* fileSpecification, uint8_t* buffer, int bufPos)
{
uint32_t fileNameStringSize = strlen(fileSpecification);
uint32_t fileNameSeqSize = 1 + BerEncoder_determineLengthSize(fileNameStringSize) + fileNameStringSize;
@@ -140,7 +140,7 @@ encodeFileSpecification(uint8_t tag, char* fileSpecification, uint8_t* buffer, i
}
void
-mmsClient_createFileDirectoryRequest(uint32_t invokeId, ByteBuffer* request, char* fileSpecification, char* continueAfter)
+mmsClient_createFileDirectoryRequest(uint32_t invokeId, ByteBuffer* request, const char* fileSpecification, const char* continueAfter)
{
uint32_t invokeIdSize = BerEncoder_UInt32determineEncodedSize(invokeId);
@@ -179,7 +179,7 @@ mmsClient_createFileDirectoryRequest(uint32_t invokeId, ByteBuffer* request, cha
void
-mmsClient_createFileRenameRequest(uint32_t invokeId, ByteBuffer* request, char* currentFileName, char* newFileName)
+mmsClient_createFileRenameRequest(uint32_t invokeId, ByteBuffer* request, const char* currentFileName, const char* newFileName)
{
uint32_t invokeIdSize = BerEncoder_UInt32determineEncodedSize(invokeId);
@@ -314,8 +314,6 @@ parseListOfDirectoryEntries(uint8_t* buffer, int bufPos, int maxBufPos,
int endPos = bufPos + length;
- // printf("bufPos: %i, length: %i, maxBufPos: %i\n", bufPos, length, maxBufPos);
-
if (endPos > maxBufPos) {
if (DEBUG_MMS_CLIENT)
printf("parseListOfDirectoryEntries: message to short!\n");
diff --git a/src/mms/iso_mms/client/mms_client_get_namelist.c b/src/mms/iso_mms/client/mms_client_get_namelist.c
index 4a9340e9..9332a120 100644
--- a/src/mms/iso_mms/client/mms_client_get_namelist.c
+++ b/src/mms/iso_mms/client/mms_client_get_namelist.c
@@ -33,7 +33,7 @@
int
mmsClient_createMmsGetNameListRequestVMDspecific(long invokeId, ByteBuffer* writeBuffer,
- char* continueAfter)
+ const char* continueAfter)
{
MmsPdu_t* mmsPdu = mmsClient_createConfirmedRequestPdu(invokeId);
@@ -45,7 +45,7 @@ mmsClient_createMmsGetNameListRequestVMDspecific(long invokeId, ByteBuffer* writ
request = &(mmsPdu->choice.confirmedRequestPdu.confirmedServiceRequest.choice.getNameList);
if (continueAfter != NULL) {
- request->continueAfter = (Identifier_t*) calloc(1, sizeof(Identifier_t));
+ request->continueAfter = (Identifier_t*) GLOBAL_CALLOC(1, sizeof(Identifier_t));
request->continueAfter->buf = (uint8_t*) copyString(continueAfter);
request->continueAfter->size = strlen(continueAfter);
}
@@ -70,7 +70,7 @@ mmsClient_createMmsGetNameListRequestVMDspecific(long invokeId, ByteBuffer* writ
int
mmsClient_createMmsGetNameListRequestAssociationSpecific(long invokeId, ByteBuffer* writeBuffer,
- char* continueAfter)
+ const char* continueAfter)
{
MmsPdu_t* mmsPdu = mmsClient_createConfirmedRequestPdu(invokeId);
@@ -83,7 +83,7 @@ mmsClient_createMmsGetNameListRequestAssociationSpecific(long invokeId, ByteBuff
if (continueAfter != NULL) {
- request->continueAfter = (Identifier_t*) calloc(1, sizeof(Identifier_t));
+ request->continueAfter = (Identifier_t*) GLOBAL_CALLOC(1, sizeof(Identifier_t));
request->continueAfter->buf = (uint8_t*) copyString(continueAfter);
request->continueAfter->size = strlen(continueAfter);
}
@@ -197,8 +197,8 @@ exit_error:
}
int
-mmsClient_createGetNameListRequestDomainOrVMDSpecific(long invokeId, char* domainName,
- ByteBuffer* writeBuffer, MmsObjectClass objectClass, char* continueAfter)
+mmsClient_createGetNameListRequestDomainOrVMDSpecific(long invokeId, const char* domainName,
+ ByteBuffer* writeBuffer, MmsObjectClass objectClass, const char* continueAfter)
{
MmsPdu_t* mmsPdu = mmsClient_createConfirmedRequestPdu(invokeId);
@@ -210,7 +210,7 @@ mmsClient_createGetNameListRequestDomainOrVMDSpecific(long invokeId, char* domai
request = &(mmsPdu->choice.confirmedRequestPdu.confirmedServiceRequest.choice.getNameList);
if (continueAfter != NULL) {
- request->continueAfter = (Identifier_t*) calloc(1, sizeof(Identifier_t));
+ request->continueAfter = (Identifier_t*) GLOBAL_CALLOC(1, sizeof(Identifier_t));
request->continueAfter->buf = (uint8_t*) copyString(continueAfter);
request->continueAfter->size = strlen(continueAfter);
}
diff --git a/src/mms/iso_mms/client/mms_client_get_var_access.c b/src/mms/iso_mms/client/mms_client_get_var_access.c
index de5fb409..4e45b34e 100644
--- a/src/mms/iso_mms/client/mms_client_get_var_access.c
+++ b/src/mms/iso_mms/client/mms_client_get_var_access.c
@@ -33,7 +33,7 @@
static MmsVariableSpecification*
createTypeSpecification(TypeSpecification_t* asnTypeSpec) {
MmsVariableSpecification* typeSpec = (MmsVariableSpecification*)
- calloc(1, sizeof(MmsVariableSpecification));
+ GLOBAL_CALLOC(1, sizeof(MmsVariableSpecification));
switch (asnTypeSpec->present) {
case TypeSpecification_PR_structure:
@@ -44,7 +44,7 @@ createTypeSpecification(TypeSpecification_t* asnTypeSpec) {
typeSpec->typeSpec.structure.elementCount = elementCount;
typeSpec->typeSpec.structure.elements = (MmsVariableSpecification**)
- calloc(elementCount, sizeof(MmsVariableSpecification*));
+ GLOBAL_CALLOC(elementCount, sizeof(MmsVariableSpecification*));
int i;
@@ -164,7 +164,7 @@ mmsClient_parseGetVariableAccessAttributesResponse(ByteBuffer* message, uint32_t
int
mmsClient_createGetVariableAccessAttributesRequest(
uint32_t invokeId,
- char* domainId, char* itemId,
+ const char* domainId, const char* itemId,
ByteBuffer* writeBuffer)
{
MmsPdu_t* mmsPdu = mmsClient_createConfirmedRequestPdu(invokeId);
diff --git a/src/mms/iso_mms/client/mms_client_identify.c b/src/mms/iso_mms/client/mms_client_identify.c
index 39f0d651..d20f2eae 100644
--- a/src/mms/iso_mms/client/mms_client_identify.c
+++ b/src/mms/iso_mms/client/mms_client_identify.c
@@ -101,7 +101,7 @@ mmsClient_parseIdentifyResponse(MmsConnection self)
}
}
- identityInfo = (MmsServerIdentity*) malloc(sizeof(MmsServerIdentity));
+ identityInfo = (MmsServerIdentity*) GLOBAL_MALLOC(sizeof(MmsServerIdentity));
identityInfo->vendorName = vendorName;
identityInfo->modelName = modelName;
diff --git a/src/mms/iso_mms/client/mms_client_initiate.c b/src/mms/iso_mms/client/mms_client_initiate.c
index 544cdc67..5eed3403 100644
--- a/src/mms/iso_mms/client/mms_client_initiate.c
+++ b/src/mms/iso_mms/client/mms_client_initiate.c
@@ -38,18 +38,18 @@ createInitiateRequestPdu(MmsConnection self)
{
InitiateRequestPdu_t request;
- request.localDetailCalling = (Integer32_t*) calloc(1, sizeof(Integer32_t));
+ request.localDetailCalling = (Integer32_t*) GLOBAL_CALLOC(1, sizeof(Integer32_t));
*(request.localDetailCalling) = self->parameters.maxPduSize;
request.proposedMaxServOutstandingCalled = DEFAULT_MAX_SERV_OUTSTANDING_CALLED;
request.proposedMaxServOutstandingCalling = DEFAULT_MAX_SERV_OUTSTANDING_CALLING;
- request.proposedDataStructureNestingLevel = (Integer8_t*) calloc(1, sizeof(Integer8_t));
+ request.proposedDataStructureNestingLevel = (Integer8_t*) GLOBAL_CALLOC(1, sizeof(Integer8_t));
*(request.proposedDataStructureNestingLevel) = DEFAULT_DATA_STRUCTURE_NESTING_LEVEL;
request.mmsInitRequestDetail.proposedParameterCBB.size = 2;
request.mmsInitRequestDetail.proposedParameterCBB.bits_unused = 5;
- request.mmsInitRequestDetail.proposedParameterCBB.buf = (uint8_t*) calloc(2, sizeof(uint8_t));
+ request.mmsInitRequestDetail.proposedParameterCBB.buf = (uint8_t*) GLOBAL_CALLOC(2, sizeof(uint8_t));
request.mmsInitRequestDetail.proposedParameterCBB.buf[0] = 0xf1;
request.mmsInitRequestDetail.proposedParameterCBB.buf[1] = 0x00;
@@ -66,15 +66,15 @@ createInitiateRequestPdu(MmsConnection self)
static void
freeInitiateRequestPdu(InitiateRequestPdu_t request)
{
- free(request.localDetailCalling);
- free(request.proposedDataStructureNestingLevel);
- free(request.mmsInitRequestDetail.proposedParameterCBB.buf);
+ GLOBAL_FREEMEM(request.localDetailCalling);
+ GLOBAL_FREEMEM(request.proposedDataStructureNestingLevel);
+ GLOBAL_FREEMEM(request.mmsInitRequestDetail.proposedParameterCBB.buf);
}
int
mmsClient_createInitiateRequest(MmsConnection self, ByteBuffer* message)
{
- MmsPdu_t* mmsPdu = (MmsPdu_t*) calloc(1, sizeof(MmsPdu_t));
+ MmsPdu_t* mmsPdu = (MmsPdu_t*) GLOBAL_CALLOC(1, sizeof(MmsPdu_t));
mmsPdu->present = MmsPdu_PR_initiateRequestPdu;
@@ -84,7 +84,7 @@ mmsClient_createInitiateRequest(MmsConnection self, ByteBuffer* message)
(asn_app_consume_bytes_f*) mmsClient_write_out, (void*) message);
freeInitiateRequestPdu(mmsPdu->choice.initiateRequestPdu);
- free(mmsPdu);
+ GLOBAL_FREEMEM(mmsPdu);
return rval.encoded;
}
diff --git a/src/mms/iso_mms/client/mms_client_named_variable_list.c b/src/mms/iso_mms/client/mms_client_named_variable_list.c
index 3939bf40..161a5c70 100644
--- a/src/mms/iso_mms/client/mms_client_named_variable_list.c
+++ b/src/mms/iso_mms/client/mms_client_named_variable_list.c
@@ -35,7 +35,7 @@
void
mmsClient_createDeleteNamedVariableListRequest(long invokeId, ByteBuffer* writeBuffer,
- char* domainId, char* listNameId)
+ const char* domainId, const char* listNameId)
{
MmsPdu_t* mmsPdu = mmsClient_createConfirmedRequestPdu(invokeId);
@@ -45,14 +45,14 @@ mmsClient_createDeleteNamedVariableListRequest(long invokeId, ByteBuffer* writeB
DeleteNamedVariableListRequest_t* request =
&(mmsPdu->choice.confirmedRequestPdu.confirmedServiceRequest.choice.deleteNamedVariableList);
- request->listOfVariableListName = (struct DeleteNamedVariableListRequest__listOfVariableListName*) calloc(1,
+ request->listOfVariableListName = (struct DeleteNamedVariableListRequest__listOfVariableListName*) GLOBAL_CALLOC(1,
sizeof(struct DeleteNamedVariableListRequest__listOfVariableListName));
request->listOfVariableListName->list.count = 1;
request->listOfVariableListName->list.size = 1;
- request->listOfVariableListName->list.array = (ObjectName_t**) calloc(1, sizeof(ObjectName_t*));
- request->listOfVariableListName->list.array[0] = (ObjectName_t*) calloc(1, sizeof(ObjectName_t));
+ request->listOfVariableListName->list.array = (ObjectName_t**) GLOBAL_CALLOC(1, sizeof(ObjectName_t*));
+ request->listOfVariableListName->list.array[0] = (ObjectName_t*) GLOBAL_CALLOC(1, sizeof(ObjectName_t));
request->listOfVariableListName->list.array[0]->present = ObjectName_PR_domainspecific;
request->listOfVariableListName->list.array[0]->choice.domainspecific.domainId.size = strlen(domainId);
@@ -60,7 +60,7 @@ mmsClient_createDeleteNamedVariableListRequest(long invokeId, ByteBuffer* writeB
request->listOfVariableListName->list.array[0]->choice.domainspecific.itemId.size = strlen(listNameId);
request->listOfVariableListName->list.array[0]->choice.domainspecific.itemId.buf = (uint8_t*) copyString(listNameId);
- request->scopeOfDelete = (INTEGER_t*) calloc(1, sizeof(INTEGER_t));
+ request->scopeOfDelete = (INTEGER_t*) GLOBAL_CALLOC(1, sizeof(INTEGER_t));
asn_long2INTEGER(request->scopeOfDelete, DeleteNamedVariableListRequest__scopeOfDelete_specific);
der_encode(&asn_DEF_MmsPdu, mmsPdu,
@@ -73,7 +73,7 @@ void
mmsClient_createDeleteAssociationSpecificNamedVariableListRequest(
long invokeId,
ByteBuffer* writeBuffer,
- char* listNameId)
+ const char* listNameId)
{
MmsPdu_t* mmsPdu = mmsClient_createConfirmedRequestPdu(invokeId);
@@ -83,21 +83,21 @@ mmsClient_createDeleteAssociationSpecificNamedVariableListRequest(
DeleteNamedVariableListRequest_t* request =
&(mmsPdu->choice.confirmedRequestPdu.confirmedServiceRequest.choice.deleteNamedVariableList);
- request->listOfVariableListName = (struct DeleteNamedVariableListRequest__listOfVariableListName*) calloc(1,
+ request->listOfVariableListName = (struct DeleteNamedVariableListRequest__listOfVariableListName*) GLOBAL_CALLOC(1,
sizeof(struct DeleteNamedVariableListRequest__listOfVariableListName));
request->listOfVariableListName->list.count = 1;
request->listOfVariableListName->list.size = 1;
- request->listOfVariableListName->list.array = (ObjectName_t**) calloc(1, sizeof(ObjectName_t*));
- request->listOfVariableListName->list.array[0] = (ObjectName_t*) calloc(1, sizeof(ObjectName_t));
+ request->listOfVariableListName->list.array = (ObjectName_t**) GLOBAL_CALLOC(1, sizeof(ObjectName_t*));
+ request->listOfVariableListName->list.array[0] = (ObjectName_t*) GLOBAL_CALLOC(1, sizeof(ObjectName_t));
request->listOfVariableListName->list.array[0]->present = ObjectName_PR_aaspecific;
request->listOfVariableListName->list.array[0]->choice.aaspecific.size = strlen(listNameId);
request->listOfVariableListName->list.array[0]->choice.aaspecific.buf = (uint8_t*) copyString(listNameId);
- request->scopeOfDelete = (INTEGER_t*) calloc(1, sizeof(INTEGER_t));
+ request->scopeOfDelete = (INTEGER_t*) GLOBAL_CALLOC(1, sizeof(INTEGER_t));
asn_long2INTEGER(request->scopeOfDelete, DeleteNamedVariableListRequest__scopeOfDelete_specific);
der_encode(&asn_DEF_MmsPdu, mmsPdu,
@@ -146,7 +146,7 @@ mmsClient_parseDeleteNamedVariableListResponse(ByteBuffer* message, uint32_t* in
void
mmsClient_createGetNamedVariableListAttributesRequest(uint32_t invokeId, ByteBuffer* writeBuffer,
- char* domainId, char* listNameId)
+ const char* domainId, const char* listNameId)
{
MmsPdu_t* mmsPdu = mmsClient_createConfirmedRequestPdu(invokeId);
@@ -172,7 +172,7 @@ mmsClient_createGetNamedVariableListAttributesRequest(uint32_t invokeId, ByteBuf
void
mmsClient_createGetNamedVariableListAttributesRequestAssociationSpecific(uint32_t invokeId,
- ByteBuffer* writeBuffer, char* listNameId)
+ ByteBuffer* writeBuffer, const char* listNameId)
{
MmsPdu_t* mmsPdu = mmsClient_createConfirmedRequestPdu(invokeId);
@@ -257,8 +257,8 @@ void
mmsClient_createDefineNamedVariableListRequest(
uint32_t invokeId,
ByteBuffer* writeBuffer,
- char* domainId,
- char* listNameId,
+ const char* domainId,
+ const char* listNameId,
LinkedList /**/ listOfVariables,
bool associationSpecific)
{
@@ -292,7 +292,7 @@ mmsClient_createDefineNamedVariableListRequest(
request->listOfVariable.list.size = listSize;
request->listOfVariable.list.array =
- (struct DefineNamedVariableListRequest__listOfVariable__Member**) calloc(listSize, sizeof(void*));
+ (struct DefineNamedVariableListRequest__listOfVariable__Member**) GLOBAL_CALLOC(listSize, sizeof(void*));
int i = 0;
LinkedList element = LinkedList_getNext(listOfVariables);
@@ -301,7 +301,7 @@ mmsClient_createDefineNamedVariableListRequest(
MmsVariableAccessSpecification* variableSpec = (MmsVariableAccessSpecification*) element->data;
request->listOfVariable.list.array[i] = (struct DefineNamedVariableListRequest__listOfVariable__Member*)
- calloc(1, sizeof(struct DefineNamedVariableListRequest__listOfVariable__Member));
+ GLOBAL_CALLOC(1, sizeof(struct DefineNamedVariableListRequest__listOfVariable__Member));
request->listOfVariable.list.array[i]->variableSpecification.present =
VariableSpecification_PR_name;
@@ -324,13 +324,13 @@ mmsClient_createDefineNamedVariableListRequest(
//TODO add alternate access
if (variableSpec->arrayIndex != -1) {
- AlternateAccess_t* alternateAccess = (AlternateAccess_t*) calloc(1, sizeof(AlternateAccess_t));
+ AlternateAccess_t* alternateAccess = (AlternateAccess_t*) GLOBAL_CALLOC(1, sizeof(AlternateAccess_t));
alternateAccess->list.count = 1;
- alternateAccess->list.array = (struct AlternateAccess__Member**) calloc(1, sizeof(struct AlternateAccess__Member*));
- alternateAccess->list.array[0] = (struct AlternateAccess__Member*) calloc(1, sizeof(struct AlternateAccess__Member));
+ alternateAccess->list.array = (struct AlternateAccess__Member**) GLOBAL_CALLOC(1, sizeof(struct AlternateAccess__Member*));
+ alternateAccess->list.array[0] = (struct AlternateAccess__Member*) GLOBAL_CALLOC(1, sizeof(struct AlternateAccess__Member));
alternateAccess->list.array[0]->present = AlternateAccess__Member_PR_unnamed;
- alternateAccess->list.array[0]->choice.unnamed = (AlternateAccessSelection_t*) calloc(1, sizeof(AlternateAccessSelection_t));
+ alternateAccess->list.array[0]->choice.unnamed = (AlternateAccessSelection_t*) GLOBAL_CALLOC(1, sizeof(AlternateAccessSelection_t));
alternateAccess->list.array[0]->choice.unnamed->present =
AlternateAccessSelection_PR_selectAlternateAccess;
@@ -343,14 +343,14 @@ mmsClient_createDefineNamedVariableListRequest(
if (variableSpec->componentName != NULL) {
- AlternateAccess_t* componentAccess = (AlternateAccess_t*) calloc(1, sizeof(AlternateAccess_t));
+ AlternateAccess_t* componentAccess = (AlternateAccess_t*) GLOBAL_CALLOC(1, sizeof(AlternateAccess_t));
componentAccess->list.count = 1;
- componentAccess->list.array = (struct AlternateAccess__Member**) calloc(1, sizeof(struct AlternateAccess__Member*));
- componentAccess->list.array[0] = (struct AlternateAccess__Member*) calloc(1, sizeof(struct AlternateAccess__Member));
+ componentAccess->list.array = (struct AlternateAccess__Member**) GLOBAL_CALLOC(1, sizeof(struct AlternateAccess__Member*));
+ componentAccess->list.array[0] = (struct AlternateAccess__Member*) GLOBAL_CALLOC(1, sizeof(struct AlternateAccess__Member));
componentAccess->list.array[0]->present = AlternateAccess__Member_PR_unnamed;
- componentAccess->list.array[0]->choice.unnamed = (AlternateAccessSelection_t*) calloc(1, sizeof(AlternateAccessSelection_t));
+ componentAccess->list.array[0]->choice.unnamed = (AlternateAccessSelection_t*) GLOBAL_CALLOC(1, sizeof(AlternateAccessSelection_t));
componentAccess->list.array[0]->choice.unnamed->present = AlternateAccessSelection_PR_selectAccess;
diff --git a/src/mms/iso_mms/client/mms_client_read.c b/src/mms/iso_mms/client/mms_client_read.c
index f860269d..5c39235e 100644
--- a/src/mms/iso_mms/client/mms_client_read.c
+++ b/src/mms/iso_mms/client/mms_client_read.c
@@ -67,14 +67,14 @@ mmsClient_parseListOfAccessResults(AccessResult_t** accessResultList, int listSi
value = MmsValue_newDataAccessError(DATA_ACCESS_ERROR_UNKNOWN);
}
else if (presentType == AccessResult_PR_array) {
- value = (MmsValue*) calloc(1, sizeof(MmsValue));
+ value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
value->type = MMS_ARRAY;
int arrayElementCount =
accessResultList[i]->choice.array.list.count;
value->value.structure.size = arrayElementCount;
- value->value.structure.components = (MmsValue**) calloc(arrayElementCount, sizeof(MmsValue*));
+ value->value.structure.components = (MmsValue**) GLOBAL_CALLOC(arrayElementCount, sizeof(MmsValue*));
int j;
@@ -84,14 +84,14 @@ mmsClient_parseListOfAccessResults(AccessResult_t** accessResultList, int listSi
}
}
else if (presentType == AccessResult_PR_structure) {
- value = (MmsValue*) calloc(1, sizeof(MmsValue));
+ value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
value->type = MMS_STRUCTURE;
int componentCount =
accessResultList[i]->choice.structure.list.count;
value->value.structure.size = componentCount;
- value->value.structure.components = (MmsValue**) calloc(componentCount, sizeof(MmsValue*));
+ value->value.structure.components = (MmsValue**) GLOBAL_CALLOC(componentCount, sizeof(MmsValue*));
int j;
for (j = 0; j < componentCount; j++) {
@@ -100,14 +100,14 @@ mmsClient_parseListOfAccessResults(AccessResult_t** accessResultList, int listSi
}
}
else if (presentType == AccessResult_PR_bitstring) {
- value = (MmsValue*) calloc(1, sizeof(MmsValue));
+ value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
value->type = MMS_BIT_STRING;
int size = accessResultList[i]->choice.bitstring.size;
value->value.bitString.size = (size * 8)
- accessResultList[i]->choice.bitstring.bits_unused;
- value->value.bitString.buf = (uint8_t*) malloc(size);
+ value->value.bitString.buf = (uint8_t*) GLOBAL_MALLOC(size);
memcpy(value->value.bitString.buf,
accessResultList[i]->choice.bitstring.buf, size);
@@ -129,7 +129,7 @@ mmsClient_parseListOfAccessResults(AccessResult_t** accessResultList, int listSi
else if (presentType == AccessResult_PR_floatingpoint) {
int size = accessResultList[i]->choice.floatingpoint.size;
- value = (MmsValue*) calloc(1, sizeof(MmsValue));
+ value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
value->type = MMS_FLOAT;
if (size == 5) { /* FLOAT32 */
@@ -138,7 +138,7 @@ mmsClient_parseListOfAccessResults(AccessResult_t** accessResultList, int listSi
uint8_t* floatBuf = (accessResultList[i]->choice.floatingpoint.buf + 1);
- value->value.floatingPoint.buf = (uint8_t*) malloc(4);
+ value->value.floatingPoint.buf = (uint8_t*) GLOBAL_MALLOC(4);
#if (ORDER_LITTLE_ENDIAN == 1)
memcpyReverseByteOrder(value->value.floatingPoint.buf, floatBuf, 4);
@@ -154,7 +154,7 @@ mmsClient_parseListOfAccessResults(AccessResult_t** accessResultList, int listSi
uint8_t* floatBuf = (accessResultList[i]->choice.floatingpoint.buf + 1);
- value->value.floatingPoint.buf = (uint8_t*) malloc(8);
+ value->value.floatingPoint.buf = (uint8_t*) GLOBAL_MALLOC(8);
#if (ORDER_LITTLE_ENDIAN == 1)
memcpyReverseByteOrder(value->value.floatingPoint.buf, floatBuf, 8);
@@ -165,13 +165,13 @@ mmsClient_parseListOfAccessResults(AccessResult_t** accessResultList, int listSi
}
else if (presentType == AccessResult_PR_visiblestring) {
- value = (MmsValue*) calloc(1, sizeof(MmsValue));
+ value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
value->type = MMS_VISIBLE_STRING;
int strSize = accessResultList[i]->choice.visiblestring.size;
- value->value.visibleString.buf = (char*) malloc(strSize + 1);
+ value->value.visibleString.buf = (char*) GLOBAL_MALLOC(strSize + 1);
value->value.visibleString.size = strSize;
memcpy(value->value.visibleString.buf,
@@ -181,13 +181,13 @@ mmsClient_parseListOfAccessResults(AccessResult_t** accessResultList, int listSi
value->value.visibleString.buf[strSize] = 0;
}
else if (presentType == AccessResult_PR_mMSString) {
- value = (MmsValue*) calloc(1, sizeof(MmsValue));
+ value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
value->type = MMS_STRING;
int strSize = accessResultList[i]->choice.mMSString.size;
- value->value.visibleString.buf = (char*) malloc(strSize + 1);
+ value->value.visibleString.buf = (char*) GLOBAL_MALLOC(strSize + 1);
value->value.visibleString.size = strSize;
memcpy(value->value.visibleString.buf,
@@ -197,7 +197,7 @@ mmsClient_parseListOfAccessResults(AccessResult_t** accessResultList, int listSi
}
else if (presentType == AccessResult_PR_utctime) {
- value = (MmsValue*) calloc(1, sizeof(MmsValue));
+ value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
value->type = MMS_UTC_TIME;
memcpy(value->value.utcTime,
@@ -210,7 +210,7 @@ mmsClient_parseListOfAccessResults(AccessResult_t** accessResultList, int listSi
int size = accessResultList[i]->choice.binarytime.size;
if (size <= 6) {
- value = (MmsValue*) calloc(1, sizeof(MmsValue));
+ value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
value->type = MMS_BINARY_TIME;
value->value.binaryTime.size = size;
memcpy(value->value.binaryTime.buf, accessResultList[i]->choice.binarytime.buf, size);
@@ -219,11 +219,11 @@ mmsClient_parseListOfAccessResults(AccessResult_t** accessResultList, int listSi
else if (presentType == AccessResult_PR_octetstring) {
int size = accessResultList[i]->choice.octetstring.size;
- value = (MmsValue*) calloc(1, sizeof(MmsValue));
+ value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
value->type = MMS_OCTET_STRING;
value->value.octetString.maxSize = size;
value->value.octetString.size = size;
- value->value.octetString.buf = (uint8_t*) malloc(size);
+ value->value.octetString.buf = (uint8_t*) GLOBAL_MALLOC(size);
memcpy(value->value.octetString.buf, accessResultList[i]->choice.octetstring.buf, size);
}
else {
@@ -291,7 +291,7 @@ createReadRequest (MmsPdu_t* mmsPdu)
int
-mmsClient_createReadNamedVariableListRequest(uint32_t invokeId, char* domainId, char* itemId,
+mmsClient_createReadNamedVariableListRequest(uint32_t invokeId, const char* domainId, const char* itemId,
ByteBuffer* writeBuffer, bool specWithResult)
{
MmsPdu_t* mmsPdu = mmsClient_createConfirmedRequestPdu(invokeId);
@@ -330,7 +330,7 @@ mmsClient_createReadNamedVariableListRequest(uint32_t invokeId, char* domainId,
int
mmsClient_createReadAssociationSpecificNamedVariableListRequest(
uint32_t invokeId,
- char* itemId,
+ const char* itemId,
ByteBuffer* writeBuffer,
bool specWithResult)
{
@@ -368,7 +368,7 @@ mmsClient_createReadAssociationSpecificNamedVariableListRequest(
* Request a single value
*/
int
-mmsClient_createReadRequest(uint32_t invokeId, char* domainId, char* itemId, ByteBuffer* writeBuffer)
+mmsClient_createReadRequest(uint32_t invokeId, const char* domainId, const char* itemId, ByteBuffer* writeBuffer)
{
MmsPdu_t* mmsPdu = mmsClient_createConfirmedRequestPdu(invokeId);
@@ -379,10 +379,10 @@ mmsClient_createReadRequest(uint32_t invokeId, char* domainId, char* itemId, Byt
readRequest->variableAccessSpecification.present = VariableAccessSpecification_PR_listOfVariable;
readRequest->variableAccessSpecification.choice.listOfVariable.list.array =
- (ListOfVariableSeq_t**) calloc(1, sizeof(ListOfVariableSeq_t*));
+ (ListOfVariableSeq_t**) GLOBAL_CALLOC(1, sizeof(ListOfVariableSeq_t*));
readRequest->variableAccessSpecification.choice.listOfVariable.list.count = 1;
- ListOfVariableSeq_t* listOfVars = (ListOfVariableSeq_t*) calloc(1, sizeof(ListOfVariableSeq_t));
+ ListOfVariableSeq_t* listOfVars = (ListOfVariableSeq_t*) GLOBAL_CALLOC(1, sizeof(ListOfVariableSeq_t));
readRequest->variableAccessSpecification.choice.listOfVariable.list.array[0] = listOfVars;
@@ -408,8 +408,8 @@ mmsClient_createReadRequest(uint32_t invokeId, char* domainId, char* itemId, Byt
(asn_app_consume_bytes_f*) mmsClient_write_out, (void*) writeBuffer);
/* clean up data structures */
- free(listOfVars);
- free(readRequest->variableAccessSpecification.choice.listOfVariable.list.array);
+ GLOBAL_FREEMEM(listOfVars);
+ GLOBAL_FREEMEM(readRequest->variableAccessSpecification.choice.listOfVariable.list.array);
readRequest->variableAccessSpecification.choice.listOfVariable.list.array = NULL;
readRequest->variableAccessSpecification.choice.listOfVariable.list.count = 0;
asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0);
@@ -420,13 +420,13 @@ mmsClient_createReadRequest(uint32_t invokeId, char* domainId, char* itemId, Byt
static AlternateAccess_t*
createAlternateAccess(uint32_t index, uint32_t elementCount)
{
- AlternateAccess_t* alternateAccess = (AlternateAccess_t*) calloc(1, sizeof(AlternateAccess_t));
+ AlternateAccess_t* alternateAccess = (AlternateAccess_t*) GLOBAL_CALLOC(1, sizeof(AlternateAccess_t));
alternateAccess->list.count = 1;
- alternateAccess->list.array = (struct AlternateAccess__Member**) calloc(1, sizeof(struct AlternateAccess__Member*));
- alternateAccess->list.array[0] = (struct AlternateAccess__Member*) calloc(1, sizeof(struct AlternateAccess__Member));
+ alternateAccess->list.array = (struct AlternateAccess__Member**) GLOBAL_CALLOC(1, sizeof(struct AlternateAccess__Member*));
+ alternateAccess->list.array[0] = (struct AlternateAccess__Member*) GLOBAL_CALLOC(1, sizeof(struct AlternateAccess__Member));
alternateAccess->list.array[0]->present = AlternateAccess__Member_PR_unnamed;
- alternateAccess->list.array[0]->choice.unnamed = (AlternateAccessSelection_t*) calloc(1, sizeof(AlternateAccessSelection_t));
+ alternateAccess->list.array[0]->choice.unnamed = (AlternateAccessSelection_t*) GLOBAL_CALLOC(1, sizeof(AlternateAccessSelection_t));
alternateAccess->list.array[0]->choice.unnamed->present = AlternateAccessSelection_PR_selectAccess;
@@ -458,9 +458,9 @@ createAlternateAccess(uint32_t index, uint32_t elementCount)
}
static ListOfVariableSeq_t*
-createVariableIdentifier(char* domainId, char* itemId)
+createVariableIdentifier(const char* domainId, const char* itemId)
{
- ListOfVariableSeq_t* variableIdentifier = (ListOfVariableSeq_t*) calloc(1, sizeof(ListOfVariableSeq_t));
+ ListOfVariableSeq_t* variableIdentifier = (ListOfVariableSeq_t*) GLOBAL_CALLOC(1, sizeof(ListOfVariableSeq_t));
variableIdentifier->variableSpecification.present = VariableSpecification_PR_name;
variableIdentifier->variableSpecification.choice.name.present = ObjectName_PR_domainspecific;
@@ -473,7 +473,7 @@ createVariableIdentifier(char* domainId, char* itemId)
}
int
-mmsClient_createReadRequestAlternateAccessIndex(uint32_t invokeId, char* domainId, char* itemId,
+mmsClient_createReadRequestAlternateAccessIndex(uint32_t invokeId, const char* domainId, const char* itemId,
uint32_t index, uint32_t elementCount, ByteBuffer* writeBuffer)
{
MmsPdu_t* mmsPdu = mmsClient_createConfirmedRequestPdu(invokeId);
@@ -483,7 +483,7 @@ mmsClient_createReadRequestAlternateAccessIndex(uint32_t invokeId, char* domainI
readRequest->variableAccessSpecification.present = VariableAccessSpecification_PR_listOfVariable;
- readRequest->variableAccessSpecification.choice.listOfVariable.list.array = (ListOfVariableSeq_t**) calloc(1, sizeof(ListOfVariableSeq_t*));
+ readRequest->variableAccessSpecification.choice.listOfVariable.list.array = (ListOfVariableSeq_t**) GLOBAL_CALLOC(1, sizeof(ListOfVariableSeq_t*));
readRequest->variableAccessSpecification.choice.listOfVariable.list.count = 1;
ListOfVariableSeq_t* variableIdentifier = createVariableIdentifier(domainId, itemId);
@@ -512,7 +512,7 @@ createListOfVariables(ReadRequest_t* readRequest, int valuesCount) {
readRequest->variableAccessSpecification.present = VariableAccessSpecification_PR_listOfVariable;
readRequest->variableAccessSpecification.choice.listOfVariable.list.array = (ListOfVariableSeq_t**)
- calloc(valuesCount, sizeof(ListOfVariableSeq_t*));
+ GLOBAL_CALLOC(valuesCount, sizeof(ListOfVariableSeq_t*));
readRequest->variableAccessSpecification.choice.listOfVariable.list.count = valuesCount;
readRequest->variableAccessSpecification.choice.listOfVariable.list.size = valuesCount;
@@ -523,7 +523,7 @@ createListOfVariables(ReadRequest_t* readRequest, int valuesCount) {
* Request multiple values of a single domain
*/
int
-mmsClient_createReadRequestMultipleValues(uint32_t invokeId, char* domainId, LinkedList items,
+mmsClient_createReadRequestMultipleValues(uint32_t invokeId, const char* domainId, LinkedList items,
ByteBuffer* writeBuffer)
{
MmsPdu_t* mmsPdu = mmsClient_createConfirmedRequestPdu(invokeId);
@@ -551,9 +551,9 @@ mmsClient_createReadRequestMultipleValues(uint32_t invokeId, char* domainId, Lin
(asn_app_consume_bytes_f*) mmsClient_write_out, (void*) writeBuffer);
for (i = 0; i < valuesCount; i++) {
- free(listOfVars[i]);
+ GLOBAL_FREEMEM(listOfVars[i]);
}
- free(listOfVars);
+ GLOBAL_FREEMEM(listOfVars);
readRequest->variableAccessSpecification.choice.listOfVariable.list.count = 0;
readRequest->variableAccessSpecification.choice.listOfVariable.list.size = 0;
diff --git a/src/mms/iso_mms/client/mms_client_write.c b/src/mms/iso_mms/client/mms_client_write.c
index 623461f8..5657ef45 100644
--- a/src/mms/iso_mms/client/mms_client_write.c
+++ b/src/mms/iso_mms/client/mms_client_write.c
@@ -172,9 +172,9 @@ mmsClient_parseWriteResponse(ByteBuffer* message, int32_t bufPos, MmsError* mmsE
}
static VariableSpecification_t*
-createNewDomainVariableSpecification(char* domainId, char* itemId)
+createNewDomainVariableSpecification(const char* domainId, const char* itemId)
{
- VariableSpecification_t* varSpec = (VariableSpecification_t*) calloc(1, sizeof(ListOfVariableSeq_t));
+ VariableSpecification_t* varSpec = (VariableSpecification_t*) GLOBAL_CALLOC(1, sizeof(ListOfVariableSeq_t));
//VariableSpecification_t* varSpec = (VariableSpecification_t*) calloc(1, sizeof(VariableSpecification_t));
@@ -204,8 +204,8 @@ deleteDataElement(Data_t* dataElement)
deleteDataElement(dataElement->choice.structure->list.array[i]);
}
- free(dataElement->choice.structure->list.array);
- free(dataElement->choice.structure);
+ GLOBAL_FREEMEM(dataElement->choice.structure->list.array);
+ GLOBAL_FREEMEM(dataElement->choice.structure);
}
else if (dataElement->present == Data_PR_array) {
int elementCount = dataElement->choice.array->list.count;
@@ -215,21 +215,21 @@ deleteDataElement(Data_t* dataElement)
deleteDataElement(dataElement->choice.array->list.array[i]);
}
- free(dataElement->choice.array->list.array);
- free(dataElement->choice.array);
+ GLOBAL_FREEMEM(dataElement->choice.array->list.array);
+ GLOBAL_FREEMEM(dataElement->choice.array);
}
else if (dataElement->present == Data_PR_floatingpoint) {
- free(dataElement->choice.floatingpoint.buf);
+ GLOBAL_FREEMEM(dataElement->choice.floatingpoint.buf);
}
else if (dataElement->present == Data_PR_utctime) {
- free(dataElement->choice.utctime.buf);
+ GLOBAL_FREEMEM(dataElement->choice.utctime.buf);
}
- free(dataElement);
+ GLOBAL_FREEMEM(dataElement);
}
int
-mmsClient_createWriteMultipleItemsRequest(uint32_t invokeId, char* domainId, LinkedList itemIds, LinkedList values,
+mmsClient_createWriteMultipleItemsRequest(uint32_t invokeId, const char* domainId, LinkedList itemIds, LinkedList values,
ByteBuffer* writeBuffer)
{
MmsPdu_t* mmsPdu = mmsClient_createConfirmedRequestPdu(invokeId);
@@ -246,12 +246,12 @@ mmsClient_createWriteMultipleItemsRequest(uint32_t invokeId, char* domainId, Lin
request->variableAccessSpecification.choice.listOfVariable.list.count = numberOfItems;
request->variableAccessSpecification.choice.listOfVariable.list.size = numberOfItems;
request->variableAccessSpecification.choice.listOfVariable.list.array =
- (ListOfVariableSeq_t**) calloc(numberOfItems, sizeof(ListOfVariableSeq_t*));
+ (ListOfVariableSeq_t**) GLOBAL_CALLOC(numberOfItems, sizeof(ListOfVariableSeq_t*));
/* Create list of data values */
request->listOfData.list.count = numberOfItems;
request->listOfData.list.size = numberOfItems;
- request->listOfData.list.array = (Data_t**) calloc(numberOfItems, sizeof(struct Data*));
+ request->listOfData.list.array = (Data_t**) GLOBAL_CALLOC(numberOfItems, sizeof(struct Data*));
int i;
@@ -283,16 +283,16 @@ mmsClient_createWriteMultipleItemsRequest(uint32_t invokeId, char* domainId, Lin
request->variableAccessSpecification.choice.listOfVariable.list.count = 0;
for (i = 0; i < numberOfItems; i++) {
- free(request->variableAccessSpecification.choice.listOfVariable.list.array[i]);
+ GLOBAL_FREEMEM(request->variableAccessSpecification.choice.listOfVariable.list.array[i]);
deleteDataElement(request->listOfData.list.array[i]);
}
- free(request->variableAccessSpecification.choice.listOfVariable.list.array);
+ GLOBAL_FREEMEM(request->variableAccessSpecification.choice.listOfVariable.list.array);
request->variableAccessSpecification.choice.listOfVariable.list.array = 0;
request->listOfData.list.count = 0;
- free(request->listOfData.list.array);
+ GLOBAL_FREEMEM(request->listOfData.list.array);
request->listOfData.list.array = 0;
asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0);
@@ -302,7 +302,7 @@ mmsClient_createWriteMultipleItemsRequest(uint32_t invokeId, char* domainId, Lin
}
int
-mmsClient_createWriteRequest(uint32_t invokeId, char* domainId, char* itemId, MmsValue* value,
+mmsClient_createWriteRequest(uint32_t invokeId, const char* domainId, const char* itemId, MmsValue* value,
ByteBuffer* writeBuffer)
{
MmsPdu_t* mmsPdu = mmsClient_createConfirmedRequestPdu(invokeId);
@@ -317,14 +317,14 @@ mmsClient_createWriteRequest(uint32_t invokeId, char* domainId, char* itemId, Mm
request->variableAccessSpecification.choice.listOfVariable.list.count = 1;
request->variableAccessSpecification.choice.listOfVariable.list.size = 1;
request->variableAccessSpecification.choice.listOfVariable.list.array =
- (ListOfVariableSeq_t**) calloc(1, sizeof(ListOfVariableSeq_t*));
+ (ListOfVariableSeq_t**) GLOBAL_CALLOC(1, sizeof(ListOfVariableSeq_t*));
request->variableAccessSpecification.choice.listOfVariable.list.array[0] = (ListOfVariableSeq_t*)
createNewDomainVariableSpecification(domainId, itemId);
/* Create list of typed data values */
request->listOfData.list.count = 1;
request->listOfData.list.size = 1;
- request->listOfData.list.array = (Data_t**) calloc(1, sizeof(struct Data*));
+ request->listOfData.list.array = (Data_t**) GLOBAL_CALLOC(1, sizeof(struct Data*));
request->listOfData.list.array[0] = mmsMsg_createBasicDataElement(value);
asn_enc_rval_t rval;
@@ -335,15 +335,15 @@ mmsClient_createWriteRequest(uint32_t invokeId, char* domainId, char* itemId, Mm
/* Free ASN structure */
request->variableAccessSpecification.choice.listOfVariable.list.count = 0;
- free(request->variableAccessSpecification.choice.listOfVariable.list.array[0]);
- free(request->variableAccessSpecification.choice.listOfVariable.list.array);
+ GLOBAL_FREEMEM(request->variableAccessSpecification.choice.listOfVariable.list.array[0]);
+ GLOBAL_FREEMEM(request->variableAccessSpecification.choice.listOfVariable.list.array);
request->variableAccessSpecification.choice.listOfVariable.list.array = 0;
request->listOfData.list.count = 0;
deleteDataElement(request->listOfData.list.array[0]);
- free(request->listOfData.list.array);
+ GLOBAL_FREEMEM(request->listOfData.list.array);
request->listOfData.list.array = 0;
asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0);
diff --git a/src/mms/iso_mms/common/mms_common_msg.c b/src/mms/iso_mms/common/mms_common_msg.c
index 019705c5..6b2e07c5 100644
--- a/src/mms/iso_mms/common/mms_common_msg.c
+++ b/src/mms/iso_mms/common/mms_common_msg.c
@@ -33,7 +33,7 @@ mmsMsg_createFloatData(MmsValue* value, int* size, uint8_t** buf)
{
if (value->value.floatingPoint.formatWidth == 64) {
*size = 9;
- *buf = (uint8_t*) malloc(9);
+ *buf = (uint8_t*) GLOBAL_MALLOC(9);
(*buf)[0] = 11;
#if (ORDER_LITTLE_ENDIAN == 1)
memcpyReverseByteOrder((*buf) + 1, value->value.floatingPoint.buf, 8);
@@ -42,7 +42,7 @@ mmsMsg_createFloatData(MmsValue* value, int* size, uint8_t** buf)
#endif
} else {
*size = 5;
- *buf = (uint8_t*) malloc(5);
+ *buf = (uint8_t*) GLOBAL_MALLOC(5);
(*buf)[0] = 8;
#if (ORDER_LITTLE_ENDIAN == 1)
memcpyReverseByteOrder((*buf) + 1, value->value.floatingPoint.buf, 4);
@@ -55,17 +55,17 @@ mmsMsg_createFloatData(MmsValue* value, int* size, uint8_t** buf)
Data_t*
mmsMsg_createBasicDataElement(MmsValue* value)
{
- Data_t* dataElement = (Data_t*) calloc(1, sizeof(Data_t));
+ Data_t* dataElement = (Data_t*) GLOBAL_CALLOC(1, sizeof(Data_t));
switch (value->type) {
case MMS_ARRAY:
{
int size = MmsValue_getArraySize(value);
dataElement->present = Data_PR_array;
- dataElement->choice.array = (DataSequence_t*) calloc(1, sizeof(DataSequence_t));
+ dataElement->choice.array = (DataSequence_t*) GLOBAL_CALLOC(1, sizeof(DataSequence_t));
dataElement->choice.array->list.count = size;
dataElement->choice.array->list.size = size;
- dataElement->choice.array->list.array = (Data_t**) calloc(size, sizeof(Data_t*));
+ dataElement->choice.array->list.array = (Data_t**) GLOBAL_CALLOC(size, sizeof(Data_t*));
int i;
for (i = 0; i < size; i++) {
dataElement->choice.array->list.array[i] =
@@ -79,10 +79,10 @@ mmsMsg_createBasicDataElement(MmsValue* value)
int size = value->value.structure.size;
dataElement->present = Data_PR_structure;
- dataElement->choice.structure = (DataSequence_t*) calloc(1, sizeof(DataSequence_t));
+ dataElement->choice.structure = (DataSequence_t*) GLOBAL_CALLOC(1, sizeof(DataSequence_t));
dataElement->choice.structure->list.count = size;
dataElement->choice.structure->list.size = size;
- dataElement->choice.structure->list.array = (Data_t**) calloc(size, sizeof(Data_t*));
+ dataElement->choice.structure->list.array = (Data_t**) GLOBAL_CALLOC(size, sizeof(Data_t*));
int i;
for (i = 0; i < size; i++) {
dataElement->choice.structure->list.array[i] = mmsMsg_createBasicDataElement(
@@ -117,7 +117,7 @@ mmsMsg_createBasicDataElement(MmsValue* value)
case MMS_UTC_TIME:
dataElement->present = Data_PR_utctime;
- dataElement->choice.utctime.buf = (uint8_t*) malloc(8);
+ dataElement->choice.utctime.buf = (uint8_t*) GLOBAL_MALLOC(8);
memcpy(dataElement->choice.utctime.buf, value->value.utcTime, 8);
dataElement->choice.utctime.size = 8;
break;
@@ -174,7 +174,7 @@ mmsMsg_createBasicDataElement(MmsValue* value)
default:
dataElement->present = Data_PR_NOTHING;
- printf("MMS read: unknown value type %i in result\n", value->type);
+
break;
}
@@ -187,13 +187,13 @@ mmsMsg_parseDataElement(Data_t* dataElement)
MmsValue* value = NULL;
if (dataElement->present == Data_PR_structure) {
- value = (MmsValue*) calloc(1, sizeof(MmsValue));
+ value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
int componentCount = dataElement->choice.structure->list.count;
value->type = MMS_STRUCTURE;
value->value.structure.size = componentCount;
- value->value.structure.components = (MmsValue**) calloc(componentCount, sizeof(MmsValue*));
+ value->value.structure.components = (MmsValue**) GLOBAL_CALLOC(componentCount, sizeof(MmsValue*));
int i;
@@ -203,13 +203,13 @@ mmsMsg_parseDataElement(Data_t* dataElement)
}
}
else if (dataElement->present == Data_PR_array) {
- value = (MmsValue*) calloc(1, sizeof(MmsValue));
+ value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
int componentCount = dataElement->choice.array->list.count;
value->type = MMS_ARRAY;
value->value.structure.size = componentCount;
- value->value.structure.components = (MmsValue**) calloc(componentCount, sizeof(MmsValue*));
+ value->value.structure.components = (MmsValue**) GLOBAL_CALLOC(componentCount, sizeof(MmsValue*));
int i;
@@ -240,7 +240,7 @@ mmsMsg_parseDataElement(Data_t* dataElement)
dataElement->choice.mMSString.size);
}
else if (dataElement->present == Data_PR_bitstring) {
- value = (MmsValue*) calloc(1, sizeof(MmsValue));
+ value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
value->type = MMS_BIT_STRING;
int size = dataElement->choice.bitstring.size;
@@ -248,13 +248,13 @@ mmsMsg_parseDataElement(Data_t* dataElement)
value->value.bitString.size = (size * 8)
- dataElement->choice.bitstring.bits_unused;
- value->value.bitString.buf = (uint8_t*) malloc(size);
+ value->value.bitString.buf = (uint8_t*) GLOBAL_MALLOC(size);
memcpy(value->value.bitString.buf,
dataElement->choice.bitstring.buf, size);
}
else if (dataElement->present == Data_PR_floatingpoint) {
- value = (MmsValue*) calloc(1, sizeof(MmsValue));
+ value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
int size = dataElement->choice.floatingpoint.size;
value->type = MMS_FLOAT;
@@ -265,7 +265,7 @@ mmsMsg_parseDataElement(Data_t* dataElement)
uint8_t* floatBuf = (dataElement->choice.floatingpoint.buf + 1);
- value->value.floatingPoint.buf = (uint8_t*) malloc(4);
+ value->value.floatingPoint.buf = (uint8_t*) GLOBAL_MALLOC(4);
#if (ORDER_LITTLE_ENDIAN == 1)
memcpyReverseByteOrder(value->value.floatingPoint.buf, floatBuf, 4);
#else
@@ -279,7 +279,7 @@ mmsMsg_parseDataElement(Data_t* dataElement)
uint8_t* floatBuf = (dataElement->choice.floatingpoint.buf + 1);
- value->value.floatingPoint.buf = (uint8_t*) malloc(8);
+ value->value.floatingPoint.buf = (uint8_t*) GLOBAL_MALLOC(8);
#if (ORDER_LITTLE_ENDIAN == 1)
memcpyReverseByteOrder(value->value.floatingPoint.buf, floatBuf, 8);
#else
@@ -288,24 +288,24 @@ mmsMsg_parseDataElement(Data_t* dataElement)
}
}
else if (dataElement->present == Data_PR_utctime) {
- value = (MmsValue*) calloc(1, sizeof(MmsValue));
+ value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
value->type = MMS_UTC_TIME;
memcpy(value->value.utcTime, dataElement->choice.utctime.buf, 8);
}
else if (dataElement->present == Data_PR_octetstring) {
- value = (MmsValue*) calloc(1, sizeof(MmsValue));
+ value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
value->type = MMS_OCTET_STRING;
int size = dataElement->choice.octetstring.size;
value->value.octetString.size = size;
value->value.octetString.maxSize = size;
- value->value.octetString.buf = (uint8_t*) malloc(size);
+ value->value.octetString.buf = (uint8_t*) GLOBAL_MALLOC(size);
memcpy(value->value.octetString.buf, dataElement->choice.octetstring.buf, size);
}
else if (dataElement->present == Data_PR_binarytime) {
int size = dataElement->choice.binarytime.size;
if (size <= 6) {
- value = (MmsValue*) calloc(1, sizeof(MmsValue));
+ value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
value->type = MMS_BINARY_TIME;
value->value.binaryTime.size = size;
memcpy(value->value.binaryTime.buf, dataElement->choice.binarytime.buf, size);
@@ -324,18 +324,18 @@ Data_t*
mmsMsg_createDataElement(MmsValue* value)
{
if (value->type == MMS_STRUCTURE) {
- Data_t* dataElement = (Data_t*) calloc(1, sizeof(Data_t));
+ Data_t* dataElement = (Data_t*) GLOBAL_CALLOC(1, sizeof(Data_t));
dataElement->present = Data_PR_structure;
int elementCount = value->value.structure.size;
- dataElement->choice.structure = (DataSequence_t*) calloc(1, sizeof(DataSequence_t));
+ dataElement->choice.structure = (DataSequence_t*) GLOBAL_CALLOC(1, sizeof(DataSequence_t));
dataElement->choice.structure->list.size = elementCount;
dataElement->choice.structure->list.count = elementCount;
- dataElement->choice.structure->list.array = (Data_t**) calloc(elementCount, sizeof(Data_t*));
+ dataElement->choice.structure->list.array = (Data_t**) GLOBAL_CALLOC(elementCount, sizeof(Data_t*));
int i;
@@ -370,7 +370,7 @@ mmsMsg_addResultToResultList(AccessResult_t* accessResult, MmsValue* value)
accessResult->present = AccessResult_PR_array;
accessResult->choice.array.list.count = size;
accessResult->choice.array.list.size = size;
- accessResult->choice.array.list.array = (Data_t**) calloc(size, sizeof(Data_t*));
+ accessResult->choice.array.list.array = (Data_t**) GLOBAL_CALLOC(size, sizeof(Data_t*));
int i;
for (i = 0; i < size; i++) {
accessResult->choice.array.list.array[i] =
@@ -384,7 +384,7 @@ mmsMsg_addResultToResultList(AccessResult_t* accessResult, MmsValue* value)
accessResult->present = AccessResult_PR_structure;
accessResult->choice.structure.list.count = size;
accessResult->choice.structure.list.size = size;
- accessResult->choice.structure.list.array = (Data_t**) calloc(size, sizeof(Data_t*));
+ accessResult->choice.structure.list.array = (Data_t**) GLOBAL_CALLOC(size, sizeof(Data_t*));
int i;
for (i = 0; i < size; i++) {
accessResult->choice.structure.list.array[i] =
@@ -416,7 +416,7 @@ mmsMsg_addResultToResultList(AccessResult_t* accessResult, MmsValue* value)
break;
case MMS_UTC_TIME:
accessResult->present = AccessResult_PR_utctime;
- accessResult->choice.utctime.buf = (uint8_t*) malloc(8);
+ accessResult->choice.utctime.buf = (uint8_t*) GLOBAL_MALLOC(8);
memcpy(accessResult->choice.utctime.buf, value->value.utcTime, 8);
accessResult->choice.utctime.size = 8;
break;
@@ -470,8 +470,8 @@ mmsMsg_addResultToResultList(AccessResult_t* accessResult, MmsValue* value)
asn_long2INTEGER(&accessResult->choice.failure, DataAccessError_typeinconsistent);
- if (1)
- printf("MMS read: unknown value type %i in result\n", value->type);
+
+
break;
}
}
@@ -485,12 +485,12 @@ mmsMsg_createAccessResultsList(MmsPdu_t* mmsPdu, int resultsCount)
readResponse->listOfAccessResult.list.size = resultsCount;
readResponse->listOfAccessResult.list.count = resultsCount;
- readResponse->listOfAccessResult.list.array = (AccessResult_t**) calloc(resultsCount, sizeof(AccessResult_t*));
+ readResponse->listOfAccessResult.list.array = (AccessResult_t**) GLOBAL_CALLOC(resultsCount, sizeof(AccessResult_t*));
int i;
for (i = 0; i < resultsCount; i++) {
- readResponse->listOfAccessResult.list.array[i] = (AccessResult_t*) calloc(1, sizeof(AccessResult_t));
+ readResponse->listOfAccessResult.list.array[i] = (AccessResult_t*) GLOBAL_CALLOC(1, sizeof(AccessResult_t));
}
AccessResult_t** accessResultList = readResponse->listOfAccessResult.list.array;
@@ -514,8 +514,8 @@ deleteDataElement(Data_t* dataElement)
deleteDataElement(dataElement->choice.structure->list.array[i]);
}
- free(dataElement->choice.structure->list.array);
- free(dataElement->choice.structure);
+ GLOBAL_FREEMEM(dataElement->choice.structure->list.array);
+ GLOBAL_FREEMEM(dataElement->choice.structure);
}
else if (dataElement->present == Data_PR_array) {
int elementCount = dataElement->choice.array->list.count;
@@ -525,17 +525,17 @@ deleteDataElement(Data_t* dataElement)
deleteDataElement(dataElement->choice.array->list.array[i]);
}
- free(dataElement->choice.array->list.array);
- free(dataElement->choice.array);
+ GLOBAL_FREEMEM(dataElement->choice.array->list.array);
+ GLOBAL_FREEMEM(dataElement->choice.array);
}
else if (dataElement->present == Data_PR_floatingpoint) {
- free(dataElement->choice.floatingpoint.buf);
+ GLOBAL_FREEMEM(dataElement->choice.floatingpoint.buf);
}
else if (dataElement->present == Data_PR_utctime) {
- free(dataElement->choice.utctime.buf);
+ GLOBAL_FREEMEM(dataElement->choice.utctime.buf);
}
- free(dataElement);
+ GLOBAL_FREEMEM(dataElement);
}
void
@@ -554,7 +554,7 @@ mmsMsg_deleteAccessResultList(AccessResult_t** accessResult, int variableCount)
deleteDataElement(accessResult[i]->choice.structure.list.array[j]);
}
- free(accessResult[i]->choice.structure.list.array);
+ GLOBAL_FREEMEM(accessResult[i]->choice.structure.list.array);
}
else if (accessResult[i]->present == AccessResult_PR_array) {
int elementCount = accessResult[i]->choice.array.list.count;
@@ -565,23 +565,23 @@ mmsMsg_deleteAccessResultList(AccessResult_t** accessResult, int variableCount)
deleteDataElement(accessResult[i]->choice.array.list.array[j]);
}
- free(accessResult[i]->choice.array.list.array);
+ GLOBAL_FREEMEM(accessResult[i]->choice.array.list.array);
}
else if (accessResult[i]->present == AccessResult_PR_integer)
- free(accessResult[i]->choice.integer.buf);
+ GLOBAL_FREEMEM(accessResult[i]->choice.integer.buf);
else if (accessResult[i]->present == AccessResult_PR_unsigned)
- free(accessResult[i]->choice.Unsigned.buf);
+ GLOBAL_FREEMEM(accessResult[i]->choice.Unsigned.buf);
else if (accessResult[i]->present == AccessResult_PR_floatingpoint)
- free(accessResult[i]->choice.floatingpoint.buf);
+ GLOBAL_FREEMEM(accessResult[i]->choice.floatingpoint.buf);
else if (accessResult[i]->present == AccessResult_PR_utctime)
- free(accessResult[i]->choice.utctime.buf);
+ GLOBAL_FREEMEM(accessResult[i]->choice.utctime.buf);
else if (accessResult[i]->present == AccessResult_PR_failure)
- free(accessResult[i]->choice.failure.buf);
+ GLOBAL_FREEMEM(accessResult[i]->choice.failure.buf);
- free(accessResult[i]);
+ GLOBAL_FREEMEM(accessResult[i]);
}
- free(accessResult);
+ GLOBAL_FREEMEM(accessResult);
}
diff --git a/src/mms/iso_mms/common/mms_type_spec.c b/src/mms/iso_mms/common/mms_type_spec.c
index b4ce3a04..e88e70d5 100644
--- a/src/mms/iso_mms/common/mms_type_spec.c
+++ b/src/mms/iso_mms/common/mms_type_spec.c
@@ -30,7 +30,7 @@ void
MmsVariableSpecification_destroy(MmsVariableSpecification* typeSpec)
{
if (typeSpec->name != NULL)
- free(typeSpec->name);
+ GLOBAL_FREEMEM(typeSpec->name);
if (typeSpec->type == MMS_STRUCTURE) {
int elementCount = typeSpec->typeSpec.structure.elementCount;
@@ -39,17 +39,17 @@ MmsVariableSpecification_destroy(MmsVariableSpecification* typeSpec)
MmsVariableSpecification_destroy(typeSpec->typeSpec.structure.elements[i]);
}
- free(typeSpec->typeSpec.structure.elements);
+ GLOBAL_FREEMEM(typeSpec->typeSpec.structure.elements);
}
else if (typeSpec->type == MMS_ARRAY) {
MmsVariableSpecification_destroy(typeSpec->typeSpec.array.elementTypeSpec);
}
- free(typeSpec);
+ GLOBAL_FREEMEM(typeSpec);
}
static size_t
-directChildStrLen(char* childId)
+directChildStrLen(const char* childId)
{
size_t i = 0;
size_t childIdLen = strlen(childId);
@@ -63,7 +63,7 @@ directChildStrLen(char* childId)
}
MmsValue*
-MmsVariableSpecification_getChildValue(MmsVariableSpecification* typeSpec, MmsValue* value, char* childId)
+MmsVariableSpecification_getChildValue(MmsVariableSpecification* typeSpec, MmsValue* value, const char* childId)
{
if (typeSpec->type == MMS_STRUCTURE) {
size_t childLen = directChildStrLen(childId);
@@ -95,7 +95,7 @@ MmsVariableSpecification_getType(MmsVariableSpecification* self)
return self->type;
}
-char*
+const char*
MmsVariableSpecification_getName(MmsVariableSpecification* self)
{
return self->name;
@@ -120,9 +120,9 @@ MmsVariableSpecification_getStructureElements(MmsVariableSpecification* self)
}
MmsVariableSpecification*
-MmsVariableSpecification_getNamedVariableRecursive(MmsVariableSpecification* variable, char* nameId)
+MmsVariableSpecification_getNamedVariableRecursive(MmsVariableSpecification* variable, const char* nameId)
{
- char* separator = strchr(nameId, '$');
+ const char* separator = strchr(nameId, '$');
int i;
diff --git a/src/mms/iso_mms/common/mms_value.c b/src/mms/iso_mms/common/mms_value.c
index bf753eae..0fc58d29 100644
--- a/src/mms/iso_mms/common/mms_value.c
+++ b/src/mms/iso_mms/common/mms_value.c
@@ -70,7 +70,7 @@ updateStructuredComponent(MmsValue* self, MmsValue* update)
MmsValue*
MmsValue_newIntegerFromBerInteger(Asn1PrimitiveValue* berInteger)
{
- MmsValue* self = (MmsValue*) calloc(1, sizeof(MmsValue));
+ MmsValue* self = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
self->type = MMS_INTEGER;
self->value.integer = berInteger;
@@ -81,7 +81,7 @@ MmsValue_newIntegerFromBerInteger(Asn1PrimitiveValue* berInteger)
MmsValue*
MmsValue_newUnsignedFromBerInteger(Asn1PrimitiveValue* berInteger)
{
- MmsValue* self = (MmsValue*) calloc(1, sizeof(MmsValue));
+ MmsValue* self = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
self->type = MMS_UNSIGNED;
self->value.integer = berInteger;
@@ -281,7 +281,7 @@ MmsValue_update(MmsValue* self, MmsValue* update)
MmsValue*
MmsValue_newDataAccessError(MmsDataAccessError accessError)
{
- MmsValue* self = (MmsValue*) calloc(1, sizeof(MmsValue));
+ MmsValue* self = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
self->type = MMS_DATA_ACCESS_ERROR;
self->value.dataAccessError = accessError;
@@ -292,11 +292,11 @@ MmsValue_newDataAccessError(MmsDataAccessError accessError)
MmsValue*
MmsValue_newBitString(int bitSize)
{
- MmsValue* self = (MmsValue*) calloc(1, sizeof(MmsValue));;
+ MmsValue* self = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));;
self->type = MMS_BIT_STRING;
self->value.bitString.size = bitSize;
- self->value.bitString.buf = (uint8_t*) calloc(bitStringByteSize(self), 1);
+ self->value.bitString.buf = (uint8_t*) GLOBAL_CALLOC(bitStringByteSize(self), 1);
return self;
}
@@ -441,16 +441,47 @@ MmsValue_setBitStringFromInteger(MmsValue* self, uint32_t intValue)
}
}
+uint32_t
+MmsValue_getBitStringAsIntegerBigEndian(MmsValue* self)
+{
+ uint32_t value = 0;
+
+ int bitPos;
+
+ for (bitPos = (self->value.bitString.size - 1); bitPos >= 0; bitPos--) {
+ if (MmsValue_getBitStringBit(self, bitPos)) {
+ value += (1 << bitPos);
+ }
+ }
+
+ return value;
+}
+
+void
+MmsValue_setBitStringFromIntegerBigEndian(MmsValue* self, uint32_t intValue)
+{
+ int bitPos;
+
+ for (bitPos = (self->value.bitString.size - 1); bitPos >= 0; bitPos--) {
+ if ((intValue & 1) == 1)
+ MmsValue_setBitStringBit(self, bitPos, true);
+ else
+ MmsValue_setBitStringBit(self, bitPos, false);
+
+ intValue = intValue >> 1;
+ }
+}
+
MmsValue*
MmsValue_newFloat(float variable)
{
- MmsValue* value = (MmsValue*) malloc(sizeof(MmsValue));;
+ MmsValue* value = (MmsValue*) GLOBAL_MALLOC(sizeof(MmsValue));;
value->type = MMS_FLOAT;
value->value.floatingPoint.formatWidth = 32;
value->value.floatingPoint.exponentWidth = 8;
- value->value.floatingPoint.buf = (uint8_t*) malloc(4);
+ value->value.floatingPoint.buf = (uint8_t*) GLOBAL_MALLOC(4);
*((float*) value->value.floatingPoint.buf) = variable;
@@ -486,12 +517,12 @@ MmsValue_setDouble(MmsValue* value, double newFloatValue)
MmsValue*
MmsValue_newDouble(double variable)
{
- MmsValue* value = (MmsValue*) calloc(1, sizeof(MmsValue));
+ MmsValue* value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
value->type = MMS_FLOAT;
value->value.floatingPoint.formatWidth = 64;
value->value.floatingPoint.exponentWidth = 11;
- value->value.floatingPoint.buf = (uint8_t*) malloc(8);
+ value->value.floatingPoint.buf = (uint8_t*) GLOBAL_MALLOC(8);
*((double*) value->value.floatingPoint.buf) = variable;
@@ -501,7 +532,7 @@ MmsValue_newDouble(double variable)
MmsValue*
MmsValue_newIntegerFromInt8(int8_t integer)
{
- MmsValue* value = (MmsValue*) calloc(1, sizeof(MmsValue));;
+ MmsValue* value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));;
value->type = MMS_INTEGER;
value->value.integer = BerInteger_createFromInt32((int32_t) integer);
@@ -512,7 +543,7 @@ MmsValue_newIntegerFromInt8(int8_t integer)
MmsValue*
MmsValue_newIntegerFromInt16(int16_t integer)
{
- MmsValue* value = (MmsValue*) calloc(1, sizeof(MmsValue));;
+ MmsValue* value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));;
value->type = MMS_INTEGER;
value->value.integer = BerInteger_createFromInt32((int32_t) integer);
@@ -704,7 +735,7 @@ MmsValue_getUtcTimeInMs(MmsValue* self)
MmsValue*
MmsValue_newIntegerFromInt32(int32_t integer)
{
- MmsValue* value = (MmsValue*) calloc(1, sizeof(MmsValue));
+ MmsValue* value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
value->type = MMS_INTEGER;
value->value.integer = BerInteger_createFromInt32(integer);
@@ -715,7 +746,7 @@ MmsValue_newIntegerFromInt32(int32_t integer)
MmsValue*
MmsValue_newUnsignedFromUint32(uint32_t integer)
{
- MmsValue* value = (MmsValue*) calloc(1, sizeof(MmsValue));;
+ MmsValue* value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));;
value->type = MMS_UNSIGNED;
value->value.integer = BerInteger_createFromUint32(integer);
@@ -726,7 +757,7 @@ MmsValue_newUnsignedFromUint32(uint32_t integer)
MmsValue*
MmsValue_newIntegerFromInt64(int64_t integer)
{
- MmsValue* value = (MmsValue*) calloc(1, sizeof(MmsValue));;
+ MmsValue* value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));;
value->type = MMS_INTEGER;
value->value.integer = BerInteger_createFromInt64(integer);
@@ -949,7 +980,7 @@ MmsValue_cloneToBuffer(MmsValue* self, uint8_t* destinationAddress)
MmsValue*
MmsValue_clone(MmsValue* value)
{
- MmsValue* newValue = (MmsValue*) calloc(1, sizeof(MmsValue));
+ MmsValue* newValue = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
newValue->deleteValue = value->deleteValue;
newValue->type = value->type;
int size;
@@ -961,7 +992,7 @@ MmsValue_clone(MmsValue* value)
{
int componentCount = value->value.structure.size;
newValue->value.structure.size = componentCount;
- newValue->value.structure.components = (MmsValue**) calloc(componentCount, sizeof(MmsValue*));
+ newValue->value.structure.components = (MmsValue**) GLOBAL_CALLOC(componentCount, sizeof(MmsValue*));
int i;
for (i = 0; i < componentCount; i++) {
newValue->value.structure.components[i] =
@@ -978,13 +1009,13 @@ MmsValue_clone(MmsValue* value)
newValue->value.floatingPoint.formatWidth = value->value.floatingPoint.formatWidth;
newValue->value.floatingPoint.exponentWidth = value->value.floatingPoint.exponentWidth;
size = value->value.floatingPoint.formatWidth / 8;
- newValue->value.floatingPoint.buf = (uint8_t*) malloc(size);
+ newValue->value.floatingPoint.buf = (uint8_t*) GLOBAL_MALLOC(size);
memcpy(newValue->value.floatingPoint.buf, value->value.floatingPoint.buf, size);
break;
case MMS_BIT_STRING:
newValue->value.bitString.size = value->value.bitString.size;
size = bitStringByteSize(value);
- newValue->value.bitString.buf = (uint8_t*) malloc(size);
+ newValue->value.bitString.buf = (uint8_t*) GLOBAL_MALLOC(size);
memcpy(newValue->value.bitString.buf, value->value.bitString.buf, size);
break;
case MMS_BOOLEAN:
@@ -994,7 +1025,7 @@ MmsValue_clone(MmsValue* value)
size = value->value.octetString.size;
newValue->value.octetString.size = size;
newValue->value.octetString.maxSize = value->value.octetString.maxSize;
- newValue->value.octetString.buf = (uint8_t*) malloc(value->value.octetString.maxSize);
+ newValue->value.octetString.buf = (uint8_t*) GLOBAL_MALLOC(value->value.octetString.maxSize);
memcpy(newValue->value.octetString.buf, value->value.octetString.buf, size);
break;
case MMS_UTC_TIME:
@@ -1007,7 +1038,7 @@ MmsValue_clone(MmsValue* value)
case MMS_VISIBLE_STRING:
case MMS_STRING:
size = value->value.visibleString.size;
- newValue->value.visibleString.buf = (char*) malloc(size + 1);
+ newValue->value.visibleString.buf = (char*) GLOBAL_MALLOC(size + 1);
newValue->value.visibleString.size = size;
strcpy(newValue->value.visibleString.buf, value->value.visibleString.buf);
break;
@@ -1043,18 +1074,18 @@ MmsValue_delete(MmsValue* value)
Asn1PrimitiveValue_destroy(value->value.integer);
break;
case MMS_FLOAT:
- free(value->value.floatingPoint.buf);
+ GLOBAL_FREEMEM(value->value.floatingPoint.buf);
break;
case MMS_BIT_STRING:
- free(value->value.bitString.buf);
+ GLOBAL_FREEMEM(value->value.bitString.buf);
break;
case MMS_OCTET_STRING:
- free(value->value.octetString.buf);
+ GLOBAL_FREEMEM(value->value.octetString.buf);
break;
case MMS_VISIBLE_STRING:
case MMS_STRING:
if (value->value.visibleString.buf != NULL)
- free(value->value.visibleString.buf);
+ GLOBAL_FREEMEM(value->value.visibleString.buf);
break;
case MMS_ARRAY:
case MMS_STRUCTURE:
@@ -1067,13 +1098,13 @@ MmsValue_delete(MmsValue* value)
MmsValue_delete(value->value.structure.components[i]);
}
}
- free(value->value.structure.components);
+ GLOBAL_FREEMEM(value->value.structure.components);
break;
default:
break;
}
- free(value);
+ GLOBAL_FREEMEM(value);
}
/* delete only when deleteValue field set */
@@ -1088,18 +1119,18 @@ MmsValue_deleteConditional(MmsValue* value)
Asn1PrimitiveValue_destroy(value->value.integer);
break;
case MMS_FLOAT:
- free(value->value.floatingPoint.buf);
+ GLOBAL_FREEMEM(value->value.floatingPoint.buf);
break;
case MMS_BIT_STRING:
- free(value->value.bitString.buf);
+ GLOBAL_FREEMEM(value->value.bitString.buf);
break;
case MMS_OCTET_STRING:
- free(value->value.octetString.buf);
+ GLOBAL_FREEMEM(value->value.octetString.buf);
break;
case MMS_VISIBLE_STRING:
case MMS_STRING:
if (value->value.visibleString.buf != NULL)
- free(value->value.visibleString.buf);
+ GLOBAL_FREEMEM(value->value.visibleString.buf);
break;
case MMS_ARRAY:
case MMS_STRUCTURE:
@@ -1112,20 +1143,20 @@ MmsValue_deleteConditional(MmsValue* value)
MmsValue_deleteConditional(value->value.structure.components[i]);
}
}
- free(value->value.structure.components);
+ GLOBAL_FREEMEM(value->value.structure.components);
break;
default:
break;
}
- free(value);
+ GLOBAL_FREEMEM(value);
}
}
MmsValue*
MmsValue_newInteger(int size /*integer size in bits*/)
{
- MmsValue* value = (MmsValue*) calloc(1, sizeof(MmsValue));
+ MmsValue* value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
value->type = MMS_INTEGER;
if (size <= 32)
@@ -1139,7 +1170,7 @@ MmsValue_newInteger(int size /*integer size in bits*/)
MmsValue*
MmsValue_newUnsigned(int size /*integer size in bits*/)
{
- MmsValue* value = (MmsValue*) calloc(1, sizeof(MmsValue));
+ MmsValue* value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
value->type = MMS_UNSIGNED;
if (size <= 32)
@@ -1153,7 +1184,7 @@ MmsValue_newUnsigned(int size /*integer size in bits*/)
MmsValue*
MmsValue_newBoolean(bool boolean)
{
- MmsValue* self = (MmsValue*) calloc(1, sizeof(MmsValue));
+ MmsValue* self = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
self->type = MMS_BOOLEAN;
if (boolean == true)
self->value.boolean = 1;
@@ -1166,11 +1197,11 @@ MmsValue_newBoolean(bool boolean)
MmsValue*
MmsValue_newOctetString(int size, int maxSize)
{
- MmsValue* self = (MmsValue*) calloc(1, sizeof(MmsValue));
+ MmsValue* self = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
self->type = MMS_OCTET_STRING;
self->value.octetString.size = size;
self->value.octetString.maxSize = maxSize;
- self->value.octetString.buf = (uint8_t*) calloc(1, maxSize);
+ self->value.octetString.buf = (uint8_t*) GLOBAL_CALLOC(1, maxSize);
return self;
}
@@ -1205,12 +1236,12 @@ MmsValue_getOctetStringBuffer(MmsValue* self)
MmsValue*
MmsValue_newStructure(MmsVariableSpecification* typeSpec)
{
- MmsValue* self = (MmsValue*) calloc(1, sizeof(MmsValue));
+ MmsValue* self = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
self->type = MMS_STRUCTURE;
int componentCount = typeSpec->typeSpec.structure.elementCount;
self->value.structure.size = componentCount;
- self->value.structure.components = (MmsValue**) calloc(componentCount, sizeof(MmsValue*));
+ self->value.structure.components = (MmsValue**) GLOBAL_CALLOC(componentCount, sizeof(MmsValue*));
int i;
for (i = 0; i < componentCount; i++) {
@@ -1234,24 +1265,24 @@ MmsValue_newDefaultValue(MmsVariableSpecification* typeSpec)
value = MmsValue_newUnsigned(typeSpec->typeSpec.unsignedInteger);
break;
case MMS_FLOAT:
- value = (MmsValue*) calloc(1, sizeof(MmsValue));
+ value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
value->type = MMS_FLOAT;
value->value.floatingPoint.exponentWidth = typeSpec->typeSpec.floatingpoint.exponentWidth;
value->value.floatingPoint.formatWidth = typeSpec->typeSpec.floatingpoint.formatWidth;
- value->value.floatingPoint.buf = (uint8_t*) calloc(1, typeSpec->typeSpec.floatingpoint.formatWidth / 8);
+ value->value.floatingPoint.buf = (uint8_t*) GLOBAL_CALLOC(1, typeSpec->typeSpec.floatingpoint.formatWidth / 8);
break;
case MMS_BIT_STRING:
- value = (MmsValue*) calloc(1, sizeof(MmsValue));
+ value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
value->type = MMS_BIT_STRING;
{
int bitSize = abs(typeSpec->typeSpec.bitString);
value->value.bitString.size = bitSize;
int size = (bitSize / 8) + ((bitSize % 8) > 0);
- value->value.bitString.buf = (uint8_t*) calloc(1, size);
+ value->value.bitString.buf = (uint8_t*) GLOBAL_CALLOC(1, size);
}
break;
case MMS_OCTET_STRING:
- value = (MmsValue*) calloc(1, sizeof(MmsValue));
+ value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
value->type = MMS_OCTET_STRING;
if (typeSpec->typeSpec.octetString < 0)
@@ -1260,7 +1291,7 @@ MmsValue_newDefaultValue(MmsVariableSpecification* typeSpec)
value->value.octetString.size = typeSpec->typeSpec.octetString;
value->value.octetString.maxSize = abs(typeSpec->typeSpec.octetString);
- value->value.octetString.buf = (uint8_t*) calloc(1, abs(typeSpec->typeSpec.octetString));
+ value->value.octetString.buf = (uint8_t*) GLOBAL_CALLOC(1, abs(typeSpec->typeSpec.octetString));
break;
case MMS_VISIBLE_STRING:
value = MmsValue_newVisibleStringWithSize(abs(typeSpec->typeSpec.visibleString));
@@ -1269,7 +1300,7 @@ MmsValue_newDefaultValue(MmsVariableSpecification* typeSpec)
value = MmsValue_newBoolean(false);
break;
case MMS_UTC_TIME:
- value = (MmsValue*) calloc(1, sizeof(MmsValue));
+ value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
value->type = MMS_UTC_TIME;
break;
case MMS_ARRAY:
@@ -1307,8 +1338,8 @@ setVisibleStringValue(MmsValue* value, char* string)
int newStringSize = strlen(string);
if (newStringSize > value->value.visibleString.size) {
- free(value->value.visibleString.buf);
- value->value.visibleString.buf = (char*) malloc(newStringSize + 1);
+ GLOBAL_FREEMEM(value->value.visibleString.buf);
+ value->value.visibleString.buf = (char*) GLOBAL_MALLOC(newStringSize + 1);
value->value.visibleString.size = newStringSize;
}
@@ -1323,7 +1354,7 @@ setVisibleStringValue(MmsValue* value, char* string)
static MmsValue*
MmsValue_newString(char* string, MmsType type)
{
- MmsValue* value = (MmsValue*) calloc(1, sizeof(MmsValue));
+ MmsValue* value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
value->type = type;
if (string == NULL) {
@@ -1334,7 +1365,7 @@ MmsValue_newString(char* string, MmsType type)
int stringSize = strlen(string);
value->value.visibleString.size = stringSize;
- value->value.visibleString.buf = (char*) malloc(stringSize + 1);
+ value->value.visibleString.buf = (char*) GLOBAL_MALLOC(stringSize + 1);
setVisibleStringValue(value, string);
}
@@ -1352,11 +1383,11 @@ MmsValue_newVisibleString(char* string)
static MmsValue*
MmsValue_newStringWithSize(int size, MmsType type)
{
- MmsValue* value = (MmsValue*) calloc(1, sizeof(MmsValue));
+ MmsValue* value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
value->type = type;
value->value.visibleString.size = size;
- value->value.visibleString.buf = (char*) malloc(size + 1);
+ value->value.visibleString.buf = (char*) GLOBAL_MALLOC(size + 1);
value->value.visibleString.buf[0] = 0;
return value;
@@ -1384,7 +1415,7 @@ MmsValue_newMmsStringWithSize(int size)
MmsValue*
MmsValue_newBinaryTime(bool timeOfDay)
{
- MmsValue* value = (MmsValue*) calloc(1, sizeof(MmsValue));
+ MmsValue* value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
value->type = MMS_BINARY_TIME;
if (timeOfDay == true)
@@ -1485,7 +1516,7 @@ MmsValue_setMmsString(MmsValue* value, char* string)
static MmsValue*
MmsValue_newStringFromByteArray(uint8_t* byteArray, int size, MmsType type)
{
- MmsValue* value = (MmsValue*) calloc(1, sizeof(MmsValue));
+ MmsValue* value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
value->type = type;
value->value.visibleString.buf = createStringFromBuffer(byteArray, size);
@@ -1528,7 +1559,7 @@ MmsValue_toString(MmsValue* value)
MmsValue*
MmsValue_newUtcTime(uint32_t timeval)
{
- MmsValue* value = (MmsValue*) calloc(1, sizeof(MmsValue));
+ MmsValue* value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
value->type = MMS_UTC_TIME;
uint8_t* timeArray = (uint8_t*) &timeval;
@@ -1553,7 +1584,7 @@ MmsValue_newUtcTime(uint32_t timeval)
MmsValue*
MmsValue_newUtcTimeByMsTime(uint64_t timeval)
{
- MmsValue* value = (MmsValue*) calloc(1, sizeof(MmsValue));
+ MmsValue* value = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
value->type = MMS_UTC_TIME;
MmsValue_setUtcTimeMs(value, timeval);
@@ -1564,11 +1595,11 @@ MmsValue_newUtcTimeByMsTime(uint64_t timeval)
MmsValue*
MmsValue_createArray(MmsVariableSpecification* elementType, int size)
{
- MmsValue* array = (MmsValue*) calloc(1, sizeof(MmsValue));
+ MmsValue* array = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
array->type = MMS_ARRAY;
array->value.structure.size = size;
- array->value.structure.components = (MmsValue**) calloc(size, sizeof(MmsValue*));
+ array->value.structure.components = (MmsValue**) GLOBAL_CALLOC(size, sizeof(MmsValue*));
int i;
for (i = 0; i < size; i++) {
@@ -1581,11 +1612,11 @@ MmsValue_createArray(MmsVariableSpecification* elementType, int size)
MmsValue*
MmsValue_createEmtpyArray(int size)
{
- MmsValue* array = (MmsValue*) calloc(1, sizeof(MmsValue));
+ MmsValue* array = (MmsValue*) GLOBAL_CALLOC(1, sizeof(MmsValue));
array->type = MMS_ARRAY;
array->value.structure.size = size;
- array->value.structure.components = (MmsValue**) calloc(size, sizeof(MmsValue*));
+ array->value.structure.components = (MmsValue**) GLOBAL_CALLOC(size, sizeof(MmsValue*));
int i;
for (i = 0; i < size; i++) {
diff --git a/src/mms/iso_mms/server/mms_device.c b/src/mms/iso_mms/server/mms_device.c
index 53d15732..f071a63f 100644
--- a/src/mms/iso_mms/server/mms_device.c
+++ b/src/mms/iso_mms/server/mms_device.c
@@ -21,13 +21,14 @@
* See COPYING file for the complete license text.
*/
+#include "mms_server_internal.h"
#include "mms_device_model.h"
#include "stack_config.h"
MmsDevice*
MmsDevice_create(char* deviceName)
{
- MmsDevice* self = (MmsDevice*) calloc(1, sizeof(MmsDevice));
+ MmsDevice* self = (MmsDevice*) GLOBAL_CALLOC(1, sizeof(MmsDevice));
self->deviceName = deviceName;
self->namedVariableLists = LinkedList_create();
@@ -56,8 +57,8 @@ MmsDevice_destroy(MmsDevice* self)
LinkedList_destroyDeep(self->namedVariableLists, (LinkedListValueDeleteFunction) MmsNamedVariableList_destroy);
- free(self->domains);
- free(self);
+ GLOBAL_FREEMEM(self->domains);
+ GLOBAL_FREEMEM(self);
}
MmsDomain*
diff --git a/src/mms/iso_mms/server/mms_domain.c b/src/mms/iso_mms/server/mms_domain.c
index 3ec82e2c..7d07dc39 100644
--- a/src/mms/iso_mms/server/mms_domain.c
+++ b/src/mms/iso_mms/server/mms_domain.c
@@ -3,22 +3,22 @@
*
* Copyright 2013, 2014 Michael Zillgith
*
- * This file is part of libIEC61850.
+ * 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 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.
+ * 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 .
+ * 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.
+ * See COPYING file for the complete license text.
*/
#include "mms_device_model.h"
@@ -36,7 +36,7 @@ freeNamedVariables(MmsVariableSpecification** variables, int variablesCount)
MmsDomain*
MmsDomain_create(char* domainName)
{
- MmsDomain* self = (MmsDomain*) calloc(1, sizeof(MmsDomain));
+ MmsDomain* self = (MmsDomain*) GLOBAL_CALLOC(1, sizeof(MmsDomain));
self->domainName = copyString(domainName);
self->namedVariableLists = LinkedList_create();
@@ -47,18 +47,18 @@ MmsDomain_create(char* domainName)
void
MmsDomain_destroy(MmsDomain* self)
{
- free(self->domainName);
+ GLOBAL_FREEMEM(self->domainName);
if (self->namedVariables != NULL) {
freeNamedVariables(self->namedVariables,
self->namedVariablesCount);
- free(self->namedVariables);
+ GLOBAL_FREEMEM(self->namedVariables);
}
LinkedList_destroyDeep(self->namedVariableLists, (LinkedListValueDeleteFunction) MmsNamedVariableList_destroy);
- free(self);
+ GLOBAL_FREEMEM(self);
}
char*
@@ -70,8 +70,6 @@ MmsDomain_getName(MmsDomain* self)
bool
MmsDomain_addNamedVariableList(MmsDomain* self, MmsNamedVariableList variableList)
{
- //TODO check if operation is allowed!
-
LinkedList_add(self->namedVariableLists, variableList);
return true;
diff --git a/src/mms/iso_mms/server/mms_file_service.c b/src/mms/iso_mms/server/mms_file_service.c
index a2af0378..ce1833df 100644
--- a/src/mms/iso_mms/server/mms_file_service.c
+++ b/src/mms/iso_mms/server/mms_file_service.c
@@ -25,7 +25,7 @@
#if (MMS_FILE_SERVICE == 1)
-#include "filesystem.h"
+#include "hal_filesystem.h"
#include "conversions.h"
#define CONFIG_MMS_FILE_SERVICE_MAX_FILENAME_LENGTH 256
diff --git a/src/mms/iso_mms/server/mms_get_namelist_service.c b/src/mms/iso_mms/server/mms_get_namelist_service.c
index 31d6600e..a6c5b37a 100644
--- a/src/mms/iso_mms/server/mms_get_namelist_service.c
+++ b/src/mms/iso_mms/server/mms_get_namelist_service.c
@@ -84,7 +84,7 @@ appendMmsSubVariable(char* name, char* child)
int newSize = nameLen + childLen + 2;
- char* newName = (char*) malloc(newSize);
+ char* newName = (char*) GLOBAL_MALLOC(newSize);
int bufPos = 0;
int i;
diff --git a/src/mms/iso_mms/server/mms_get_var_access_service.c b/src/mms/iso_mms/server/mms_get_var_access_service.c
index 97d3d81e..92201944 100644
--- a/src/mms/iso_mms/server/mms_get_var_access_service.c
+++ b/src/mms/iso_mms/server/mms_get_var_access_service.c
@@ -42,7 +42,7 @@ createTypeSpecification (
(long) namedVariable->typeSpec.array.elementCount);
typeSpec->choice.array.packed = NULL;
- typeSpec->choice.array.elementType = (TypeSpecification_t*) calloc(1, sizeof(TypeSpecification_t));
+ typeSpec->choice.array.elementType = (TypeSpecification_t*) GLOBAL_CALLOC(1, sizeof(TypeSpecification_t));
createTypeSpecification(namedVariable->typeSpec.array.elementTypeSpec,
typeSpec->choice.array.elementType);
@@ -57,17 +57,17 @@ createTypeSpecification (
typeSpec->choice.structure.components.list.size = componentCount;
typeSpec->choice.structure.components.list.array
- = (StructComponent_t**) calloc(componentCount, sizeof(StructComponent_t*));
+ = (StructComponent_t**) GLOBAL_CALLOC(componentCount, sizeof(StructComponent_t*));
int i;
for (i = 0; i < componentCount; i++) {
typeSpec->choice.structure.components.list.array[i] =
- (StructComponent_t*) calloc(1, sizeof(StructComponent_t));
+ (StructComponent_t*) GLOBAL_CALLOC(1, sizeof(StructComponent_t));
typeSpec->choice.structure.components.list.array[i]->componentName =
- (Identifier_t*) calloc(1, sizeof(Identifier_t));
+ (Identifier_t*) GLOBAL_CALLOC(1, sizeof(Identifier_t));
typeSpec->choice.structure.components.list.array[i]->componentName->buf =
(uint8_t*) copyString(namedVariable->typeSpec.structure.elements[i]->name);
@@ -76,7 +76,7 @@ createTypeSpecification (
strlen(namedVariable->typeSpec.structure.elements[i]->name);
typeSpec->choice.structure.components.list.array[i]->componentType =
- (TypeSpecification_t*) calloc(1, sizeof(TypeSpecification_t));
+ (TypeSpecification_t*) GLOBAL_CALLOC(1, sizeof(TypeSpecification_t));
createTypeSpecification(namedVariable->typeSpec.structure.elements[i],
typeSpec->choice.structure.components.list.array[i]->componentType);
@@ -151,19 +151,19 @@ freeTypeSpecRecursive(TypeSpecification_t* typeSpec) {
int i;
for (i = 0; i < elementCount; i++) {
- free(typeSpec->choice.structure.components.list.array[i]->componentName->buf);
- free(typeSpec->choice.structure.components.list.array[i]->componentName);
+ GLOBAL_FREEMEM(typeSpec->choice.structure.components.list.array[i]->componentName->buf);
+ GLOBAL_FREEMEM(typeSpec->choice.structure.components.list.array[i]->componentName);
freeTypeSpecRecursive(typeSpec->choice.structure.components.list.array[i]->componentType);
- free(typeSpec->choice.structure.components.list.array[i]->componentType);
- free(typeSpec->choice.structure.components.list.array[i]);
+ GLOBAL_FREEMEM(typeSpec->choice.structure.components.list.array[i]->componentType);
+ GLOBAL_FREEMEM(typeSpec->choice.structure.components.list.array[i]);
}
- free(typeSpec->choice.structure.components.list.array);
+ GLOBAL_FREEMEM(typeSpec->choice.structure.components.list.array);
}
else if (typeSpec->present == TypeSpecification_PR_array) {
- free(typeSpec->choice.array.numberOfElements.buf);
+ GLOBAL_FREEMEM(typeSpec->choice.array.numberOfElements.buf);
freeTypeSpecRecursive(typeSpec->choice.array.elementType);
- free(typeSpec->choice.array.elementType);
+ GLOBAL_FREEMEM(typeSpec->choice.array.elementType);
}
}
@@ -176,27 +176,27 @@ deleteVariableAccessAttributesResponse(
int i;
for (i = 0; i < count; i++) {
- free(getVarAccessAttr->typeSpecification.choice.structure.components.list.array[i]->componentName->buf);
- free(getVarAccessAttr->typeSpecification.choice.structure.components.list.array[i]->componentName);
+ GLOBAL_FREEMEM(getVarAccessAttr->typeSpecification.choice.structure.components.list.array[i]->componentName->buf);
+ GLOBAL_FREEMEM(getVarAccessAttr->typeSpecification.choice.structure.components.list.array[i]->componentName);
TypeSpecification_t* typeSpec =
getVarAccessAttr->typeSpecification.choice.structure.components.list.array[i]->componentType;
freeTypeSpecRecursive(typeSpec);
- free(typeSpec);
- free(getVarAccessAttr->typeSpecification.choice.structure.components.list.array[i]);
+ GLOBAL_FREEMEM(typeSpec);
+ GLOBAL_FREEMEM(getVarAccessAttr->typeSpecification.choice.structure.components.list.array[i]);
}
- free(getVarAccessAttr->typeSpecification.choice.structure.components.list.array);
+ GLOBAL_FREEMEM(getVarAccessAttr->typeSpecification.choice.structure.components.list.array);
getVarAccessAttr->typeSpecification.choice.structure.components.list.array = NULL;
getVarAccessAttr->typeSpecification.choice.structure.components.list.count = 0;
getVarAccessAttr->typeSpecification.choice.structure.components.list.size = 0;
} else if (getVarAccessAttr->typeSpecification.present == TypeSpecification_PR_array) {
- free(getVarAccessAttr->typeSpecification.choice.array.numberOfElements.buf);
+ GLOBAL_FREEMEM(getVarAccessAttr->typeSpecification.choice.array.numberOfElements.buf);
getVarAccessAttr->typeSpecification.choice.array.numberOfElements.buf = NULL;
getVarAccessAttr->typeSpecification.choice.array.numberOfElements.size = 0;
freeTypeSpecRecursive(getVarAccessAttr->typeSpecification.choice.array.elementType);
- free(getVarAccessAttr->typeSpecification.choice.array.elementType);
+ GLOBAL_FREEMEM(getVarAccessAttr->typeSpecification.choice.array.elementType);
getVarAccessAttr->typeSpecification.choice.array.elementType = NULL;
}
@@ -301,8 +301,8 @@ mmsServer_handleGetVariableAccessAttributesRequest(
createVariableAccessAttributesResponse(connection, domainIdStr, nameIdStr, invokeId, response);
- free(domainIdStr);
- free(nameIdStr);
+ GLOBAL_FREEMEM(domainIdStr);
+ GLOBAL_FREEMEM(nameIdStr);
}
#if (CONFIG_MMS_SUPPORT_VMD_SCOPE_NAMED_VARIABLES == 1)
else if (request->choice.name.present == ObjectName_PR_vmdspecific) {
@@ -314,7 +314,7 @@ mmsServer_handleGetVariableAccessAttributesRequest(
createVariableAccessAttributesResponse(connection, NULL, nameIdStr, invokeId, response);
- free(nameIdStr);
+ GLOBAL_FREEMEM(nameIdStr);
}
#endif /* (CONFIG_MMS_SUPPORT_VMD_SCOPE_NAMED_VARIABLES == 1) */
else {
diff --git a/src/mms/iso_mms/server/mms_information_report.c b/src/mms/iso_mms/server/mms_information_report.c
index 2349df73..4380d727 100644
--- a/src/mms/iso_mms/server/mms_information_report.c
+++ b/src/mms/iso_mms/server/mms_information_report.c
@@ -97,19 +97,18 @@ MmsServerConnection_sendInformationReportListOfVariables(
uint32_t varSpecSize = BerEncoder_determineEncodedStringSize(spec->itemId);
- if (spec->domainId != NULL) {
+ if (spec->domainId != NULL)
varSpecSize += BerEncoder_determineEncodedStringSize(spec->domainId);
- varSpecSize += BerEncoder_determineLengthSize(varSpecSize) + 1;
- }
- listOfVarSpecSize += varSpecSize;
+ uint32_t sequenceSize = (varSpecSize + 1 + BerEncoder_determineLengthSize(varSpecSize));
+
+ listOfVarSpecSize += (1 + BerEncoder_determineLengthSize(sequenceSize) + sequenceSize);
i++;
specElement = LinkedList_getNext(specElement);
}
- uint32_t sequenceSize = 1 + BerEncoder_determineLengthSize(listOfVarSpecSize) + listOfVarSpecSize;
- uint32_t listOfVariableSize = 1 + BerEncoder_determineLengthSize(sequenceSize) + sequenceSize;
+ uint32_t listOfVariableSize = 1 + BerEncoder_determineLengthSize(listOfVarSpecSize) + listOfVarSpecSize;
uint32_t accessResultSize = 0;
@@ -146,7 +145,7 @@ MmsServerConnection_sendInformationReportListOfVariables(
/* encode list of variable access specifications */
bufPos = BerEncoder_encodeTL(0xa0, listOfVariableSize, buffer, bufPos);
- bufPos = BerEncoder_encodeTL(0x30, sequenceSize, buffer, bufPos);
+
specElement = LinkedList_getNext(variableAccessDeclarations);
i = 0;
@@ -160,13 +159,17 @@ MmsServerConnection_sendInformationReportListOfVariables(
varSpecSize += BerEncoder_determineEncodedStringSize(spec->domainId);
uint32_t varSpecSizeComplete = varSpecSize + BerEncoder_determineLengthSize(varSpecSize) + 1;
+ uint32_t sequenceSize = varSpecSizeComplete + BerEncoder_determineLengthSize(varSpecSizeComplete) + 1;
+ bufPos = BerEncoder_encodeTL(0x30, sequenceSize, buffer, bufPos);
bufPos = BerEncoder_encodeTL(0xa0, varSpecSizeComplete, buffer, bufPos); /* domain-specific */
bufPos = BerEncoder_encodeTL(0xa1, varSpecSize, buffer, bufPos);
bufPos = BerEncoder_encodeStringWithTag(0x1a, spec->domainId, buffer, bufPos);
bufPos = BerEncoder_encodeStringWithTag(0x1a, spec->itemId, buffer, bufPos);
}
else {
+ uint32_t sequenceSize = varSpecSize + BerEncoder_determineLengthSize(varSpecSize) + 1;
+ bufPos = BerEncoder_encodeTL(0x30, sequenceSize, buffer, bufPos);
bufPos = BerEncoder_encodeTL(0xa0, varSpecSize, buffer, bufPos); /* vmd-specific */
bufPos = BerEncoder_encodeStringWithTag(0x80, spec->itemId, buffer, bufPos);
}
diff --git a/src/mms/iso_mms/server/mms_named_variable_list.c b/src/mms/iso_mms/server/mms_named_variable_list.c
index bd318301..9fe16a9c 100644
--- a/src/mms/iso_mms/server/mms_named_variable_list.c
+++ b/src/mms/iso_mms/server/mms_named_variable_list.c
@@ -28,7 +28,7 @@
MmsNamedVariableListEntry
MmsNamedVariableListEntry_create(MmsAccessSpecifier accessSpecifier)
{
- MmsNamedVariableListEntry listEntry = (MmsNamedVariableListEntry) malloc(sizeof(MmsAccessSpecifier));
+ MmsNamedVariableListEntry listEntry = (MmsNamedVariableListEntry) GLOBAL_MALLOC(sizeof(MmsAccessSpecifier));
listEntry->domain = accessSpecifier.domain;
listEntry->variableName = copyString(accessSpecifier.variableName);
@@ -45,8 +45,8 @@ MmsNamedVariableListEntry_create(MmsAccessSpecifier accessSpecifier)
void
MmsNamedVariableListEntry_destroy(MmsNamedVariableListEntry self)
{
- free(self->variableName);
- free(self);
+ GLOBAL_FREEMEM(self->variableName);
+ GLOBAL_FREEMEM(self);
}
@@ -64,7 +64,7 @@ MmsNamedVariableListEntry_getVariableName(MmsNamedVariableListEntry self) {
MmsNamedVariableList
MmsNamedVariableList_create(char* name, bool deletable)
{
- MmsNamedVariableList self = (MmsNamedVariableList) malloc(sizeof(struct sMmsNamedVariableList));
+ MmsNamedVariableList self = (MmsNamedVariableList) GLOBAL_MALLOC(sizeof(struct sMmsNamedVariableList));
self->deletable = deletable;
self->name = copyString(name);
@@ -108,8 +108,8 @@ void
MmsNamedVariableList_destroy(MmsNamedVariableList self)
{
LinkedList_destroyDeep(self->listOfVariables, deleteVariableListEntry);
- free(self->name);
- free(self);
+ GLOBAL_FREEMEM(self->name);
+ GLOBAL_FREEMEM(self);
}
diff --git a/src/mms/iso_mms/server/mms_named_variable_list_service.c b/src/mms/iso_mms/server/mms_named_variable_list_service.c
index 61d7ebd1..e12a3c07 100644
--- a/src/mms/iso_mms/server/mms_named_variable_list_service.c
+++ b/src/mms/iso_mms/server/mms_named_variable_list_service.c
@@ -1,7 +1,7 @@
/*
* mms_named_variable_list_service.c
*
- * Copyright 2013 Michael Zillgith
+ * Copyright 2013, 2014 Michael Zillgith
*
* This file is part of libIEC61850.
*
@@ -29,8 +29,20 @@
#if (MMS_DATA_SET_SERVICE == 1)
-
#if (MMS_DYNAMIC_DATA_SETS == 1)
+
+#ifndef CONFIG_MMS_MAX_NUMBER_OF_DOMAIN_SPECIFIC_DATA_SETS
+#define CONFIG_MMS_MAX_NUMBER_OF_DOMAIN_SPECIFIC_DATA_SETS 10
+#endif
+
+#ifndef CONFIG_MMS_MAX_NUMBER_OF_ASSOCIATION_SPECIFIC_DATA_SETS
+#define CONFIG_MMS_MAX_NUMBER_OF_ASSOCIATION_SPECIFIC_DATA_SETS 10
+#endif
+
+#ifndef CONFIG_MMS_MAX_NUMBER_OF_VMD_SPECIFIC_DATA_SETS
+#define CONFIG_MMS_MAX_NUMBER_OF_VMD_SPECIFIC_DATA_SETS 10
+#endif
+
static void
createDeleteNamedVariableListResponse(uint32_t invokeId, ByteBuffer* response,
uint32_t numberMatched, uint32_t numberDeleted)
@@ -134,9 +146,8 @@ mmsServer_handleDeleteNamedVariableListRequest(MmsServerConnection* connection,
MmsServerConnection_deleteNamedVariableList(connection, itemId);
}
- free(itemId);
+ GLOBAL_FREEMEM(itemId);
}
- //TODO else send error???
}
createDeleteNamedVariableListResponse(invokeId, response, numberMatched, numberDeleted);
@@ -168,10 +179,39 @@ createDefineNamedVariableListResponse(uint32_t invokeId, ByteBuffer* response)
response->size = bufPos;
}
+static bool
+checkIfVariableExists(MmsDevice* device, MmsAccessSpecifier* accessSpecifier)
+{
+ if (accessSpecifier->domain == NULL)
+ return false;
+
+ MmsVariableSpecification* variableSpec =
+ MmsDomain_getNamedVariable(accessSpecifier->domain, accessSpecifier->variableName);
+
+ if (variableSpec == NULL)
+ return false;
+
+ if (accessSpecifier->arrayIndex != -1) {
+ if (variableSpec->type != MMS_ARRAY)
+ return false;
+
+ if (accessSpecifier->arrayIndex >= variableSpec->typeSpec.array.elementCount)
+ return false;
+
+ if (accessSpecifier->componentName != NULL) {
+ if (MmsVariableSpecification_getNamedVariableRecursive(variableSpec, accessSpecifier->componentName) == NULL)
+ return false;
+ }
+ }
+
+ return true;
+}
+
+
static MmsNamedVariableList
createNamedVariableList(MmsDevice* device,
DefineNamedVariableListRequest_t* request,
- char* variableListName)
+ char* variableListName, MmsError* mmsError)
{
MmsNamedVariableList namedVariableList = MmsNamedVariableList_create(variableListName, true);
@@ -199,10 +239,11 @@ createNamedVariableList(MmsDevice* device,
struct AlternateAccess__Member* alternateAccess =
request->listOfVariable.list.array[i]->alternateAccess->list.array[0];
- if (alternateAccess->present == AlternateAccess__Member_PR_unnamed)
+ if ((alternateAccess->present == AlternateAccess__Member_PR_unnamed)
+ &&(alternateAccess->choice.unnamed->present == AlternateAccessSelection_PR_selectAlternateAccess)
+ && (alternateAccess->choice.unnamed->choice.selectAlternateAccess.accessSelection.present ==
+ AlternateAccessSelection__selectAlternateAccess__accessSelection_PR_index))
{
- //TODO add checks!
-
asn_INTEGER2long(&(alternateAccess->choice.unnamed->choice.selectAlternateAccess.accessSelection.choice.index),
&arrayIndex);
@@ -215,6 +256,7 @@ createNamedVariableList(MmsDevice* device,
else {
MmsNamedVariableList_destroy(namedVariableList);
namedVariableList = NULL;
+ *mmsError = MMS_ERROR_DEFINITION_INVALID_ADDRESS;
break;
}
@@ -240,17 +282,28 @@ createNamedVariableList(MmsDevice* device,
accessSpecifier.arrayIndex = arrayIndex;
accessSpecifier.componentName = componentName;
- MmsNamedVariableListEntry variable =
- MmsNamedVariableListEntry_create(accessSpecifier);
+ // check if element exists
+ if (checkIfVariableExists(device, &accessSpecifier) == true) {
- MmsNamedVariableList_addVariable(namedVariableList, variable);
+ MmsNamedVariableListEntry variable =
+ MmsNamedVariableListEntry_create(accessSpecifier);
- free(domainId);
- free(variableName);
+ MmsNamedVariableList_addVariable(namedVariableList, variable);
+ }
+ else {
+ MmsNamedVariableList_destroy(namedVariableList);
+ namedVariableList = NULL;
+ i = variableCount; // exit loop after freeing loop variables
+ *mmsError = MMS_ERROR_DEFINITION_OBJECT_UNDEFINED;
+ }
+
+ GLOBAL_FREEMEM(domainId);
+ GLOBAL_FREEMEM(variableName);
}
else {
MmsNamedVariableList_destroy(namedVariableList);
namedVariableList = NULL;
+ *mmsError = MMS_ERROR_DEFINITION_INVALID_ADDRESS;
break;
}
}
@@ -286,60 +339,75 @@ mmsServer_handleDefineNamedVariableListRequest(
MmsDomain* domain = MmsDevice_getDomain(device, domainName);
- free(domainName);
+ GLOBAL_FREEMEM(domainName);
if (domain == NULL) {
mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT);
return;
}
- char* variableListName = createStringFromBuffer(
- request->variableListName.choice.domainspecific.itemId.buf,
- request->variableListName.choice.domainspecific.itemId.size);
+ if (LinkedList_size(domain->namedVariableLists) < CONFIG_MMS_MAX_NUMBER_OF_DOMAIN_SPECIFIC_DATA_SETS) {
+ char* variableListName = createStringFromBuffer(
+ request->variableListName.choice.domainspecific.itemId.buf,
+ request->variableListName.choice.domainspecific.itemId.size);
- if (MmsDomain_getNamedVariableList(domain, variableListName) != NULL) {
- mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_DEFINITION_OBJECT_EXISTS);
- }
- else {
- MmsNamedVariableList namedVariableList = createNamedVariableList(device,
- request, variableListName);
-
- if (namedVariableList != NULL) {
- MmsDomain_addNamedVariableList(domain, namedVariableList);
- createDefineNamedVariableListResponse(invokeId, response);
- }
- else
- mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_ACCESS_UNSUPPORTED);
+ if (MmsDomain_getNamedVariableList(domain, variableListName) != NULL) {
+ mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_DEFINITION_OBJECT_EXISTS);
+ }
+ else {
+ MmsError mmsError;
+
+ MmsNamedVariableList namedVariableList = createNamedVariableList(device,
+ request, variableListName, &mmsError);
+
+ if (namedVariableList != NULL) {
+ MmsDomain_addNamedVariableList(domain, namedVariableList);
+ createDefineNamedVariableListResponse(invokeId, response);
+ }
+ else
+ mmsServer_createConfirmedErrorPdu(invokeId, response, mmsError);
+ }
+
+ GLOBAL_FREEMEM(variableListName);
}
+ else
+ mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_RESOURCE_CAPABILITY_UNAVAILABLE);
+
- free(variableListName);
}
else if (request->variableListName.present == ObjectName_PR_aaspecific) {
- char* variableListName = createStringFromBuffer(
- request->variableListName.choice.aaspecific.buf,
- request->variableListName.choice.aaspecific.size);
+ if (LinkedList_size(connection->namedVariableLists) < CONFIG_MMS_MAX_NUMBER_OF_ASSOCIATION_SPECIFIC_DATA_SETS) {
+ char* variableListName = createStringFromBuffer(
+ request->variableListName.choice.aaspecific.buf,
+ request->variableListName.choice.aaspecific.size);
- if (MmsServerConnection_getNamedVariableList(connection, variableListName) != NULL) {
- mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_DEFINITION_OBJECT_EXISTS);
- }
- else {
- MmsNamedVariableList namedVariableList = createNamedVariableList(device,
- request, variableListName);
- if (namedVariableList != NULL) {
- MmsServerConnection_addNamedVariableList(connection, namedVariableList);
- createDefineNamedVariableListResponse(invokeId, response);
+ if (MmsServerConnection_getNamedVariableList(connection, variableListName) != NULL) {
+ mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_DEFINITION_OBJECT_EXISTS);
+ }
+ else {
+ MmsError mmsError;
+
+ MmsNamedVariableList namedVariableList = createNamedVariableList(device,
+ request, variableListName, &mmsError);
+
+ if (namedVariableList != NULL) {
+ MmsServerConnection_addNamedVariableList(connection, namedVariableList);
+ createDefineNamedVariableListResponse(invokeId, response);
+ }
+ else
+ mmsServer_createConfirmedErrorPdu(invokeId, response, mmsError);
}
- else
- mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_ACCESS_UNSUPPORTED);
- }
- free(variableListName);
+ GLOBAL_FREEMEM(variableListName);
+ }
+ else
+ mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_RESOURCE_CAPABILITY_UNAVAILABLE);
}
else
- mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_ACCESS_UNSUPPORTED);
+ mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_DEFINITION_TYPE_UNSUPPORTED);
asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0);
}
@@ -371,7 +439,7 @@ createGetNamedVariableListAttributesResponse(int invokeId, ByteBuffer* response,
varListResponse->listOfVariable.list.size = variableCount;
varListResponse->listOfVariable.list.array = (struct GetNamedVariableListAttributesResponse__listOfVariable__Member**)
- calloc(variableCount, sizeof(void*));
+ GLOBAL_CALLOC(variableCount, sizeof(void*));
LinkedList variable = LinkedList_getNext(variables);
@@ -380,7 +448,7 @@ createGetNamedVariableListAttributesResponse(int invokeId, ByteBuffer* response,
MmsNamedVariableListEntry variableEntry = (MmsNamedVariableListEntry) variable->data;
varListResponse->listOfVariable.list.array[i] = (struct GetNamedVariableListAttributesResponse__listOfVariable__Member*)
- calloc(1, sizeof(struct GetNamedVariableListAttributesResponse__listOfVariable__Member));
+ GLOBAL_CALLOC(1, sizeof(struct GetNamedVariableListAttributesResponse__listOfVariable__Member));
varListResponse->listOfVariable.list.array[i]->variableSpecification.present =
VariableSpecification_PR_name;
@@ -454,8 +522,8 @@ mmsServer_handleGetNamedVariableListAttributesRequest(
mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT);
- free(domainName);
- free(itemName);
+ GLOBAL_FREEMEM(domainName);
+ GLOBAL_FREEMEM(itemName);
}
else {
mmsServer_createConfirmedErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_ACCESS_UNSUPPORTED);
diff --git a/src/mms/iso_mms/server/mms_read_service.c b/src/mms/iso_mms/server/mms_read_service.c
index 4a9fea2c..80399ec7 100644
--- a/src/mms/iso_mms/server/mms_read_service.c
+++ b/src/mms/iso_mms/server/mms_read_service.c
@@ -78,7 +78,7 @@ addNamedVariableValue(MmsVariableSpecification* namedVariable, MmsServerConnecti
MmsValue_setElement(value, i, element);
- free(newNameIdStr);
+ GLOBAL_FREEMEM(newNameIdStr);
}
}
}
diff --git a/src/mms/iso_mms/server/mms_server.c b/src/mms/iso_mms/server/mms_server.c
index 3e9fa375..42550b3d 100644
--- a/src/mms/iso_mms/server/mms_server.c
+++ b/src/mms/iso_mms/server/mms_server.c
@@ -49,7 +49,7 @@ createValueCaches(MmsDevice* device)
MmsServer
MmsServer_create(IsoServer isoServer, MmsDevice* device)
{
- MmsServer self = (MmsServer) malloc(sizeof(struct sMmsServer));
+ MmsServer self = (MmsServer) GLOBAL_MALLOC(sizeof(struct sMmsServer));
memset(self, 0, sizeof(struct sMmsServer));
@@ -58,9 +58,12 @@ MmsServer_create(IsoServer isoServer, MmsDevice* device)
self->openConnections = Map_create();
self->valueCaches = createValueCaches(device);
self->isLocked = false;
+
+#if (CONFIG_MMS_THREADLESS_STACK != 1)
self->modelMutex = Semaphore_create(1);
IsoServer_setUserLock(isoServer, self->modelMutex);
+#endif
return self;
}
@@ -68,24 +71,35 @@ MmsServer_create(IsoServer isoServer, MmsDevice* device)
void
MmsServer_lockModel(MmsServer self)
{
+#if (CONFIG_MMS_THREADLESS_STACK != 1)
Semaphore_wait(self->modelMutex);
+#endif
}
void
MmsServer_unlockModel(MmsServer self)
{
+#if (CONFIG_MMS_THREADLESS_STACK != 1)
Semaphore_post(self->modelMutex);
+#endif
}
void
-MmsServer_installReadHandler(MmsServer self, ReadVariableHandler readHandler, void* parameter)
+MmsServer_installReadHandler(MmsServer self, MmsReadVariableHandler readHandler, void* parameter)
{
self->readHandler = readHandler;
self->readHandlerParameter = parameter;
}
void
-MmsServer_installWriteHandler(MmsServer self, WriteVariableHandler writeHandler, void* parameter)
+MmsServer_installReadAccessHandler(MmsServer self, MmsReadAccessHandler readAccessHandler, void* parameter)
+{
+ self->readAccessHandler = readAccessHandler;
+ self->readAccessHandlerParameter = parameter;
+}
+
+void
+MmsServer_installWriteHandler(MmsServer self, MmsWriteVariableHandler writeHandler, void* parameter)
{
self->writeHandler = writeHandler;
self->writeHandlerParameter = parameter;
@@ -124,8 +138,12 @@ MmsServer_destroy(MmsServer self)
{
Map_deleteDeep(self->openConnections, false, closeConnection);
Map_deleteDeep(self->valueCaches, false, (void (*) (void*)) deleteSingleCache);
+
+#if (CONFIG_MMS_THREADLESS_STACK != 1)
Semaphore_destroy(self->modelMutex);
- free(self);
+#endif
+
+ GLOBAL_FREEMEM(self);
}
MmsValue*
@@ -177,11 +195,20 @@ mmsServer_setValue(MmsServer self, MmsDomain* domain, char* itemId, MmsValue* va
return indication;
}
+
MmsValue*
mmsServer_getValue(MmsServer self, MmsDomain* domain, char* itemId, MmsServerConnection* connection)
{
MmsValue* value = NULL;
+ if (self->readAccessHandler != NULL) {
+ MmsDataAccessError accessError =
+ self->readAccessHandler(self->readAccessHandlerParameter, domain, itemId, connection);
+
+ if (accessError != DATA_ACCESS_ERROR_SUCCESS)
+ return NULL;
+ }
+
value = MmsServer_getValueFromCache(self, domain, itemId);
if (value == NULL)
@@ -233,6 +260,7 @@ isoConnectionIndicationHandler(IsoConnectionIndication indication,
}
}
+#if (CONFIG_MMS_THREADLESS_STACK != 1)
void
MmsServer_startListening(MmsServer server, int tcpPort)
{
@@ -246,3 +274,31 @@ MmsServer_stopListening(MmsServer server)
{
IsoServer_stopListening(server->isoServer);
}
+#endif /* (CONFIG_MMS_THREADLESS_STACK != 1)*/
+
+void
+MmsServer_startListeningThreadless(MmsServer self, int tcpPort)
+{
+ IsoServer_setConnectionHandler(self->isoServer, isoConnectionIndicationHandler, (void*) self);
+ IsoServer_setTcpPort(self->isoServer, tcpPort);
+ IsoServer_startListeningThreadless(self->isoServer);
+}
+
+int
+MmsServer_waitReady(MmsServer self, unsigned int timeoutMs)
+{
+ return IsoServer_waitReady(self->isoServer, timeoutMs);
+}
+
+void
+MmsServer_handleIncomingMessages(MmsServer self)
+{
+ IsoServer_processIncomingMessages(self->isoServer);
+}
+
+void
+MmsServer_stopListeningThreadless(MmsServer self)
+{
+ IsoServer_stopListeningThreadless(self->isoServer);
+}
+
diff --git a/src/mms/iso_mms/server/mms_server_common.c b/src/mms/iso_mms/server/mms_server_common.c
index c34220aa..31348c57 100644
--- a/src/mms/iso_mms/server/mms_server_common.c
+++ b/src/mms/iso_mms/server/mms_server_common.c
@@ -34,7 +34,7 @@ mmsServer_write_out(const void *buffer, size_t size, void *app_key)
MmsPdu_t*
mmsServer_createConfirmedResponse(uint32_t invokeId)
{
- MmsPdu_t* mmsPdu = (MmsPdu_t*) calloc(1, sizeof(MmsPdu_t));
+ MmsPdu_t* mmsPdu = (MmsPdu_t*) GLOBAL_CALLOC(1, sizeof(MmsPdu_t));
mmsPdu->present = MmsPdu_PR_confirmedResponsePdu;
@@ -48,7 +48,7 @@ mmsServer_createConfirmedResponse(uint32_t invokeId)
void
mmsServer_createConfirmedErrorPdu(uint32_t invokeId, ByteBuffer* response, MmsError errorType)
{
- MmsPdu_t* mmsPdu = (MmsPdu_t*) calloc(1, sizeof(MmsPdu_t));
+ MmsPdu_t* mmsPdu = (MmsPdu_t*) GLOBAL_CALLOC(1, sizeof(MmsPdu_t));
mmsPdu->present = MmsPdu_PR_confirmedErrorPDU;
asn_long2INTEGER(&(mmsPdu->choice.confirmedErrorPDU.invokeID),
@@ -87,6 +87,18 @@ mmsServer_createConfirmedErrorPdu(uint32_t invokeId, ByteBuffer* response, MmsEr
asn_long2INTEGER(&mmsPdu->choice.confirmedErrorPDU.serviceError.errorClass.choice.access,
ServiceError__errorClass__definition_objectexists);
}
+ else if (errorType == MMS_ERROR_DEFINITION_OBJECT_UNDEFINED) {
+ mmsPdu->choice.confirmedErrorPDU.serviceError.errorClass.present =
+ ServiceError__errorClass_PR_definition;
+ asn_long2INTEGER(&mmsPdu->choice.confirmedErrorPDU.serviceError.errorClass.choice.access,
+ ServiceError__errorClass__definition_objectundefined);
+ }
+ else if (errorType == MMS_ERROR_DEFINITION_TYPE_UNSUPPORTED) {
+ mmsPdu->choice.confirmedErrorPDU.serviceError.errorClass.present =
+ ServiceError__errorClass_PR_definition;
+ asn_long2INTEGER(&mmsPdu->choice.confirmedErrorPDU.serviceError.errorClass.choice.access,
+ ServiceError__errorClass__definition_typeunsupported);
+ }
else if (errorType == MMS_ERROR_FILE_FILE_NON_EXISTENT) {
mmsPdu->choice.confirmedErrorPDU.serviceError.errorClass.present =
ServiceError__errorClass_PR_file;
@@ -105,6 +117,12 @@ mmsServer_createConfirmedErrorPdu(uint32_t invokeId, ByteBuffer* response, MmsEr
asn_long2INTEGER(&mmsPdu->choice.confirmedErrorPDU.serviceError.errorClass.choice.access,
ServiceError__errorClass__resource_other);
}
+ else if (errorType == MMS_ERROR_RESOURCE_CAPABILITY_UNAVAILABLE) {
+ mmsPdu->choice.confirmedErrorPDU.serviceError.errorClass.present =
+ ServiceError__errorClass_PR_resource;
+ asn_long2INTEGER(&mmsPdu->choice.confirmedErrorPDU.serviceError.errorClass.choice.access,
+ ServiceError__errorClass__resource_capabilityunavailable);
+ }
der_encode(&asn_DEF_MmsPdu, mmsPdu,
mmsServer_write_out, (void*) response);
@@ -188,7 +206,7 @@ mmsServer_deleteVariableList(LinkedList namedVariableLists, char* variableListNa
if (strcmp(MmsNamedVariableList_getName(varList), variableListName)
== 0) {
previousElement->next = element->next;
- free(element);
+ GLOBAL_FREEMEM(element);
MmsNamedVariableList_destroy(varList);
break;
diff --git a/src/mms/iso_mms/server/mms_server_connection.c b/src/mms/iso_mms/server/mms_server_connection.c
index 66cbff4f..3292d6c3 100644
--- a/src/mms/iso_mms/server/mms_server_connection.c
+++ b/src/mms/iso_mms/server/mms_server_connection.c
@@ -38,12 +38,12 @@
void
mmsServer_writeMmsRejectPdu(uint32_t* invokeId, int reason, ByteBuffer* response) {
- MmsPdu_t* mmsPdu = (MmsPdu_t*) calloc(1, sizeof(MmsPdu_t));
+ MmsPdu_t* mmsPdu = (MmsPdu_t*) GLOBAL_CALLOC(1, sizeof(MmsPdu_t));
mmsPdu->present = MmsPdu_PR_rejectPDU;
if (invokeId != NULL) {
- mmsPdu->choice.rejectPDU.originalInvokeID = (Unsigned32_t*) calloc(1, sizeof(Unsigned32_t));
+ mmsPdu->choice.rejectPDU.originalInvokeID = (Unsigned32_t*) GLOBAL_CALLOC(1, sizeof(Unsigned32_t));
asn_long2INTEGER(mmsPdu->choice.rejectPDU.originalInvokeID, *invokeId);
}
@@ -291,7 +291,7 @@ MmsServerConnection_init(MmsServerConnection* connection, MmsServer server, IsoC
MmsServerConnection* self;
if (connection == NULL)
- self = (MmsServerConnection*) calloc(1, sizeof(MmsServerConnection));
+ self = (MmsServerConnection*) GLOBAL_CALLOC(1, sizeof(MmsServerConnection));
else
self = connection;
@@ -321,7 +321,7 @@ MmsServerConnection_destroy(MmsServerConnection* self)
#endif
LinkedList_destroyDeep(self->namedVariableLists, (LinkedListValueDeleteFunction) MmsNamedVariableList_destroy);
- free(self);
+ GLOBAL_FREEMEM(self);
}
bool
diff --git a/src/mms/iso_mms/server/mms_value_cache.c b/src/mms/iso_mms/server/mms_value_cache.c
index ae584eeb..161ae9b9 100644
--- a/src/mms/iso_mms/server/mms_value_cache.c
+++ b/src/mms/iso_mms/server/mms_value_cache.c
@@ -40,7 +40,7 @@ typedef struct sMmsValueCacheEntry {
MmsValueCache
MmsValueCache_create(MmsDomain* domain)
{
- MmsValueCache self = (MmsValueCache) calloc(1, sizeof(struct sMmsValueCache));
+ MmsValueCache self = (MmsValueCache) GLOBAL_CALLOC(1, sizeof(struct sMmsValueCache));
self->domain = domain;
@@ -55,7 +55,7 @@ MmsValueCache_insertValue(MmsValueCache self, char* itemId, MmsValue* value)
MmsVariableSpecification* typeSpec = MmsDomain_getNamedVariable(self->domain, itemId);
if (typeSpec != NULL) {
- MmsValueCacheEntry* cacheEntry = (MmsValueCacheEntry*) malloc(sizeof(MmsValueCacheEntry));
+ MmsValueCacheEntry* cacheEntry = (MmsValueCacheEntry*) GLOBAL_MALLOC(sizeof(MmsValueCacheEntry));
cacheEntry->value = value;
cacheEntry->typeSpec = typeSpec;
@@ -135,7 +135,7 @@ MmsValueCache_lookupValue(MmsValueCache self, char* itemId)
value = searchCacheForValue(self, itemId, parentItemId);
}
- free(itemIdCopy);
+ GLOBAL_FREEMEM(itemIdCopy);
}
if (cacheEntry != NULL)
@@ -149,7 +149,7 @@ cacheEntryDelete(MmsValueCacheEntry* entry)
{
if (entry != NULL) {
MmsValue_delete(entry->value);
- free(entry);
+ GLOBAL_FREEMEM(entry);
}
}
@@ -157,5 +157,5 @@ void
MmsValueCache_destroy(MmsValueCache self)
{
Map_deleteDeep(self->map, true, (void (*) (void*)) cacheEntryDelete);
- free(self);
+ GLOBAL_FREEMEM(self);
}
diff --git a/src/mms/iso_mms/server/mms_write_service.c b/src/mms/iso_mms/server/mms_write_service.c
index 26deacdb..afd531a7 100644
--- a/src/mms/iso_mms/server/mms_write_service.c
+++ b/src/mms/iso_mms/server/mms_write_service.c
@@ -47,13 +47,13 @@ mmsServer_createMmsWriteResponse(MmsServerConnection* connection,
writeResponse->list.count = numberOfItems;
writeResponse->list.size = numberOfItems;
- writeResponse->list.array = (struct WriteResponse__Member**) calloc(numberOfItems,
+ writeResponse->list.array = (struct WriteResponse__Member**) GLOBAL_CALLOC(numberOfItems,
sizeof(struct WriteResponse__Member*));
int i;
for (i = 0; i < numberOfItems; i++) {
- writeResponse->list.array[i] = (struct WriteResponse__Member*) calloc(1, sizeof(struct WriteResponse__Member));
+ writeResponse->list.array[i] = (struct WriteResponse__Member*) GLOBAL_CALLOC(1, sizeof(struct WriteResponse__Member));
if (accessResults[i] == DATA_ACCESS_ERROR_SUCCESS)
writeResponse->list.array[i]->present = WriteResponse__Member_PR_success;
@@ -72,13 +72,13 @@ mmsServer_createMmsWriteResponse(MmsServerConnection* connection,
void
-MmsServerConnection_sendWriteResponse(MmsServerConnection* self, uint32_t invokeId, MmsDataAccessError indication)
+MmsServerConnection_sendWriteResponse(MmsServerConnection* self, uint32_t invokeId, MmsDataAccessError indication, bool handlerMode)
{
ByteBuffer* response = ByteBuffer_create(NULL, self->maxPduSize);
mmsServer_createMmsWriteResponse(self, invokeId, response, 1, &indication);
- IsoConnection_sendMessage(self->isoConnection, response, false);
+ IsoConnection_sendMessage(self->isoConnection, response, handlerMode);
ByteBuffer_destroy(response);
}
@@ -151,7 +151,7 @@ mmsServer_handleWriteRequest(
domain = MmsDevice_getDomain(device, domainIdStr);
- free(domainIdStr);
+ GLOBAL_FREEMEM(domainIdStr);
if (domain == NULL) {
accessResults[i] = DATA_ACCESS_ERROR_OBJECT_NONE_EXISTENT;
@@ -180,7 +180,7 @@ mmsServer_handleWriteRequest(
}
if (variable == NULL) {
- free(nameIdStr);
+ GLOBAL_FREEMEM(nameIdStr);
accessResults[i] = DATA_ACCESS_ERROR_OBJECT_NONE_EXISTENT;
continue;
}
@@ -189,13 +189,13 @@ mmsServer_handleWriteRequest(
if (alternateAccess != NULL) {
if (variable->type != MMS_ARRAY) {
- free(nameIdStr);
+ GLOBAL_FREEMEM(nameIdStr);
accessResults[i] = DATA_ACCESS_ERROR_OBJECT_ATTRIBUTE_INCONSISTENT;
continue;
}
if (!mmsServer_isIndexAccess(alternateAccess)) {
- free(nameIdStr);
+ GLOBAL_FREEMEM(nameIdStr);
accessResults[i] = DATA_ACCESS_ERROR_OBJECT_ACCESS_UNSUPPORTED;
continue;
}
@@ -206,7 +206,7 @@ mmsServer_handleWriteRequest(
MmsValue* value = mmsMsg_parseDataElement(dataElement);
if (value == NULL) {
- free(nameIdStr);
+ GLOBAL_FREEMEM(nameIdStr);
accessResults[i] = DATA_ACCESS_ERROR_OBJECT_ATTRIBUTE_INCONSISTENT;
continue;
}
@@ -219,7 +219,7 @@ mmsServer_handleWriteRequest(
MmsValue* cachedArray = MmsServer_getValueFromCache(connection->server, domain, nameIdStr);
if (cachedArray == NULL) {
- free(nameIdStr);
+ GLOBAL_FREEMEM(nameIdStr);
MmsValue_delete(value);
accessResults[i] = DATA_ACCESS_ERROR_OBJECT_ATTRIBUTE_INCONSISTENT;
continue;
@@ -230,20 +230,20 @@ mmsServer_handleWriteRequest(
MmsValue* elementValue = MmsValue_getElement(cachedArray, index);
if (elementValue == NULL) {
- free(nameIdStr);
+ GLOBAL_FREEMEM(nameIdStr);
MmsValue_delete(value);
accessResults[i] = DATA_ACCESS_ERROR_OBJECT_ATTRIBUTE_INCONSISTENT;
continue;
}
if (MmsValue_update(elementValue, value) == false) {
- free(nameIdStr);
+ GLOBAL_FREEMEM(nameIdStr);
MmsValue_delete(value);
accessResults[i] = DATA_ACCESS_ERROR_TYPE_INCONSISTENT;
continue;
}
- free(nameIdStr);
+ GLOBAL_FREEMEM(nameIdStr);
MmsValue_delete(value);
accessResults[i] = DATA_ACCESS_ERROR_SUCCESS;
continue;
@@ -260,7 +260,7 @@ mmsServer_handleWriteRequest(
MmsValue_delete(value);
- free(nameIdStr);
+ GLOBAL_FREEMEM(nameIdStr);
}
if (sendResponse) {
diff --git a/src/mms/iso_server/iso_connection.c b/src/mms/iso_server/iso_connection.c
index f3539b71..19201cd5 100644
--- a/src/mms/iso_server/iso_connection.c
+++ b/src/mms/iso_server/iso_connection.c
@@ -24,15 +24,14 @@
#include "libiec61850_platform_includes.h"
#include "stack_config.h"
-#include "byte_stream.h"
#include "buffer_chain.h"
#include "cotp.h"
#include "iso_session.h"
#include "iso_presentation.h"
#include "acse.h"
#include "iso_server.h"
-#include "socket.h"
-#include "thread.h"
+#include "hal_socket.h"
+#include "hal_thread.h"
#include "iso_server_private.h"
@@ -47,6 +46,8 @@
#define RECEIVE_BUF_SIZE CONFIG_MMS_MAXIMUM_PDU_SIZE + 100
#define SEND_BUF_SIZE CONFIG_MMS_MAXIMUM_PDU_SIZE + 100
+#define TPKT_RFC1006_HEADER_SIZE 4
+
#define ISO_CON_STATE_RUNNING 1
#define ISO_CON_STATE_STOPPED 0
@@ -54,353 +55,448 @@ struct sIsoConnection
{
uint8_t* receiveBuffer;
uint8_t* sendBuffer;
+
+ ByteBuffer rcvBuffer;
+
+ uint8_t* cotpReadBuf;
+ uint8_t* cotpWriteBuf;
+ ByteBuffer cotpReadBuffer;
+ ByteBuffer cotpWriteBuffer;
+
MessageReceivedHandler msgRcvdHandler;
- IsoServer isoServer;
void* msgRcvdHandlerParameter;
+
+ IsoServer isoServer;
+
Socket socket;
int state;
IsoSession* session;
IsoPresentation* presentation;
CotpConnection* cotpConnection;
+
+ AcseConnection* acseConnection;
+
char* clientAddress;
+
+#if (CONFIG_MMS_THREADLESS_STACK != 1)
Thread thread;
Semaphore conMutex;
-
- void* securityToken;
+ bool isInsideCallback;
+#endif
};
static void
-handleTcpConnection(IsoConnection self)
+finalizeIsoConnection(IsoConnection self)
{
if (DEBUG_ISO_SERVER)
- printf("ISO_SERVER: connection %p started\n", self);
+ printf("ISO_SERVER: finalizeIsoConnection --> close transport connection\n");
- CotpIndication cotpIndication;
+ IsoServer_closeConnection(self->isoServer, self);
+ if (self->socket != NULL)
+ Socket_destroy(self->socket);
- IsoSessionIndication sIndication;
+ GLOBAL_FREEMEM(self->session);
+ GLOBAL_FREEMEM(self->presentation);
+ AcseConnection_destroy(self->acseConnection);
+ GLOBAL_FREEMEM(self->acseConnection);
- AcseIndication aIndication;
- AcseConnection acseConnection;
+ GLOBAL_FREEMEM(self->cotpReadBuf);
+ GLOBAL_FREEMEM(self->cotpWriteBuf);
- ByteBuffer receiveBuffer;
+ GLOBAL_FREEMEM(self->cotpConnection);
- self->cotpConnection = (CotpConnection*) calloc(1, sizeof(CotpConnection));
- CotpConnection_init(self->cotpConnection, self->socket, &receiveBuffer);
+#if (CONFIG_MMS_THREADLESS_STACK != 1)
+ Semaphore_destroy(self->conMutex);
+#endif
- self->session = (IsoSession*) calloc(1, sizeof(IsoSession));
- IsoSession_init(self->session);
+ GLOBAL_FREEMEM(self->receiveBuffer);
+ GLOBAL_FREEMEM(self->sendBuffer);
+ GLOBAL_FREEMEM(self->clientAddress);
+ IsoServer isoServer = self->isoServer;
+ GLOBAL_FREEMEM(self);
+ if (DEBUG_ISO_SERVER)
+ printf("ISO_SERVER: connection %p closed\n", self);
- self->presentation = (IsoPresentation*) calloc(1, sizeof(IsoPresentation));
- IsoPresentation_init(self->presentation);
+ private_IsoServer_decreaseConnectionCounter(isoServer);
+}
- AcseConnection_init(&acseConnection, IsoServer_getAuthenticator(self->isoServer),
- IsoServer_getAuthenticatorParameter(self->isoServer));
+void
+IsoConnection_addHandleSet(const IsoConnection self, HandleSet handles)
+{
+ Handleset_addSocket(handles, self->socket);
+}
- while (self->msgRcvdHandlerParameter == NULL)
- Thread_sleep(1);
+void
+IsoConnection_handleTcpConnection(IsoConnection self)
+{
+ assert(self->msgRcvdHandler != NULL);
- if (DEBUG_ISO_SERVER)
- printf("ISO_SERVER: IsoConnection: Start to handle connection for client %s\n", self->clientAddress);
+ TpktState tpktState = CotpConnection_readToTpktBuffer(self->cotpConnection);
- while (self->state == ISO_CON_STATE_RUNNING) {
- ByteBuffer_wrap(&receiveBuffer, self->receiveBuffer, 0, RECEIVE_BUF_SIZE);
+ if (tpktState == TPKT_ERROR)
+ self->state = ISO_CON_STATE_STOPPED;
- cotpIndication = CotpConnection_parseIncomingMessage(self->cotpConnection);
+ if (tpktState != TPKT_PACKET_COMPLETE)
+ return;
- switch (cotpIndication) {
- case CONNECT_INDICATION:
- if (DEBUG_ISO_SERVER)
- printf("ISO_SERVER: COTP connection indication\n");
+ CotpIndication cotpIndication = CotpConnection_parseIncomingMessage(self->cotpConnection);
+
+ switch (cotpIndication) {
+ case COTP_MORE_FRAGMENTS_FOLLOW:
+ return;
+ case COTP_CONNECT_INDICATION:
+ if (DEBUG_ISO_SERVER)
+ printf("ISO_SERVER: COTP connection indication\n");
- Semaphore_wait(self->conMutex);
+#if (CONFIG_MMS_THREADLESS_STACK != 1)
+ Semaphore_wait(self->conMutex);
+#endif
- CotpConnection_sendConnectionResponseMessage(self->cotpConnection);
+ CotpConnection_sendConnectionResponseMessage(self->cotpConnection);
- Semaphore_post(self->conMutex);
+#if (CONFIG_MMS_THREADLESS_STACK != 1)
+ Semaphore_post(self->conMutex);
+#endif
- break;
- case DATA_INDICATION:
- {
- if (DEBUG_ISO_SERVER)
- printf("ISO_SERVER: COTP data indication\n");
+ break;
+ case COTP_DATA_INDICATION:
+ {
+ ByteBuffer* cotpPayload = CotpConnection_getPayload(self->cotpConnection);
- ByteBuffer* cotpPayload = CotpConnection_getPayload(self->cotpConnection);
+ if (DEBUG_ISO_SERVER)
+ printf("ISO_SERVER: COTP data indication (payload size = %i)\n", cotpPayload->size);
- sIndication = IsoSession_parseMessage(self->session, cotpPayload);
+ IsoSessionIndication sIndication = IsoSession_parseMessage(self->session, cotpPayload);
- ByteBuffer* sessionUserData = IsoSession_getUserData(self->session);
+ ByteBuffer* sessionUserData = IsoSession_getUserData(self->session);
- switch (sIndication) {
- case SESSION_CONNECT:
+ switch (sIndication) {
+ case SESSION_CONNECT:
+ if (DEBUG_ISO_SERVER)
+ printf("ISO_SERVER: iso_connection: session connect indication\n");
+
+ if (IsoPresentation_parseConnect(self->presentation, sessionUserData)) {
if (DEBUG_ISO_SERVER)
- printf("ISO_SERVER: iso_connection: session connect indication\n");
+ printf("ISO_SERVER: iso_connection: presentation ok\n");
- if (IsoPresentation_parseConnect(self->presentation, sessionUserData)) {
- if (DEBUG_ISO_SERVER)
- printf("ISO_SERVER: iso_connection: presentation ok\n");
+ ByteBuffer* acseBuffer = &(self->presentation->nextPayload);
- ByteBuffer* acseBuffer = &(self->presentation->nextPayload);
+ AcseIndication aIndication = AcseConnection_parseMessage(self->acseConnection, acseBuffer);
- aIndication = AcseConnection_parseMessage(&acseConnection, acseBuffer);
+ if (aIndication == ACSE_ASSOCIATE) {
- self->securityToken = acseConnection.securityToken;
+#if (CONFIG_MMS_THREADLESS_STACK != 1)
+ Semaphore_wait(self->conMutex);
+#endif
- if (aIndication == ACSE_ASSOCIATE) {
+ if (DEBUG_ISO_SERVER)
+ printf("ISO_SERVER: cotp_server: acse associate\n");
- Semaphore_wait(self->conMutex);
+ ByteBuffer mmsRequest;
- if (DEBUG_ISO_SERVER)
- printf("ISO_SERVER: cotp_server: acse associate\n");
+ ByteBuffer_wrap(&mmsRequest, self->acseConnection->userDataBuffer,
+ self->acseConnection->userDataBufferSize, self->acseConnection->userDataBufferSize);
+ ByteBuffer mmsResponseBuffer; /* new */
- ByteBuffer mmsRequest;
+ ByteBuffer_wrap(&mmsResponseBuffer, self->sendBuffer, 0, SEND_BUF_SIZE);
- ByteBuffer_wrap(&mmsRequest, acseConnection.userDataBuffer,
- acseConnection.userDataBufferSize, acseConnection.userDataBufferSize);
- ByteBuffer mmsResponseBuffer; /* new */
+ if (self->msgRcvdHandler != NULL) {
- ByteBuffer_wrap(&mmsResponseBuffer, self->sendBuffer, 0, SEND_BUF_SIZE);
+#if (CONFIG_MMS_THREADLESS_STACK != 1)
+ self->isInsideCallback = true;
+#endif
self->msgRcvdHandler(self->msgRcvdHandlerParameter,
&mmsRequest, &mmsResponseBuffer);
- struct sBufferChain mmsBufferPartStruct;
- BufferChain mmsBufferPart = &mmsBufferPartStruct;
+#if (CONFIG_MMS_THREADLESS_STACK != 1)
+ self->isInsideCallback = false;
+#endif
+ }
- BufferChain_init(mmsBufferPart, mmsResponseBuffer.size, mmsResponseBuffer.size, NULL,
- self->sendBuffer);
+ struct sBufferChain mmsBufferPartStruct;
+ BufferChain mmsBufferPart = &mmsBufferPartStruct;
- if (mmsResponseBuffer.size > 0) {
- if (DEBUG_ISO_SERVER)
- printf("iso_connection: application payload size: %i\n",
- mmsResponseBuffer.size);
+ BufferChain_init(mmsBufferPart, mmsResponseBuffer.size, mmsResponseBuffer.size, NULL,
+ self->sendBuffer);
- struct sBufferChain acseBufferPartStruct;
- BufferChain acseBufferPart = &acseBufferPartStruct;
+ if (mmsResponseBuffer.size > 0) {
+ if (DEBUG_ISO_SERVER)
+ printf("ISO_SERVER: iso_connection: application payload size: %i\n",
+ mmsResponseBuffer.size);
- acseBufferPart->buffer = self->sendBuffer + mmsBufferPart->length;
- acseBufferPart->partMaxLength = SEND_BUF_SIZE - mmsBufferPart->length;
+ struct sBufferChain acseBufferPartStruct;
+ BufferChain acseBufferPart = &acseBufferPartStruct;
- AcseConnection_createAssociateResponseMessage(&acseConnection,
- ACSE_RESULT_ACCEPT, acseBufferPart, mmsBufferPart);
+ acseBufferPart->buffer = self->sendBuffer + mmsBufferPart->length;
+ acseBufferPart->partMaxLength = SEND_BUF_SIZE - mmsBufferPart->length;
- struct sBufferChain presentationBufferPartStruct;
- BufferChain presentationBufferPart = &presentationBufferPartStruct;
+ AcseConnection_createAssociateResponseMessage(self->acseConnection,
+ ACSE_RESULT_ACCEPT, acseBufferPart, mmsBufferPart);
- presentationBufferPart->buffer = self->sendBuffer + acseBufferPart->length;
- presentationBufferPart->partMaxLength = SEND_BUF_SIZE - acseBufferPart->length;
+ struct sBufferChain presentationBufferPartStruct;
+ BufferChain presentationBufferPart = &presentationBufferPartStruct;
- IsoPresentation_createCpaMessage(self->presentation, presentationBufferPart,
- acseBufferPart);
+ presentationBufferPart->buffer = self->sendBuffer + acseBufferPart->length;
+ presentationBufferPart->partMaxLength = SEND_BUF_SIZE - acseBufferPart->length;
- struct sBufferChain sessionBufferPartStruct;
- BufferChain sessionBufferPart = &sessionBufferPartStruct;
- sessionBufferPart->buffer = self->sendBuffer + presentationBufferPart->length;
- sessionBufferPart->partMaxLength = SEND_BUF_SIZE - presentationBufferPart->length;
+ IsoPresentation_createCpaMessage(self->presentation, presentationBufferPart,
+ acseBufferPart);
- IsoSession_createAcceptSpdu(self->session, sessionBufferPart, presentationBufferPart);
+ struct sBufferChain sessionBufferPartStruct;
+ BufferChain sessionBufferPart = &sessionBufferPartStruct;
+ sessionBufferPart->buffer = self->sendBuffer + presentationBufferPart->length;
+ sessionBufferPart->partMaxLength = SEND_BUF_SIZE - presentationBufferPart->length;
- CotpConnection_sendDataMessage(self->cotpConnection, sessionBufferPart);
- }
- else {
- if (DEBUG_ISO_SERVER)
- printf(
- "ISO_SERVER: iso_connection: association error. No response from application!\n");
- }
+ IsoSession_createAcceptSpdu(self->session, sessionBufferPart, presentationBufferPart);
- Semaphore_post(self->conMutex);
+ CotpConnection_sendDataMessage(self->cotpConnection, sessionBufferPart);
}
else {
if (DEBUG_ISO_SERVER)
- printf("ISO_SERVER: iso_connection: acse association failed\n");
- self->state = ISO_CON_STATE_STOPPED;
+ printf("ISO_SERVER: iso_connection: association error. No response from application!\n");
}
+#if (CONFIG_MMS_THREADLESS_STACK != 1)
+ Semaphore_post(self->conMutex);
+#endif
}
- break;
- case SESSION_DATA:
- if (DEBUG_ISO_SERVER)
- printf("ISO_SERVER: iso_connection: session data indication\n");
-
- if (!IsoPresentation_parseUserData(self->presentation, sessionUserData)) {
+ else {
if (DEBUG_ISO_SERVER)
- printf("ISO_SERVER: cotp_server: presentation error\n");
+ printf("ISO_SERVER: iso_connection: acse association failed\n");
self->state = ISO_CON_STATE_STOPPED;
- break;
}
- if (self->presentation->nextContextId == self->presentation->mmsContextId) {
- if (DEBUG_ISO_SERVER)
- printf("ISO_SERVER: iso_connection: mms message\n");
-
- ByteBuffer* mmsRequest = &(self->presentation->nextPayload);
-
- ByteBuffer mmsResponseBuffer;
-
- IsoServer_userLock(self->isoServer);
- Semaphore_wait(self->conMutex);
-
- ByteBuffer_wrap(&mmsResponseBuffer, self->sendBuffer, 0, SEND_BUF_SIZE);
+ }
+ break;
+ case SESSION_DATA:
+ if (DEBUG_ISO_SERVER)
+ printf("ISO_SERVER: iso_connection: session data indication\n");
- self->msgRcvdHandler(self->msgRcvdHandlerParameter,
- mmsRequest, &mmsResponseBuffer);
+ if (!IsoPresentation_parseUserData(self->presentation, sessionUserData)) {
+ if (DEBUG_ISO_SERVER)
+ printf("ISO_SERVER: presentation layer error\n");
+ self->state = ISO_CON_STATE_STOPPED;
+ break;
+ }
- if (mmsResponseBuffer.size > 0) {
+ if (self->presentation->nextContextId == self->presentation->mmsContextId) {
+ if (DEBUG_ISO_SERVER)
+ printf("ISO_SERVER: iso_connection: mms message\n");
+ ByteBuffer* mmsRequest = &(self->presentation->nextPayload);
- struct sBufferChain mmsBufferPartStruct;
- BufferChain mmsBufferPart = &mmsBufferPartStruct;
+ ByteBuffer mmsResponseBuffer;
- BufferChain_init(mmsBufferPart, mmsResponseBuffer.size,
- mmsResponseBuffer.size, NULL, self->sendBuffer);
+#if (CONFIG_MMS_THREADLESS_STACK != 1)
+ IsoServer_userLock(self->isoServer);
+ Semaphore_wait(self->conMutex);
+#endif
- struct sBufferChain presentationBufferPartStruct;
- BufferChain presentationBufferPart = &presentationBufferPartStruct;
- presentationBufferPart->buffer = self->sendBuffer + mmsBufferPart->length;
- presentationBufferPart->partMaxLength = SEND_BUF_SIZE - mmsBufferPart->length;
+ ByteBuffer_wrap(&mmsResponseBuffer, self->sendBuffer, 0, SEND_BUF_SIZE);
- IsoPresentation_createUserData(self->presentation,
- presentationBufferPart, mmsBufferPart);
+ if (self->msgRcvdHandler != NULL) {
+#if (CONFIG_MMS_THREADLESS_STACK != 1)
+ self->isInsideCallback = true;
+#endif
- struct sBufferChain sessionBufferPartStruct;
- BufferChain sessionBufferPart = &sessionBufferPartStruct;
- sessionBufferPart->buffer = self->sendBuffer + presentationBufferPart->length;
- sessionBufferPart->partMaxLength = SEND_BUF_SIZE - presentationBufferPart->length;
-
- IsoSession_createDataSpdu(self->session, sessionBufferPart, presentationBufferPart);
-
- CotpConnection_sendDataMessage(self->cotpConnection, sessionBufferPart);
- }
+ self->msgRcvdHandler(self->msgRcvdHandlerParameter,
+ mmsRequest, &mmsResponseBuffer);
- Semaphore_post(self->conMutex);
- IsoServer_userUnlock(self->isoServer);
- }
- else {
- if (DEBUG_ISO_SERVER)
- printf("ISO_SERVER: iso_connection: unknown presentation layer context!");
+#if (CONFIG_MMS_THREADLESS_STACK != 1)
+ self->isInsideCallback = false;
+#endif
}
- break;
-
- case SESSION_FINISH:
- if (DEBUG_ISO_SERVER)
- printf("ISO_SERVER: iso_connection: session finish indication\n");
-
- if (IsoPresentation_parseUserData(self->presentation, sessionUserData)) {
- if (DEBUG_ISO_SERVER)
- printf("ISO_SERVER: iso_connection: presentation ok\n");
+ /* send a response if required */
+ if (mmsResponseBuffer.size > 0) {
- struct sBufferChain acseBufferPartStruct;
- BufferChain acseBufferPart = &acseBufferPartStruct;
- acseBufferPart->buffer = self->sendBuffer;
- acseBufferPart->partMaxLength = SEND_BUF_SIZE;
+ struct sBufferChain mmsBufferPartStruct;
+ BufferChain mmsBufferPart = &mmsBufferPartStruct;
- AcseConnection_createReleaseResponseMessage(&acseConnection, acseBufferPart);
+ BufferChain_init(mmsBufferPart, mmsResponseBuffer.size,
+ mmsResponseBuffer.size, NULL, self->sendBuffer);
struct sBufferChain presentationBufferPartStruct;
BufferChain presentationBufferPart = &presentationBufferPartStruct;
- presentationBufferPart->buffer = self->sendBuffer + acseBufferPart->length;
- presentationBufferPart->partMaxLength = SEND_BUF_SIZE - acseBufferPart->length;
+ presentationBufferPart->buffer = self->sendBuffer + mmsBufferPart->length;
+ presentationBufferPart->partMaxLength = SEND_BUF_SIZE - mmsBufferPart->length;
- IsoPresentation_createUserDataACSE(self->presentation, presentationBufferPart, acseBufferPart);
+ IsoPresentation_createUserData(self->presentation,
+ presentationBufferPart, mmsBufferPart);
struct sBufferChain sessionBufferPartStruct;
BufferChain sessionBufferPart = &sessionBufferPartStruct;
sessionBufferPart->buffer = self->sendBuffer + presentationBufferPart->length;
sessionBufferPart->partMaxLength = SEND_BUF_SIZE - presentationBufferPart->length;
- IsoSession_createDisconnectSpdu(self->session, sessionBufferPart, presentationBufferPart);
+ IsoSession_createDataSpdu(self->session, sessionBufferPart, presentationBufferPart);
CotpConnection_sendDataMessage(self->cotpConnection, sessionBufferPart);
}
- self->state = ISO_CON_STATE_STOPPED;
+#if (CONFIG_MMS_THREADLESS_STACK != 1)
+ Semaphore_post(self->conMutex);
+ IsoServer_userUnlock(self->isoServer);
+#endif
+ }
+ else {
+ if (DEBUG_ISO_SERVER)
+ printf("ISO_SERVER: iso_connection: unknown presentation layer context!");
+ }
- break;
+ break;
- case SESSION_ABORT:
- self->state = ISO_CON_STATE_STOPPED;
- break;
+ case SESSION_FINISH:
+ if (DEBUG_ISO_SERVER)
+ printf("ISO_SERVER: iso_connection: session finish indication\n");
- case SESSION_ERROR:
- self->state = ISO_CON_STATE_STOPPED;
- break;
+ if (IsoPresentation_parseUserData(self->presentation, sessionUserData)) {
+ if (DEBUG_ISO_SERVER)
+ printf("ISO_SERVER: iso_connection: presentation ok\n");
- default: /* illegal state */
- self->state = ISO_CON_STATE_STOPPED;
- break;
- }
- }
- break;
- case ERROR:
- if (DEBUG_ISO_SERVER)
- printf("ISO_SERVER: Connection closed\n");
- self->state = ISO_CON_STATE_STOPPED;
- break;
- default:
- if (DEBUG_ISO_SERVER)
- printf("ISO_SERVER: COTP Unknown Indication: %i\n", cotpIndication);
- self->state = ISO_CON_STATE_STOPPED;
- break;
- }
- }
+ struct sBufferChain acseBufferPartStruct;
+ BufferChain acseBufferPart = &acseBufferPartStruct;
+ acseBufferPart->buffer = self->sendBuffer;
+ acseBufferPart->partMaxLength = SEND_BUF_SIZE;
- if (DEBUG_ISO_SERVER)
- printf("ISO_SERVER: Connection handling loop finished --> close transport connection\n");
+ AcseConnection_createReleaseResponseMessage(self->acseConnection, acseBufferPart);
- IsoServer_closeConnection(self->isoServer, self);
+ struct sBufferChain presentationBufferPartStruct;
+ BufferChain presentationBufferPart = &presentationBufferPartStruct;
+ presentationBufferPart->buffer = self->sendBuffer + acseBufferPart->length;
+ presentationBufferPart->partMaxLength = SEND_BUF_SIZE - acseBufferPart->length;
- if (self->socket != NULL)
- Socket_destroy(self->socket);
+ IsoPresentation_createUserDataACSE(self->presentation, presentationBufferPart, acseBufferPart);
- free(self->session);
- free(self->presentation);
+ struct sBufferChain sessionBufferPartStruct;
+ BufferChain sessionBufferPart = &sessionBufferPartStruct;
+ sessionBufferPart->buffer = self->sendBuffer + presentationBufferPart->length;
+ sessionBufferPart->partMaxLength = SEND_BUF_SIZE - presentationBufferPart->length;
- AcseConnection_destroy(&acseConnection);
+ IsoSession_createDisconnectSpdu(self->session, sessionBufferPart, presentationBufferPart);
- CotpConnection_destroy(self->cotpConnection);
- free(self->cotpConnection);
+ CotpConnection_sendDataMessage(self->cotpConnection, sessionBufferPart);
+ }
- Semaphore_destroy(self->conMutex);
+ self->state = ISO_CON_STATE_STOPPED;
- free(self->receiveBuffer);
- free(self->sendBuffer);
- free(self->clientAddress);
+ break;
- IsoServer isoServer = self->isoServer;
+ case SESSION_ABORT:
+ if (DEBUG_ISO_SERVER)
+ printf("ISO_SERVER: iso_connection: session abort indication\n");
+ self->state = ISO_CON_STATE_STOPPED;
+ break;
- free(self);
+ case SESSION_ERROR:
+ if (DEBUG_ISO_SERVER)
+ printf("ISO_SERVER: iso_connection: session error indication\n");
+ self->state = ISO_CON_STATE_STOPPED;
+ break;
- if (DEBUG_ISO_SERVER)
- printf("ISO_SERVER: connection %p closed\n", self);
+ default: /* illegal state */
+ if (DEBUG_ISO_SERVER)
+ printf("ISO_SERVER: iso_connection: session illegal state\n");
- private_IsoServer_decreaseConnectionCounter(isoServer);
+ self->state = ISO_CON_STATE_STOPPED;
+ break;
+ }
+
+ CotpConnection_resetPayload(self->cotpConnection);
+ }
+ break;
+ case COTP_ERROR:
+ if (DEBUG_ISO_SERVER)
+ printf("ISO_SERVER: Connection closed\n");
+ self->state = ISO_CON_STATE_STOPPED;
+ break;
+ default:
+ if (DEBUG_ISO_SERVER)
+ printf("ISO_SERVER: COTP unknown indication: %i\n", cotpIndication);
+ self->state = ISO_CON_STATE_STOPPED;
+ break;
+ }
}
+#if (CONFIG_MMS_SINGLE_THREADED == 0)
+static void
+handleTcpConnection(void* parameter)
+{
+ IsoConnection self = (IsoConnection) parameter;
+
+ while(self->state == ISO_CON_STATE_RUNNING) {
+ IsoConnection_handleTcpConnection(self);
+ Thread_sleep(1);
+ }
+
+ finalizeIsoConnection(self);
+}
+#endif /* (CONFIG_MMS_SINGLE_THREADED == 0) */
+
IsoConnection
IsoConnection_create(Socket socket, IsoServer isoServer)
{
- IsoConnection self = (IsoConnection) calloc(1, sizeof(struct sIsoConnection));
+ IsoConnection self = (IsoConnection) GLOBAL_CALLOC(1, sizeof(struct sIsoConnection));
self->socket = socket;
- self->receiveBuffer = (uint8_t*) malloc(RECEIVE_BUF_SIZE);
- self->sendBuffer = (uint8_t*) malloc(SEND_BUF_SIZE);
+ self->receiveBuffer = (uint8_t*) GLOBAL_MALLOC(RECEIVE_BUF_SIZE);
+ self->sendBuffer = (uint8_t*) GLOBAL_MALLOC(SEND_BUF_SIZE);
self->msgRcvdHandler = NULL;
self->msgRcvdHandlerParameter = NULL;
self->isoServer = isoServer;
self->state = ISO_CON_STATE_RUNNING;
self->clientAddress = Socket_getPeerAddress(self->socket);
- self->thread = Thread_create((ThreadExecutionFunction) handleTcpConnection, self, true);
+#if (CONFIG_MMS_THREADLESS_STACK != 1)
+ self->isInsideCallback = false;
self->conMutex = Semaphore_create(1);
+#endif
- Thread_start(self->thread);
+ ByteBuffer_wrap(&(self->rcvBuffer), self->receiveBuffer, 0, RECEIVE_BUF_SIZE);
+
+ self->cotpReadBuf = (uint8_t*) GLOBAL_MALLOC(CONFIG_COTP_MAX_TPDU_SIZE + TPKT_RFC1006_HEADER_SIZE);
+ self->cotpWriteBuf = (uint8_t*) GLOBAL_MALLOC(CONFIG_COTP_MAX_TPDU_SIZE + TPKT_RFC1006_HEADER_SIZE);
+
+ ByteBuffer_wrap(&(self->cotpReadBuffer), self->cotpReadBuf, 0, CONFIG_COTP_MAX_TPDU_SIZE + TPKT_RFC1006_HEADER_SIZE);
+ ByteBuffer_wrap(&(self->cotpWriteBuffer), self->cotpWriteBuf, 0, CONFIG_COTP_MAX_TPDU_SIZE + TPKT_RFC1006_HEADER_SIZE);
+
+ self->cotpConnection = (CotpConnection*) GLOBAL_CALLOC(1, sizeof(CotpConnection));
+ CotpConnection_init(self->cotpConnection, self->socket, &(self->rcvBuffer), &(self->cotpReadBuffer), &(self->cotpWriteBuffer));
+
+ self->session = (IsoSession*) GLOBAL_CALLOC(1, sizeof(IsoSession));
+ IsoSession_init(self->session);
+
+ self->presentation = (IsoPresentation*) GLOBAL_CALLOC(1, sizeof(IsoPresentation));
+ IsoPresentation_init(self->presentation);
+
+ self->acseConnection = (AcseConnection*) GLOBAL_CALLOC(1, sizeof(AcseConnection));
+ AcseConnection_init(self->acseConnection, IsoServer_getAuthenticator(self->isoServer),
+ IsoServer_getAuthenticatorParameter(self->isoServer));
if (DEBUG_ISO_SERVER)
- printf("ISO_SERVER: new iso connection thread started\n");
+ printf("ISO_SERVER: IsoConnection: Start to handle connection for client %s\n", self->clientAddress);
+
+#if (CONFIG_MMS_SINGLE_THREADED == 0)
+#if (CONFIG_MMS_THREADLESS_STACK == 0)
+ self->thread = Thread_create((ThreadExecutionFunction) handleTcpConnection, self, true);
+
+ Thread_start(self->thread);
+#endif
+#endif
return self;
}
+void
+IsoConnection_destroy(IsoConnection self)
+{
+ if (DEBUG_ISO_SERVER)
+ printf("ISO_SERVER: destroy called for IsoConnection.\n");
+
+ finalizeIsoConnection(self);
+}
+
char*
IsoConnection_getPeerAddress(IsoConnection self)
{
@@ -416,8 +512,10 @@ IsoConnection_sendMessage(IsoConnection self, ByteBuffer* message, bool handlerM
return;
}
- if (!handlerMode)
+#if (CONFIG_MMS_THREADLESS_STACK != 1)
+ if (self->isInsideCallback == false)
Semaphore_wait(self->conMutex);
+#endif
struct sBufferChain payloadBufferStruct;
BufferChain payloadBuffer = &payloadBufferStruct;
@@ -446,14 +544,16 @@ IsoConnection_sendMessage(IsoConnection self, ByteBuffer* message, bool handlerM
indication = CotpConnection_sendDataMessage(self->cotpConnection, sessionBuffer);
if (DEBUG_ISO_SERVER) {
- if (indication != OK)
+ if (indication != COTP_OK)
printf("ISO_SERVER: IsoConnection_sendMessage failed!\n");
else
printf("ISO_SERVER: IsoConnection_sendMessage success!\n");
}
- if (!handlerMode)
+#if (CONFIG_MMS_THREADLESS_STACK != 1)
+ if (self->isInsideCallback == false)
Semaphore_post(self->conMutex);
+#endif
}
void
@@ -479,6 +579,14 @@ IsoConnection_installListener(IsoConnection self, MessageReceivedHandler handler
void*
IsoConnection_getSecurityToken(IsoConnection self)
{
- return self->securityToken;
+ return self->acseConnection->securityToken;
}
+bool
+IsoConnection_isRunning(IsoConnection self)
+{
+ if (self->state == ISO_CON_STATE_RUNNING)
+ return true;
+ else
+ return false;
+}
diff --git a/src/mms/iso_server/iso_server.c b/src/mms/iso_server/iso_server.c
index dcb7e445..7bdbbba1 100644
--- a/src/mms/iso_server/iso_server.c
+++ b/src/mms/iso_server/iso_server.c
@@ -35,7 +35,7 @@
#include "mms_server_connection.h"
-#include "thread.h"
+#include "hal_thread.h"
#include "iso_server.h"
@@ -57,23 +57,47 @@ struct sIsoServer {
AcseAuthenticator authenticator;
void* authenticatorParameter;
+#if (CONFIG_MMS_THREADLESS_STACK != 1)
Thread serverThread;
+#endif
+
Socket serverSocket;
int tcpPort;
char* localIpAddress;
#if (CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS == -1)
LinkedList openClientConnections;
+
+#if (CONFIG_MMS_THREADLESS_STACK != 1)
+ Semaphore openClientConnectionsMutex; /* mutex for openClientConnections list */
+#endif
+
#else
IsoConnection* openClientConnections;
-#endif
+#endif /* (CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS == -1) */
+#if (CONFIG_MMS_THREADLESS_STACK != 1)
Semaphore userLock;
Semaphore connectionCounterMutex;
+#endif
int connectionCounter;
};
+#if (CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS == -1)
+static inline void
+lockClientConnections(IsoServer self)
+{
+ Semaphore_wait(self->openClientConnectionsMutex);
+}
+
+static inline void
+unlockClientConnections(IsoServer self)
+{
+ Semaphore_post(self->openClientConnectionsMutex);
+}
+#endif /* (CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS == -1) */
+
static void
addClientConnection(IsoServer self, IsoConnection connection)
{
@@ -86,6 +110,10 @@ addClientConnection(IsoServer self, IsoConnection connection)
for (i = 0; i < CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS; i++) {
if (self->openClientConnections[i] == NULL) {
self->openClientConnections[i] = connection;
+
+ if (DEBUG_ISO_SERVER)
+ printf("ISO_SERVER: added connection (%p) index:%i\n", connection, i);
+
break;
}
}
@@ -96,17 +124,37 @@ static void
removeClientConnection(IsoServer self, IsoConnection connection)
{
#if (CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS == -1)
+
+
+#if (CONFIG_MMS_SINGLE_THREADED == 0)
+
+#if (CONFIG_MMS_THREADLESS_STACK != 1)
+ lockClientConnections(self);
+#endif
+
LinkedList_remove(self->openClientConnections, connection);
+
+#if (CONFIG_MMS_THREADLESS_STACK != 1)
+ unlockClientConnections(self);
+#endif
+
+#endif /* (CONFIG_MMS_SINGLE_THREADED == 0) */
+
+
#else
int i;
for (i = 0; i < CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS; i++) {
if (self->openClientConnections[i] == connection) {
+
+ if (DEBUG_ISO_SERVER)
+ printf("ISO_SERVER: removed connection (%p) index:%i\n", connection, i);
+
self->openClientConnections[i] = NULL;
break;
}
}
-#endif
+#endif /* (CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS == -1) */
}
static void
@@ -114,14 +162,35 @@ closeAllOpenClientConnections(IsoServer self)
{
#if (CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS == -1)
+
+#if (CONFIG_MMS_THREADLESS_STACK != 1)
+ lockClientConnections(self);
+#endif
+
LinkedList openConnection = LinkedList_getNext(self->openClientConnections);
while (openConnection != NULL) {
IsoConnection isoConnection = (IsoConnection) openConnection->data;
IsoConnection_close(isoConnection);
+#if (CONFIG_MMS_SINGLE_THREADED == 1)
+ /* if CONFIG_MMS_SINGLE_THREADED == 0 connection instance will be destroyed by connection thread. */
+ IsoConnection_destroy(isoConnection);
+#endif
+
openConnection = LinkedList_getNext(openConnection);
}
+
+#if (CONFIG_MMS_SINGLE_THREADED == 1)
+ LinkedList_destroyStatic(self->openClientConnections);
+ self->openClientConnections = NULL;
+#endif
+
+
+#if (CONFIG_MMS_THREADLESS_STACK != 1)
+ unlockClientConnections(self);
+#endif
+
#else
int i;
@@ -130,27 +199,78 @@ closeAllOpenClientConnections(IsoServer self)
IsoConnection_close(self->openClientConnections[i]);
- break;
+#if (CONFIG_MMS_SINGLE_THREADED == 1)
+ /* if CONFIG_MMS_SINGLE_THREADED == 0 connection instance will be destroyed by connection thread. */
+ IsoConnection_destroy(self->openClientConnections[i]);
+#endif
+
}
}
#endif
}
static void
-isoServerThread(void* isoServerParam)
+handleClientConnections(IsoServer self)
{
- IsoServer self = (IsoServer) isoServerParam;
+#if (CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS == -1)
- if (DEBUG_ISO_SERVER)
- printf("ISO_SERVER: isoServerThread %p started\n", &isoServerParam);
+#if (CONFIG_MMS_THREADLESS_STACK != 1)
+ lockClientConnections(self);
+#endif
- Socket connectionSocket;
+ LinkedList openConnection = LinkedList_getNext(self->openClientConnections);
+ LinkedList lastConnection = self->openClientConnections;
+
+ while (openConnection != NULL) {
+ IsoConnection isoConnection = (IsoConnection) openConnection->data;
+ if (IsoConnection_isRunning(isoConnection))
+ IsoConnection_handleTcpConnection(isoConnection);
+ else {
+ IsoConnection_destroy(isoConnection);
+
+ lastConnection->next = openConnection->next;
+
+ GLOBAL_FREEMEM(openConnection);
+ }
+
+ openConnection = LinkedList_getNext(openConnection);
+ }
+
+#if (CONFIG_MMS_THREADLESS_STACK != 1)
+ unlockClientConnections(self);
+#endif
+
+#else
+
+
+ int i;
+
+ for (i = 0; i < CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS; i++) {
+ if (self->openClientConnections[i] != NULL) {
+ if (IsoConnection_isRunning(self->openClientConnections[i])) {
+
+ IsoConnection_handleTcpConnection(self->openClientConnections[i]);
+ }
+ else {
+ IsoConnection_destroy(self->openClientConnections[i]);
+
+ self->openClientConnections[i] = NULL;
+ }
+
+ }
+ }
+#endif /* (CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS == -1) */
+}
+
+static bool
+setupIsoServer(IsoServer self)
+{
self->serverSocket = (Socket) TcpServerSocket_create(self->localIpAddress, self->tcpPort);
if (self->serverSocket == NULL) {
self->state = ISO_SVR_STATE_ERROR;
- goto cleanUp;
+ return false;
}
ServerSocket_setBacklog((ServerSocket) self->serverSocket, BACKLOG);
@@ -159,36 +279,113 @@ isoServerThread(void* isoServerParam)
self->state = ISO_SVR_STATE_RUNNING;
- while (self->state == ISO_SVR_STATE_RUNNING)
- {
+#if (CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS != -1)
+ if (DEBUG_ISO_SERVER)
+ printf("ISO_SERVER: server is limited to %i client connections.\n", (int) CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS);
+#endif
- if ((connectionSocket = ServerSocket_accept((ServerSocket) self->serverSocket)) == NULL) {
- break;
- }
- else {
+ return true;
+}
+
+
+#if (CONFIG_MMS_THREADLESS_STACK == 0)
+// used by single and multi-threaded versions
+static void
+handleIsoConnections(IsoServer self)
+{
+ Socket connectionSocket;
+
+ if ((connectionSocket = ServerSocket_accept((ServerSocket) self->serverSocket)) != NULL) {
#if (CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS != -1)
- if (private_IsoServer_getConnectionCounter(self) >= CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS) {
- if (DEBUG_ISO_SERVER)
- printf("ISO_SERVER: maximum number of connections reached -> reject connection attempt.\n");
+ if (private_IsoServer_getConnectionCounter(self) >= CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS) {
+ if (DEBUG_ISO_SERVER)
+ printf("ISO_SERVER: maximum number of connections reached -> reject connection attempt.\n");
- Socket_destroy(connectionSocket);
- continue;
- }
+ Socket_destroy(connectionSocket);
+
+#if (CONFIG_MMS_SINGLE_THREADED == 1)
+ handleClientConnections(self);
#endif
- IsoConnection isoConnection = IsoConnection_create(connectionSocket, self);
+ return;
+ }
+#endif
- private_IsoServer_increaseConnectionCounter(self);
+ IsoConnection isoConnection = IsoConnection_create(connectionSocket, self);
- addClientConnection(self, isoConnection);
+ private_IsoServer_increaseConnectionCounter(self);
+ addClientConnection(self, isoConnection);
- self->connectionHandler(ISO_CONNECTION_OPENED, self->connectionHandlerParameter,
- isoConnection);
+ self->connectionHandler(ISO_CONNECTION_OPENED, self->connectionHandlerParameter,
+ isoConnection);
+ }
+
+#if (CONFIG_MMS_SINGLE_THREADED == 1)
+ handleClientConnections(self);
+#endif
+}
+#endif /* (CONFIG_MMS_THREADLESS_STACK == 0) */
+
+// used by non-threaded version
+static void
+handleIsoConnectionsThreadless(IsoServer self)
+{
+ Socket connectionSocket;
+
+ if ((connectionSocket = ServerSocket_accept((ServerSocket) self->serverSocket)) != NULL) {
+
+#if (CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS != -1)
+ if (private_IsoServer_getConnectionCounter(self) >= CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS) {
+ if (DEBUG_ISO_SERVER)
+ printf("ISO_SERVER: maximum number of connections reached -> reject connection attempt.\n");
+
+ Socket_destroy(connectionSocket);
+
+ handleClientConnections(self);
+
+ return;
}
+#endif
+
+ IsoConnection isoConnection = IsoConnection_create(connectionSocket, self);
+
+ private_IsoServer_increaseConnectionCounter(self);
+
+ addClientConnection(self, isoConnection);
+
+ self->connectionHandler(ISO_CONNECTION_OPENED, self->connectionHandlerParameter,
+ isoConnection);
+
+ }
+
+ handleClientConnections(self);
+}
+
+#if (CONFIG_MMS_THREADLESS_STACK != 1)
+// only required for multi-threaded server!
+static void
+isoServerThread(void* isoServerParam)
+{
+ IsoServer self = (IsoServer) isoServerParam;
+
+ if (!setupIsoServer(self)) {
+ if (DEBUG_ISO_SERVER)
+ printf("ISO_SERVER: starting server failed!\n");
+
+ goto cleanUp;
+ }
+
+ if (DEBUG_ISO_SERVER)
+ printf("ISO_SERVER: isoServerThread %p started\n", &isoServerParam);
+ while (self->state == ISO_SVR_STATE_RUNNING)
+ {
+ handleIsoConnections(self);
+
+ Thread_sleep(1);
}
self->state = ISO_SVR_STATE_STOPPED;
@@ -200,11 +397,12 @@ isoServerThread(void* isoServerParam)
printf("ISO_SERVER: isoServerThread %p stopped\n", &isoServerParam);
}
+#endif
IsoServer
IsoServer_create()
{
- IsoServer self = (IsoServer) calloc(1, sizeof(struct sIsoServer));
+ IsoServer self = (IsoServer) GLOBAL_CALLOC(1, sizeof(struct sIsoServer));
self->state = ISO_SVR_STATE_IDLE;
self->tcpPort = TCP_PORT;
@@ -213,10 +411,17 @@ IsoServer_create()
self->openClientConnections = LinkedList_create();
#else
self->openClientConnections = (IsoConnection*)
- calloc(CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS, sizeof(IsoConnection));
+ GLOBAL_CALLOC(CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS, sizeof(IsoConnection));
#endif
+#if (CONFIG_MMS_THREADLESS_STACK != 1)
self->connectionCounterMutex = Semaphore_create(1);
+#if (CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS == -1)
+ self->openClientConnectionsMutex = Semaphore_create(1);
+#endif
+
+#endif /* (CONFIG_MMS_THREADLESS_STACK != 1) */
+
self->connectionCounter = 0;
return self;
@@ -259,6 +464,7 @@ IsoServer_getAuthenticatorParameter(IsoServer self)
return self->authenticatorParameter;
}
+#if (CONFIG_MMS_THREADLESS_STACK != 1)
void
IsoServer_startListening(IsoServer self)
{
@@ -266,22 +472,132 @@ IsoServer_startListening(IsoServer self)
Thread_start(self->serverThread);
+ /* wait until server is up */
while (self->state == ISO_SVR_STATE_IDLE)
Thread_sleep(1);
if (DEBUG_ISO_SERVER)
printf("ISO_SERVER: new iso server thread started\n");
}
+#endif
void
-IsoServer_stopListening(IsoServer self)
+IsoServer_startListeningThreadless(IsoServer self)
{
- self->state = ISO_SVR_STATE_STOPPED;
+ if (!setupIsoServer(self)) {
+ if (DEBUG_ISO_SERVER)
+ printf("ISO_SERVER: starting server failed!\n");
+
+ self->serverSocket = NULL;
+ }
+ else {
+ self->state = ISO_SVR_STATE_RUNNING;
+
+ if (DEBUG_ISO_SERVER)
+ printf("ISO_SERVER: new iso server (threadless) started\n");
+ }
+}
+
+int
+IsoServer_waitReady(IsoServer self, unsigned int timeoutMs)
+{
+ int result;
+
+ if (self->state == ISO_SVR_STATE_RUNNING) {
+ HandleSet handles;
+
+ handles = Handleset_new();
+ if (handles != NULL) {
+#if (CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS == -1)
+
+#if (CONFIG_MMS_THREADLESS_STACK != 1)
+ lockClientConnections(self);
+#endif
+
+ LinkedList openConnection = LinkedList_getNext(self->openClientConnections);
+ LinkedList lastConnection = self->openClientConnections;
+
+ while (openConnection != NULL) {
+ IsoConnection isoConnection = (IsoConnection) openConnection->data;
+
+ if (IsoConnection_isRunning(isoConnection)) {
+ IsoConnection_addHandleSet(isoConnection, handles);
+ openConnection = LinkedList_getNext(openConnection);
+ } else {
+ IsoConnection_destroy(isoConnection);
+ lastConnection->next = openConnection->next;
+ free(openConnection);
+ openConnection = lastConnection->next;
+ }
+
+ lastConnection = lastConnection->next;
+ }
+
+#if (CONFIG_MMS_THREADLESS_STACK != 1)
+ unlockClientConnections(self);
+#endif
+#else
+ int i;
+
+ for (i = 0; i < CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS; i++) {
+ if (self->openClientConnections[i] != NULL) {
+ if (IsoConnection_isRunning(self->openClientConnections[i])) {
+ IsoConnection_addHandleSet(self->openClientConnections[i], handles);
+ } else {
+ IsoConnection_destroy(self->openClientConnections[i]);
+ self->openClientConnections[i] = NULL;
+ }
+ }
+ }
+#endif /* (CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS == -1) */
+ Handleset_addSocket(handles, self->serverSocket);
+ result = Handleset_waitReady(handles, timeoutMs);
+ Handleset_destroy(handles);
+ } else {
+ result = -1;
+ }
+ } else {
+ result = -1;
+ }
+
+ return result;
+}
+
+
+void
+IsoServer_processIncomingMessages(IsoServer self)
+{
+ if (self->state == ISO_SVR_STATE_RUNNING)
+ handleIsoConnectionsThreadless(self);
+}
+
+static void
+stopListening(IsoServer self)
+{
+ self->state = ISO_SVR_STATE_STOPPED;
if (self->serverSocket != NULL) {
ServerSocket_destroy((ServerSocket) self->serverSocket);
self->serverSocket = NULL;
}
+}
+
+void
+IsoServer_stopListeningThreadless(IsoServer self)
+{
+ stopListening(self);
+
+ closeAllOpenClientConnections(self);
+
+ if (DEBUG_ISO_SERVER)
+ printf("ISO_SERVER: IsoServer_stopListeningThreadless finished!\n");
+}
+
+#if (CONFIG_MMS_THREADLESS_STACK != 1)
+void
+IsoServer_stopListening(IsoServer self)
+{
+ stopListening(self);
if (self->serverThread != NULL)
Thread_destroy(self->serverThread);
@@ -295,6 +611,7 @@ IsoServer_stopListening(IsoServer self)
if (DEBUG_ISO_SERVER)
printf("ISO_SERVER: IsoServer_stopListening finished!\n");
}
+#endif
void
IsoServer_closeConnection(IsoServer self, IsoConnection isoConnection)
@@ -318,40 +635,69 @@ IsoServer_setConnectionHandler(IsoServer self, ConnectionIndicationHandler handl
void
IsoServer_destroy(IsoServer self)
{
+
+#if (CONFIG_MMS_THREADLESS_STACK != 1)
if (self->state == ISO_SVR_STATE_RUNNING)
IsoServer_stopListening(self);
+#endif
#if (CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS == -1)
- LinkedList_destroy(self->openClientConnections);
+
+#if (CONFIG_MMS_SINGLE_THREADED == 1)
+ if (self->openClientConnections != NULL)
+ LinkedList_destroy(self->openClientConnections);
#else
- free(self->openClientConnections);
+ if (self->openClientConnections != NULL)
+ LinkedList_destroyStatic(self->openClientConnections);
+#endif /* (CONFIG_MMS_SINGLE_THREADED == 1) */
+
+#if (CONFIG_MMS_THREADLESS_STACK != 1)
+ lockClientConnections(self);
+ Semaphore_destroy(self->openClientConnectionsMutex);
#endif
+#else
+ GLOBAL_FREEMEM(self->openClientConnections);
+#endif /* (CONFIG_MAXIMUM_TCP_CLIENT_CONNECTIONS == -1) */
+
+#if (CONFIG_MMS_THREADLESS_STACK != 1)
Semaphore_destroy(self->connectionCounterMutex);
+#endif
- free(self);
+ GLOBAL_FREEMEM(self);
}
void
private_IsoServer_increaseConnectionCounter(IsoServer self)
{
+#if (CONFIG_MMS_THREADLESS_STACK != 1)
Semaphore_wait(self->connectionCounterMutex);
+#endif
+
self->connectionCounter++;
if (DEBUG_ISO_SERVER)
printf("IsoServer: increase connection counter to %i!\n", self->connectionCounter);
+
+#if (CONFIG_MMS_THREADLESS_STACK != 1)
Semaphore_post(self->connectionCounterMutex);
+#endif
}
void
private_IsoServer_decreaseConnectionCounter(IsoServer self)
{
-
+#if (CONFIG_MMS_THREADLESS_STACK != 1)
Semaphore_wait(self->connectionCounterMutex);
+#endif
+
self->connectionCounter--;
if (DEBUG_ISO_SERVER)
printf("IsoServer: decrease connection counter to %i!\n", self->connectionCounter);
+
+#if (CONFIG_MMS_THREADLESS_STACK != 1)
Semaphore_post(self->connectionCounterMutex);
+#endif
}
int
@@ -359,13 +705,20 @@ private_IsoServer_getConnectionCounter(IsoServer self)
{
int connectionCounter;
+#if (CONFIG_MMS_THREADLESS_STACK != 1)
Semaphore_wait(self->connectionCounterMutex);
+#endif
+
connectionCounter = self->connectionCounter;
+
+#if (CONFIG_MMS_THREADLESS_STACK != 1)
Semaphore_post(self->connectionCounterMutex);
+#endif
return connectionCounter;
}
+#if (CONFIG_MMS_THREADLESS_STACK != 1)
void
IsoServer_setUserLock(IsoServer self, Semaphore userLock)
{
@@ -385,3 +738,4 @@ IsoServer_userUnlock(IsoServer self)
if (self->userLock != NULL)
Semaphore_post(self->userLock);
}
+#endif
diff --git a/src/mms/iso_session/iso_session.c b/src/mms/iso_session/iso_session.c
index 0b3b1614..8e0fe0ca 100644
--- a/src/mms/iso_session/iso_session.c
+++ b/src/mms/iso_session/iso_session.c
@@ -127,12 +127,13 @@ parseSessionHeaderParameters(IsoSession* session, ByteBuffer* message, int param
case 1: /* Connection Identifier */
if (DEBUG_SESSION)
printf("SESSION: PGI - connection identifier\n");
- printf("TODO: PGI not implemented!");
+
offset += parameterLength;
break;
case 5: /* Connection/Accept Item */
if (DEBUG_SESSION)
printf("SESSION: PGI - Connection/Accept Item\n");
+
int connectAcceptLen;
connectAcceptLen = parseAcceptParameters(session, message, offset, parameterLength);
diff --git a/src/sampled_values/sv_publisher.c b/src/sampled_values/sv_publisher.c
index aa3b2b60..d98c9e2f 100644
--- a/src/sampled_values/sv_publisher.c
+++ b/src/sampled_values/sv_publisher.c
@@ -95,7 +95,7 @@ preparePacketBuffer(SampledValuesPublisher self, CommParameters* parameters, cha
else
self->ethernetSocket = Ethernet_createSocket(CONFIG_ETHERNET_INTERFACE_ID, dstAddr);
- self->buffer = (uint8_t*) malloc(SV_MAX_MESSAGE_SIZE);
+ self->buffer = (uint8_t*) GLOBAL_MALLOC(SV_MAX_MESSAGE_SIZE);
memcpy(self->buffer, dstAddr, 6);
memcpy(self->buffer + 6, srcAddr, 6);
diff --git a/src/vs/libiec61850-wo-goose.def b/src/vs/libiec61850-wo-goose.def
index b550d1dd..a531d9ab 100644
--- a/src/vs/libiec61850-wo-goose.def
+++ b/src/vs/libiec61850-wo-goose.def
@@ -93,6 +93,7 @@ EXPORTS
ControlObjectClient_select @220
ControlObjectClient_selectWithValue @221
ControlObjectClient_setLastApplError @222
+ ControlObjectClient_setCommandTerminationHandler
DataAttribute_create @273
DataObject_create @274
DataObject_hasFCData @275
@@ -378,6 +379,8 @@ EXPORTS
MmsValue_toUint32 @774
MmsValue_toUnixTimestamp @775
MmsValue_update @776
+ MmsValue_getBitStringAsIntegerBigEndian
+ MmsValue_setBitStringFromIntegerBigEndian
MmsVariableAccessSpecification_create @777
MmsVariableAccessSpecification_createAlternateAccess @778
MmsVariableAccessSpecification_destroy @779
@@ -390,6 +393,7 @@ EXPORTS
MmsVariableSpecification_getSize @786
MmsVariableSpecification_getStructureElements @787
MmsVariableSpecification_getType @788
+ MmsVariableSpecification_getNamedVariableRecursive
ModelNode_getChild @789
ModelNode_getChildCount @790
ModelNode_getObjectReference @791
@@ -438,3 +442,32 @@ EXPORTS
AcseAuthenticationParameter_destroy
AcseAuthenticationParameter_setAuthMechanism
AcseAuthenticationParameter_setPassword
+ IedServer_startThreadless
+ IedServer_processIncomingData
+ IedServer_performPeriodicTasks
+ IedServer_stopThreadless
+ Dbpos_fromMmsValue
+ Dbpos_toMmsValue
+ SettingGroupControlBlock_create
+ MmsConnection_setConnectTimeout
+ IedConnection_setConnectTimeout
+ MmsValue_newVisibleStringWithSize
+ MmsValue_newMmsStringWithSize
+ MmsValue_setInt8
+ MmsValue_setInt16
+ LogicalDevice_getSettingGroupControlBlock
+ IedServer_changeActiveSettingGroup
+ IedServer_setActiveSettingGroupChangedHandler
+ IedServer_disableGoosePublishing
+ IedServer_setEditSettingGroupChangedHandler
+ IedServer_setEditSettingGroupConfirmationHandler
+ IedConnection_getDataDirectoryByFC
+ IedServer_getActiveSettingGroup
+ ClientReport_hasSeqNum
+ ClientReport_getSeqNum
+ ClientReport_hasDataSetName
+ ClientReport_hasReasonForInclusion
+ ClientReport_hasConfRev
+ ClientReport_getConfRev
+ ClientReport_hasBufOvfl
+ ClientReport_hasDataReference
diff --git a/src/vs/libiec61850.def b/src/vs/libiec61850.def
index 807393a8..2fc47403 100644
--- a/src/vs/libiec61850.def
+++ b/src/vs/libiec61850.def
@@ -91,8 +91,9 @@ EXPORTS
ControlObjectClient_getObjectReference @218
ControlObjectClient_operate @219
ControlObjectClient_select @220
- ControlObjectClient_selectWithValue @221
+ ControlObjectClient_selectWithValue @221MmsConnection_setConnectTimeout
ControlObjectClient_setLastApplError @222
+ ControlObjectClient_setCommandTerminationHandler
DataAttribute_create @273
DataObject_create @274
DataObject_hasFCData @275
@@ -138,10 +139,7 @@ EXPORTS
GooseSubscriber_isTest @347
GooseSubscriber_needsCommission @348
GooseSubscriber_setAppId @349
- GooseSubscriber_setInterfaceId @350
GooseSubscriber_setListener @351
- GooseSubscriber_subscribe @352
- GooseSubscriber_unsubscribe @353
Hal_getTimeInMs @354
IedConnection_abort @366
IedConnection_close @367
@@ -405,6 +403,8 @@ EXPORTS
MmsValue_toUint32 @774
MmsValue_toUnixTimestamp @775
MmsValue_update @776
+ MmsValue_getBitStringAsIntegerBigEndian
+ MmsValue_setBitStringFromIntegerBigEndian
MmsVariableAccessSpecification_create @777
MmsVariableAccessSpecification_createAlternateAccess @778
MmsVariableAccessSpecification_destroy @779
@@ -417,6 +417,7 @@ EXPORTS
MmsVariableSpecification_getSize @786
MmsVariableSpecification_getStructureElements @787
MmsVariableSpecification_getType @788
+ MmsVariableSpecification_getNamedVariableRecursive
ModelNode_getChild @789
ModelNode_getChildCount @790
ModelNode_getObjectReference @791
@@ -465,5 +466,32 @@ EXPORTS
AcseAuthenticationParameter_destroy
AcseAuthenticationParameter_setAuthMechanism
AcseAuthenticationParameter_setPassword
-
-
+ IedServer_startThreadless
+ IedServer_processIncomingData
+ IedServer_performPeriodicTasks
+ IedServer_stopThreadless
+ Dbpos_fromMmsValue
+ Dbpos_toMmsValue
+ SettingGroupControlBlock_create
+ MmsConnection_setConnectTimeout
+ IedConnection_setConnectTimeout
+ MmsValue_newVisibleStringWithSize
+ MmsValue_newMmsStringWithSize
+ MmsValue_setInt8
+ MmsValue_setInt16
+ LogicalDevice_getSettingGroupControlBlock
+ IedServer_changeActiveSettingGroup
+ IedServer_setActiveSettingGroupChangedHandler
+ IedServer_disableGoosePublishing
+ IedServer_setEditSettingGroupChangedHandler
+ IedServer_setEditSettingGroupConfirmationHandler
+ IedConnection_getDataDirectoryByFC
+ IedServer_getActiveSettingGroup
+ ClientReport_hasSeqNum
+ ClientReport_getSeqNum
+ ClientReport_hasDataSetName
+ ClientReport_hasReasonForInclusion
+ ClientReport_hasConfRev
+ ClientReport_getConfRev
+ ClientReport_hasBufOvfl
+ ClientReport_hasDataReference
diff --git a/tools/model_generator/genconfig.jar b/tools/model_generator/genconfig.jar
index 9d65c0bc..51a60770 100644
Binary files a/tools/model_generator/genconfig.jar and b/tools/model_generator/genconfig.jar differ
diff --git a/tools/model_generator/genmodel.jar b/tools/model_generator/genmodel.jar
index f04e74a0..84067d06 100644
Binary files a/tools/model_generator/genmodel.jar and b/tools/model_generator/genmodel.jar differ
diff --git a/tools/model_generator/src/com/libiec61850/scl/DataAttributeDefinition.java b/tools/model_generator/src/com/libiec61850/scl/DataAttributeDefinition.java
index 6fbc447a..bbc2fba4 100644
--- a/tools/model_generator/src/com/libiec61850/scl/DataAttributeDefinition.java
+++ b/tools/model_generator/src/com/libiec61850/scl/DataAttributeDefinition.java
@@ -23,11 +23,17 @@ package com.libiec61850.scl;
* See COPYING file for the complete license text.
*/
+import java.util.LinkedList;
+
import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
import com.libiec61850.scl.model.AttributeType;
+import com.libiec61850.scl.model.DataModelValue;
import com.libiec61850.scl.model.FunctionalConstraint;
import com.libiec61850.scl.model.TriggerOptions;
+import com.libiec61850.scl.types.IllegalValueException;
+import com.libiec61850.scl.types.SclType;
public class DataAttributeDefinition {
@@ -38,8 +44,9 @@ public class DataAttributeDefinition {
private FunctionalConstraint fc = null;
private AttributeType attributeType = null;
private TriggerOptions triggerOptions = null;
+ private DataModelValue value = null;
- public DataAttributeDefinition(Node node) throws SclParserException {
+ public DataAttributeDefinition(Node node) throws SclParserException {
this.name = ParserUtils.parseAttribute(node, "name");
this.bType = ParserUtils.parseAttribute(node, "bType");
this.type = ParserUtils.parseAttribute(node, "type");
@@ -89,6 +96,31 @@ public class DataAttributeDefinition {
if (countStr != null)
count = new Integer(countStr);
+
+ if (this.bType != null) {
+
+ NodeList elementNodes = node.getChildNodes();
+
+ if (elementNodes != null) {
+
+ for (int i = 0; i < elementNodes.getLength(); i++) {
+ Node elementNode = elementNodes.item(i);
+ if (elementNode.getNodeName().equals("Val")) {
+
+ String value = elementNode.getTextContent();
+
+ if (attributeType != AttributeType.ENUMERATED)
+ try {
+ this.value = new DataModelValue(attributeType, null, value);
+ } catch (IllegalValueException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ }
+ }
+ }
}
public String getName() {
@@ -115,6 +147,10 @@ public class DataAttributeDefinition {
return count;
}
+ public DataModelValue getValue() {
+ return value;
+ }
+
public TriggerOptions getTriggerOptions() {
return this.triggerOptions;
}
diff --git a/tools/model_generator/src/com/libiec61850/scl/model/DataAttribute.java b/tools/model_generator/src/com/libiec61850/scl/model/DataAttribute.java
index 7318aa1d..573183f2 100644
--- a/tools/model_generator/src/com/libiec61850/scl/model/DataAttribute.java
+++ b/tools/model_generator/src/com/libiec61850/scl/model/DataAttribute.java
@@ -47,6 +47,8 @@ public class DataAttribute implements DataModelNode {
private SclType sclType = null;
private TriggerOptions triggerOptions = null;
+
+ private DataAttributeDefinition definition = null;
public DataAttribute(DataAttributeDefinition daDefinition, TypeDeclarations typeDeclarations, FunctionalConstraint fc,
DataModelNode parent) throws SclParserException {
@@ -55,6 +57,7 @@ public class DataAttribute implements DataModelNode {
this.type = daDefinition.getAttributeType();
this.count = daDefinition.getCount();
this.parent = parent;
+ this.definition = daDefinition;
if (this.fc == null)
this.fc = fc;
@@ -163,6 +166,10 @@ public class DataAttribute implements DataModelNode {
public TriggerOptions getTriggerOptions() {
return this.triggerOptions;
}
+
+ public DataAttributeDefinition getDefinition() {
+ return this.definition;
+ }
@Override
public DataModelNode getParent() {
diff --git a/tools/model_generator/src/com/libiec61850/scl/model/LogicalNode.java b/tools/model_generator/src/com/libiec61850/scl/model/LogicalNode.java
index fb35f5f3..8fa7c58c 100644
--- a/tools/model_generator/src/com/libiec61850/scl/model/LogicalNode.java
+++ b/tools/model_generator/src/com/libiec61850/scl/model/LogicalNode.java
@@ -51,7 +51,7 @@ public class LogicalNode implements DataModelNode {
private List logs;
private List settingGroupControlBlocks;
- private LogicalDevice parentLogicalDevice;
+ private LogicalDevice parentLogicalDevice;
public LogicalNode(Node lnNode, TypeDeclarations typeDeclarations, LogicalDevice parent) throws SclParserException {
@@ -133,6 +133,9 @@ public class LogicalNode implements DataModelNode {
List sgNodes = ParserUtils.getChildNodesWithTag(lnNode, "SettingControl");
+ if ((this.lnClass.equals("LLN0") == false) && (sgNodes.size() > 0))
+ throw new SclParserException(lnNode, "LN other than LN0 is not allowed to contain SettingControl");
+
if (sgNodes.size() > 1)
throw new SclParserException(lnNode, "LN contains more then one SettingControl");
@@ -257,6 +260,10 @@ public class LogicalNode implements DataModelNode {
public List getGSEControlBlocks() {
return gseControlBlocks;
}
+
+ public List getSettingGroupControlBlocks() {
+ return settingGroupControlBlocks;
+ }
@Override
public DataModelNode getChildByName(String childName) {
diff --git a/tools/model_generator/src/com/libiec61850/scl/types/DataAttributeType.java b/tools/model_generator/src/com/libiec61850/scl/types/DataAttributeType.java
index ed56dda3..928547c8 100644
--- a/tools/model_generator/src/com/libiec61850/scl/types/DataAttributeType.java
+++ b/tools/model_generator/src/com/libiec61850/scl/types/DataAttributeType.java
@@ -66,6 +66,7 @@ public class DataAttributeType extends SclType {
subDataAttributes.add(dad);
}
+
}
}
}
diff --git a/tools/model_generator/src/com/libiec61850/scl/types/DataObjectType.java b/tools/model_generator/src/com/libiec61850/scl/types/DataObjectType.java
index b818f225..3e0f3456 100644
--- a/tools/model_generator/src/com/libiec61850/scl/types/DataObjectType.java
+++ b/tools/model_generator/src/com/libiec61850/scl/types/DataObjectType.java
@@ -75,12 +75,22 @@ public class DataObjectType extends SclType {
if (elementNode.getNodeName().equals("DA")) {
DataAttributeDefinition dad = new DataAttributeDefinition(elementNode);
+
+ DataAttributeDefinition otherDefinition = getDataAttributeByName(dad.getName());
+
+ if (otherDefinition != null) {
+
+ if (otherDefinition.getFc() == dad.getFc())
+ throw new SclParserException(xmlNode,
+ "DO type definition contains multiple elements of name \"" +
+ dad.getName() + "\"");
+ }
- if ((getDataAttributeByName(dad.getName()) != null) ||
- (getDataObjectByName(dad.getName()) != null))
+ if (getDataObjectByName(dad.getName()) != null) {
throw new SclParserException(xmlNode,
"DO type definition contains multiple elements of name \"" +
dad.getName() + "\"");
+ }
dataAttributes.add(dad);
diff --git a/tools/model_generator/src/com/libiec61850/tools/DynamicModelGenerator.java b/tools/model_generator/src/com/libiec61850/tools/DynamicModelGenerator.java
index 9b5868f5..2fb76e4f 100644
--- a/tools/model_generator/src/com/libiec61850/tools/DynamicModelGenerator.java
+++ b/tools/model_generator/src/com/libiec61850/tools/DynamicModelGenerator.java
@@ -31,6 +31,7 @@ import java.io.InputStream;
import java.io.PrintStream;
import java.util.List;
+import com.libiec61850.scl.DataAttributeDefinition;
import com.libiec61850.scl.SclParser;
import com.libiec61850.scl.SclParserException;
import com.libiec61850.scl.communication.ConnectedAP;
@@ -46,6 +47,7 @@ import com.libiec61850.scl.model.IED;
import com.libiec61850.scl.model.LogicalDevice;
import com.libiec61850.scl.model.LogicalNode;
import com.libiec61850.scl.model.ReportControlBlock;
+import com.libiec61850.scl.model.SettingControl;
public class DynamicModelGenerator {
@@ -82,7 +84,7 @@ public class DynamicModelGenerator {
output.println("MODEL(" + ied.getName() + "){");
for (LogicalDevice logicalDevice : logicalDevices) {
output.print("LD(");
- output.print(ied.getName() + logicalDevice.getInst() + "){\n");
+ output.print(logicalDevice.getInst() + "){\n");
exportLogicalNodes(output, logicalDevice);
@@ -106,6 +108,11 @@ public class DynamicModelGenerator {
}
private void exportLogicalNode(PrintStream output, LogicalNode logicalNode) {
+
+ for (SettingControl sgcb : logicalNode.getSettingGroupControlBlocks()) {
+ output.print("SG(" + sgcb.getActSG() + " " + sgcb.getNumOfSGs() + ")\n");
+ }
+
for (DataObject dataObject : logicalNode.getDataObjects()) {
output.print("DO(" + dataObject.getName() + " " + dataObject.getCount() + "){\n");
@@ -274,8 +281,12 @@ public class DynamicModelGenerator {
output.print(")");
if (dataAttribute.isBasicAttribute()) {
- DataModelValue value = dataAttribute.getValue();
-
+ DataModelValue value = dataAttribute.getValue();
+
+ /* if no value is given use default value for type if present */
+ if (value == null)
+ value = dataAttribute.getDefinition().getValue();
+
if (value != null) {
switch (dataAttribute.getType()) {
diff --git a/tools/model_generator/src/com/libiec61850/tools/StaticModelGenerator.java b/tools/model_generator/src/com/libiec61850/tools/StaticModelGenerator.java
index bd744a06..0c6afc0b 100644
--- a/tools/model_generator/src/com/libiec61850/tools/StaticModelGenerator.java
+++ b/tools/model_generator/src/com/libiec61850/tools/StaticModelGenerator.java
@@ -44,6 +44,7 @@ import com.libiec61850.scl.model.DataAttribute;
import com.libiec61850.scl.model.DataModelValue;
import com.libiec61850.scl.model.DataObject;
import com.libiec61850.scl.model.DataSet;
+import com.libiec61850.scl.model.FunctionalConstraint;
import com.libiec61850.scl.model.FunctionalConstraintData;
import com.libiec61850.scl.model.GSEControl;
import com.libiec61850.scl.model.IED;
@@ -51,6 +52,7 @@ import com.libiec61850.scl.model.LogicalDevice;
import com.libiec61850.scl.model.LogicalNode;
import com.libiec61850.scl.model.ReportControlBlock;
import com.libiec61850.scl.model.Server;
+import com.libiec61850.scl.model.SettingControl;
import com.libiec61850.scl.model.TriggerOptions;
public class StaticModelGenerator {
@@ -68,6 +70,10 @@ public class StaticModelGenerator {
private StringBuffer gseControlBlocks;
private List gseVariableNames;
private int currentGseVariableNumber = 0;
+
+ private StringBuffer settingGroupControlBlocks;
+ private List sgcbVariableNames;
+ private int currentSGCBVariableNumber = 0;
private List dataSetNames;
@@ -88,6 +94,9 @@ public class StaticModelGenerator {
this.rcbVariableNames = new LinkedList();
this.gseControlBlocks = new StringBuffer();
this.gseVariableNames = new LinkedList();
+
+ this.settingGroupControlBlocks = new StringBuffer();
+ this.sgcbVariableNames = new LinkedList();
SclParser sclParser = new SclParser(stream);
@@ -195,15 +204,19 @@ public class StaticModelGenerator {
}
}
- private String getLogicalDeviceName(LogicalDevice logicalDevice) {
- String logicalDeviceName = logicalDevice.getLdName();
-
- if (logicalDeviceName == null)
- logicalDeviceName = ied.getName() + logicalDevice.getInst();
-
- return logicalDeviceName;
+// private String getLogicalDeviceName(LogicalDevice logicalDevice) {
+// String logicalDeviceName = logicalDevice.getLdName();
+//
+// if (logicalDeviceName == null)
+// logicalDeviceName = ied.getName() + logicalDevice.getInst();
+//
+// return logicalDeviceName;
+// }
+
+ private String getLogicalDeviceInst(LogicalDevice logicalDevice) {
+ return logicalDevice.getInst();
}
-
+
private void printDeviceModelDefinitions() {
printDataSets();
@@ -213,6 +226,8 @@ public class StaticModelGenerator {
createReportVariableList(logicalDevices);
createGooseVariableList(logicalDevices);
+
+ createSettingControlsVariableList(logicalDevices);
for (int i = 0; i < logicalDevices.size(); i++) {
@@ -222,7 +237,7 @@ public class StaticModelGenerator {
variablesList.add(ldName);
- String logicalDeviceName = getLogicalDeviceName(logicalDevice);
+ String logicalDeviceName = getLogicalDeviceInst(logicalDevice);
cOut.println("\nLogicalDevice " + ldName + " = {");
@@ -257,6 +272,11 @@ public class StaticModelGenerator {
cOut.println("extern GSEControlBlock " + gcb + ";");
cOut.println(gseControlBlocks);
+
+ for (String sgcb : sgcbVariableNames)
+ cOut.println("extern SettingGroupControlBlock " + sgcb + ";");
+
+ cOut.println(settingGroupControlBlocks);
String firstLogicalDeviceName = logicalDevices.get(0).getInst();
cOut.println("\nIedModel iedModel = {");
@@ -277,6 +297,11 @@ public class StaticModelGenerator {
cOut.println(" &" + gseVariableNames.get(0) + ",");
else
cOut.println(" NULL,");
+
+ if (sgcbVariableNames.size() > 0)
+ cOut.println(" &" + sgcbVariableNames.get(0) + ",");
+ else
+ cOut.println(" NULL,");
cOut.println(" initializeValues\n};");
}
@@ -315,7 +340,12 @@ public class StaticModelGenerator {
for (ReportControlBlock rcb : rcbs) {
- for (int i = 0; i < rcb.getRptEna().getMaxInstances(); i++) {
+ int maxInstances = 1;
+
+ if (rcb.getRptEna() != null)
+ maxInstances = rcb.getRptEna().getMaxInstances();
+
+ for (int i = 0; i < maxInstances; i++) {
String rcbVariableName = "iedModel_" + ldName + "_" + ln.getName() + "_report" + rcbCount;
rcbVariableNames.add(rcbVariableName);
rcbCount++;
@@ -325,6 +355,26 @@ public class StaticModelGenerator {
}
}
}
+
+ private void createSettingControlsVariableList(List logicalDevices) {
+ for (LogicalDevice ld : logicalDevices) {
+ List lnodes = ld.getLogicalNodes();
+
+ String ldName = ld.getInst();
+
+ for (LogicalNode ln : lnodes) {
+ List sgcbs = ln.getSettingGroupControlBlocks();
+
+ for (SettingControl sgcb : sgcbs) {
+
+ String sgcbVariableName = "iedModel_" + ldName + "_" + ln.getName() + "_sgcb";
+
+ sgcbVariableNames.add(sgcbVariableName);
+
+ }
+ }
+ }
+ }
private void printLogicalNodeDefinitions(String ldName, List logicalNodes) {
for (int i = 0; i < logicalNodes.size(); i++) {
@@ -354,6 +404,8 @@ public class StaticModelGenerator {
printReportControlBlocks(lnName, logicalNode);
printGSEControlBlocks(ldName, lnName, logicalNode);
+
+ printSettingControlBlock(lnName, logicalNode);
}
}
@@ -412,6 +464,13 @@ public class StaticModelGenerator {
DataAttribute dataAttribute = dataAttributes.get(i);
String daName = doName + "_" + dataAttribute.getName();
+
+ if (dataAttribute.getFc() == FunctionalConstraint.SE) {
+
+ if (daName.startsWith("iedModel_SE_") == false)
+ daName = daName.substring(0, 9) + "SE_" + daName.substring(9);
+
+ }
variablesList.add(daName);
@@ -419,8 +478,18 @@ public class StaticModelGenerator {
cOut.println(" DataAttributeModelType,");
cOut.println(" \"" + dataAttribute.getName() + "\",");
cOut.println(" (ModelNode*) &" + doName + ",");
- if (i < (dataAttributes.size() - 1))
- cOut.println(" (ModelNode*) &" + doName + "_" + dataAttributes.get(i + 1).getName() + ",");
+ if (i < (dataAttributes.size() - 1)) {
+ DataAttribute sibling = dataAttributes.get(i + 1);
+
+ String siblingDoName = doName;
+
+ if (sibling.getFc() == FunctionalConstraint.SE) {
+ if (siblingDoName.startsWith("iedModel_SE_") == false)
+ siblingDoName = siblingDoName.substring(0, 9) + "SE_" + siblingDoName.substring(9);
+ }
+
+ cOut.println(" (ModelNode*) &" + siblingDoName + "_" + dataAttributes.get(i + 1).getName() + ",");
+ }
else
cOut.println(" NULL,");
if ((dataAttribute.getSubDataAttributes() != null) && (dataAttribute.getSubDataAttributes().size() > 0))
@@ -570,7 +639,13 @@ public class StaticModelGenerator {
private void printDataAttributeForwardDeclarations(String doName, List dataAttributes) {
for (DataAttribute dataAttribute : dataAttributes) {
String daName = doName + "_" + dataAttribute.getName();
-
+
+ if (dataAttribute.getFc() == FunctionalConstraint.SE) {
+
+ if (daName.startsWith("iedModel_SE_") == false)
+ daName = daName.substring(0, 9) + "SE_" + daName.substring(9);
+ }
+
cOut.println("extern DataAttribute " + daName + ";");
hOut.println("extern DataAttribute " + daName + ";");
@@ -587,7 +662,7 @@ public class StaticModelGenerator {
cOut.println(" * automatically generated from " + filename);
cOut.println(" */");
cOut.println("#include ");
- cOut.println("#include \"model.h\"");
+ cOut.println("#include \"iec61850_model.h\"");
cOut.println();
}
@@ -600,7 +675,7 @@ public class StaticModelGenerator {
hOut.println("#ifndef STATIC_MODEL_H_");
hOut.println("#define STATIC_MODEL_H_\n");
hOut.println("#include ");
- hOut.println("#include \"model.h\"");
+ hOut.println("#include \"iec61850_model.h\"");
hOut.println();
}
@@ -718,9 +793,37 @@ public class StaticModelGenerator {
printReportControlBlockInstance(lnPrefix, rcb, "", reportNumber, reportsCount);
reportNumber++;
}
-
}
-
+ }
+
+ private void printSettingControlBlock(String lnPrefix, LogicalNode logicalNode)
+ {
+ List settingControls = logicalNode.getSettingGroupControlBlocks();
+
+ if (settingControls.size() > 0) {
+ System.out.println("print SGCB for " + lnPrefix);
+
+ SettingControl sgcb = settingControls.get(0);
+
+ String sgcbVariableName = lnPrefix + "_sgcb";
+
+ String sgcbString = "\nSettingGroupControlBlock " + sgcbVariableName + " = {";
+
+ sgcbString += "&" + lnPrefix + ", ";
+
+ sgcbString += sgcb.getActSG() + ", " + sgcb.getNumOfSGs() + ", 0, false, 0, 0, ";
+
+ if (currentSGCBVariableNumber < (sgcbVariableNames.size() - 1))
+ sgcbString += "&" + sgcbVariableNames.get(currentGseVariableNumber + 1);
+ else
+ sgcbString += "NULL";
+
+ sgcbString += "};\n";
+
+ this.settingGroupControlBlocks.append(sgcbString);
+
+ currentSGCBVariableNumber++;
+ }
}
private void printReportControlBlockInstance(String lnPrefix, ReportControlBlock rcb, String index, int reportNumber, int reportsCount) {
@@ -798,8 +901,6 @@ public class StaticModelGenerator {
rcbString += "NULL";
rcbString += "};\n";
-
- System.out.println("RCB: " + rcbString);
this.reportControlBlocks.append(rcbString);
}
@@ -873,7 +974,7 @@ public class StaticModelGenerator {
String dataSetEntryName = dataSetVariableName + "_fcda" + fcdaCount;
cOut.println("DataSetEntry " + dataSetEntryName + " = {");
- cOut.println(" \"" + ied.getName() + fcda.getLdInstance() + "\",");
+ cOut.println(" \"" + fcda.getLdInstance() + "\",");
String mmsVariableName = "";
@@ -918,7 +1019,7 @@ public class StaticModelGenerator {
String lnVariableName = "iedModel_" + logicalDevice.getInst() + "_" + logicalNode.getName();
- cOut.println(" \"" + ied.getName() + logicalDevice.getInst() + "\",");
+ cOut.println(" \"" + logicalDevice.getInst() + "\",");
cOut.println(" \"" + logicalNode.getName() + "$" + dataSet.getName() + "\",");
cOut.println(" " + dataSet.getFcda().size() + ",");
cOut.println(" &" + dataSetVariableName + "_fcda0,");