浏览代码

Merge branch 'Issue_252'

Martin Melik Merkumians 5 年之前
父节点
当前提交
7e004e9c17
共有 36 个文件被更改,包括 1683 次插入1968 次删除
  1. 5 4
      source/CMakeLists.txt
  2. 189 53
      source/buildsupport/CodeCoverage.cmake
  3. 1 1
      source/buildsupport/OpENer.cmake
  4. 9 10
      source/src/cip/cipassembly.c
  5. 247 383
      source/src/cip/cipcommon.c
  6. 4 10
      source/src/cip/cipcommon.h
  7. 42 31
      source/src/cip/cipconnectionmanager.c
  8. 1 1
      source/src/cip/cipconnectionobject.c
  9. 67 112
      source/src/cip/cipdlr.c
  10. 21 21
      source/src/cip/cipepath.c
  11. 3 3
      source/src/cip/cipepath.h
  12. 195 257
      source/src/cip/cipethernetlink.c
  13. 49 15
      source/src/cip/cipidentity.c
  14. 14 12
      source/src/cip/cipioconnection.c
  15. 32 32
      source/src/cip/cipmessagerouter.c
  16. 1 7
      source/src/cip/cipmessagerouter.h
  17. 20 37
      source/src/cip/cipqos.c
  18. 209 267
      source/src/cip/ciptcpipinterface.c
  19. 1 0
      source/src/cip/ciptcpipinterface.h
  20. 62 11
      source/src/cip/ciptypes.h
  21. 119 177
      source/src/enet_encap/cpf.c
  22. 2 2
      source/src/enet_encap/cpf.h
  23. 42 83
      source/src/enet_encap/encap.c
  24. 66 77
      source/src/enet_encap/endianconv.c
  25. 21 20
      source/src/enet_encap/endianconv.h
  26. 84 16
      source/src/opener_api.h
  27. 1 0
      source/src/ports/MINGW/CMakeLists.txt
  28. 11 9
      source/src/ports/MINGW/main.c
  29. 1 0
      source/src/ports/POSIX/CMakeLists.txt
  30. 23 18
      source/src/ports/POSIX/main.c
  31. 1 1
      source/src/ports/POSIX/sample_application/sampleapplication.c
  32. 1 0
      source/src/ports/WIN32/CMakeLists.txt
  33. 19 14
      source/src/ports/generic_networkhandler.c
  34. 52 229
      source/tests/cip/cipcommontests.cpp
  35. 58 55
      source/tests/enet_encap/endianconvtest.cpp
  36. 10 0
      source/tests/ports/socket_timer_tests.cpp

+ 5 - 4
source/CMakeLists.txt

@@ -31,7 +31,7 @@ configure_file(
 	)
 
 find_path( OpENer_BUILDSUPPORT_DIR OpENer.cmake ${PROJECT_SOURCE_DIR}/buildsupport )
- 
+
 INCLUDE( ${OpENer_BUILDSUPPORT_DIR}/OpENer.cmake )
 
 option(OPENER_PRODUCED_DATA_HAS_RUN_IDLE_HEADER "Shall produced data from OpENer also include a run idle header?" FALSE)
@@ -62,7 +62,7 @@ add_definitions(-DOPENER_MESSAGE_DATA_REPLY_BUFFER=${OPENER_MESSAGE_DATA_REPLY_B
 #######################################
 set( OpENer_KNOWN_PLATFORMS "POSIX" "WIN32" "MINGW")
 
-set( OpENer_PLATFORM CACHE STRINGS "Platform OpENer will be built for" )
+set( OpENer_PLATFORM CACHE STRING "Platform OpENer will be built for" )
 set_property(CACHE OpENer_PLATFORM PROPERTY STRINGS ${OpENer_KNOWN_PLATFORMS} )
 
 #######################################
@@ -139,8 +139,9 @@ if( OpENer_TESTS )
   set( CPPUTEST_HOME "" CACHE PATH "Path to CppUTest directory" )
   INCLUDE( ${OpENer_BUILDSUPPORT_DIR}/OpENer_Tests.cmake )
   INCLUDE( ${OpENer_BUILDSUPPORT_DIR}/CodeCoverage.cmake )
-  set(COVERAGE_LCOV_EXCLUDES 'tests/*' 'usr/*' 'ports/POSIX/sample_application/*')
-  SETUP_TARGET_FOR_COVERAGE_LCOV(NAME ${PROJECT_NAME}_coverage EXECUTABLE OpENer_Tests DEPENDENCIES OpENer_Tests)
+  APPEND_COVERAGE_COMPILER_FLAGS()
+  # The used CppUTest framework does not support parallel jobs
+  SETUP_TARGET_FOR_COVERAGE_LCOV(NAME ${PROJECT_NAME}_coverage EXECUTABLE OpENer_Tests EXCLUDE "tests/*" "src/ports/*/sample_application/*")
   add_test_includes()
   add_subdirectory( tests )
 endif( OpENer_TESTS )

+ 189 - 53
source/buildsupport/CodeCoverage.cmake

@@ -41,21 +41,71 @@
 # 2017-06-02, Lars Bilke
 # - Merged with modified version from github.com/ufz/ogs
 #
+# 2019-05-06, Anatolii Kurotych
+# - Remove unnecessary --coverage flag
 #
+# 2019-12-13, FeRD (Frank Dana)
+# - Deprecate COVERAGE_LCOVR_EXCLUDES and COVERAGE_GCOVR_EXCLUDES lists in favor
+#   of tool-agnostic COVERAGE_EXCLUDES variable, or EXCLUDE setup arguments.
+# - CMake 3.4+: All excludes can be specified relative to BASE_DIRECTORY
+# - All setup functions: accept BASE_DIRECTORY, EXCLUDE list
+# - Set lcov basedir with -b argument
+# - Add automatic --demangle-cpp in lcovr, if 'c++filt' is available (can be
+#   overridden with NO_DEMANGLE option in setup_target_for_coverage_lcovr().)
+# - Delete output dir, .info file on 'make clean'
+# - Remove Python detection, since version mismatches will break gcovr
+# - Minor cleanup (lowercase function names, update examples...)
+#
+# 2019-12-19, FeRD (Frank Dana)
+# - Rename Lcov outputs, make filtered file canonical, fix cleanup for targets
+#
+# 2020-01-19, Bob Apthorpe
+# - Added gfortran support
+#
+# 2020-02-17, FeRD (Frank Dana)
+# - Make all add_custom_target()s VERBATIM to auto-escape wildcard characters
+#   in EXCLUDEs, and remove manual escaping from gcovr targets
+#
+# 2020-05-04, Mihchael Davis
+#     - Add -fprofile-abs-path to make gcno files contain absolute paths
+#     - Fix BASE_DIRECTORY not working when defined
+#     - Change BYPRODUCT from folder to index.html to stop ninja from complaining about double defines
 # USAGE:
 #
 # 1. Copy this file into your cmake modules path.
 #
-# 2. Add the following line to your CMakeLists.txt:
+# 2. Add the following line to your CMakeLists.txt (best inside an if-condition
+#    using a CMake option() to enable it just optionally):
 #      include(CodeCoverage)
 #
 # 3. Append necessary compiler flags:
-#      APPEND_COVERAGE_COMPILER_FLAGS()
+#      append_coverage_compiler_flags()
+#
+# 3.a (OPTIONAL) Set appropriate optimization flags, e.g. -O0, -O1 or -Og
 #
 # 4. If you need to exclude additional directories from the report, specify them
-#    using the COVERAGE_LCOV_EXCLUDES variable before calling SETUP_TARGET_FOR_COVERAGE_LCOV.
+#    using full paths in the COVERAGE_EXCLUDES variable before calling
+#    setup_target_for_coverage_*().
 #    Example:
-#      set(COVERAGE_LCOV_EXCLUDES 'dir1/*' 'dir2/*')
+#      set(COVERAGE_EXCLUDES
+#          '${PROJECT_SOURCE_DIR}/src/dir1/*'
+#          '/path/to/my/src/dir2/*')
+#    Or, use the EXCLUDE argument to setup_target_for_coverage_*().
+#    Example:
+#      setup_target_for_coverage_lcov(
+#          NAME coverage
+#          EXECUTABLE testrunner
+#          EXCLUDE "${PROJECT_SOURCE_DIR}/src/dir1/*" "/path/to/my/src/dir2/*")
+#
+# 4.a NOTE: With CMake 3.4+, COVERAGE_EXCLUDES or EXCLUDE can also be set
+#     relative to the BASE_DIRECTORY (default: PROJECT_SOURCE_DIR)
+#     Example:
+#       set(COVERAGE_EXCLUDES "dir1/*")
+#       setup_target_for_coverage_gcovr_html(
+#           NAME coverage
+#           EXECUTABLE testrunner
+#           BASE_DIRECTORY "${PROJECT_SOURCE_DIR}/src"
+#           EXCLUDE "dir2/*")
 #
 # 5. Use the functions described below to create a custom make target which
 #    runs your test executable and produces a code coverage report.
@@ -73,7 +123,7 @@ find_program( GCOV_PATH gcov )
 find_program( LCOV_PATH  NAMES lcov lcov.bat lcov.exe lcov.perl)
 find_program( GENHTML_PATH NAMES genhtml genhtml.perl genhtml.bat )
 find_program( GCOVR_PATH gcovr PATHS ${CMAKE_SOURCE_DIR}/scripts/test)
-find_program( SIMPLE_PYTHON_EXECUTABLE python )
+find_program( CPPFILT_PATH NAMES c++filt )
 
 if(NOT GCOV_PATH)
     message(FATAL_ERROR "gcov not found! Aborting...")
@@ -84,12 +134,22 @@ if("${CMAKE_CXX_COMPILER_ID}" MATCHES "(Apple)?[Cc]lang")
         message(FATAL_ERROR "Clang version must be 3.0.0 or greater! Aborting...")
     endif()
 elseif(NOT CMAKE_COMPILER_IS_GNUCXX)
-    message(FATAL_ERROR "Compiler is not GNU gcc! Aborting...")
+    if("${CMAKE_Fortran_COMPILER_ID}" MATCHES "[Ff]lang")
+        # Do nothing; exit conditional without error if true
+    elseif("${CMAKE_Fortran_COMPILER_ID}" MATCHES "GNU")
+        # Do nothing; exit conditional without error if true
+    else()
+        message(FATAL_ERROR "Compiler is not GNU gcc! Aborting...")
+    endif()
 endif()
 
-set(COVERAGE_COMPILER_FLAGS "-g -O0 --coverage -fprofile-arcs -ftest-coverage"
+set(COVERAGE_COMPILER_FLAGS "-g -fprofile-arcs -ftest-coverage -fprofile-abs-path"
     CACHE INTERNAL "")
 
+set(CMAKE_Fortran_FLAGS_COVERAGE
+    ${COVERAGE_COMPILER_FLAGS}
+    CACHE STRING "Flags used by the Fortran compiler during coverage builds."
+    FORCE )
 set(CMAKE_CXX_FLAGS_COVERAGE
     ${COVERAGE_COMPILER_FLAGS}
     CACHE STRING "Flags used by the C++ compiler during coverage builds."
@@ -107,6 +167,7 @@ set(CMAKE_SHARED_LINKER_FLAGS_COVERAGE
     CACHE STRING "Flags used by the shared libraries linker during coverage builds."
     FORCE )
 mark_as_advanced(
+    CMAKE_Fortran_FLAGS_COVERAGE
     CMAKE_CXX_FLAGS_COVERAGE
     CMAKE_C_FLAGS_COVERAGE
     CMAKE_EXE_LINKER_FLAGS_COVERAGE
@@ -116,10 +177,8 @@ if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
     message(WARNING "Code coverage results with an optimised (non-Debug) build may be misleading")
 endif() # NOT CMAKE_BUILD_TYPE STREQUAL "Debug"
 
-if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
+if(CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_Fortran_COMPILER_ID STREQUAL "GNU")
     link_libraries(gcov)
-else()
-    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --coverage")
 endif()
 
 # Defines a target for running and collection code coverage information
@@ -127,16 +186,22 @@ endif()
 # NOTE! The executable should always have a ZERO as exit code otherwise
 # the coverage generation will not complete.
 #
-# SETUP_TARGET_FOR_COVERAGE_LCOV(
+# setup_target_for_coverage_lcov(
 #     NAME testrunner_coverage                    # New target name
 #     EXECUTABLE testrunner -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
 #     DEPENDENCIES testrunner                     # Dependencies to build first
+#     BASE_DIRECTORY "../"                        # Base directory for report
+#                                                 #  (defaults to PROJECT_SOURCE_DIR)
+#     EXCLUDE "src/dir1/*" "src/dir2/*"           # Patterns to exclude (can be relative
+#                                                 #  to BASE_DIRECTORY, with CMake 3.4+)
+#     NO_DEMANGLE                                 # Don't demangle C++ symbols
+#                                                 #  even if c++filt is found
 # )
-function(SETUP_TARGET_FOR_COVERAGE_LCOV)
+function(setup_target_for_coverage_lcov)
 
-    set(options NONE)
-    set(oneValueArgs NAME)
-    set(multiValueArgs EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES LCOV_ARGS GENHTML_ARGS)
+    set(options NO_DEMANGLE)
+    set(oneValueArgs BASE_DIRECTORY NAME)
+    set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES LCOV_ARGS GENHTML_ARGS)
     cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
 
     if(NOT LCOV_PATH)
@@ -147,27 +212,59 @@ function(SETUP_TARGET_FOR_COVERAGE_LCOV)
         message(FATAL_ERROR "genhtml not found! Aborting...")
     endif() # NOT GENHTML_PATH
 
+    # Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR
+    if(DEFINED Coverage_BASE_DIRECTORY)
+        get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE)
+    else()
+        set(BASEDIR ${PROJECT_SOURCE_DIR})
+    endif()
+
+    # Collect excludes (CMake 3.4+: Also compute absolute paths)
+    set(LCOV_EXCLUDES "")
+    foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_LCOV_EXCLUDES})
+        if(CMAKE_VERSION VERSION_GREATER 3.4)
+            get_filename_component(EXCLUDE ${EXCLUDE} ABSOLUTE BASE_DIR ${BASEDIR})
+        endif()
+        list(APPEND LCOV_EXCLUDES "${EXCLUDE}")
+    endforeach()
+    list(REMOVE_DUPLICATES LCOV_EXCLUDES)
+
+    # Conditional arguments
+    if(CPPFILT_PATH AND NOT ${Coverage_NO_DEMANGLE})
+      set(GENHTML_EXTRA_ARGS "--demangle-cpp")
+    endif()
+
     # Setup target
     add_custom_target(${Coverage_NAME}
 
         # Cleanup lcov
-        COMMAND ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -directory . --zerocounters
+        COMMAND ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -directory . -b ${BASEDIR} --zerocounters
         # Create baseline to make sure untouched files show up in the report
-        COMMAND ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -c -i -d . -o ${Coverage_NAME}.base
+        COMMAND ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -c -i -d . -b ${BASEDIR} -o ${Coverage_NAME}.base
 
         # Run tests
         COMMAND ${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS}
 
         # Capturing lcov counters and generating report
-        COMMAND ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} --directory . --capture --output-file ${Coverage_NAME}.info
+        COMMAND ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} --directory . -b ${BASEDIR} --capture --output-file ${Coverage_NAME}.capture
         # add baseline counters
-        COMMAND ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -a ${Coverage_NAME}.base -a ${Coverage_NAME}.info --output-file ${Coverage_NAME}.total
-        COMMAND ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} --remove ${Coverage_NAME}.total ${COVERAGE_LCOV_EXCLUDES} --output-file ${PROJECT_BINARY_DIR}/${Coverage_NAME}.info.cleaned
-        COMMAND ${GENHTML_PATH} ${Coverage_GENHTML_ARGS} -o ${Coverage_NAME} ${PROJECT_BINARY_DIR}/${Coverage_NAME}.info.cleaned
-        COMMAND ${CMAKE_COMMAND} -E remove ${Coverage_NAME}.base ${Coverage_NAME}.total ${PROJECT_BINARY_DIR}/${Coverage_NAME}.info.cleaned
-
+        COMMAND ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -a ${Coverage_NAME}.base -a ${Coverage_NAME}.capture --output-file ${Coverage_NAME}.total
+        # filter collected data to final coverage report
+        COMMAND ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} --remove ${Coverage_NAME}.total ${LCOV_EXCLUDES} --output-file ${Coverage_NAME}.info
+
+        # Generate HTML output
+        COMMAND ${GENHTML_PATH} ${GENHTML_EXTRA_ARGS} ${Coverage_GENHTML_ARGS} -o ${Coverage_NAME} ${Coverage_NAME}.info
+
+        # Set output files as GENERATED (will be removed on 'make clean')
+        BYPRODUCTS
+            ${Coverage_NAME}.base
+            ${Coverage_NAME}.capture
+            ${Coverage_NAME}.total
+            ${Coverage_NAME}.info
+            ${Coverage_NAME}/index.html
         WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
         DEPENDS ${Coverage_DEPENDENCIES}
+        VERBATIM # Protect arguments to commands
         COMMENT "Resetting code coverage counters to zero.\nProcessing code coverage counters and generating report."
     )
 
@@ -183,39 +280,56 @@ function(SETUP_TARGET_FOR_COVERAGE_LCOV)
         COMMENT "Open ./${Coverage_NAME}/index.html in your browser to view the coverage report."
     )
 
-endfunction() # SETUP_TARGET_FOR_COVERAGE_LCOV
+endfunction() # setup_target_for_coverage_lcov
 
 # Defines a target for running and collection code coverage information
 # Builds dependencies, runs the given executable and outputs reports.
 # NOTE! The executable should always have a ZERO as exit code otherwise
 # the coverage generation will not complete.
 #
-# SETUP_TARGET_FOR_COVERAGE_GCOVR_XML(
+# setup_target_for_coverage_gcovr_xml(
 #     NAME ctest_coverage                    # New target name
 #     EXECUTABLE ctest -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
 #     DEPENDENCIES executable_target         # Dependencies to build first
+#     BASE_DIRECTORY "../"                   # Base directory for report
+#                                            #  (defaults to PROJECT_SOURCE_DIR)
+#     EXCLUDE "src/dir1/*" "src/dir2/*"      # Patterns to exclude (can be relative
+#                                            #  to BASE_DIRECTORY, with CMake 3.4+)
 # )
-function(SETUP_TARGET_FOR_COVERAGE_GCOVR_XML)
+function(setup_target_for_coverage_gcovr_xml)
 
     set(options NONE)
-    set(oneValueArgs NAME)
-    set(multiValueArgs EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES)
+    set(oneValueArgs BASE_DIRECTORY NAME)
+    set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES)
     cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
 
-    if(NOT SIMPLE_PYTHON_EXECUTABLE)
-        message(FATAL_ERROR "python not found! Aborting...")
-    endif() # NOT SIMPLE_PYTHON_EXECUTABLE
-
     if(NOT GCOVR_PATH)
         message(FATAL_ERROR "gcovr not found! Aborting...")
     endif() # NOT GCOVR_PATH
 
-    # Combine excludes to several -e arguments
+    # Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR
+    if(DEFINED Coverage_BASE_DIRECTORY)
+        get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE)
+    else()
+        set(BASEDIR ${PROJECT_SOURCE_DIR})
+    endif()
+
+    # Collect excludes (CMake 3.4+: Also compute absolute paths)
     set(GCOVR_EXCLUDES "")
-    foreach(EXCLUDE ${COVERAGE_GCOVR_EXCLUDES})
-        list(APPEND GCOVR_EXCLUDES "-e")
+    foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_GCOVR_EXCLUDES})
+        if(CMAKE_VERSION VERSION_GREATER 3.4)
+            get_filename_component(EXCLUDE ${EXCLUDE} ABSOLUTE BASE_DIR ${BASEDIR})
+        endif()
         list(APPEND GCOVR_EXCLUDES "${EXCLUDE}")
     endforeach()
+    list(REMOVE_DUPLICATES GCOVR_EXCLUDES)
+
+    # Combine excludes to several -e arguments
+    set(GCOVR_EXCLUDE_ARGS "")
+    foreach(EXCLUDE ${GCOVR_EXCLUDES})
+        list(APPEND GCOVR_EXCLUDE_ARGS "-e")
+        list(APPEND GCOVR_EXCLUDE_ARGS "${EXCLUDE}")
+    endforeach()
 
     add_custom_target(${Coverage_NAME}
         # Run tests
@@ -223,11 +337,13 @@ function(SETUP_TARGET_FOR_COVERAGE_GCOVR_XML)
 
         # Running gcovr
         COMMAND ${GCOVR_PATH} --xml
-            -r ${PROJECT_SOURCE_DIR} ${GCOVR_EXCLUDES}
+            -r ${BASEDIR} ${GCOVR_EXCLUDE_ARGS}
             --object-directory=${PROJECT_BINARY_DIR}
             -o ${Coverage_NAME}.xml
+        BYPRODUCTS ${Coverage_NAME}.xml
         WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
         DEPENDS ${Coverage_DEPENDENCIES}
+        VERBATIM # Protect arguments to commands
         COMMENT "Running gcovr to produce Cobertura code coverage report."
     )
 
@@ -236,40 +352,56 @@ function(SETUP_TARGET_FOR_COVERAGE_GCOVR_XML)
         COMMAND ;
         COMMENT "Cobertura code coverage report saved in ${Coverage_NAME}.xml."
     )
-
-endfunction() # SETUP_TARGET_FOR_COVERAGE_GCOVR_XML
+endfunction() # setup_target_for_coverage_gcovr_xml
 
 # Defines a target for running and collection code coverage information
 # Builds dependencies, runs the given executable and outputs reports.
 # NOTE! The executable should always have a ZERO as exit code otherwise
 # the coverage generation will not complete.
 #
-# SETUP_TARGET_FOR_COVERAGE_GCOVR_HTML(
+# setup_target_for_coverage_gcovr_html(
 #     NAME ctest_coverage                    # New target name
 #     EXECUTABLE ctest -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
 #     DEPENDENCIES executable_target         # Dependencies to build first
+#     BASE_DIRECTORY "../"                   # Base directory for report
+#                                            #  (defaults to PROJECT_SOURCE_DIR)
+#     EXCLUDE "src/dir1/*" "src/dir2/*"      # Patterns to exclude (can be relative
+#                                            #  to BASE_DIRECTORY, with CMake 3.4+)
 # )
-function(SETUP_TARGET_FOR_COVERAGE_GCOVR_HTML)
+function(setup_target_for_coverage_gcovr_html)
 
     set(options NONE)
-    set(oneValueArgs NAME)
-    set(multiValueArgs EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES)
+    set(oneValueArgs BASE_DIRECTORY NAME)
+    set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES)
     cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
 
-    if(NOT SIMPLE_PYTHON_EXECUTABLE)
-        message(FATAL_ERROR "python not found! Aborting...")
-    endif() # NOT SIMPLE_PYTHON_EXECUTABLE
-
     if(NOT GCOVR_PATH)
         message(FATAL_ERROR "gcovr not found! Aborting...")
     endif() # NOT GCOVR_PATH
 
-    # Combine excludes to several -e arguments
+    # Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR
+    if(DEFINED Coverage_BASE_DIRECTORY)
+        get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE)
+    else()
+        set(BASEDIR ${PROJECT_SOURCE_DIR})
+    endif()
+
+    # Collect excludes (CMake 3.4+: Also compute absolute paths)
     set(GCOVR_EXCLUDES "")
-    foreach(EXCLUDE ${COVERAGE_GCOVR_EXCLUDES})
-        list(APPEND GCOVR_EXCLUDES "-e")
+    foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_GCOVR_EXCLUDES})
+        if(CMAKE_VERSION VERSION_GREATER 3.4)
+            get_filename_component(EXCLUDE ${EXCLUDE} ABSOLUTE BASE_DIR ${BASEDIR})
+        endif()
         list(APPEND GCOVR_EXCLUDES "${EXCLUDE}")
     endforeach()
+    list(REMOVE_DUPLICATES GCOVR_EXCLUDES)
+
+    # Combine excludes to several -e arguments
+    set(GCOVR_EXCLUDE_ARGS "")
+    foreach(EXCLUDE ${GCOVR_EXCLUDES})
+        list(APPEND GCOVR_EXCLUDE_ARGS "-e")
+        list(APPEND GCOVR_EXCLUDE_ARGS "${EXCLUDE}")
+    endforeach()
 
     add_custom_target(${Coverage_NAME}
         # Run tests
@@ -280,11 +412,14 @@ function(SETUP_TARGET_FOR_COVERAGE_GCOVR_HTML)
 
         # Running gcovr
         COMMAND ${GCOVR_PATH} --html --html-details
-            -r ${PROJECT_SOURCE_DIR} ${GCOVR_EXCLUDES}
+            -r ${BASEDIR} ${GCOVR_EXCLUDE_ARGS}
             --object-directory=${PROJECT_BINARY_DIR}
             -o ${Coverage_NAME}/index.html
+
+        BYPRODUCTS ${PROJECT_BINARY_DIR}/${Coverage_NAME}/index.html  # report directory
         WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
         DEPENDS ${Coverage_DEPENDENCIES}
+        VERBATIM # Protect arguments to commands
         COMMENT "Running gcovr to produce HTML code coverage report."
     )
 
@@ -294,10 +429,11 @@ function(SETUP_TARGET_FOR_COVERAGE_GCOVR_HTML)
         COMMENT "Open ./${Coverage_NAME}/index.html in your browser to view the coverage report."
     )
 
-endfunction() # SETUP_TARGET_FOR_COVERAGE_GCOVR_HTML
+endfunction() # setup_target_for_coverage_gcovr_html
 
-function(APPEND_COVERAGE_COMPILER_FLAGS)
+function(append_coverage_compiler_flags)
     set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE)
     set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE)
+    set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE)
     message(STATUS "Appending code coverage compiler flags: ${COVERAGE_COMPILER_FLAGS}")
-endfunction() # APPEND_COVERAGE_COMPILER_FLAGS
+endfunction() # append_coverage_compiler_flags

+ 1 - 1
source/buildsupport/OpENer.cmake

@@ -22,7 +22,7 @@ endmacro(opener_platform_support ARGS)
 # Adds common Include directories     #
 #######################################
 macro(opener_common_includes)
-  set( SRC_DIR "${PROJECT_SOURCE_DIR}/src" )
+  set( SRC_DIR "${OpENer_SOURCE_DIR}/src" )
   set( CIP_SRC_DIR "${SRC_DIR}/cip" )
   set( ENET_ENCAP_SRC_DIR "${SRC_DIR}/enet_encap" )
   set( PORTS_SRC_DIR "${SRC_DIR}/ports")

+ 9 - 10
source/src/cip/cipassembly.c

@@ -120,12 +120,14 @@ CipInstance *CreateAssemblyObject(const EipUint32 instance_id,
   InsertAttribute(instance,
                   3,
                   kCipByteArray,
+                  EncodeCipByteArray,
                   assembly_byte_array,
                   kSetAndGetAble | kPreGetFunc | kPostSetFunc);
   /* Attribute 4 Number of bytes in Attribute 3 */
   InsertAttribute(instance,
                   4,
                   kCipUint,
+                  EncodeCipUint,
                   &(assembly_byte_array->length),
                   kGetableSingle);
 
@@ -161,7 +163,6 @@ EipStatus SetAssemblyAttributeSingle(CipInstance *const instance,
 
   const EipUint8 *const router_request_data = message_router_request->data;
 
-  message_router_response->data_length = 0;
   message_router_response->reply_service =
     (0x80 | message_router_request->service);
   message_router_response->general_status = kCipErrorAttributeNotSupported;
@@ -194,11 +195,11 @@ EipStatus SetAssemblyAttributeSingle(CipInstance *const instance,
             message_router_response->general_status = kCipErrorTooMuchData;
           }
           else{
-            if (attribute->attribute_flags & kPreSetFunc
-                && instance->cip_class->PreSetCallback) {
-                instance->cip_class->PreSetCallback(instance,
-                                                    attribute,
-                                                    message_router_request->service);
+            if ( (attribute->attribute_flags & kPreSetFunc)
+                 && instance->cip_class->PreSetCallback ) {
+              instance->cip_class->PreSetCallback(instance,
+                                                  attribute,
+                                                  message_router_request->service);
             }
 
             memcpy(data->data, router_request_data, data->length);
@@ -241,8 +242,7 @@ static EipStatus AssemblyPreGetCallback
   CipInstance *const instance,
   CipAttributeStruct *const attribute,
   CipByte service
-)
-{
+) {
   int rc;
   (void) attribute; (void) service; /* no unused parameter warnings */
 
@@ -256,8 +256,7 @@ static EipStatus AssemblyPostSetCallback
   CipInstance *const instance,
   CipAttributeStruct *const attribute,
   CipByte service
-)
-{
+) {
   int rc;
   (void) attribute; (void) service; /* no unused parameter warnings */
 

+ 247 - 383
source/src/cip/cipcommon.c

@@ -29,14 +29,11 @@
 #include "cipepath.h"
 #include "stdlib.h"
 
-/* global public variables */
-EipUint8 g_message_data_reply_buffer[OPENER_MESSAGE_DATA_REPLY_BUFFER]; /**< Reply buffer */
-
 /* private functions*/
-int EncodeEPath(CipEpath *epath,
-                EipUint8 **message);
+void EncodeEPath(CipEpath *epath,
+                 ENIPMessage *message);
 
-void CipStackInit(const EipUint16 unique_connection_id) {
+EipStatus CipStackInit(const EipUint16 unique_connection_id) {
   /* The message router is the first CIP object be initialized!!! */
   EipStatus eip_status = CipMessageRouterInit();
   OPENER_ASSERT(kEipStatusOk == eip_status);
@@ -60,8 +57,7 @@ void CipStackInit(const EipUint16 unique_connection_id) {
   eip_status = ApplicationInitialization();
   OPENER_ASSERT(kEipStatusOk == eip_status);
 
-  /* Shut up compiler warning with traces disabled */
-  (void) eip_status;
+  return eip_status;
 }
 
 void ShutdownCipStack(void) {
@@ -128,7 +124,7 @@ EipStatus NotifyClass(const CipClass *RESTRICT const cip_class,
 
   /* handle error replies*/
   message_router_response->size_of_additional_status = 0;       /* fill in the rest of the reply with not much of anything*/
-  message_router_response->data_length = 0;
+  InitializeENIPMessage(&message_router_response->message);
   message_router_response->reply_service = (0x80
                                             | message_router_request->service); /* except the reply code is an echo of the command + the reply flag */
 
@@ -229,7 +225,7 @@ CipClass *CreateCipClass(const CipUdint class_code,
      and contains a pointer to a metaclass
      CIP never explicitly addresses a metaclass*/
 
-  CipClass *const cip_class = (CipClass *) CipCalloc(1, sizeof(CipClass) );       /* create the class object*/
+  CipClass * const cip_class = (CipClass *) CipCalloc(1, sizeof(CipClass) );       /* create the class object*/
   CipClass *const meta_class = (CipClass *) CipCalloc(1, sizeof(CipClass) );       /* create the metaclass object*/
 
   /* initialize the class-specific fields of the Class struct*/
@@ -271,8 +267,9 @@ CipClass *CreateCipClass(const CipUdint class_code,
   meta_class->services = (CipServiceStruct *) CipCalloc(
     meta_class->number_of_services, sizeof(CipServiceStruct) );
 
-  cip_class->services = (CipServiceStruct *) CipCalloc(cip_class->number_of_services,
-                                                   sizeof(CipServiceStruct) );
+  cip_class->services = (CipServiceStruct *) CipCalloc(
+    cip_class->number_of_services,
+    sizeof(CipServiceStruct) );
 
   if (number_of_instances > 0) {
     AddCipInstances(cip_class, number_of_instances);  /*TODO handle return value and clean up if necessary*/
@@ -286,46 +283,53 @@ CipClass *CreateCipClass(const CipUdint class_code,
   AllocateAttributeMasks(cip_class);  /* Allocation of bitmasks for Instance Attributes */
 
   if (NULL == initializer) {
-    InsertAttribute( (CipInstance *) cip_class, 1, kCipUint,
+    InsertAttribute( (CipInstance *) cip_class, 1, kCipUint, EncodeCipUint,
                      (void *) &cip_class->revision, kGetableSingleAndAll ); /* revision */
-    InsertAttribute( (CipInstance *) cip_class, 2, kCipUint,
+    InsertAttribute( (CipInstance *) cip_class, 2, kCipUint, EncodeCipUint,
                      (void *) &cip_class->number_of_instances,
-                     kGetableSingleAndAll );                        /*  largest instance number */
-    InsertAttribute( (CipInstance *) cip_class, 3, kCipUint,
+                     kGetableSingleAndAll );                        /* #2 Max instance no. */
+    InsertAttribute( (CipInstance *) cip_class, 3, kCipUint, EncodeCipUint,
                      (void *) &cip_class->number_of_instances,
                      kGetableSingleAndAll );                        /* number of instances currently existing*/
-    InsertAttribute( (CipInstance *) cip_class, 4, kCipUint,
-                     (void *) &kCipUintZero, kGetableAll );         /* optional attribute list - default = 0 */
-    InsertAttribute( (CipInstance *) cip_class, 5, kCipUint,
+    InsertAttribute( (CipInstance *) cip_class, 4, kCipUint, EncodeCipUint,
+                     (void *) &kCipUintZero, kGetableAllDummy );         /* optional attribute list - default = 0 */
+    InsertAttribute( (CipInstance *) cip_class, 5, kCipUint, EncodeCipUint,
                      (void *) &kCipUintZero, kNotSetOrGetable );    /* optional service list - default = 0 */
-    InsertAttribute( (CipInstance *) cip_class, 6, kCipUint,
+    InsertAttribute( (CipInstance *) cip_class, 6, kCipUint, EncodeCipUint,
                      (void *) &meta_class->highest_attribute_number,
                      kGetableSingle );                              /* max class attribute number*/
-    InsertAttribute( (CipInstance *) cip_class, 7, kCipUint,
+    InsertAttribute( (CipInstance *) cip_class, 7, kCipUint, EncodeCipUint,
                      (void *) &cip_class->highest_attribute_number,
                      kGetableSingle );                              /* max instance attribute number*/
+    if (number_of_class_services > 0) {
+      if (number_of_class_services > 1) {                 /*only if the mask has values add the get_attribute_all service */
+        InsertService(meta_class,
+                      kGetAttributeAll,
+                      &GetAttributeAll,
+                      "GetAttributeAll");                                                                         /* bind instance services to the metaclass*/
+      }
+      InsertService(meta_class,
+                    kGetAttributeSingle,
+                    &GetAttributeSingle,
+                    "GetAttributeSingle");
+    }
   } else {
     initializer(cip_class);
   }
 
   /* create the standard class services*/
-  if (number_of_class_services > 0) {
-    if (number_of_class_services > 1) {             /*only if the mask has values add the get_attribute_all service */
-      InsertService(meta_class, kGetAttributeAll, &GetAttributeAll,
-                    "GetAttributeAll");                     /* bind instance services to the metaclass*/
-    }
-    InsertService(meta_class, kGetAttributeSingle, &GetAttributeSingle,
-                  "GetAttributeSingle");
-  }
   return cip_class;
 }
 
 void InsertAttribute(CipInstance *const instance,
                      const EipUint16 attribute_number,
                      const EipUint8 cip_type,
+                     CipAttributeEncodeInMessage encode_function,
                      void *const data,
                      const EipByte cip_flags) {
 
+  OPENER_ASSERT(NULL != data); /* Its not allowed to push a NULL pointer, as this marks an unused attribute struct */
+
   CipAttributeStruct *attribute = instance->attributes;
   CipClass *cip_class = instance->cip_class;
 
@@ -335,6 +339,7 @@ void InsertAttribute(CipInstance *const instance,
     if (attribute->data == NULL) {             /* found non set attribute */
       attribute->attribute_number = attribute_number;
       attribute->type = cip_type;
+      attribute->encode = encode_function;
       attribute->attribute_flags = cip_flags;
       attribute->data = data;
 
@@ -346,7 +351,8 @@ void InsertAttribute(CipInstance *const instance,
         (cip_flags & kGetableSingle) ?
         1 << (attribute_number) % 8 : 0;
       cip_class->get_all_bit_mask[index] |=
-        (cip_flags & kGetableAll) ? 1 << (attribute_number) % 8 : 0;
+        (cip_flags & (kGetableAll | kGetableAllDummy) ) ? 1 <<
+        (attribute_number) % 8 : 0;
       cip_class->set_bit_mask[index] |=
         ( (cip_flags & kSetable) ? 1 : 0 ) << ( (attribute_number) % 8 );
 
@@ -356,7 +362,9 @@ void InsertAttribute(CipInstance *const instance,
   }
   OPENER_TRACE_ERR(
     "Tried to insert too many attributes into class: %" PRIu32 " '%s', instance %" PRIu32 "\n",
-    cip_class->class_code, cip_class->class_name, instance->instance_number);
+    cip_class->class_code,
+    cip_class->class_name,
+    instance->instance_number);
   OPENER_ASSERT(false);
   /* trying to insert too many attributes*/
 }
@@ -392,20 +400,20 @@ void InsertGetSetCallback
 (
   CipClass *const cip_class,
   CipGetSetCallback callback_function,
-  CIPAttributeFlag  callbacks_to_install
+  CIPAttributeFlag callbacks_to_install
 ) {
-  if (0 != (kPreGetFunc & callbacks_to_install)) {
+  if (0 != (kPreGetFunc & callbacks_to_install) ) {
     cip_class->PreGetCallback = callback_function;
   }
-  if (0 != (kPostGetFunc & callbacks_to_install)) {
+  if (0 != (kPostGetFunc & callbacks_to_install) ) {
     cip_class->PostGetCallback = callback_function;
   }
-  if (0 != (kPreSetFunc & callbacks_to_install)) {
+  if (0 != (kPreSetFunc & callbacks_to_install) ) {
     cip_class->PreSetCallback = callback_function;
   }
   /* The PostSetCallback is used for both, the after set action and the storage
    * of non volatile data. Therefore check for both flags set. */
-  if (0 != ((kPostSetFunc | kNvDataFunc) & callbacks_to_install)) {
+  if (0 != ( (kPostSetFunc | kNvDataFunc) & callbacks_to_install ) ) {
     cip_class->PostSetCallback = callback_function;
   }
 }
@@ -427,6 +435,16 @@ CipAttributeStruct *GetCipAttribute(const CipInstance *const instance,
   return NULL;
 }
 
+void GenerateGetAttributeSingleHeader(
+  const CipMessageRouterRequest *const message_router_request,
+  CipMessageRouterResponse *const message_router_response) {
+  InitializeENIPMessage(&message_router_response->message);
+  message_router_response->reply_service =
+    (0x80 | message_router_request->service);
+  message_router_response->general_status = kCipErrorAttributeNotSupported;
+  message_router_response->size_of_additional_status = 0;
+}
+
 /* TODO this needs to check for buffer overflow*/
 EipStatus GetAttributeSingle(CipInstance *RESTRICT const instance,
                              CipMessageRouterRequest *const message_router_request,
@@ -437,47 +455,40 @@ EipStatus GetAttributeSingle(CipInstance *RESTRICT const instance,
 
   CipAttributeStruct *attribute = GetCipAttribute(instance,
                                                   message_router_request->request_path.attribute_number);
-  EipByte *message = message_router_response->data;
 
-  message_router_response->data_length = 0;
-  message_router_response->reply_service = (0x80
-                                            | message_router_request->service);
-  message_router_response->general_status = kCipErrorAttributeNotSupported;
-  message_router_response->size_of_additional_status = 0;
+  GenerateGetAttributeSingleHeader(message_router_request,
+                                   message_router_response);
 
   EipUint16 attribute_number =
     message_router_request->request_path.attribute_number;
 
   if ( (NULL != attribute) && (NULL != attribute->data) ) {
-    uint8_t get_bit_mask = 0;
-    if (kGetAttributeAll == message_router_request->service) {
-      get_bit_mask =
-        (instance->cip_class->get_all_bit_mask[CalculateIndex(
-                                                 attribute_number)]);
-      message_router_response->general_status = kCipErrorSuccess;
-    } else {
-      get_bit_mask =
-        (instance->cip_class->get_single_bit_mask[CalculateIndex(
-                                                    attribute_number)]);
-    }
+    uint8_t get_bit_mask =
+      (instance->cip_class->get_single_bit_mask[CalculateIndex(
+                                                  attribute_number)
+       ]);
     if (0 != (get_bit_mask & (1 << (attribute_number % 8) ) ) ) {
       OPENER_TRACE_INFO("getAttribute %d\n",
                         message_router_request->request_path.attribute_number);                 /* create a reply message containing the data*/
 
       /* Call the PreGetCallback if enabled for this attribute and the class provides one. */
-      if (attribute->attribute_flags & kPreGetFunc && NULL != instance->cip_class->PreGetCallback) {
-        instance->cip_class->PreGetCallback(instance, attribute, message_router_request->service);
+      if ( (attribute->attribute_flags & kPreGetFunc) &&
+           NULL != instance->cip_class->PreGetCallback ) {
+        instance->cip_class->PreGetCallback(instance,
+                                            attribute,
+                                            message_router_request->service);
       }
 
       OPENER_ASSERT(NULL != attribute);
-      message_router_response->data_length = EncodeData(attribute->type,
-                                                        attribute->data,
-                                                        &message);
+      attribute->encode(attribute->data, &message_router_response->message);
       message_router_response->general_status = kCipErrorSuccess;
 
       /* Call the PostGetCallback if enabled for this attribute and the class provides one. */
-      if (attribute->attribute_flags & kPostGetFunc && NULL != instance->cip_class->PostGetCallback) {
-        instance->cip_class->PostGetCallback(instance, attribute, message_router_request->service);
+      if ( (attribute->attribute_flags & kPostGetFunc) &&
+           NULL != instance->cip_class->PostGetCallback ) {
+        instance->cip_class->PostGetCallback(instance,
+                                             attribute,
+                                             message_router_request->service);
       }
     }
   }
@@ -485,170 +496,180 @@ EipStatus GetAttributeSingle(CipInstance *RESTRICT const instance,
   return kEipStatusOkSend;
 }
 
-int EncodeData(const EipUint8 cip_type,
-               const void *const cip_data,
-               EipUint8 **cip_message) {
-  int counter = 0;
+void EncodeCipBool(const CipBool *const data,
+                   ENIPMessage *const outgoing_message) {
+  AddSintToMessage(*(EipUint8 *) (data), outgoing_message);
+}
 
-  switch (cip_type)
-  /* check the data type of attribute */
-  {
-    case (kCipBool):
-    case (kCipSint):
-    case (kCipUsint):
-    case (kCipByte):
-      counter = AddSintToMessage(*(EipUint8 *) (cip_data), cip_message);
-      break;
+void EncodeCipByte(const CipByte *const data,
+                   ENIPMessage *const outgoing_message) {
+  AddSintToMessage(*(EipUint8 *) (data), outgoing_message);
+}
 
-    case (kCipInt):
-    case (kCipUint):
-    case (kCipWord):
-      counter = AddIntToMessage(*(EipUint16 *) (cip_data), cip_message);
-      break;
+void EncodeCipWord(const CipWord *const data,
+                   ENIPMessage *const outgoing_message) {
+  AddIntToMessage(*(EipUint16 *) (data), outgoing_message);
+}
 
-    case (kCipDint):
-    case (kCipUdint):
-    case (kCipDword):
-    case (kCipReal):
-      counter = AddDintToMessage(*(EipUint32 *) (cip_data), cip_message);
-      break;
+void EncodeCipDword(const CipDword *const data,
+                    ENIPMessage *const outgoing_message) {
+  AddDintToMessage(*(EipUint32 *) (data), outgoing_message);
+}
 
-#ifdef OPENER_SUPPORT_64BIT_DATATYPES
-    case (kCipLint):
-    case (kCipUlint):
-    case (kCipLword):
-    case (kCipLreal):
-      counter = AddLintToMessage(*(EipUint64 *) (cip_data), cip_message);
-      break;
-#endif
+void EncodeCipLword(const CipLword *const data,
+                    ENIPMessage *const outgoing_message) {
+  AddLintToMessage(*(EipUint64 *) (data), outgoing_message);
+}
 
-    case (kCipStime):
-    case (kCipDate):
-    case (kCipTimeOfDay):
-    case (kCipDateAndTime):
-      break;
-    case (kCipString): {
-      CipString *const string = (CipString *) cip_data;
+void EncodeCipUsint(const CipUsint *const data,
+                    ENIPMessage *const outgoing_message) {
+  AddSintToMessage(*(EipUint8 *) (data), outgoing_message);
+}
 
-      AddIntToMessage(*(EipUint16 *) &(string->length), cip_message);
-      memcpy(*cip_message, string->string, string->length);
-      *cip_message += string->length;
+void EncodeCipUint(const CipUint *const data,
+                   ENIPMessage *const outgoing_message) {
+  AddIntToMessage(*(EipUint16 *) (data), outgoing_message);
+}
 
-      counter = string->length + 2;           /* we have a two byte length field */
-      if (counter & 0x01) {
-        /* we have an odd byte count */
-        **cip_message = 0;
-        ++(*cip_message);
-        counter++;
-      }
-      break;
-    }
-    case (kCipString2):
-    case (kCipFtime):
-    case (kCipLtime):
-    case (kCipItime):
-    case (kCipStringN):
-      break;
+void EncodeCipUdint(const CipUdint *const data,
+                    ENIPMessage *const outgoing_message) {
+  AddDintToMessage(*(EipUint32 *) (data), outgoing_message);
+}
 
-    case (kCipShortString): {
-      CipShortString *const short_string = (CipShortString *) cip_data;
+void EncodeCipUlint(const CipUlint *const data,
+                    ENIPMessage *const outgoing_message) {
+  AddLintToMessage(*(EipUint64 *) (data), outgoing_message);
+}
 
-      **cip_message = short_string->length;
-      ++(*cip_message);
+void EncodeCipSint(const CipSint *const data,
+                   ENIPMessage *const outgoing_message) {
+  AddSintToMessage(*(EipUint8 *) (data), outgoing_message);
+}
 
-      memcpy(*cip_message, short_string->string, short_string->length);
-      *cip_message += short_string->length;
+void EncodeCipInt(const CipInt *const data,
+                  ENIPMessage *const outgoing_message) {
+  AddIntToMessage(*(EipUint16 *) (data), outgoing_message);
+}
 
-      counter = short_string->length + 1;
-      break;
-    }
+void EncodeCipDint(const CipDint *const data,
+                   ENIPMessage *const outgoing_message) {
+  AddDintToMessage(*(EipUint32 *) (data), outgoing_message);
+}
 
-    case (kCipTime):
-      break;
+void EncodeCipLint(const CipLint *const data,
+                   ENIPMessage *const outgoing_message) {
+  AddLintToMessage(*(EipUint64 *) (data), outgoing_message);
+}
 
-    case (kCipEpath):
-      counter = EncodeEPath( (CipEpath *) cip_data, cip_message );
-      break;
+void EncodeCipReal(const CipReal *const data,
+                   ENIPMessage *const outgoing_message) {
+  AddDintToMessage(*(EipUint32 *) (data), outgoing_message);
+}
 
-    case (kCipEngUnit):
-      break;
+void EncodeCipLreal(const CipLreal *const data,
+                    ENIPMessage *const outgoing_message) {
+  AddLintToMessage(*(EipUint64 *) (data), outgoing_message);
+}
 
-    case (kCipUsintUsint): {
-      CipRevision *revision = (CipRevision *) cip_data;
+void EncodeCipShortString(const CipShortString *const data,
+                          ENIPMessage *const outgoing_message) {
+  CipShortString *const short_string = (CipShortString *) data;
 
-      **cip_message = revision->major_revision;
-      ++(*cip_message);
-      **cip_message = revision->minor_revision;
-      ++(*cip_message);
-      counter = 2;
-      break;
-    }
+  AddSintToMessage(short_string->length, outgoing_message);
 
-    case (kCipUdintUdintUdintUdintUdintString): {
-      /* TCP/IP attribute 5 */
-      CipTcpIpInterfaceConfiguration *
-        tcp_ip_network_interface_configuration =
-        (CipTcpIpInterfaceConfiguration *) cip_data;
-      counter += AddDintToMessage(
-        ntohl(tcp_ip_network_interface_configuration->ip_address),
-        cip_message);
-      counter += AddDintToMessage(
-        ntohl(tcp_ip_network_interface_configuration->network_mask),
-        cip_message);
-      counter += AddDintToMessage(
-        ntohl(tcp_ip_network_interface_configuration->gateway),
-        cip_message);
-      counter += AddDintToMessage(
-        ntohl(tcp_ip_network_interface_configuration->name_server),
-        cip_message);
-      counter += AddDintToMessage(
-        ntohl(tcp_ip_network_interface_configuration->name_server_2),
-        cip_message);
-      counter += EncodeData(kCipString,
-                            &(tcp_ip_network_interface_configuration->
-                              domain_name),
-                            cip_message);
-      break;
-    }
+  memcpy(outgoing_message->current_message_position,
+         short_string->string,
+         short_string->length);
+  outgoing_message->current_message_position += short_string->length;
+  outgoing_message->used_message_length += short_string->length;
+}
 
-    case (kCip6Usint): {
-      EipUint8 *p = (EipUint8 *) cip_data;
-      memcpy(*cip_message, p, 6);
-      counter = 6;
-      break;
-    }
+void EncodeCipString(const CipString *const data,
+                     ENIPMessage *const outgoing_message) {
+  CipString *const string = (CipString *) data;
 
-    case (kCipMemberList):
-      break;
+  AddIntToMessage(*(EipUint16 *) &(string->length), outgoing_message);
+  if(0 != string->length) {
+    memcpy(outgoing_message->current_message_position,
+           string->string,
+           string->length);
+    outgoing_message->current_message_position += string->length;
+    outgoing_message->used_message_length += string->length;
 
-    case (kCipByteArray): {
-      OPENER_TRACE_INFO(" -> get attribute byte array\r\n");
-      CipByteArray *cip_byte_array = (CipByteArray *) cip_data;
-      memcpy(*cip_message, cip_byte_array->data, cip_byte_array->length);
-      *cip_message += cip_byte_array->length;
-      counter = cip_byte_array->length;
+    if (outgoing_message->used_message_length & 0x01) {
+      /* we have an odd byte count */
+      AddSintToMessage(0, outgoing_message);
     }
-    break;
+  }
+}
 
-    case (kInternalUint6):     /* TODO for port class attribute 9, hopefully we can find a better way to do this*/
-    {
-      EipUint16 *internal_unit16_6 = (EipUint16 *) cip_data;
-
-      AddIntToMessage(internal_unit16_6[0], cip_message);
-      AddIntToMessage(internal_unit16_6[1], cip_message);
-      AddIntToMessage(internal_unit16_6[2], cip_message);
-      AddIntToMessage(internal_unit16_6[3], cip_message);
-      AddIntToMessage(internal_unit16_6[4], cip_message);
-      AddIntToMessage(internal_unit16_6[5], cip_message);
-      counter = 12;
-      break;
-    }
-    default:
-      break;
+void EncodeCipString2(const CipString2 *const data,
+                      ENIPMessage *const outgoing_message) {
+  OPENER_ASSERT(false); /* Not implemented yet */
+}
 
+void EncodeCipStringN(const CipStringN *const data,
+                      ENIPMessage *const outgoing_message) {
+  OPENER_ASSERT(false); /* Not implemented yet */
+}
+
+static void CipStringIHeaderEncoding(const CipStringIStruct *const string,
+                                     ENIPMessage *const outgoing_message) {
+  EncodeCipUsint(&(string->language_char_1), outgoing_message);
+  EncodeCipUsint(&(string->language_char_2), outgoing_message);
+  EncodeCipUsint(&(string->language_char_3), outgoing_message);
+  EncodeCipUsint(&(string->char_string_struct), outgoing_message);
+  EncodeCipUint(&(string->character_set), outgoing_message);
+}
+
+void EncodeCipStringI(const CipStringI *const data,
+                      ENIPMessage *const outgoing_message) {
+  const CipStringI *const string_i = data;
+  EncodeCipUsint(&(string_i->number_of_strings), outgoing_message);
+  for (size_t i = 0; i < string_i->number_of_strings; ++i) {
+    CipStringIHeaderEncoding( (string_i->array_of_string_i_structs) + i,
+                              outgoing_message );
+    switch(string_i->array_of_string_i_structs[i].char_string_struct) {
+      case kCipString: EncodeCipString(
+          string_i->array_of_string_i_structs[i].string,
+          outgoing_message); break;
+      case kCipString2: EncodeCipString2(
+          string_i->array_of_string_i_structs[i].string,
+          outgoing_message); break;
+      case kCipStringN: EncodeCipStringN(
+          string_i->array_of_string_i_structs[i].string,
+          outgoing_message); break;
+      case kCipShortString: EncodeCipShortString(
+          string_i->array_of_string_i_structs[i].string,
+          outgoing_message); break;
+      default: OPENER_ASSERT(false); break;
+    }
   }
+}
 
-  return counter;
+void EncodeCipByteArray(const CipByteArray *const data,
+                        ENIPMessage *const outgoing_message) {
+  OPENER_TRACE_INFO(" -> get attribute byte array\r\n");
+  CipByteArray *cip_byte_array = (CipByteArray *) data;
+  memcpy(outgoing_message->current_message_position,
+         cip_byte_array->data,
+         cip_byte_array->length);
+  outgoing_message->current_message_position += cip_byte_array->length;
+  outgoing_message->used_message_length += cip_byte_array->length;
+}
+
+void EncodeCipEPath(const CipEpath *const data,
+                    ENIPMessage *const outgoing_message) {
+  EncodeEPath( (CipEpath *) data, outgoing_message );
+}
+
+void EncodeCipEthernetLinkPhyisicalAddress(const void *const data,
+                                           ENIPMessage *const outgoing_message)
+{
+  EipUint8 *p = (EipUint8 *) data;
+  memcpy(outgoing_message->current_message_position, p, 6);
+  outgoing_message->current_message_position += 6;
+  outgoing_message->used_message_length += 6;
 }
 
 int DecodeData(const EipUint8 cip_data_type,
@@ -746,106 +767,84 @@ EipStatus GetAttributeAll(CipInstance *instance,
                           const struct sockaddr *originator_address,
                           const int encapsulation_session) {
 
-  EipUint8 *reply = message_router_response->data;       /* pointer into the reply */
+  InitializeENIPMessage(&message_router_response->message);
   CipAttributeStruct *attribute = instance->attributes;       /* pointer to list of attributes*/
-  CipServiceStruct *service = GetCipService(instance, kGetAttributeSingle);       /* pointer to list of services*/
 
-  if(NULL == service) {
-    /* GetAttributeAll service not found */
-    /* Return kEipStatusOk if cannot find GET_ATTRIBUTE_SINGLE service*/
-    return kEipStatusOk;
-  }
+  //Missing header
 
   if (0 == instance->cip_class->number_of_attributes) {
-    message_router_response->data_length = 0;                         /*there are no attributes to be sent back*/
+    /*there are no attributes to be sent back*/
     message_router_response->reply_service =
       (0x80 | message_router_request->service);
     message_router_response->general_status = kCipErrorServiceNotSupported;
     message_router_response->size_of_additional_status = 0;
   } else {
+    GenerateGetAttributeSingleHeader(message_router_request,
+                                     message_router_response);
+    message_router_response->general_status = kCipErrorSuccess;
     for (size_t j = 0; j < instance->cip_class->number_of_attributes; j++) {
       /* for each instance attribute of this class */
-      int attribute_number = attribute->attribute_number;
+      EipUint16 attribute_number = attribute->attribute_number;
       if ( (instance->cip_class->get_all_bit_mask[CalculateIndex(
                                                     attribute_number)]) &
            (1 << (attribute_number % 8) ) ) {
-        /* only return attributes that are flagged as being part of GetAttributeALl */
+        /* only return attributes that are flagged as being part of GetAttributeAll */
         message_router_request->request_path.attribute_number =
           attribute_number;
-        if (kEipStatusOkSend !=
-            service->service_function(instance, message_router_request,
-                                      message_router_response,
-                                      originator_address,
-                                      encapsulation_session) ) {
-          message_router_response->data = reply;
-          return kEipStatusError;
-        }
-        message_router_response->data += message_router_response->data_length;
+
+        attribute->encode(attribute->data, &message_router_response->message);
       }
       attribute++;
     }
-    message_router_response->data_length = message_router_response->data -
-                                           reply;
-    message_router_response->data = reply;
   }
   return kEipStatusOkSend;
 }
 
-int EncodeEPath(CipEpath *epath,
-                EipUint8 **message) {
+void EncodeEPath(CipEpath *epath,
+                 ENIPMessage *message) {
   unsigned int length = epath->path_size;
+  size_t start_length = message->used_message_length;
   AddIntToMessage(epath->path_size, message);
 
   if (epath->class_id < 256) {
-    **message = 0x20;             /*8Bit Class Id */
-    ++(*message);
-    **message = (EipUint8) epath->class_id;
-    ++(*message);
+    AddSintToMessage(0x20, message);     /* 8 Bit Class Id */
+    AddSintToMessage( (EipUint8) epath->class_id, message );
     length -= 1;
   } else {
-    **message = 0x21;             /*16Bit Class Id */
-    ++(*message);
-    **message = 0;             /*pad byte */
-    ++(*message);
+    AddSintToMessage(0x21, message);     /*16Bit Class Id */
+    AddSintToMessage(0, message);     /*pad byte */
     AddIntToMessage(epath->class_id, message);
     length -= 2;
   }
 
   if (0 < length) {
     if (epath->instance_number < 256) {
-      **message = 0x24;                   /*8Bit Instance Id */
-      ++(*message);
-      **message = (EipUint8) epath->instance_number;
-      ++(*message);
+      AddSintToMessage(0x24, message); /*8Bit Instance Id */
+      AddSintToMessage(epath->instance_number, message);
       length -= 1;
     } else {
-      **message = 0x25;                   /*16Bit Instance Id */
-      ++(*message);
-      **message = 0;                   /*padd byte */
-      ++(*message);
+      AddSintToMessage(0x25, message); /*16Bit Instance Id */
+      AddSintToMessage(0, message); /*pad byte */
       AddIntToMessage(epath->instance_number, message);
       length -= 2;
     }
 
     if (0 < length) {
       if (epath->attribute_number < 256) {
-        **message = 0x30;                         /*8Bit Attribute Id */
-        ++(*message);
-        **message = (EipUint8) epath->attribute_number;
-        ++(*message);
+        AddSintToMessage(0x30, message); /*8Bit Attribute Id */
+        AddSintToMessage(epath->attribute_number, message);
         length -= 1;
       } else {
-        **message = 0x31;                         /*16Bit Attribute Id */
-        ++(*message);
-        **message = 0;                         /*pad byte */
-        ++(*message);
+        AddSintToMessage(0x31, message); /*16Bit Attribute Id */
+        AddSintToMessage(0, message); /*pad byte */
         AddIntToMessage(epath->attribute_number, message);
         length -= 2;
       }
     }
   }
 
-  return 2 + epath->path_size * 2;       /* path size is in 16 bit chunks according to the specification */
+  OPENER_ASSERT(
+    2 + epath->path_size * 2 == message->used_message_length - start_length);              /* path size is in 16 bit chunks according to the specification */
 }
 
 int DecodePaddedEPath(CipEpath *epath,
@@ -943,138 +942,3 @@ size_t CalculateIndex(EipUint16 attribute_number) {
   size_t index = attribute_number / 8;
   return index;
 }
-
-size_t GetSizeOfAttribute(const CipAttributeStruct *const attribute_struct) {
-  size_t data_type_size = 0;
-  switch (attribute_struct->type) {
-    case (kCipBool):
-      data_type_size = sizeof(CipBool);
-      break;
-    case (kCipSint):
-      data_type_size = sizeof(CipSint);
-      break;
-    case (kCipInt):
-      data_type_size = sizeof(CipInt);
-      break;
-    case (kCipDint):
-      data_type_size = sizeof(CipDint);
-      break;
-    case (kCipUsint):
-      data_type_size = sizeof(CipUsint);
-      break;
-    case (kCipUint):
-      data_type_size = sizeof(CipUint);
-      break;
-    case (kCipUdint):
-      data_type_size = sizeof(CipUdint);
-      break;
-    case (kCipReal):
-      data_type_size = sizeof(CipReal);
-      break;
-#ifdef OPENER_SUPPORT_64BIT_DATATYPES
-    case (kCipLreal):
-      data_type_size = sizeof(CipLreal);
-      break;
-    case (kCipUlint):
-      data_type_size = sizeof(CipUlint);
-      break;
-    case (kCipLint):
-      data_type_size = sizeof(CipLint);
-      break;
-    case (kCipLword):
-      data_type_size = sizeof(CipLword);
-      break;
-    case (kCipLtime):
-      data_type_size = sizeof(CipLint);
-      break;
-#endif /* OPENER_SUPPORT_64BIT_DATATYPES */
-
-    case (kCipStime):
-      data_type_size = sizeof(CipDint);
-      break;
-    case (kCipDate):
-      data_type_size = sizeof(CipUint);
-      break;
-    case (kCipTimeOfDay):
-      data_type_size = sizeof(CipUdint);
-      break;
-    case (kCipDateAndTime):
-      data_type_size = sizeof(CipUdint) + sizeof(CipUint);
-      break;
-    case (kCipString): {
-      CipString *data = (CipString *) attribute_struct->data;
-      data_type_size = sizeof(CipUint) + (data->length) * sizeof(CipOctet);
-    }
-    break;
-    case (kCipByte):
-      data_type_size = sizeof(CipByte);
-      break;
-    case (kCipWord):
-      data_type_size = sizeof(CipWord);
-      break;
-    case (kCipDword):
-      data_type_size = sizeof(CipDword);
-      break;
-    case (kCipString2): {
-      CipString *data = (CipString *) attribute_struct->data;
-      data_type_size = sizeof(CipUint) + 2 * (data->length) * sizeof(CipOctet);
-    }
-    break;
-    case (kCipFtime):
-      data_type_size = sizeof(CipDint);
-      break;
-    case (kCipItime):
-      data_type_size = sizeof(CipInt);
-      break;
-    case (kCipStringN): {
-      CipStringN *data = (CipStringN *) attribute_struct->data;
-      data_type_size = sizeof(CipUint) + sizeof(CipUint)
-                       + (size_t) (data->length) * (size_t) (data->size);
-    }
-    break;
-    case (kCipShortString): {
-      CipShortString *data = (CipShortString *) attribute_struct->data;
-      data_type_size = sizeof(CipUsint) + (data->length) * sizeof(CipOctet);
-    }
-    break;
-    case (kCipTime):
-      data_type_size = sizeof(CipDint);
-      break;
-    case (kCipEpath): {
-      CipEpath *data = (CipEpath *) attribute_struct->data;
-      data_type_size = 2 * (data->path_size);
-    }
-    break;
-    case (kCipEngUnit):
-      data_type_size = sizeof(CipUint);
-      break;
-    case (kCipUsintUsint):
-      data_type_size = 2 * sizeof(CipUsint);
-      break;
-    case (kCipUdintUdintUdintUdintUdintString): {
-      CipTcpIpInterfaceConfiguration *data =
-        (CipTcpIpInterfaceConfiguration *) attribute_struct->data;
-      data_type_size = 5 * sizeof(CipUdint) + sizeof(CipUint)
-                       + (data->domain_name.length) * sizeof(EipByte);
-    }
-    break;
-    case (kCip6Usint):
-      data_type_size = 6 * sizeof(CipUsint);
-      break;
-    case (kCipMemberList):
-      data_type_size = 0;
-      break;
-    case (kCipByteArray): {
-      CipByteArray *data = (CipByteArray *) attribute_struct->data;
-      data_type_size = sizeof(CipUint) + (data->length) * sizeof(CipOctet);
-    }
-    break;
-    case (kInternalUint6):
-      data_type_size = 6 * sizeof(CipUint);
-      break;
-    default:
-      data_type_size = 0;
-      break;
-  }
-  return data_type_size;
-}

+ 4 - 10
source/src/cip/cipcommon.h

@@ -13,14 +13,6 @@
 #include "typedefs.h"
 #include "ciptypes.h"
 
-/** A buffer for holding the replay generated by explicit message requests
- *  or producing I/O connections. These will use this buffer in the following
- *  ways:
- *    1. Explicit messages will use this buffer to store the data generated by the request
- *    2. I/O Connections will use this buffer for the produced data
- */
-extern EipUint8 g_message_data_reply_buffer[];
-
 static const EipUint16 kCipUintZero = 0; /**< Zero value for returning the UINT standard value */
 
 /** @brief Check if requested service present in class/instance and call appropriate service.
@@ -41,6 +33,10 @@ EipStatus NotifyClass(const CipClass *const RESTRICT cip_class,
                       const struct sockaddr *originator_address,
                       const int encapsulation_session);
 
+void GenerateGetAttributeSingleHeader(
+  const CipMessageRouterRequest *const message_router_request,
+  CipMessageRouterResponse *const message_router_response);
+
 /** @brief Generic implementation of the GetAttributeSingle CIP service
  *
  * Check from classID which Object requests an attribute, search if object has
@@ -87,6 +83,4 @@ EipStatus GetAttributeAll(CipInstance *instance,
 int DecodePaddedEPath(CipEpath *epath,
                       const EipUint8 **message);
 
-size_t GetSizeOfAttribute(const CipAttributeStruct *const attribute_struct);
-
 #endif /* OPENER_CIPCOMMON_H_ */

+ 42 - 31
source/src/cip/cipconnectionmanager.c

@@ -176,24 +176,35 @@ void InitializeConnectionManager(CipClass *class) {
 
   CipClass *meta_class = class->class_instance.cip_class;
 
-  InsertAttribute( (CipInstance *) class, 1, kCipUint,
+  InsertAttribute( (CipInstance *) class, 1, kCipUint, EncodeCipUint,
                    (void *) &class->revision,
                    kGetableSingleAndAll ); /* revision */
-  InsertAttribute( (CipInstance *) class, 2, kCipUint,
+  InsertAttribute( (CipInstance *) class, 2, kCipUint, EncodeCipUint,
                    (void *) &class->number_of_instances, kGetableSingleAndAll ); /*  largest instance number */
-  InsertAttribute( (CipInstance *) class, 3, kCipUint,
+  InsertAttribute( (CipInstance *) class, 3, kCipUint, EncodeCipUint,
                    (void *) &class->number_of_instances, kGetableSingle ); /* number of instances currently existing*/
-  InsertAttribute( (CipInstance *) class, 4, kCipUint, (void *) &kCipUintZero,
+  InsertAttribute( (CipInstance *) class, 4, kCipUint, EncodeCipUint,
+                   (void *) &kCipUintZero,
                    kNotSetOrGetable ); /* optional attribute list - default = 0 */
-  InsertAttribute( (CipInstance *) class, 5, kCipUint, (void *) &kCipUintZero,
+  InsertAttribute( (CipInstance *) class, 5, kCipUint, EncodeCipUint,
+                   (void *) &kCipUintZero,
                    kNotSetOrGetable ); /* optional service list - default = 0 */
-  InsertAttribute( (CipInstance *) class, 6, kCipUint,
+  InsertAttribute( (CipInstance *) class, 6, kCipUint, EncodeCipUint,
                    (void *) &meta_class->highest_attribute_number,
                    kGetableSingleAndAll ); /* max class attribute number*/
-  InsertAttribute( (CipInstance *) class, 7, kCipUint,
+  InsertAttribute( (CipInstance *) class, 7, kCipUint, EncodeCipUint,
                    (void *) &class->highest_attribute_number,
                    kGetableSingleAndAll ); /* max instance attribute number*/
 
+  InsertService(meta_class,
+                kGetAttributeAll,
+                &GetAttributeAll,
+                "GetAttributeAll");                                                 /* bind instance services to the metaclass*/
+  InsertService(meta_class,
+                kGetAttributeSingle,
+                &GetAttributeSingle,
+                "GetAttributeSingle");
+
 }
 
 EipStatus ConnectionManagerInit(EipUint16 unique_connection_id) {
@@ -751,7 +762,6 @@ EipStatus AssembleForwardOpenResponse(
   /* write reply information in CPF struct dependent of pa_status */
   CipCommonPacketFormatData *cip_common_packet_format_data =
     &g_common_packet_format_data_item;
-  EipByte *message = message_router_response->data;
   cip_common_packet_format_data->item_count = 2;
   cip_common_packet_format_data->data_item.type_id =
     kCipItemIdUnconnectedDataItem;
@@ -763,7 +773,7 @@ EipStatus AssembleForwardOpenResponse(
 
   if (kCipErrorSuccess == general_status) {
     OPENER_TRACE_INFO("assembleFWDOpenResponse: sending success response\n");
-    message_router_response->data_length = 26; /* if there is no application specific data */
+    /* if there is no application specific data, total length should be 26 */
     message_router_response->size_of_additional_status = 0;
 
     if (cip_common_packet_format_data->address_info_item[0].type_id != 0) {
@@ -773,14 +783,16 @@ EipStatus AssembleForwardOpenResponse(
       }
     }
 
-    AddDintToMessage(connection_object->cip_consumed_connection_id, &message);
-    AddDintToMessage(connection_object->cip_produced_connection_id, &message);
+    AddDintToMessage(connection_object->cip_consumed_connection_id,
+                     &message_router_response->message);
+    AddDintToMessage(connection_object->cip_produced_connection_id,
+                     &message_router_response->message);
   } else {
     /* we have an connection creation error */
     OPENER_TRACE_INFO("AssembleForwardOpenResponse: sending error response\n");
     ConnectionObjectSetState(connection_object,
                              kConnectionObjectStateNonExistent);
-    message_router_response->data_length = 10;
+    /* Expected data length is 10 octets */
 
     switch (general_status) {
       case kCipErrorNotEnoughData:
@@ -824,22 +836,23 @@ EipStatus AssembleForwardOpenResponse(
     }
   }
 
-  AddIntToMessage(connection_object->connection_serial_number, &message);
-  AddIntToMessage(connection_object->originator_vendor_id, &message);
-  AddDintToMessage(connection_object->originator_serial_number, &message);
+  AddIntToMessage(connection_object->connection_serial_number,
+                  &message_router_response->message);
+  AddIntToMessage(connection_object->originator_vendor_id,
+                  &message_router_response->message);
+  AddDintToMessage(connection_object->originator_serial_number,
+                   &message_router_response->message);
 
   if (kCipErrorSuccess == general_status) {
     /* set the actual packet rate to requested packet rate */
     AddDintToMessage(connection_object->o_to_t_requested_packet_interval,
-                     &message);
+                     &message_router_response->message);
     AddDintToMessage(connection_object->t_to_o_requested_packet_interval,
-                     &message);
+                     &message_router_response->message);
   }
 
-  *message = 0; /* remaining path size - for routing devices relevant */
-  message++;
-  *message = 0; /* reserved */
-  message++;
+  AddSintToMessage(0, &message_router_response->message); /* remaining path size - for routing devices relevant */
+  AddSintToMessage(0, &message_router_response->message); /* reserved */
 
   return kEipStatusOkSend; /* send reply */
 }
@@ -885,27 +898,27 @@ EipStatus AssembleForwardCloseResponse(
   /* write reply information in CPF struct dependent of pa_status */
   CipCommonPacketFormatData *common_data_packet_format_data =
     &g_common_packet_format_data_item;
-  EipByte *message = message_router_response->data;
   common_data_packet_format_data->item_count = 2;
   common_data_packet_format_data->data_item.type_id =
     kCipItemIdUnconnectedDataItem;
 
   AddNullAddressItem(common_data_packet_format_data);
 
-  AddIntToMessage(connection_serial_number, &message);
-  AddIntToMessage(originatior_vendor_id, &message);
-  AddDintToMessage(originator_serial_number, &message);
+  AddIntToMessage(connection_serial_number, &message_router_response->message);
+  AddIntToMessage(originatior_vendor_id, &message_router_response->message);
+  AddDintToMessage(originator_serial_number, &message_router_response->message);
 
   message_router_response->reply_service = (0x80
                                             | message_router_request->service);
-  message_router_response->data_length = 10; /* if there is no application specific data */
+  /* Excepted length is 10 if there is no application specific data */
 
   if (kConnectionManagerExtendedStatusCodeSuccess == extended_error_code) {
-    *message = 0; /* no application data */
+    AddSintToMessage(0, &message_router_response->message); /* no application data */
     message_router_response->general_status = kCipErrorSuccess;
     message_router_response->size_of_additional_status = 0;
   } else {
-    *message = *message_router_request->data; /* remaining path size */
+    AddSintToMessage(*message_router_request->data,
+                     &message_router_response->message);                                /* remaining path size */
     if (kConnectionManagerExtendedStatusWrongCloser == extended_error_code) {
       message_router_response->general_status = kCipErrorPrivilegeViolation;
     } else {
@@ -915,9 +928,7 @@ EipStatus AssembleForwardCloseResponse(
     }
   }
 
-  message++;
-  *message = 0; /* reserved */
-  message++;
+  AddSintToMessage(0, &message_router_response->message); /* reserved */
 
   return kEipStatusOkSend;
 }

+ 1 - 1
source/src/cip/cipconnectionobject.c

@@ -147,7 +147,7 @@ void ConnectionObjectInitializeFromMessage(
                                                  GetSintFromMessage(
                                                    message) );
 
-  MoveMessageNOctets(3, message); /* 3 bytes reserved */
+  (*message) += 3; /* 3 bytes reserved */
 
   /* the requested packet interval parameter needs to be a multiple of TIMERTICK from the header file */
   OPENER_TRACE_INFO(

+ 67 - 112
source/src/cip/cipdlr.c

@@ -49,6 +49,7 @@
 #include "cipcommon.h"
 #include "opener_api.h"
 #include "trace.h"
+#include "endianconv.h"
 
 /* ********************************************************************
  * defines
@@ -89,107 +90,20 @@ CipDlrObject g_dlr;  /**< definition of DLR object instance 1 data */
 /* ********************************************************************
  * local functions
  */
-static int EncodeNodeAddress(CipNodeAddress *node_address, CipOctet **message) {
-  int encoded_len = 0;
-  encoded_len += EncodeData(kCipUdint, &node_address->device_ip,
-                            message);
-  encoded_len += EncodeData(kCip6Usint,
-                            &node_address->device_mac,
-                            message);
-  return encoded_len;
+static void EncodeCipRingSupervisorConfig(const void *const data,
+                                          ENIPMessage *const outgoing_message) {
+  const size_t kRingSupStructSize = 12u;
+  FillNextNMessageOctetsWithValueAndMoveToNextPosition(0,
+                                                       kRingSupStructSize,
+                                                       outgoing_message);
 }
 
-static EipStatus GetAttributeSingleDlr(
-  CipInstance *RESTRICT const instance,
-  CipMessageRouterRequest *const message_router_request,
-  CipMessageRouterResponse *const message_router_response,
-  const struct sockaddr *originator_address,
-  const int encapsulation_session) {
-
-  CipAttributeStruct *attribute = GetCipAttribute(
-    instance, message_router_request->request_path.attribute_number);
-  EipByte *message = message_router_response->data;
-
-  message_router_response->data_length = 0;
-  message_router_response->reply_service = (0x80
-                                            | message_router_request->service);
-  message_router_response->general_status = kCipErrorAttributeNotSupported;
-  message_router_response->size_of_additional_status = 0;
-
-  EipUint16 attribute_number = message_router_request->request_path
-                               .attribute_number;
-
-  if ( (NULL != attribute) && (NULL != attribute->data) ) {
-    /* Mask for filtering get-ability */
-    uint8_t get_bit_mask = 0;
-    if (kGetAttributeAll == message_router_request->service) {
-      get_bit_mask = (instance->cip_class->get_all_bit_mask[CalculateIndex(
-                                                              attribute_number)]);
-      message_router_response->general_status = kCipErrorSuccess;
-    } else {
-      get_bit_mask = (instance->cip_class->get_single_bit_mask[CalculateIndex(
-                                                                 attribute_number)
-                      ]);
-    }
-    if ( 0 != ( get_bit_mask & ( 1 << (attribute_number % 8) ) ) ) {
-      /* create a reply message containing the data*/
-      bool use_common_handler;
-      switch (attribute_number) {
-      case 4: /* fall through */
-      case 6: /* fall through */
-      case 7: /* fall through */
-      case 10:
-        use_common_handler = false;
-        OPENER_TRACE_INFO("getAttribute %d\n", attribute_number);
-        break;
-      default:
-        use_common_handler = true;
-        break;
-      }
-
-      /* Call the PreGetCallback if enabled for this attribute and the common handler is not used. */
-      if (!use_common_handler) {
-        if (attribute->attribute_flags & kPreGetFunc && NULL != instance->cip_class->PreGetCallback) {
-          instance->cip_class->PreGetCallback(instance, attribute, message_router_request->service);
-        }
-      }
-
-      switch (attribute_number) {
-        case 4: {
-          /* This attribute is not implemented and only reached by GetAttributesAll. */
-          const size_t kRingSupStructSize = 12u;
-          memset(message_router_response->data, 0, kRingSupStructSize);
-          message_router_response->data += kRingSupStructSize;
-          message_router_response->general_status = kCipErrorSuccess;
-          break;
-        }
-        case 6: /* fall through */
-        case 7: /* fall through */
-        case 10:
-          message_router_response->data_length = EncodeNodeAddress(
-            (CipNodeAddress *)attribute->data,
-            &message);
-          message_router_response->general_status = kCipErrorSuccess;
-          break;
-
-        default:
-          GetAttributeSingle(instance, message_router_request,
-                             message_router_response,
-                             originator_address,
-                             encapsulation_session);
-      }
-
-      /* Call the PostGetCallback if enabled for this attribute and the common handler is not used. */
-      if (!use_common_handler) {
-        if (attribute->attribute_flags & kPostGetFunc && NULL != instance->cip_class->PostGetCallback) {
-          instance->cip_class->PostGetCallback(instance, attribute, message_router_request->service);
-        }
-      }
-
-    }
-  }
-
-  return kEipStatusOkSend;
+static void EncodeCipNodeAddress(const void *const data,
+                                 ENIPMessage *const outgoing_message) {
+  CipNodeAddress *node_address = (CipNodeAddress *)data;
+  EncodeCipUdint(&node_address->device_ip, outgoing_message);
+  EncodeCipEthernetLinkPhyisicalAddress(&node_address->device_mac,
+                                        outgoing_message);
 }
 
 
@@ -218,36 +132,77 @@ EipStatus CipDlrInit(void) {
 
   /* Add services to the class */
   InsertService(dlr_class, kGetAttributeSingle,
-                GetAttributeSingleDlr, "GetAttributeSingleDlr");
+                GetAttributeSingle, "GetAttributeSingle");
   InsertService(dlr_class, kGetAttributeAll,
                 GetAttributeAll, "GetAttributeAll");
 
   /* Bind attributes to the instance */
   CipInstance *dlr_instance = GetCipInstance(dlr_class, 1u);
 
-  InsertAttribute(dlr_instance,  1, kCipUsint, &g_dlr.network_topology,
+  InsertAttribute(dlr_instance,
+                  1,
+                  kCipUsint,
+                  EncodeCipUsint,
+                  &g_dlr.network_topology,
                   kGetableSingleAndAll);
-  InsertAttribute(dlr_instance,  2, kCipUsint, &g_dlr.network_status,
+  InsertAttribute(dlr_instance,
+                  2,
+                  kCipUsint,
+                  EncodeCipUsint,
+                  &g_dlr.network_status,
                   kGetableSingleAndAll);
-  InsertAttribute(dlr_instance,  3, kCipUsint, (void *)&s_0xFF_default,
-                  kGetableAll);
-  InsertAttribute(dlr_instance,  4, kCipAny, (void *)&s_0x00000000_default,
+  InsertAttribute(dlr_instance,
+                  3,
+                  kCipUsint,
+                  EncodeCipUsint,
+                  (void *)&s_0xFF_default,
                   kGetableAll);
-  InsertAttribute(dlr_instance,  5, kCipUint, (void *)&s_0x0000_default,
+  InsertAttribute(dlr_instance,  4, kCipAny, EncodeCipRingSupervisorConfig,
+                  (void *)&s_0x00000000_default,
+                  kGetableAllDummy);
+  InsertAttribute(dlr_instance,
+                  5,
+                  kCipUint,
+                  EncodeCipUint,
+                  (void *)&s_0x0000_default,
                   kGetableAll);
-  InsertAttribute(dlr_instance,  6, kCipAny, (void *)&s_zero_node,
+  InsertAttribute(dlr_instance,
+                  6,
+                  kCipAny,
+                  EncodeCipNodeAddress,
+                  (void *)&s_zero_node,
                   kGetableAll);
-  InsertAttribute(dlr_instance,  7, kCipAny, (void *)&s_zero_node,
+  InsertAttribute(dlr_instance,
+                  7,
+                  kCipAny,
+                  EncodeCipNodeAddress,
+                  (void *)&s_zero_node,
                   kGetableAll);
-  InsertAttribute(dlr_instance,  8, kCipUint, (void *)&s_0xFFFF_default,
+  InsertAttribute(dlr_instance,
+                  8,
+                  kCipUint,
+                  EncodeCipUint,
+                  (void *)&s_0xFFFF_default,
                   kGetableAll);
   /* Attribute #9 is not implemented and also NOT part of the GetAttributesAll
    *  response. Therefore it is not added here! */
-  InsertAttribute(dlr_instance, 10, kCipAny, &g_dlr.active_supervisor_address,
+  InsertAttribute(dlr_instance,
+                  10,
+                  kCipAny,
+                  EncodeCipNodeAddress,
+                  &g_dlr.active_supervisor_address,
                   kGetableSingleAndAll);
-  InsertAttribute(dlr_instance, 11, kCipUsint, (void *)&s_0x00_default,
+  InsertAttribute(dlr_instance,
+                  11,
+                  kCipUsint,
+                  EncodeCipUsint,
+                  (void *)&s_0x00_default,
                   kGetableAll);
-  InsertAttribute(dlr_instance, 12, kCipDword, &g_dlr.capability_flags,
+  InsertAttribute(dlr_instance,
+                  12,
+                  kCipDword,
+                  EncodeCipDword,
+                  &g_dlr.capability_flags,
                   kGetableSingleAndAll);
 
   /* Set attributes to initial values */

+ 21 - 21
source/src/cip/cipepath.c

@@ -340,17 +340,17 @@ CipDword CipEpathGetLogicalValue(const EipUint8 **message) {
   LogicalSegmentLogicalFormat logical_format =
     GetPathLogicalSegmentLogicalFormat(*message);
   CipDword data = 0;
-  MoveMessageNOctets(1, message); /* Move to logical value */
+  (*message) += 1; /* Move to logical value */
   switch (logical_format) {
     case kLogicalSegmentLogicalFormatEightBit:
       data = GetSintFromMessage(message);
       break;
     case kLogicalSegmentLogicalFormatSixteenBit:
-      MoveMessageNOctets(1, message); /* Pad byte needs to be skipped */
+      (*message) += 1; /* Pad byte needs to be skipped */
       data = GetIntFromMessage(message);
       break;
     case kLogicalSegmentLogicalFormatThirtyTwoBit:
-      MoveMessageNOctets(1, message); /* Pad byte needs to be skipped */
+      (*message) += 1; /* Pad byte needs to be skipped */
       data = GetDintFromMessage(message);
       break;
     default:
@@ -360,27 +360,25 @@ CipDword CipEpathGetLogicalValue(const EipUint8 **message) {
   return data;
 }
 
-size_t CipEpathSetLogicalValue(const CipDword logical_value,
-                               const LogicalSegmentLogicalFormat logical_format,
-                               CipOctet **message) {
-  size_t written_bytes = 0;
+void CipEpathSetLogicalValue(const CipDword logical_value,
+                             const LogicalSegmentLogicalFormat logical_format,
+                             CipMessageRouterResponse *const message) {
   switch(logical_value) {
     case kLogicalSegmentLogicalFormatEightBit:
-      written_bytes = AddSintToMessage(logical_value, message);
+      AddSintToMessage(logical_value, &message->message);
       break;
     case kLogicalSegmentLogicalFormatSixteenBit:
-      written_bytes = MoveMessageNOctets(1, (const CipOctet **)message); /* Needed for padding */
-      written_bytes += AddIntToMessage(logical_value, message);
+      MoveMessageNOctets(1, &message->message); /* Needed for padding */
+      AddIntToMessage(logical_value, message);
       break;
     case kLogicalSegmentLogicalFormatThirtyTwoBit:
-      written_bytes = MoveMessageNOctets(1,(const CipOctet **)message); /* Needed for padding */
-      written_bytes += AddDintToMessage(logical_value, message);
+      MoveMessageNOctets(1, &message->message); /* Needed for padding */
+      AddDintToMessage(logical_value, message);
       break;
     default:
-      OPENER_ASSERT(false);/* This should never happen! */
-      written_bytes = 0;
+      OPENER_ASSERT(false); /* This should never happen! */
+      break;
   }
-  return written_bytes;
 }
 
 LogicalSegmentExtendedLogicalType GetPathLogicalSegmentExtendedLogicalType(
@@ -451,7 +449,7 @@ void GetElectronicKeyFormat4FromMessage(
   OPENER_ASSERT( kElectronicKeySegmentFormatKeyFormat4 ==
                  GetPathLogicalSegmentElectronicKeyFormat(*message) );
 
-  MoveMessageNOctets(2, message);
+    (*message) += 2;
   ElectronicKeyFormat4SetVendorId(key, GetIntFromMessage(message) );
   ElectronicKeyFormat4SetDeviceType(key, GetIntFromMessage(message) );
   ElectronicKeyFormat4SetProductCode(key, GetIntFromMessage(message) );
@@ -649,6 +647,8 @@ LogicalSegmentLogicalFormat CipEpathGetNeededLogicalFormatForValue(
   return logical_format;
 }
 
+
+//TODO: Does not match the actual interface anymore, check how to fix
 size_t CipEpathEncodeConnectionEpath(
   const CipConnectionPathEpath *const connection_epath,
   CipOctet **encoded_path) {
@@ -663,9 +663,9 @@ size_t CipEpathEncodeConnectionEpath(
     SetPathLogicalSegmentLogicalFormat(logical_value, *encoded_path);
     encoded_path_length += 1;
     MoveMessageNOctets(1, (const CipOctet **)encoded_path);
-    encoded_path_length += CipEpathSetLogicalValue(connection_epath->class_id,
-                                                   logical_value,
-                                                   encoded_path);
+    CipEpathSetLogicalValue(connection_epath->class_id,
+                            logical_value,
+                            encoded_path);
   }
 
   {
@@ -677,7 +677,7 @@ size_t CipEpathEncodeConnectionEpath(
     SetPathLogicalSegmentLogicalFormat(logical_value, *encoded_path);
     encoded_path_length += 1;
     MoveMessageNOctets(1, (const CipOctet **)encoded_path);
-    encoded_path_length += CipEpathSetLogicalValue(
+    CipEpathSetLogicalValue(
       connection_epath->instance_id,
       logical_value,
       encoded_path);
@@ -693,7 +693,7 @@ size_t CipEpathEncodeConnectionEpath(
     SetPathLogicalSegmentLogicalFormat(logical_value, *encoded_path);
     encoded_path_length += 1;
     MoveMessageNOctets(1, (const CipOctet **)encoded_path);
-    encoded_path_length += CipEpathSetLogicalValue(
+    CipEpathSetLogicalValue(
       connection_epath->attribute_id_or_connection_point,
       logical_value,
       encoded_path);

+ 3 - 3
source/src/cip/cipepath.h

@@ -259,9 +259,9 @@ void SetPathLogicalSegmentLogicalFormat(LogicalSegmentLogicalFormat format,
 
 CipDword CipEpathGetLogicalValue(const EipUint8 **message);
 
-size_t CipEpathSetLogicalValue(const CipDword logical_value,
-                               const LogicalSegmentLogicalFormat logical_format,
-                               CipOctet **message);
+void CipEpathSetLogicalValue(const CipDword logical_value,
+                             const LogicalSegmentLogicalFormat logical_format,
+                             CipMessageRouterResponse *const message);
 
 /** @brief  Gets the Extended Logical Type of a Logical Segment EPath message
  *

+ 195 - 257
source/src/cip/cipethernetlink.c

@@ -50,10 +50,11 @@
 #include "opener_api.h"
 #include "trace.h"
 #include "opener_user_conf.h"
+#include "endianconv.h"
 
 #if OPENER_ETHLINK_INSTANCE_CNT > 1
-  /* If we have more than 1 Ethernet Link instance then the interface label
-   * attribute is mandatory. We need then OPENER_ETHLINK_LABEL_ENABLE. */
+/* If we have more than 1 Ethernet Link instance then the interface label
+ * attribute is mandatory. We need then OPENER_ETHLINK_LABEL_ENABLE. */
   #define OPENER_ETHLINK_LABEL_ENABLE  1
 #endif
 
@@ -70,7 +71,8 @@
   #define IFACE_LABEL_ACCESS_MODE kGetableAll
 #endif
 
-#if defined(OPENER_ETHLINK_IFACE_CTRL_ENABLE) && 0 != OPENER_ETHLINK_IFACE_CTRL_ENABLE
+#if defined(OPENER_ETHLINK_IFACE_CTRL_ENABLE) && \
+  0 != OPENER_ETHLINK_IFACE_CTRL_ENABLE
   #define IFACE_CTRL_ACCESS_MODE  (kSetAndGetAble | kNvDataFunc)
 #else
   #define IFACE_CTRL_ACCESS_MODE  kGetableAll
@@ -84,22 +86,17 @@ typedef struct speed_duplex_array_entry {
 
 
 /* forward declaration of functions to encode certain attribute objects */
-static int EncodeInterfaceCounters(CipUdint instance_id, CipOctet **message);
+static void EncodeCipEthernetLinkInterfaceCounters(const void *const data,
+                                                   ENIPMessage *const outgoing_message);
 
-static int EncodeMediaCounters(CipUdint instance_id, CipOctet **message);
+static void EncodeCipEthernetLinkMediaCounters(const void *const data,
+                                               ENIPMessage *const outgoing_message);
 
-static int EncodeInterfaceControl(CipUdint instance_id, CipOctet **message);
+static void EncodeCipEthernetLinkInterfaceControl(const void *const data,
+                                                  ENIPMessage *const outgoing_message);
 
-static int EncodeInterfaceCapability(CipUdint instance_id, CipOctet **message);
-
-
-/* forward declaration for the GetAttributeSingle service handler function */
-EipStatus GetAttributeSingleEthernetLink(
-  CipInstance *RESTRICT const instance,
-  CipMessageRouterRequest *const message_router_request,
-  CipMessageRouterResponse *const message_router_response,
-  const struct sockaddr *originator_address,
-  const int encapsulation_session);
+static void EncodeCipEthernetLinkInterfaceCaps(const void *const data,
+                                               ENIPMessage *const outgoing_message);
 
 #if defined(OPENER_ETHLINK_CNTRS_ENABLE) && 0 != OPENER_ETHLINK_CNTRS_ENABLE
 /* forward declaration for the GetAndClear service handler function */
@@ -111,7 +108,8 @@ EipStatus GetAndClearEthernetLink(
   const int encapsulation_session);
 #endif  /* ... && 0 != OPENER_ETHLINK_CNTRS_ENABLE */
 
-#if defined(OPENER_ETHLINK_IFACE_CTRL_ENABLE) && 0 != OPENER_ETHLINK_IFACE_CTRL_ENABLE
+#if defined(OPENER_ETHLINK_IFACE_CTRL_ENABLE) && \
+  0 != OPENER_ETHLINK_IFACE_CTRL_ENABLE
 EipStatus SetAttributeSingleEthernetLink(
   CipInstance *instance,
   CipMessageRouterRequest *message_router_request,
@@ -162,18 +160,18 @@ static const CipEthernetLinkSpeedDuplexArrayEntry speed_duplex_table[] =
 static const CipShortString iface_label_table[OPENER_ETHLINK_INSTANCE_CNT] =
 {
   {
-    .length = sizeof IFACE_LABEL -1,
+    .length = sizeof IFACE_LABEL - 1,
     .string = (EipByte *)IFACE_LABEL
   },
 #if OPENER_ETHLINK_INSTANCE_CNT > 1
   {
-    .length = sizeof IFACE_LABEL_1 -1,
+    .length = sizeof IFACE_LABEL_1 - 1,
     .string = (EipByte *)IFACE_LABEL_1
   },
 #endif
 #if OPENER_ETHLINK_INSTANCE_CNT > 2
   {
-    .length = sizeof IFACE_LABEL_2 -1,
+    .length = sizeof IFACE_LABEL_2 - 1,
     .string = (EipByte *)IFACE_LABEL_2
   },
 #endif
@@ -187,7 +185,8 @@ static CipUsint dummy_attribute_usint = 0;
 static CipUdint dummy_attribute_udint = 0;
 #endif
 
-#if defined(OPENER_ETHLINK_IFACE_CTRL_ENABLE) && 0 != OPENER_ETHLINK_IFACE_CTRL_ENABLE
+#if defined(OPENER_ETHLINK_IFACE_CTRL_ENABLE) && \
+  0 != OPENER_ETHLINK_IFACE_CTRL_ENABLE
 #else
 /* Constant dummy data for attribute #6 */
 static CipEthernetLinkInterfaceControl s_interface_control =
@@ -202,24 +201,32 @@ CipEthernetLinkObject g_ethernet_link[OPENER_ETHLINK_INSTANCE_CNT];
 
 EipStatus CipEthernetLinkInit(void) {
   CipClass *ethernet_link_class = CreateCipClass(kCipEthernetLinkClassCode,
-                                                 0, /* # class attributes*/
-                                                 7, /* # highest class attribute number*/
-                                                 2, /* # class services*/
-                                                 11, /* # instance attributes*/
-                                                 11, /* # highest instance attribute number*/
+                                                 0,
+                                                 /* # class attributes*/
+                                                 7,
+                                                 /* # highest class attribute number*/
+                                                 2,
+                                                 /* # class services*/
+                                                 11,
+                                                 /* # instance attributes*/
+                                                 11,
+                                                 /* # highest instance attribute number*/
                                                  /* # instance services follow */
-                                                 2+OPENER_ETHLINK_CNTRS_ENABLE+OPENER_ETHLINK_IFACE_CTRL_ENABLE,
-                                                 OPENER_ETHLINK_INSTANCE_CNT, /* # instances*/
-                                                 "Ethernet Link", /* # class name */
-                                                 4, /* # class revision*/
+                                                 2 + OPENER_ETHLINK_CNTRS_ENABLE + OPENER_ETHLINK_IFACE_CTRL_ENABLE,
+                                                 OPENER_ETHLINK_INSTANCE_CNT,
+                                                 /* # instances*/
+                                                 "Ethernet Link",
+                                                 /* # class name */
+                                                 4,
+                                                 /* # class revision*/
                                                  NULL); /* # function pointer for initialization*/
 
   /* set attributes to initial values */
-  for (size_t idx = 0;  idx < OPENER_ETHLINK_INSTANCE_CNT; ++idx) {
-    g_ethernet_link[idx].interface_speed = 100U;
+  for (size_t idx = 0; idx < OPENER_ETHLINK_INSTANCE_CNT; ++idx) {
+    g_ethernet_link[idx].interface_speed = 100;
     /* successful speed and duplex neg, full duplex active link.
      * TODO: in future it should be checked if link is active */
-    g_ethernet_link[idx].interface_flags = 0xFU;
+    g_ethernet_link[idx].interface_flags = 0xF;
 
     g_ethernet_link[idx].interface_type = kEthLinkIfTypeTwistedPair;
     if (2 == idx) {
@@ -231,10 +238,10 @@ EipStatus CipEthernetLinkInit(void) {
     g_ethernet_link[idx].interface_caps.capability_bits = kEthLinkCapAutoNeg;
     g_ethernet_link[idx].interface_caps.speed_duplex_selector =
       kEthLinkSpeedDpx_100_FD;
-#if defined(OPENER_ETHLINK_IFACE_CTRL_ENABLE) && 0 != OPENER_ETHLINK_IFACE_CTRL_ENABLE
-    /* If auto-negotiation is enabled the forced_interface_speed must not be set, i. e.
-     *  be zero. See Vol. 2, section 5-5.3.2.6.2 */
-    g_ethernet_link[idx].interface_control.control_bits = kEthLinkIfCntrlAutonegotiate;
+#if defined(OPENER_ETHLINK_IFACE_CTRL_ENABLE) && \
+    0 != OPENER_ETHLINK_IFACE_CTRL_ENABLE
+    g_ethernet_link[idx].interface_control.control_bits =
+      kEthLinkIfCntrlAutonegotiate;
     g_ethernet_link[idx].interface_control.forced_interface_speed = 0U;
 #endif
   }
@@ -242,15 +249,16 @@ EipStatus CipEthernetLinkInit(void) {
   if (ethernet_link_class != NULL) {
     /* add services to the class */
     InsertService(ethernet_link_class, kGetAttributeSingle,
-                  &GetAttributeSingleEthernetLink,
-                  "GetAttributeSingleEthernetLink");
+                  &GetAttributeSingle,
+                  "GetAttributeSingle");
     InsertService(ethernet_link_class, kGetAttributeAll, &GetAttributeAll,
                   "GetAttributeAll");
 #if defined(OPENER_ETHLINK_CNTRS_ENABLE) && 0 != OPENER_ETHLINK_CNTRS_ENABLE
     InsertService(ethernet_link_class, kEthLinkGetAndClear,
                   &GetAndClearEthernetLink, "GetAndClear");
 #endif
-#if defined(OPENER_ETHLINK_IFACE_CTRL_ENABLE) && 0 != OPENER_ETHLINK_IFACE_CTRL_ENABLE
+#if defined(OPENER_ETHLINK_IFACE_CTRL_ENABLE) && \
+    0 != OPENER_ETHLINK_IFACE_CTRL_ENABLE
     InsertService(ethernet_link_class, kSetAttributeSingle,
                   &SetAttributeSingleEthernetLink,
                   "SetAttributeSingleEthernetLink");
@@ -259,51 +267,94 @@ EipStatus CipEthernetLinkInit(void) {
     /* bind attributes to the instance */
     for (size_t idx = 0; idx < OPENER_ETHLINK_INSTANCE_CNT; ++idx) {
       CipInstance *ethernet_link_instance =
-        GetCipInstance(ethernet_link_class, idx+1);
-
-      InsertAttribute(ethernet_link_instance, 1, kCipUdint,
-                      &g_ethernet_link[idx].interface_speed, kGetableSingleAndAll);
-      InsertAttribute(ethernet_link_instance, 2, kCipDword,
-                      &g_ethernet_link[idx].interface_flags, kGetableSingleAndAll);
-      InsertAttribute(ethernet_link_instance, 3, kCip6Usint,
-                      &g_ethernet_link[idx].physical_address, kGetableSingleAndAll);
+        GetCipInstance(ethernet_link_class, idx + 1);
+
+      InsertAttribute(ethernet_link_instance,
+                      1,
+                      kCipUdint,
+                      EncodeCipUdint,
+                      &g_ethernet_link[idx].interface_speed,
+                      kGetableSingleAndAll);
+      InsertAttribute(ethernet_link_instance,
+                      2,
+                      kCipDword,
+                      EncodeCipDword,
+                      &g_ethernet_link[idx].interface_flags,
+                      kGetableSingleAndAll);
+      InsertAttribute(ethernet_link_instance,
+                      3,
+                      kCip6Usint,
+                      EncodeCipEthernetLinkPhyisicalAddress,
+                      &g_ethernet_link[idx].physical_address,
+                      kGetableSingleAndAll);
 #if defined(OPENER_ETHLINK_CNTRS_ENABLE) && 0 != OPENER_ETHLINK_CNTRS_ENABLE
-      InsertAttribute(ethernet_link_instance, 4, kCipUsint,
-                      &g_ethernet_link[idx].interface_cntrs, kGetableSingleAndAll);
-      InsertAttribute(ethernet_link_instance, 5, kCipUsint,
+      InsertAttribute(ethernet_link_instance,
+                      4,
+                      kCipUsint,
+                      EncodeCipUsint,
+                      &g_ethernet_link[idx].interface_cntrs,
+                      kGetableSingleAndAll);
+      InsertAttribute(ethernet_link_instance, 5, kCipUsint, EncodeCipUsint,
                       &g_ethernet_link[idx].media_cntrs, kGetableSingleAndAll);
 #else
-      InsertAttribute(ethernet_link_instance, 4, kCipUsint,
-                      &dummy_attribute_udint, kGetableAll);
-      InsertAttribute(ethernet_link_instance, 5, kCipUsint,
-                      &dummy_attribute_udint, kGetableAll);
+      InsertAttribute(ethernet_link_instance,
+                      4,
+                      kCipAny,
+                      EncodeCipEthernetLinkInterfaceCounters,
+                      &dummy_attribute_udint,
+                      kGetableAllDummy);
+      InsertAttribute(ethernet_link_instance,
+                      5,
+                      kCipAny,
+                      EncodeCipEthernetLinkMediaCounters,
+                      &dummy_attribute_udint,
+                      kGetableAllDummy);
 #endif  /* ... && 0 != OPENER_ETHLINK_CNTRS_ENABLE */
-#if defined(OPENER_ETHLINK_IFACE_CTRL_ENABLE) && 0 != OPENER_ETHLINK_IFACE_CTRL_ENABLE
+#if defined(OPENER_ETHLINK_IFACE_CTRL_ENABLE) && \
+      0 != OPENER_ETHLINK_IFACE_CTRL_ENABLE
       if (2 == idx) {
         /* Interface control of internal switch port is never settable. */
-        InsertAttribute(ethernet_link_instance, 6, kCipAny,
+        InsertAttribute(ethernet_link_instance,
+                        6,
+                        kCipAny,
+                        EncodeCipEthernetLinkInterfaceControl,
                         &g_ethernet_link[idx].interface_control,
                         IFACE_CTRL_ACCESS_MODE & ~kSetable);
       } else {
-        InsertAttribute(ethernet_link_instance, 6, kCipAny,
+        InsertAttribute(ethernet_link_instance,
+                        6,
+                        kCipAny,
+                        EncodeCipEthernetLinkInterfaceControl,
                         &g_ethernet_link[idx].interface_control,
                         IFACE_CTRL_ACCESS_MODE);
       }
 #else
-      InsertAttribute(ethernet_link_instance, 6, kCipAny, &s_interface_control,
+      InsertAttribute(ethernet_link_instance,
+                      6,
+                      kCipAny,
+                      EncodeCipEthernetLinkInterfaceControl,
+                      &s_interface_control,
                       kGetableAll);
 #endif
-      InsertAttribute(ethernet_link_instance, 7, kCipUsint,
-                      &g_ethernet_link[idx].interface_type, kGetableSingleAndAll);
-      InsertAttribute(ethernet_link_instance, 8, kCipUsint,
-                      &dummy_attribute_usint, kGetableAll);
-      InsertAttribute(ethernet_link_instance, 9, kCipUsint,
-                      &dummy_attribute_usint, kGetableAll);
-      InsertAttribute(ethernet_link_instance, 10, kCipShortString,
+      InsertAttribute(ethernet_link_instance, 7, kCipUsint, EncodeCipUsint,
+                      &g_ethernet_link[idx].interface_type,
+                      kGetableSingleAndAll);
+      InsertAttribute(ethernet_link_instance, 8, kCipUsint, EncodeCipUsint,
+                      &dummy_attribute_usint, kGetableAllDummy);
+      InsertAttribute(ethernet_link_instance, 9, kCipUsint, EncodeCipUsint,
+                      &dummy_attribute_usint, kGetableAllDummy);
+      InsertAttribute(ethernet_link_instance,
+                      10,
+                      kCipShortString,
+                      EncodeCipShortString,
                       &g_ethernet_link[idx].interface_label,
                       IFACE_LABEL_ACCESS_MODE);
-      InsertAttribute(ethernet_link_instance, 11, kCipAny,
-                      &g_ethernet_link[idx].interface_caps, kGetableSingleAndAll);
+      InsertAttribute(ethernet_link_instance,
+                      11,
+                      kCipAny,
+                      EncodeCipEthernetLinkInterfaceCaps,
+                      &g_ethernet_link[idx].interface_caps,
+                      kGetableSingleAndAll);
     }
   } else {
     return kEipStatusError;
@@ -322,189 +373,79 @@ void CipEthernetLinkSetMac(EipUint8 *p_physical_address) {
   return;
 }
 
-static int EncodeInterfaceCounters(CipUdint instance_id, CipOctet **message) {
-  int encoded_len = 0;
-  for (size_t i = 0; i < 11; i++) {
+static void EncodeCipEthernetLinkInterfaceCounters(const void *const data,
+                                                   ENIPMessage *const outgoing_message)
+{
 #if defined(OPENER_ETHLINK_CNTRS_ENABLE) && 0 != OPENER_ETHLINK_CNTRS_ENABLE
+  for (size_t i = 0; i < 11; i++) {
     /* Encode real values using the access through the array of the
      *  interface_cntrs union. */
-    encoded_len += EncodeData(
-                    kCipUdint,
-                    g_ethernet_link[instance_id-1].interface_cntrs.cntr32 +i,
-                    message);
+    EncodeData(kCipUdint,
+               g_ethernet_link[instance_id - 1].interface_cntrs.cntr32 + i,
+               message_router_response);
+  }
 #else
-    /* Encode the default counter value of 0 */
-    encoded_len += EncodeData(kCipUdint, &dummy_attribute_udint, message);
+  /* Encode the default counter value of 0 */
+  FillNextNMessageOctetsWithValueAndMoveToNextPosition(0,
+                                                       11 * sizeof(CipUdint),
+                                                       outgoing_message);
 #endif
-  }
-  return encoded_len;
 }
 
-static int EncodeMediaCounters(CipUdint instance_id, CipOctet **message) {
-  int encoded_len = 0;
-  for (size_t i = 0; i < 12; i++) {
+static void EncodeCipEthernetLinkMediaCounters(const void *const data,
+                                               ENIPMessage *const outgoing_message)
+{
 #if defined(OPENER_ETHLINK_CNTRS_ENABLE) && 0 != OPENER_ETHLINK_CNTRS_ENABLE
+  for (size_t i = 0; i < 12; i++) {
     /* Encode real values using the access through the array of the
      *  media_cntrs union. */
-    encoded_len += EncodeData(
-                    kCipUdint,
-                    g_ethernet_link[instance_id-1].media_cntrs.cntr32 +i,
-                    message);
+    EncodeData(kCipUdint,
+               g_ethernet_link[instance_id - 1].media_cntrs.cntr32 + i,
+               message_router_response);
+  }
 #else
-    /* Encode the default counter value of 0 */
-    encoded_len += EncodeData(kCipUdint, &dummy_attribute_udint, message);
+  /* Encode the default counter value of 0 */
+  FillNextNMessageOctetsWithValueAndMoveToNextPosition(0,
+                                                       12 * sizeof(CipUdint),
+                                                       outgoing_message);
 #endif
-  }
-  return encoded_len;
 }
 
-static int EncodeInterfaceControl(CipUdint instance_id, CipOctet **message) {
-#if defined(OPENER_ETHLINK_IFACE_CTRL_ENABLE) && 0 != OPENER_ETHLINK_IFACE_CTRL_ENABLE
-  CipEthernetLinkInterfaceControl *interface_control =
-  	&g_ethernet_link[instance_id-1].interface_control;
+static void EncodeCipEthernetLinkInterfaceControl(const void *const data,
+                                                  ENIPMessage *const outgoing_message)
+{
+#if defined(OPENER_ETHLINK_IFACE_CTRL_ENABLE) && \
+  0 != OPENER_ETHLINK_IFACE_CTRL_ENABLE
+  const CipEthernetLinkInterfaceControl *const interface_control =
+    data;
 #else
   CipEthernetLinkInterfaceControl *interface_control = &s_interface_control;
 #endif
-  int encoded_len = 0;
-  encoded_len += EncodeData(kCipWord, &interface_control->control_bits,
-                            message);
-  encoded_len += EncodeData(kCipUint,
-                            &interface_control->forced_interface_speed,
-                            message);
-  return encoded_len;
+  EncodeCipWord(&interface_control->control_bits, outgoing_message);
+  EncodeCipUint(&interface_control->forced_interface_speed, outgoing_message);
 }
 
-#define NELEMENTS(x)  ((sizeof(x)/sizeof(x[0])))
-static int EncodeInterfaceCapability(CipUdint instance_id, CipOctet **message)
+#define NELEMENTS(x)  ( (sizeof(x) / sizeof(x[0]) ) )
+static void EncodeCipEthernetLinkInterfaceCaps(const void *const data,
+                                               ENIPMessage *const outgoing_message)
 {
-  int encoded_len = 0;
-  encoded_len += EncodeData(
-                    kCipDword,
-                    &g_ethernet_link[instance_id - 1].interface_caps.capability_bits,
-                    message);
-  uint16_t selected = g_ethernet_link[instance_id - 1].interface_caps.speed_duplex_selector;
+  const CipEthernetLinkMetaInterfaceCapability *const interface_caps = data;
+  EncodeCipDword(&interface_caps->capability_bits, outgoing_message);
+  uint16_t selected = interface_caps->speed_duplex_selector;
   CipUsint count;
   for (count = 0; selected; count++) { /* count # of bits set */
-	  selected &= selected - 1U;  /* clear the least significant bit set */
+    selected &= selected - 1U;        /* clear the least significant bit set */
   }
-  encoded_len += EncodeData(kCipUsint, &count, message);
+  EncodeCipUsint(&count, outgoing_message);
 
   for (size_t i = 0; i < NELEMENTS(speed_duplex_table); i++) {
-    if (g_ethernet_link[instance_id - 1].interface_caps.speed_duplex_selector &
-        (1U << i)) {
-      encoded_len += EncodeData(
-                        kCipUint,
-                        &speed_duplex_table[i].interface_speed,
-                        message);
-      encoded_len += EncodeData(
-                        kCipUsint,
-                        &speed_duplex_table[i].interface_duplex_mode,
-                        message);
+    if (interface_caps->speed_duplex_selector &
+        (1U << i) ) {
+      EncodeCipUint(&speed_duplex_table[i].interface_speed, outgoing_message);
+      EncodeCipUsint(&speed_duplex_table[i].interface_duplex_mode,
+                     outgoing_message);
     }
   }
-  return encoded_len;
-}
-
-EipStatus GetAttributeSingleEthernetLink(
-  CipInstance *RESTRICT const instance,
-  CipMessageRouterRequest *const message_router_request,
-  CipMessageRouterResponse *const message_router_response,
-  const struct sockaddr *originator_address,
-  const int encapsulation_session) {
-
-  CipAttributeStruct *attribute = GetCipAttribute(
-    instance, message_router_request->request_path.attribute_number);
-  EipByte *message = message_router_response->data;
-
-  message_router_response->data_length = 0;
-  message_router_response->reply_service = (0x80
-                                            | message_router_request->service);
-  message_router_response->general_status = kCipErrorAttributeNotSupported;
-  message_router_response->size_of_additional_status = 0;
-
-  EipUint16 attribute_number = message_router_request->request_path
-                               .attribute_number;
-
-  if ( (NULL != attribute) && (NULL != attribute->data) ) {
-    /* Mask for filtering get-ability */
-    uint8_t get_bit_mask = 0;
-    if (kGetAttributeAll == message_router_request->service) {
-      get_bit_mask = (instance->cip_class->get_all_bit_mask[CalculateIndex(
-                                                              attribute_number)]);
-      message_router_response->general_status = kCipErrorSuccess;
-    } else {
-      get_bit_mask = (instance->cip_class->get_single_bit_mask[CalculateIndex(
-                                                                 attribute_number)
-                      ]);
-    }
-    if ( 0 != ( get_bit_mask & ( 1 << (attribute_number % 8) ) ) ) {
-
-      /* create a reply message containing the data*/
-      bool use_common_handler;
-      switch (attribute_number) {
-      case 4: /* fall through */
-      case 5: /* fall through */
-      case 6: /* fall through */
-      case 11:
-        use_common_handler = false;
-        OPENER_TRACE_INFO("getAttribute %d\n", attribute_number);
-        break;
-      default:
-        use_common_handler = true;
-        break;
-      }
-
-      /* Call the PreGetCallback if enabled for this attribute and the common handler is not used. */
-      if (!use_common_handler) {
-        if (attribute->attribute_flags & kPreGetFunc && NULL != instance->cip_class->PreGetCallback) {
-          instance->cip_class->PreGetCallback(instance, attribute, message_router_request->service);
-        }
-      }
-
-      switch (attribute_number) {
-        case 4:
-          message_router_response->data_length = EncodeInterfaceCounters(
-            instance->instance_number,
-            &message);
-          message_router_response->general_status = kCipErrorSuccess;
-          break;
-        case 5:
-          message_router_response->data_length = EncodeMediaCounters(
-            instance->instance_number,
-            &message);
-          message_router_response->general_status = kCipErrorSuccess;
-          break;
-        case 6:
-          message_router_response->data_length = EncodeInterfaceControl(
-            instance->instance_number,
-            &message);
-          message_router_response->general_status = kCipErrorSuccess;
-          break;
-        case 11:
-          message_router_response->data_length = EncodeInterfaceCapability(
-            instance->instance_number,
-            &message);
-          message_router_response->general_status = kCipErrorSuccess;
-          break;
-
-        default:
-          GetAttributeSingle(instance, message_router_request,
-                             message_router_response,
-                             originator_address,
-                             encapsulation_session);
-      }
-
-      /* Call the PostGetCallback if enabled for this attribute and the common handler is not used. */
-      if (!use_common_handler) {
-        if (attribute->attribute_flags & kPostGetFunc && NULL != instance->cip_class->PostGetCallback) {
-          instance->cip_class->PostGetCallback(instance, attribute, message_router_request->service);
-        }
-      }
-
-    }
-  }
-
-  return kEipStatusOkSend;
 }
 
 #if defined(OPENER_ETHLINK_CNTRS_ENABLE) && 0 != OPENER_ETHLINK_CNTRS_ENABLE
@@ -536,10 +477,10 @@ EipStatus GetAndClearEthernetLink(
       case 4: /* fall through */
       case 5:
         GetAttributeSingleEthernetLink(
-                           instance, message_router_request,
-                           message_router_response,
-                           originator_address,
-                           encapsulation_session);
+          instance, message_router_request,
+          message_router_response,
+          originator_address,
+          encapsulation_session);
         break;
       default:
         message_router_response->general_status =
@@ -559,19 +500,19 @@ EipStatus GetAndClearEthernetLink(
 }
 #endif  /* ... && 0 != OPENER_ETHLINK_CNTRS_ENABLE */
 
-#if defined(OPENER_ETHLINK_IFACE_CTRL_ENABLE) && 0 != OPENER_ETHLINK_IFACE_CTRL_ENABLE
-static bool IsIfaceControlAllowed
-(
-  CipUdint instance_id,
-  CipEthernetLinkInterfaceControl const *iface_cntrl)
+#if defined(OPENER_ETHLINK_IFACE_CTRL_ENABLE) && \
+  0 != OPENER_ETHLINK_IFACE_CTRL_ENABLE
+static bool IsIfaceControlAllowed(CipUdint instance_id,
+                                  CipEthernetLinkInterfaceControl const *iface_cntrl)
 {
   const CipUsint duplex_mode =
-       (iface_cntrl->control_bits & kEthLinkIfCntrlForceDuplexFD) ? 1 : 0;
+    (iface_cntrl->control_bits & kEthLinkIfCntrlForcedDuplex) ? 1 : 0;
   for (size_t i = 0; i < NELEMENTS(speed_duplex_table); i++) {
     if (g_ethernet_link[instance_id - 1].interface_caps.speed_duplex_selector &
-        (1U << i)) {
+        (1U << i) ) {
       if (duplex_mode == speed_duplex_table[i].interface_duplex_mode &&
-          iface_cntrl->forced_interface_speed == speed_duplex_table[i].interface_speed) {
+          iface_cntrl->forced_interface_speed ==
+          speed_duplex_table[i].interface_speed) {
         return true;
       }
     }
@@ -590,15 +531,7 @@ EipStatus SetAttributeSingleEthernetLink(
   EipUint16 attribute_number = message_router_request->request_path
                                .attribute_number;
 
-
-  /* For attributes that are only kGetableAll we also need to return 
-   *  kCipErrorAttributeNotSupported. Therefore we return that error code if
-   *  these attributes don't have the kGetableSingle property set. */
-  uint8_t get_bit_mask =
-    instance->cip_class->get_single_bit_mask[CalculateIndex(attribute_number)];
-  
-  if (NULL != attribute &&
-      0 != ( get_bit_mask & ( 1 << (attribute_number % 8) ) )) {
+  if (NULL != attribute) {
     uint8_t set_bit_mask = (instance->cip_class->set_bit_mask[CalculateIndex(
                                                                 attribute_number)
                             ]);
@@ -606,9 +539,9 @@ EipStatus SetAttributeSingleEthernetLink(
 
       if (attribute->attribute_flags & kPreSetFunc
           && instance->cip_class->PreSetCallback) {
-          instance->cip_class->PreSetCallback(instance,
-                                              attribute,
-                                              message_router_request->service);
+        instance->cip_class->PreSetCallback(instance,
+                                            attribute,
+                                            message_router_request->service);
       }
 
       OPENER_TRACE_INFO(" setAttribute %d\n", attribute_number);
@@ -616,25 +549,30 @@ EipStatus SetAttributeSingleEthernetLink(
         case 6: {
           CipEthernetLinkInterfaceControl if_cntrl;
           (void)DecodeData(kCipWord, &if_cntrl.control_bits,
-                           &(message_router_request->data));
+                           &(message_router_request->data) );
           (void)DecodeData(kCipUint, &if_cntrl.forced_interface_speed,
-                           &(message_router_request->data));
+                           &(message_router_request->data) );
 
           if (if_cntrl.control_bits > kEthLinkIfCntrlMaxValid) {
             message_router_response->general_status =
               kCipErrorInvalidAttributeValue;
 
           } else {
-            if ((0 != (if_cntrl.control_bits & kEthLinkIfCntrlAutonegotiate)) &&
-                ((0 != (if_cntrl.control_bits & kEthLinkIfCntrlForceDuplexFD)) ||
-                 (0 != if_cntrl.forced_interface_speed))) {
+            if ( (0 !=
+                  (if_cntrl.control_bits & kEthLinkIfCntrlAutonegotiate) ) &&
+                 ( (0 !=
+                    (if_cntrl.control_bits & kEthLinkIfCntrlForcedDuplex) ) ||
+                   (0 != if_cntrl.forced_interface_speed) ) ) {
               message_router_response->general_status =
                 kCipErrorObjectStateConflict;
             } else {
-              if (0 == (if_cntrl.control_bits & kEthLinkIfCntrlAutonegotiate)) {
+              if (0 ==
+                  (if_cntrl.control_bits & kEthLinkIfCntrlAutonegotiate) ) {
                 /* Need to check if a supported mode is forced. */
-                if (!IsIfaceControlAllowed(instance->instance_number, &if_cntrl)) {
-                  message_router_response->general_status = kCipErrorInvalidAttributeValue;
+                if (!IsIfaceControlAllowed(instance->instance_number,
+                                           &if_cntrl) ) {
+                  message_router_response->general_status =
+                    kCipErrorInvalidAttributeValue;
                   break;
                 }
               }
@@ -657,7 +595,7 @@ EipStatus SetAttributeSingleEthernetLink(
           && NULL != instance->cip_class->PostSetCallback) {
         CipUsint service = message_router_request->service;
         if (kCipErrorSuccess != message_router_response->general_status) {
-            service |= 0x80;  /* Flag no update, TODO: remove this workaround */
+          service |= 0x80;    /* Flag no update, TODO: remove this workaround */
         }
         instance->cip_class->PostSetCallback(instance, attribute, service);
       }

+ 49 - 15
source/src/cip/cipidentity.c

@@ -72,14 +72,14 @@ void SetDeviceStatus(const CipWord status) {
   g_identity.ext_status = status & kExtStatusMask;
 }
 
-static inline void MergeStatusAndExtStatus(void)
-{
+static inline void MergeStatusAndExtStatus(void) {
   CipWord status_flags = g_identity.status & (~kExtStatusMask);
   CipWord ext_status = g_identity.ext_status & kExtStatusMask;
 
   /* Any major fault will override the current extended status with kMajorFault.
-    See comment on Major Fault at Vol. 1, Table 5A-2.4. */
-  if(0 != (status_flags & (kMajorRecoverableFault | kMajorUnrecoverableFault))) {
+     See comment on Major Fault at Vol. 1, Table 5A-2.4. */
+  if(0 !=
+     (status_flags & (kMajorRecoverableFault | kMajorUnrecoverableFault) ) ) {
     ext_status = kMajorFault;
   }
   g_identity.status = status_flags | ext_status;
@@ -107,7 +107,7 @@ void CipIdentitySetStatusFlags(const CipWord status_flags) {
  *  value.
  */
 void CipIdentityClearStatusFlags(const CipWord status_flags) {
-  g_identity.status &= ~(status_flags & (~kExtStatusMask));
+  g_identity.status &= ~(status_flags & (~kExtStatusMask) );
   MergeStatusAndExtStatus();
 }
 
@@ -171,7 +171,7 @@ static EipStatus Reset(CipInstance *instance,
         break;
 
       /* case 2: Not supported Reset type 2 ->
-        Return to factory defaults except communications parameters & power cycle*/
+         Return to factory defaults except communications parameters & power cycle*/
 
       default:
         message_router_response->general_status = kCipErrorInvalidParameter;
@@ -179,7 +179,7 @@ static EipStatus Reset(CipInstance *instance,
     }
   }
 
-  message_router_response->data_length = 0;
+  InitializeENIPMessage(&message_router_response->message);
   return eip_status;
 }
 
@@ -189,23 +189,40 @@ void InitializeCipIdentity(CipClass *class) {
   CipClass *meta_class = class->class_instance.cip_class;
 
   InsertAttribute( (CipInstance *) class, 1, kCipUint,
+                   EncodeCipUint,
                    (void *) &class->revision,
                    kGetableSingleAndAll );                 /* revision */
   InsertAttribute( (CipInstance *) class, 2, kCipUint,
+                   EncodeCipUint,
                    (void *) &class->number_of_instances, kGetableSingleAndAll ); /*  largest instance number */
   InsertAttribute( (CipInstance *) class, 3, kCipUint,
-                   (void *) &class->number_of_instances, kGetAttributeSingle ); /* number of instances currently existing*/
-  InsertAttribute( (CipInstance *) class, 4, kCipUint, (void *) &kCipUintZero,
+                   EncodeCipUint,
+                   (void *) &class->number_of_instances, kGetableSingle ); /* number of instances currently existing*/
+  InsertAttribute( (CipInstance *) class, 4, kCipUint, EncodeCipUint,
+                   (void *) &kCipUintZero,
                    kNotSetOrGetable ); /* optional attribute list - default = 0 */
-  InsertAttribute( (CipInstance *) class, 5, kCipUint, (void *) &kCipUintZero,
+  InsertAttribute( (CipInstance *) class, 5, kCipUint, EncodeCipUint,
+                   (void *) &kCipUintZero,
                    kNotSetOrGetable ); /* optional service list - default = 0 */
-  InsertAttribute( (CipInstance *) class, 6, kCipUint,
+  InsertAttribute( (CipInstance *) class, 6, kCipUint, EncodeCipUint,
                    (void *) &meta_class->highest_attribute_number,
                    kGetableSingleAndAll );                 /* max class attribute number*/
-  InsertAttribute( (CipInstance *) class, 7, kCipUint,
+  InsertAttribute( (CipInstance *) class, 7, kCipUint, EncodeCipUint,
                    (void *) &class->highest_attribute_number,
                    kGetableSingleAndAll );                 /* max instance attribute number*/
 
+  InsertService(meta_class, kGetAttributeAll, &GetAttributeAll,
+                "GetAttributeAll");                         /* bind instance services to the metaclass*/
+  InsertService(meta_class, kGetAttributeSingle, &GetAttributeSingle,
+                "GetAttributeSingle");
+
+}
+
+void EncodeRevision(const void *const data,
+                    ENIPMessage *const outgoing_message) {
+  CipRevision *revision = (CipRevision *) data;
+  AddSintToMessage(revision->major_revision, outgoing_message);
+  AddSintToMessage(revision->minor_revision, outgoing_message);
 }
 
 EipStatus CipIdentityInit() {
@@ -230,29 +247,46 @@ EipStatus CipIdentityInit() {
   InsertAttribute(instance,
                   1,
                   kCipUint,
+                  EncodeCipUint,
                   &g_identity.vendor_id,
                   kGetableSingleAndAll);
   InsertAttribute(instance,
                   2,
                   kCipUint,
+                  EncodeCipUint,
                   &g_identity.device_type,
                   kGetableSingleAndAll);
   InsertAttribute(instance,
                   3,
                   kCipUint,
+                  EncodeCipUint,
                   &g_identity.product_code,
                   kGetableSingleAndAll);
-  InsertAttribute(instance, 4, kCipUsintUsint, &g_identity.revision,
+  InsertAttribute(instance,
+                  4,
+                  kCipUsintUsint,
+                  EncodeRevision,
+                  &g_identity.revision,
                   kGetableSingleAndAll);
   InsertAttribute(instance,
                   5,
                   kCipWord,
+                  EncodeCipWord,
                   &g_identity.status,
                   kGetableSingleAndAll);
-  InsertAttribute(instance, 6, kCipUdint, &g_identity.serial_number,
+  InsertAttribute(instance,
+                  6,
+                  kCipUdint,
+                  EncodeCipUdint,
+                  &g_identity.serial_number,
                   kGetableSingleAndAll);
-  InsertAttribute(instance, 7, kCipShortString, &g_identity.product_name,
+  InsertAttribute(instance,
+                  7,
+                  kCipShortString,
+                  EncodeCipShortString,
+                  &g_identity.product_name,
                   kGetableSingleAndAll);
+
   InsertService(class, kGetAttributeSingle, &GetAttributeSingle,
                 "GetAttributeSingle");
   InsertService(class, kGetAttributeAll, &GetAttributeAll, "GetAttributeAll");

+ 14 - 12
source/src/cip/cipioconnection.c

@@ -92,7 +92,8 @@ EipUint16 ProcessProductionInhibitTime(CipConnectionObject *io_connection_object
                 io_connection_object)
               / 1000) ) {
         /* see section C-1.4.3.3 */
-        return kConnectionManagerExtendedStatusCodeRpiNotSupported; /**< RPI not supported. Extended Error code deprecated */
+        return
+          kConnectionManagerExtendedStatusCodeProductionInhibitTimerGreaterThanRpi;
       }
     }
   }
@@ -454,7 +455,7 @@ EipStatus OpenProducingMulticastConnection(
   /* Here we look for existing multi-cast IO connections only. */
   CipConnectionObject *existing_connection_object =
     GetExistingProducerIoConnection(true,
-      connection_object->produced_path.instance_id);
+                                    connection_object->produced_path.instance_id);
 
   int j = 0; /* allocate an unused sockaddr struct to use */
   if (g_common_packet_format_data_item.address_info_item[0].type_id == 0) { /* it is not used yet */
@@ -829,11 +830,10 @@ EipStatus SendConnectedData(CipConnectionObject *connection_object) {
 
   ENIPMessage outgoing_message;
   InitializeENIPMessage(&outgoing_message);
-  EipUint16 reply_length = AssembleIOMessage(common_packet_format_data,
-                                             &outgoing_message);
-  (void) reply_length;  /* Silence unused variable compiler warning */
+  AssembleIOMessage(common_packet_format_data,
+                    &outgoing_message);
 
-  outgoing_message.current_message_position -= 2;
+  MoveMessageNOctets(-2, &outgoing_message);
   common_packet_format_data->data_item.length = producing_instance_attributes
                                                 ->length;
 #ifdef OPENER_PRODUCED_DATA_HAS_RUN_IDLE_HEADER
@@ -845,30 +845,32 @@ EipStatus SendConnectedData(CipConnectionObject *connection_object) {
   {
     common_packet_format_data->data_item.length += 2;
     AddIntToMessage(common_packet_format_data->data_item.length,
-                    &outgoing_message.current_message_position);
+                    &outgoing_message);
     AddIntToMessage(connection_object->sequence_count_producing,
-                    &outgoing_message.current_message_position);
+                    &outgoing_message);
   } else {
     AddIntToMessage(common_packet_format_data->data_item.length,
-                    &outgoing_message.current_message_position);
+                    &outgoing_message);
   }
 
 #ifdef OPENER_PRODUCED_DATA_HAS_RUN_IDLE_HEADER
   AddDintToMessage( g_run_idle_state,
-                    &(outgoing_message.current_message_position) );
+                    &outgoing_message );
 #endif /* OPENER_PRODUCED_DATA_HAS_RUN_IDLE_HEADER */
 
   memcpy(outgoing_message.current_message_position,
          producing_instance_attributes->data,
          producing_instance_attributes->length);
 
+  outgoing_message.current_message_position +=
+    producing_instance_attributes->length;
   outgoing_message.used_message_length +=
-    common_packet_format_data->data_item.length;
+    producing_instance_attributes->length;
 
   return SendUdpData(
     &connection_object->remote_address,
     connection_object->socket[kUdpCommuncationDirectionProducing],
-    outgoing_message.message_buffer, outgoing_message.used_message_length);
+    &outgoing_message);
 }
 
 EipStatus HandleReceivedIoConnectionData(

+ 32 - 32
source/src/cip/cipmessagerouter.c

@@ -5,13 +5,14 @@
  ******************************************************************************/
 #include "opener_api.h"
 #include "cipcommon.h"
-#include "cipmessagerouter.h"
 #include "endianconv.h"
 #include "ciperror.h"
 #include "trace.h"
+#include "enipmessage.h"
+
+#include "cipmessagerouter.h"
 
 CipMessageRouterRequest g_message_router_request;
-CipMessageRouterResponse g_message_router_response;
 
 /** @brief A class registry list node
  *
@@ -53,32 +54,37 @@ void InitializeCipMessageRouterClass(CipClass *cip_class) {
 
   CipClass *meta_class = cip_class->class_instance.cip_class;
 
-  InsertAttribute( (CipInstance *) cip_class, 1, kCipUint,
+  InsertAttribute( (CipInstance *) cip_class, 1, kCipUint, EncodeCipUint,
                    (void *) &cip_class->revision, kGetableSingleAndAll );   /* revision */
-  InsertAttribute( (CipInstance *) cip_class, 2, kCipUint,
+  InsertAttribute( (CipInstance *) cip_class, 2, kCipUint, EncodeCipUint,
                    (void *) &cip_class->number_of_instances,
                    kGetableSingle );                                       /*  largest instance number */
-  InsertAttribute( (CipInstance *) cip_class, 3, kCipUint,
+  InsertAttribute( (CipInstance *) cip_class, 3, kCipUint, EncodeCipUint,
                    (void *) &cip_class->number_of_instances,
                    kGetableSingle );                                                           /* number of instances currently existing*/
-  InsertAttribute( (CipInstance *) cip_class, 4, kCipUint,
+  InsertAttribute( (CipInstance *) cip_class, 4, kCipUint, EncodeCipUint,
                    (void *) &kCipUintZero,
                    kGetableAll );   /* optional attribute list - default = 0 */
-  InsertAttribute( (CipInstance *) cip_class, 5, kCipUint,
+  InsertAttribute( (CipInstance *) cip_class, 5, kCipUint, EncodeCipUint,
                    (void *) &kCipUintZero,
                    kGetableAll ); /* optional service list - default = 0 */
-  InsertAttribute( (CipInstance *) cip_class, 6, kCipUint,
+  InsertAttribute( (CipInstance *) cip_class, 6, kCipUint, EncodeCipUint,
                    (void *) &meta_class->highest_attribute_number,
                    kGetableSingleAndAll );                       /* max class attribute number*/
-  InsertAttribute( (CipInstance *) cip_class, 7, kCipUint,
+  InsertAttribute( (CipInstance *) cip_class, 7, kCipUint, EncodeCipUint,
                    (void *) &cip_class->highest_attribute_number,
                    kGetableSingleAndAll );                       /* max instance attribute number*/
+
+  InsertService(meta_class, kGetAttributeAll, &GetAttributeAll,
+                "GetAttributeAll");                         /* bind instance services to the metaclass*/
+  InsertService(meta_class, kGetAttributeSingle, &GetAttributeSingle,
+                "GetAttributeSingle");
 }
 
 EipStatus CipMessageRouterInit() {
 
   CipClass *message_router = CreateCipClass(kCipMessageRouterClassCode, /* class code */
-                                            0, /* # of class attributes */
+                                            7, /* # of class attributes */
                                             7, /* # highest class attribute number */
                                             2, /* # of class services */
                                             0, /* # of instance attributes */
@@ -95,9 +101,6 @@ EipStatus CipMessageRouterInit() {
                 "GetAttributeSingle");
 
   /* reserved for future use -> set to zero */
-  g_message_router_response.reserved = 0;
-  g_message_router_response.data = g_message_data_reply_buffer; /* set reply buffer, using a fixed buffer (OPENER_MESSAGE_DATA_REPLY_BUFFER bytes) */
-
   return kEipStatusOk;
 }
 
@@ -173,26 +176,24 @@ EipStatus RegisterCipClass(CipClass *cip_class) {
 
 EipStatus NotifyMessageRouter(EipUint8 *data,
                               int data_length,
+                              CipMessageRouterResponse *message_router_response,
                               const struct sockaddr *const originator_address,
                               const int encapsulation_session) {
   EipStatus eip_status = kEipStatusOkSend;
   CipError status = kCipErrorSuccess;
 
-  g_message_router_response.data = g_message_data_reply_buffer; /* set reply buffer, using a fixed buffer (OPENER_MESSAGE_DATA_REPLY_BUFFER bytes) */
-
   OPENER_TRACE_INFO("NotifyMessageRouter: routing unconnected message\n");
   if ( kCipErrorSuccess
        != ( status = CreateMessageRouterRequestStructure(
               data, data_length, &g_message_router_request) ) ) { /* error from create MR structure*/
     OPENER_TRACE_ERR(
       "NotifyMessageRouter: error from createMRRequeststructure\n");
-    g_message_router_response.general_status = status;
-    g_message_router_response.size_of_additional_status = 0;
-    g_message_router_response.reserved = 0;
-    g_message_router_response.data_length = 0;
-    g_message_router_response.reply_service = (0x80
-                                               | g_message_router_request.
-                                               service);
+    message_router_response->general_status = status;
+    message_router_response->size_of_additional_status = 0;
+    message_router_response->reserved = 0;
+    message_router_response->reply_service = (0x80
+                                              | g_message_router_request.
+                                              service);
   } else {
     /* forward request to appropriate Object if it is registered*/
     CipMessageRouterObject *registered_object = GetRegisteredObject(
@@ -201,25 +202,24 @@ EipStatus NotifyMessageRouter(EipUint8 *data,
       OPENER_TRACE_ERR(
         "NotifyMessageRouter: sending CIP_ERROR_OBJECT_DOES_NOT_EXIST reply, class id 0x%x is not registered\n",
         (unsigned ) g_message_router_request.request_path.class_id);
-      g_message_router_response.general_status =
+      message_router_response->general_status =
         kCipErrorPathDestinationUnknown;   /*according to the test tool this should be the correct error flag instead of CIP_ERROR_OBJECT_DOES_NOT_EXIST;*/
-      g_message_router_response.size_of_additional_status = 0;
-      g_message_router_response.reserved = 0;
-      g_message_router_response.data_length = 0;
-      g_message_router_response.reply_service = (0x80
-                                                 | g_message_router_request.
-                                                 service);
+      message_router_response->size_of_additional_status = 0;
+      message_router_response->reserved = 0;
+      message_router_response->reply_service = (0x80
+                                                | g_message_router_request.
+                                                service);
     } else {
       /* call notify function from Object with ClassID (gMRRequest.RequestPath.ClassID)
          object will or will not make an reply into gMRResponse*/
-      g_message_router_response.reserved = 0;
-      OPENER_ASSERT(NULL != registered_object->cip_class);
+      message_router_response->reserved = 0;
+      OPENER_ASSERT(NULL != registered_object->cip_class)
       OPENER_TRACE_INFO(
         "NotifyMessageRouter: calling notify function of class '%s'\n",
         registered_object->cip_class->class_name);
       eip_status = NotifyClass(registered_object->cip_class,
                                &g_message_router_request,
-                               &g_message_router_response,
+                               message_router_response,
                                originator_address,
                                encapsulation_session);
 

+ 1 - 7
source/src/cip/cipmessagerouter.h

@@ -12,13 +12,6 @@
 /** @brief Message Router class code */
 static const CipUint kCipMessageRouterClassCode = 0x02U;
 
-/** @brief Structure for storing the Response generated by an explict message.
- *
- *  This buffer will be used for storing the result. The response message will be generated
- *  by AssembleLinearMessage().
- */
-extern CipMessageRouterResponse g_message_router_response;
-
 /* public functions */
 
 /** @brief Initialize the data structures of the message router
@@ -43,6 +36,7 @@ void DeleteAllClasses(void);
  */
 EipStatus NotifyMessageRouter(EipUint8 *data,
                               int data_length,
+                              CipMessageRouterResponse *message_router_response,
                               const struct sockaddr *const originator_address,
                               const int encapsulation_session);
 

+ 20 - 37
source/src/cip/cipqos.c

@@ -55,18 +55,6 @@ static CipQosDscpValues s_active_dscp = {
 };
 
 /************** Functions ****************************************/
-EipStatus GetAttributeSingleQoS(
-  CipInstance *const RESTRICT instance,
-  CipMessageRouterRequest *RESTRICT const message_router_request,
-  CipMessageRouterResponse *RESTRICT const message_router_response,
-  const struct sockaddr *originator_address,
-  const int encapsulation_session) {
-
-  return GetAttributeSingle(instance, message_router_request,
-                            message_router_response, originator_address,
-                            encapsulation_session);
-}
-
 EipStatus SetAttributeSingleQoS(
   CipInstance *instance,
   CipMessageRouterRequest *message_router_request,
@@ -93,20 +81,20 @@ EipStatus SetAttributeSingleQoS(
 
       if(NULL != attribute->data) {
         /* Call the PreSetCallback if enabled. */
-        if (attribute->attribute_flags & kPreSetFunc
-            && NULL != instance->cip_class->PreSetCallback) {
+        if ( (attribute->attribute_flags & kPreSetFunc)
+             && NULL != instance->cip_class->PreSetCallback ) {
           instance->cip_class->PreSetCallback(instance, attribute,
-                                            message_router_request->service);
+                                              message_router_request->service);
         }
 
         CipUsint *data = (CipUsint *) attribute->data;
         *(data) = attribute_value_received;
 
         /* Call the PostSetCallback if enabled. */
-        if (attribute->attribute_flags & (kPostSetFunc | kNvDataFunc)
-            && NULL != instance->cip_class->PostSetCallback) {
+        if ( (attribute->attribute_flags & (kPostSetFunc | kNvDataFunc) )
+             && NULL != instance->cip_class->PostSetCallback ) {
           instance->cip_class->PostSetCallback(instance, attribute,
-                                            message_router_request->service);
+                                               message_router_request->service);
         }
 
         message_router_response->general_status = kCipErrorSuccess;
@@ -123,7 +111,7 @@ EipStatus SetAttributeSingleQoS(
   }
 
   message_router_response->size_of_additional_status = 0;
-  message_router_response->data_length = 0;
+  InitializeENIPMessage(&message_router_response->message);
   message_router_response->reply_service = (0x80
                                             | message_router_request->service);
 
@@ -154,34 +142,21 @@ CipUsint CipQosGetDscpPriority(ConnectionObjectPriority priority) {
   return priority_value;
 }
 
-/** @brief Class level attribute initializer for QoS class
- *
- * This function is provided as class level attribute initializer to
- *  @ref CreateCipClass. It replaces the default initialization of
- *  @ref CreateCipClass.
- * Because we do NOT initialize anything here all the class attributes
- *  which are optional for the QoS class are NOT created!
- *  This is intended.
- */
-void InitializeCipQos(CipClass *class) {
-  /* Function is empty by intend. */
-}
-
 EipStatus CipQoSInit() {
 
   CipClass *qos_class = NULL;
 
   if( ( qos_class = CreateCipClass(kCipQoSClassCode,
-                                   0, /* # class attributes */
+                                   7, /* # class attributes */
                                    7, /* # highest class attribute number */
-                                   0, /* # class services */
+                                   2, /* # class services */
                                    8, /* # instance attributes */
                                    8, /* # highest instance attribute number */
                                    2, /* # instance services */
                                    1, /* # instances */
                                    "Quality of Service",
                                    1, /* # class revision */
-                                   &InitializeCipQos /* # function pointer for initialization */
+                                   NULL /* # function pointer for initialization */
                                    ) ) == 0 ) {
 
     return kEipStatusError;
@@ -192,46 +167,54 @@ EipStatus CipQoSInit() {
   InsertAttribute(instance,
                   1,
                   kCipUsint,
+                  EncodeCipUsint,
                   (void *) &g_qos.q_frames_enable,
                   kNotSetOrGetable);
   InsertAttribute(instance,
                   2,
                   kCipUsint,
+                  EncodeCipUsint,
                   (void *) &g_qos.dscp.event,
                   kNotSetOrGetable);
   InsertAttribute(instance,
                   3,
                   kCipUsint,
+                  EncodeCipUsint,
                   (void *) &g_qos.dscp.general,
                   kNotSetOrGetable);
   InsertAttribute(instance,
                   4,
                   kCipUsint,
+                  EncodeCipUsint,
                   (void *) &g_qos.dscp.urgent,
                   kGetableSingle | kSetable | kNvDataFunc);
   InsertAttribute(instance,
                   5,
                   kCipUsint,
+                  EncodeCipUsint,
                   (void *) &g_qos.dscp.scheduled,
                   kGetableSingle | kSetable | kNvDataFunc);
   InsertAttribute(instance,
                   6,
                   kCipUsint,
+                  EncodeCipUsint,
                   (void *) &g_qos.dscp.high,
                   kGetableSingle | kSetable | kNvDataFunc);
   InsertAttribute(instance,
                   7,
                   kCipUsint,
+                  EncodeCipUsint,
                   (void *) &g_qos.dscp.low,
                   kGetableSingle | kSetable | kNvDataFunc);
   InsertAttribute(instance,
                   8,
                   kCipUsint,
+                  EncodeCipUsint,
                   (void *) &g_qos.dscp.explicit,
                   kGetableSingle | kSetable | kNvDataFunc);
 
-  InsertService(qos_class, kGetAttributeSingle, &GetAttributeSingleQoS,
-                "GetAttributeSingleQoS");
+  InsertService(qos_class, kGetAttributeSingle, &GetAttributeSingle,
+                "GetAttributeSingle");
   InsertService(qos_class, kSetAttributeSingle, &SetAttributeSingleQoS,
                 "SetAttributeSingleQoS");
 

+ 209 - 267
source/src/cip/ciptcpipinterface.c

@@ -29,13 +29,15 @@
 #define CFG_CAPS_ACD_CAPABLE          0x80U /**< Device supports ACD */
 
 /* OPENER_TCPIP_IFACE_CFG_SETTABLE controls if the interface configuration is fully settable.
-*   Prepare additional defines needed here:
-*   - IFACE_CFG_SET_MODE is used to initialize the set mode of the affected attributes (3, 5, 6).
-*   - CFG_CAPS is the matching initial value for .config_capability
-*/
-#if defined (OPENER_TCPIP_IFACE_CFG_SETTABLE) && 0 != OPENER_TCPIP_IFACE_CFG_SETTABLE
+ *   Prepare additional defines needed here:
+ *   - IFACE_CFG_SET_MODE is used to initialize the set mode of the affected attributes (3, 5, 6).
+ *   - CFG_CAPS is the matching initial value for .config_capability
+ */
+#if defined (OPENER_TCPIP_IFACE_CFG_SETTABLE) && \
+  0 != OPENER_TCPIP_IFACE_CFG_SETTABLE
   #define IFACE_CFG_SET_MODE  kSetable
-  #define CFG_CAPS  (CFG_CAPS_DHCP_CLIENT | CFG_CAPS_CFG_SETTABLE | CFG_CAPS_CFG_CHG_NEEDS_RESET)
+  #define CFG_CAPS  (CFG_CAPS_DHCP_CLIENT | CFG_CAPS_CFG_SETTABLE | \
+                     CFG_CAPS_CFG_CHG_NEEDS_RESET)
 #else
   #define IFACE_CFG_SET_MODE  kNotSetOrGetable
   #define CFG_CAPS  (CFG_CAPS_DHCP_CLIENT)
@@ -85,18 +87,19 @@ CipTcpIpObject g_tcpip =
     1,  /* we currently use only one multicast address */
     0   /* the multicast address will be allocated on IP address configuration */
   },
+  .select_acd = false,
   .encapsulation_inactivity_timeout = 120 /* attribute #13 encapsulation_inactivity_timeout, use a default value of 120 */
 };
 
 /************** Static Functions *********************************/
 
-#if defined (OPENER_TCPIP_IFACE_CFG_SETTABLE) && 0 != OPENER_TCPIP_IFACE_CFG_SETTABLE
+#if defined (OPENER_TCPIP_IFACE_CFG_SETTABLE) && \
+  0 != OPENER_TCPIP_IFACE_CFG_SETTABLE
 /** Check for pb being an alphanumerical character
  *
  * Is slow but avoids issues with the locale if we're NOT in the 'C' locale.
  */
-static bool isalnum_c(const EipByte byte)
-{
+static bool isalnum_c(const EipByte byte) {
   return
     ('a' <= byte && byte <= 'z') ||
     ('A' <= byte && byte <= 'Z') ||
@@ -116,13 +119,12 @@ static bool isalnum_c(const EipByte byte)
  *  The minimum length of 1 is checked but not the maximum length
  *  that has already been enforced on data reception.
  */
-static bool IsValidNameLabel(const EipByte *label)
-{
-  if (!isalnum_c(*label)) {
+static bool IsValidNameLabel(const EipByte *label) {
+  if (!isalnum_c(*label) ) {
     return false;
   }
   ++label;
-  while ('\0' != *label && (isalnum_c(*label) || '-' == *label)) {
+  while ('\0' != *label && (isalnum_c(*label) || '-' == *label) ) {
     ++label;
   }
   return ('\0' == *label && '-' != label[-1]);
@@ -141,15 +143,14 @@ static bool IsValidNameLabel(const EipByte *label)
  *    be converted to punycode (see https://www.punycoder.com/) by
  *    the user in advance.
  */
-static bool IsValidDomain(EipByte *domain)
-{
+static bool IsValidDomain(EipByte *domain) {
   bool status = true;
 
   OPENER_TRACE_INFO("Enter '%s'->", domain);
   if ('.' == *domain) { /* Forbid leading dot */
     return false;
   }
-  EipByte *dot = (EipByte *)strchr((char *)domain, '.');
+  EipByte *dot = (EipByte *)strchr( (char *)domain, '.' );
   if (dot) {
     bool rc;
 
@@ -157,7 +158,7 @@ static bool IsValidDomain(EipByte *domain)
     status &= rc = IsValidNameLabel(domain);
     OPENER_TRACE_INFO("Checked %d '%s'\n", rc, domain);
     if ('\0' != dot[1]) {
-      status &= IsValidDomain(dot +1);
+      status &= IsValidDomain(dot + 1);
     }
     else {  /* Forbid trailing dot */
       status = false;
@@ -180,15 +181,14 @@ static bool IsValidDomain(EipByte *domain)
  *  Check if it is a valid network mask pattern. The pattern 0xffffffff and
  *  0x00000000 are considered as invalid.
  */
-static bool IsValidNetmask(in_addr_t netmask)
-{
-    in_addr_t v = ntohl(netmask);
+static bool IsValidNetmask(in_addr_t netmask) {
+  in_addr_t v = ntohl(netmask);
 
-    v = ~v; /* Create the host mask */
-    ++v;    /* This must be a power of 2 then */
-    bool valid = v && !(v & (v - 1)); /* Check if it is a power of 2 */
+  v = ~v;   /* Create the host mask */
+  ++v;      /* This must be a power of 2 then */
+  bool valid = v && !(v & (v - 1) );  /* Check if it is a power of 2 */
 
-    return valid && (INADDR_BROADCAST != netmask);
+  return valid && (INADDR_BROADCAST != netmask);
 }
 
 /** Check if an IP address is in one of the network classes A, B or C
@@ -198,8 +198,7 @@ static bool IsValidNetmask(in_addr_t netmask)
  *
  *  Check if the IP address belongs to the network classes A, B or C.
  */
-static bool IsInClassAbc(in_addr_t ip_addr)
-{
+static bool IsInClassAbc(in_addr_t ip_addr) {
   in_addr_t ip = ntohl(ip_addr);
   return IN_CLASSA(ip) || IN_CLASSB(ip) || IN_CLASSC(ip);
 }
@@ -212,8 +211,7 @@ static bool IsInClassAbc(in_addr_t ip_addr)
  *  Check if the IP address belongs to the loopback network
  *  127.0.0.0 - 127.255.255.255.
  */
-static bool IsOnLoopbackNetwork(in_addr_t ip_addr)
-{
+static bool IsOnLoopbackNetwork(in_addr_t ip_addr) {
   in_addr_t ip = ntohl(ip_addr);
   return (ip & IN_CLASSA_NET) == (INADDR_LOOPBACK & IN_CLASSA_NET);
 }
@@ -228,9 +226,10 @@ static bool IsOnLoopbackNetwork(in_addr_t ip_addr)
  *  In this case it is not a valid IP address for a host.
  *  This check is endian agnostic.
  */
-static bool IsNetworkOrBroadcastIp(in_addr_t ip_addr, in_addr_t net_mask) {
-  return  ((ip_addr & net_mask) == ip_addr) ||  /* is network address */
-          ((ip_addr | ~net_mask) == ip_addr);   /* is broadcast address */
+static bool IsNetworkOrBroadcastIp(in_addr_t ip_addr,
+                                   in_addr_t net_mask) {
+  return ( (ip_addr & net_mask) == ip_addr ) ||  /* is network address */
+         ( (ip_addr | ~net_mask) == ip_addr );  /* is broadcast address */
 }
 
 /** Check the Interface configuration being valid according to EIP specification
@@ -255,44 +254,42 @@ static bool IsNetworkOrBroadcastIp(in_addr_t ip_addr, in_addr_t net_mask) {
  *   - |   -  |  +  |   -  |  - | name_server / name_server_2
  * A configured gateway must be reachable according to the network mask.
  */
-static bool IsValidNetworkConfig(const CipTcpIpInterfaceConfiguration *if_cfg)
-{
-  if (INADDR_ANY == ntohl(if_cfg->ip_address)) {  /* N0 */
+static bool IsValidNetworkConfig(const CipTcpIpInterfaceConfiguration *if_cfg) {
+  if (INADDR_ANY == ntohl(if_cfg->ip_address) ) {  /* N0 */
     return false;
   }
   if (INADDR_ANY != ntohl(if_cfg->network_mask) &&  /* MASK */
-      !IsValidNetmask(if_cfg->network_mask)) {
+      !IsValidNetmask(if_cfg->network_mask) ) {
     return false;
   }
   if (!IsInClassAbc(if_cfg->ip_address) ||        /* ABC */
       !IsInClassAbc(if_cfg->gateway) ||
       !IsInClassAbc(if_cfg->name_server) ||
-      !IsInClassAbc(if_cfg->name_server_2)) {
+      !IsInClassAbc(if_cfg->name_server_2) ) {
     return false;
   }
   if (IsOnLoopbackNetwork(if_cfg->ip_address) ||  /* NLCL */
-      IsOnLoopbackNetwork(if_cfg->gateway)) {
+      IsOnLoopbackNetwork(if_cfg->gateway) ) {
     return false;
   }
   /* Check NB */
   if (IsNetworkOrBroadcastIp(if_cfg->ip_address, if_cfg->network_mask) ||
       (INADDR_ANY != ntohl(if_cfg->gateway) &&
-       IsNetworkOrBroadcastIp(if_cfg->gateway, if_cfg->network_mask))) {
+       IsNetworkOrBroadcastIp(if_cfg->gateway, if_cfg->network_mask) ) ) {
     return false;
   }
   if (INADDR_ANY != ntohl(if_cfg->gateway) &&
-      INADDR_ANY != ntohl(if_cfg->network_mask)) {
+      INADDR_ANY != ntohl(if_cfg->network_mask) ) {
     /* gateway is configured. Check if it is reachable. */
-    if ((if_cfg->network_mask & if_cfg->ip_address) !=
-        (if_cfg->network_mask & if_cfg->gateway)) {
+    if ( (if_cfg->network_mask & if_cfg->ip_address) !=
+         (if_cfg->network_mask & if_cfg->gateway) ) {
       return false;
     }
   }
   return true;
 }
 
-static bool IsIOConnectionActive(void)
-{
+static bool IsIOConnectionActive(void) {
   DoublyLinkedListNode *node = connection_list.first;
 
   while (NULL != node) {
@@ -311,20 +308,58 @@ static bool IsIOConnectionActive(void)
 #endif /* defined (OPENER_TCPIP_IFACE_CFG_SETTABLE) && 0 != OPENER_TCPIP_IFACE_CFG_SETTABLE*/
 
 
+static CipUsint dummy_data_field = 0; /**< dummy data fiel to provide non-null data pointers for attributes without data fields */
+
 /************** Functions ****************************************/
-EipStatus GetAttributeSingleTcpIpInterface(
-  CipInstance *const RESTRICT instance,
-  CipMessageRouterRequest *const RESTRICT message_router_request,
-  CipMessageRouterResponse *const RESTRICT message_router_response,
-  const struct sockaddr *originator_address,
-  const int encapsulation_session);
 
-EipStatus GetAttributeAllTcpIpInterface(
-  CipInstance *instance,
-  CipMessageRouterRequest *message_router_request,
-  CipMessageRouterResponse *message_router_response,
-  const struct sockaddr *originator_address,
-  const int encapsulation_session);
+void EncoodeCipTcpIpInterfaceConfiguration(const void *const data,
+                                           ENIPMessage *const outgoing_message)
+{
+  CipTcpIpInterfaceConfiguration *
+    tcp_ip_network_interface_configuration =
+    (CipTcpIpInterfaceConfiguration *) data;
+  AddDintToMessage(ntohl(tcp_ip_network_interface_configuration->ip_address),
+                   outgoing_message);
+  AddDintToMessage(ntohl(tcp_ip_network_interface_configuration->network_mask),
+                   outgoing_message);
+  AddDintToMessage(ntohl(tcp_ip_network_interface_configuration->gateway),
+                   outgoing_message);
+  AddDintToMessage(ntohl(tcp_ip_network_interface_configuration->name_server),
+                   outgoing_message);
+  AddDintToMessage(ntohl(tcp_ip_network_interface_configuration->name_server_2),
+                   outgoing_message);
+  EncodeCipString(&(tcp_ip_network_interface_configuration->domain_name),
+                  outgoing_message);
+}
+
+void EncodeCipTcpIpMulticastConfiguration(const void *const data,
+                                          ENIPMessage *const outgoing_message) {
+  EncodeCipUsint(&(g_tcpip.mcast_config.alloc_control), outgoing_message);
+  EncodeCipUsint(&(g_tcpip.mcast_config.reserved_shall_be_zero),
+                 outgoing_message);
+  EncodeCipUint(&(g_tcpip.mcast_config.number_of_allocated_multicast_addresses),
+                outgoing_message);
+
+  CipUdint multicast_address = ntohl(
+    g_tcpip.mcast_config.starting_multicast_address);
+
+  EncodeCipUdint(&multicast_address, outgoing_message);
+}
+
+void EncodeSafetyNetworkNumber(const void *const data,
+                               ENIPMessage *const outgoing_message) {
+  FillNextNMessageOctetsWithValueAndMoveToNextPosition(0, 6, outgoing_message);
+}
+
+void EncodeCipLastConflictDetected(const void *const data,
+                                   ENIPMessage *const outgoing_message) {
+  const size_t kAttribute11Size = sizeof(CipUsint) + 6 * sizeof(CipUsint) + 28 *
+                                  sizeof(CipUsint);
+  OPENER_ASSERT(kAttribute11Size == 35);
+  FillNextNMessageOctetsWithValueAndMoveToNextPosition(0,
+                                                       kAttribute11Size,
+                                                       outgoing_message);
+}
 
 EipStatus SetAttributeSingleTcpIpInterface(
   CipInstance *instance,
@@ -337,68 +372,50 @@ EipStatus SetAttributeSingleTcpIpInterface(
   EipUint16 attribute_number = message_router_request->request_path
                                .attribute_number;
 
-  if (NULL != attribute) {
+  /* Check attribute exists and is not a dummy for GetAttributeAll */
+  if (NULL != attribute && !(kGetableAllDummy & attribute->attribute_flags) ) {
     uint8_t set_bit_mask = (instance->cip_class->set_bit_mask[CalculateIndex(
                                                                 attribute_number)
                             ]);
     if ( set_bit_mask & ( 1 << ( (attribute_number) % 8 ) ) ) {
 
-      if (attribute->attribute_flags & kPreSetFunc
-          && instance->cip_class->PreSetCallback) {
-          instance->cip_class->PreSetCallback(instance,
-                                              attribute,
-                                              message_router_request->service);
+      if ( (attribute->attribute_flags & kPreSetFunc)
+           && instance->cip_class->PreSetCallback ) {
+        instance->cip_class->PreSetCallback(instance,
+                                            attribute,
+                                            message_router_request->service);
       }
 
       switch (attribute_number) {
         case 3: {
           CipDword configuration_control_received = GetUdintFromMessage(
             &(message_router_request->data) );
-          if ((configuration_control_received & kTcpipCfgCtrlMethodMask) >= 0x03 || /* only modes 0..2 */
-              (configuration_control_received & ~(kTcpipCfgCtrlMethodMask|kTcpipCfgCtrlDnsEnable))) { /* no reserved bits */
-            message_router_response->general_status = kCipErrorInvalidAttributeValue;
-            break;
-          }
-          {
-            /* check requested mode against capabilities */
-            CipDword cfg_method = (configuration_control_received & kTcpipCfgCtrlMethodMask);
-            CipDword caps = g_tcpip.config_capability;
-            if(cfg_method == kTcpipCfgCtrlBootp) {
-              /* BOOTP selected */
-              if((caps & CFG_CAPS_BOOTP_CLIENT) == 0) { /* we have no BOOTP */
-                OPENER_TRACE_INFO(" setAttribute 3 BOOTP not supported\n");
-                message_router_response->general_status = kCipErrorInvalidAttributeValue;
-                break;
-              }
-            } else if(cfg_method == kTcpipCfgCtrlDhcp) {
-              /* DHCP selected */
-              if((caps & CFG_CAPS_DHCP_CLIENT) == 0) { /* we have no DHCP */
-                OPENER_TRACE_INFO(" setAttribute 3 DHCP not supported\n");
-                message_router_response->general_status = kCipErrorInvalidAttributeValue;
-                break;
-              }
-            }
-            if((configuration_control_received & kTcpipCfgCtrlDnsEnable) &&
-               ((caps & CFG_CAPS_DNS_CLIENT) == 0)) { /* we are no DNS client */
-              OPENER_TRACE_INFO(" setAttribute 3 DNS not supported\n");
-              message_router_response->general_status = kCipErrorInvalidAttributeValue;
-              break;
-            }
-          }
-          OPENER_TRACE_INFO(" setAttribute %d\n", attribute_number);
-          if (attribute->data != NULL) {
-            CipDword *data = (CipDword *) attribute->data;
-            /* Set reserved bits to zero on reception. */
-            configuration_control_received &= (kTcpipCfgCtrlMethodMask | kTcpipCfgCtrlDnsEnable);
-            *(data) = configuration_control_received;
-            message_router_response->general_status = kCipErrorSuccess;
+          if ( (configuration_control_received & kTcpipCfgCtrlMethodMask) >=
+               0x03 ||
+               (configuration_control_received & ~kTcpipCfgCtrlMethodMask) ) {
+            message_router_response->general_status =
+              kCipErrorInvalidAttributeValue;
+
           } else {
-            message_router_response->general_status = kCipErrorNotEnoughData;
+
+            OPENER_TRACE_INFO(" setAttribute %d\n", attribute_number);
+
+            if (attribute->data != NULL) {
+              CipDword *data = (CipDword *) attribute->data;
+              /* Set reserved bits to zero on reception. */
+              configuration_control_received &=
+                (kTcpipCfgCtrlMethodMask | kTcpipCfgCtrlDnsEnable);
+              *(data) = configuration_control_received;
+              message_router_response->general_status = kCipErrorSuccess;
+            } else {
+              message_router_response->general_status = kCipErrorNotEnoughData;
+            }
           }
         }
         break;
 
-#if defined (OPENER_TCPIP_IFACE_CFG_SETTABLE) && 0 != OPENER_TCPIP_IFACE_CFG_SETTABLE
+#if defined (OPENER_TCPIP_IFACE_CFG_SETTABLE) && \
+          0 != OPENER_TCPIP_IFACE_CFG_SETTABLE
         case 5: { /* Interface configuration */
           CipTcpIpInterfaceConfiguration if_cfg;
           CipUdint tmp_ip;
@@ -412,34 +429,41 @@ EipStatus SetAttributeSingleTcpIpInterface(
             break;
           }
           memset(&if_cfg, 0, sizeof if_cfg);
-          tmp_ip = GetUdintFromMessage(&(message_router_request->data));
+          tmp_ip = GetUdintFromMessage(&(message_router_request->data) );
           if_cfg.ip_address = htonl(tmp_ip);
-          tmp_ip = GetUdintFromMessage(&(message_router_request->data));
+          tmp_ip = GetUdintFromMessage(&(message_router_request->data) );
           if_cfg.network_mask = htonl(tmp_ip);
-          tmp_ip = GetUdintFromMessage(&(message_router_request->data));
+          tmp_ip = GetUdintFromMessage(&(message_router_request->data) );
           if_cfg.gateway = htonl(tmp_ip);
-          tmp_ip = GetUdintFromMessage(&(message_router_request->data));
+          tmp_ip = GetUdintFromMessage(&(message_router_request->data) );
           if_cfg.name_server = htonl(tmp_ip);
-          tmp_ip = GetUdintFromMessage(&(message_router_request->data));
+          tmp_ip = GetUdintFromMessage(&(message_router_request->data) );
           if_cfg.name_server_2 = htonl(tmp_ip);
 
-          CipUint domain_name_length = GetUintFromMessage(&(message_router_request->data));
+          CipUint domain_name_length =
+            GetUintFromMessage(&(message_router_request->data) );
           if (domain_name_length > 48) {  /* see Vol. 2, Table 5-4.3 Instance Attributes */
             message_router_response->general_status = kCipErrorTooMuchData;
             break;
           }
-          SetCipStringByData(&if_cfg.domain_name, domain_name_length, message_router_request->data);
-          domain_name_length = (domain_name_length +1) & (~0x0001u);  /* Align for possible pad byte */
-          OPENER_TRACE_INFO("Domain: ds %hu '%s'\n", domain_name_length, if_cfg.domain_name.string);
+          SetCipStringByData(&if_cfg.domain_name,
+                             domain_name_length,
+                             message_router_request->data);
+          domain_name_length = (domain_name_length + 1) & (~0x0001u);  /* Align for possible pad byte */
+          OPENER_TRACE_INFO("Domain: ds %hu '%s'\n",
+                            domain_name_length,
+                            if_cfg.domain_name.string);
           message_router_request->data += domain_name_length;
 
           if (!IsValidNetworkConfig(&if_cfg) ||
-              (domain_name_length > 0 && !IsValidDomain(if_cfg.domain_name.string)) ) {
-            message_router_response->general_status = kCipErrorInvalidAttributeValue;
+              (domain_name_length > 0 &&
+               !IsValidDomain(if_cfg.domain_name.string) ) ) {
+            message_router_response->general_status =
+              kCipErrorInvalidAttributeValue;
             break;
           }
           OPENER_TRACE_INFO(" setAttribute %d\n", attribute_number);
-          CipTcpIpInterfaceConfiguration * const p_interface_configuration =
+          CipTcpIpInterfaceConfiguration *const p_interface_configuration =
             (CipTcpIpInterfaceConfiguration *)attribute->data;
           /* Free first and then making a shallow copy of if_cfg.domain_name is ok,
            * because if_cfg goes out of scope now. */
@@ -456,17 +480,23 @@ EipStatus SetAttributeSingleTcpIpInterface(
             .length = 0u,
             .string = NULL
           };
-          CipUint host_name_length = GetUintFromMessage(&(message_router_request->data));
+          CipUint host_name_length =
+            GetUintFromMessage(&(message_router_request->data) );
           if (host_name_length > 64) {  /* see RFC 1123 on more details */
             message_router_response->general_status = kCipErrorTooMuchData;
             break;
           }
-          SetCipStringByData(&tmp_host_name, host_name_length, message_router_request->data);
-          host_name_length = (host_name_length +1) & (~0x0001u);  /* Align for possible pad byte */
-          OPENER_TRACE_INFO("Host Name: ds %hu '%s'\n", host_name_length, tmp_host_name.string);
+          SetCipStringByData(&tmp_host_name,
+                             host_name_length,
+                             message_router_request->data);
+          host_name_length = (host_name_length + 1) & (~0x0001u);  /* Align for possible pad byte */
+          OPENER_TRACE_INFO("Host Name: ds %hu '%s'\n",
+                            host_name_length,
+                            tmp_host_name.string);
           message_router_request->data += host_name_length;
-          if (!IsValidNameLabel(tmp_host_name.string)) {
-            message_router_response->general_status = kCipErrorInvalidAttributeValue;
+          if (!IsValidNameLabel(tmp_host_name.string) ) {
+            message_router_response->general_status =
+              kCipErrorInvalidAttributeValue;
             break;
           }
           OPENER_TRACE_INFO(" setAttribute %d\n", attribute_number);
@@ -513,11 +543,11 @@ EipStatus SetAttributeSingleTcpIpInterface(
       }
 
       /* Call the PostSetCallback if enabled. */
-      if (attribute->attribute_flags & (kPostSetFunc | kNvDataFunc)
-          && NULL != instance->cip_class->PostSetCallback) {
+      if ( (attribute->attribute_flags & (kPostSetFunc | kNvDataFunc) )
+           && NULL != instance->cip_class->PostSetCallback ) {
         CipUsint service = message_router_request->service;
         if (kCipErrorSuccess != message_router_response->general_status) {
-            service |= 0x80;  /* Flag no update, TODO: remove this workaround*/
+          service |= 0x80;    /* Flag no update, TODO: remove this workaround*/
         }
         instance->cip_class->PostSetCallback(instance, attribute, service);
       }
@@ -530,7 +560,7 @@ EipStatus SetAttributeSingleTcpIpInterface(
   }
 
   message_router_response->size_of_additional_status = 0;
-  message_router_response->data_length = 0;
+  InitializeENIPMessage(&message_router_response->message);
   message_router_response->reply_service = (0x80
                                             | message_router_request->service);
   return kEipStatusOkSend;
@@ -543,7 +573,7 @@ EipStatus CipTcpIpInterfaceInit() {
                                        0, /* # class attributes */
                                        7, /* # highest class attribute number */
                                        2, /* # class services */
-                                       9, /* # instance attributes */
+                                       13, /* # instance attributes */
                                        13, /* # highest instance attribute number */
                                        3, /* # instance services */
                                        1, /* # instances */
@@ -555,36 +585,75 @@ EipStatus CipTcpIpInterfaceInit() {
 
   CipInstance *instance = GetCipInstance(tcp_ip_class, 1); /* bind attributes to the instance #1 that was created above */
 
-  InsertAttribute(instance, 1, kCipDword, &g_tcpip.status,
+  InsertAttribute(instance, 1, kCipDword, EncodeCipDword, &g_tcpip.status,
                   kGetableSingleAndAll);
-  InsertAttribute(instance, 2, kCipDword, &g_tcpip.config_capability,
+  InsertAttribute(instance,
+                  2,
+                  kCipDword,
+                  EncodeCipDword,
+                  &g_tcpip.config_capability,
                   kGetableSingleAndAll);
-  InsertAttribute(instance, 3, kCipDword, &g_tcpip.config_control,
+  InsertAttribute(instance,
+                  3,
+                  kCipDword,
+                  EncodeCipDword,
+                  &g_tcpip.config_control,
                   kSetAndGetAble | kNvDataFunc | IFACE_CFG_SET_MODE );
-  InsertAttribute(instance, 4, kCipEpath, &g_tcpip.physical_link_object,
+  InsertAttribute(instance,
+                  4,
+                  kCipEpath,
+                  EncodeCipEPath,
+                  &g_tcpip.physical_link_object,
                   kGetableSingleAndAll);
-  InsertAttribute(instance, 5, kCipUdintUdintUdintUdintUdintString,
+  InsertAttribute(instance,
+                  5,
+                  kCipUdintUdintUdintUdintUdintString,
+                  EncoodeCipTcpIpInterfaceConfiguration,
                   &g_tcpip.interface_configuration,
                   kGetableSingleAndAll | kNvDataFunc | IFACE_CFG_SET_MODE);
-  InsertAttribute(instance, 6, kCipString, &g_tcpip.hostname,
+  InsertAttribute(instance, 6, kCipString, EncodeCipString, &g_tcpip.hostname,
                   kGetableSingleAndAll | kNvDataFunc | IFACE_CFG_SET_MODE);
-
-  InsertAttribute(instance, 8, kCipUsint, &g_tcpip.mcast_ttl_value,
+  InsertAttribute(instance,
+                  7,
+                  kCipAny,
+                  EncodeSafetyNetworkNumber,
+                  &dummy_data_field,
+                  kGetableAllDummy);
+  InsertAttribute(instance,
+                  8,
+                  kCipUsint,
+                  EncodeCipUsint,
+                  &g_tcpip.mcast_ttl_value,
                   kGetableSingleAndAll);
-  InsertAttribute(instance, 9, kCipAny, &g_tcpip.mcast_config,
+  InsertAttribute(instance,
+                  9,
+                  kCipAny,
+                  EncodeCipTcpIpMulticastConfiguration,
+                  &g_tcpip.mcast_config,
                   kGetableSingleAndAll);
+  InsertAttribute(instance, 10, kCipBool, EncodeCipBool, &g_tcpip.select_acd,
+                  kGetableAllDummy);
+  InsertAttribute(instance,
+                  11,
+                  kCipBool,
+                  EncodeCipLastConflictDetected,
+                  &dummy_data_field,
+                  kGetableAllDummy);
+  InsertAttribute(instance, 12, kCipBool, EncodeCipBool, &dummy_data_field,
+                  kGetableAllDummy);
   InsertAttribute(instance,
                   13,
                   kCipUint,
+                  EncodeCipUint,
                   &g_tcpip.encapsulation_inactivity_timeout,
                   kSetAndGetAble | kNvDataFunc);
 
   InsertService(tcp_ip_class, kGetAttributeSingle,
-                &GetAttributeSingleTcpIpInterface,
-                "GetAttributeSingleTCPIPInterface");
+                &GetAttributeSingle,
+                "GetAttributeSingle");
 
-  InsertService(tcp_ip_class, kGetAttributeAll, &GetAttributeAllTcpIpInterface,
-                "GetAttributeAllTCPIPInterface");
+  InsertService(tcp_ip_class, kGetAttributeAll, &GetAttributeAll,
+                "GetAttributeAll");
 
   InsertService(tcp_ip_class, kSetAttributeSingle,
                 &SetAttributeSingleTcpIpInterface,
@@ -606,151 +675,24 @@ void ShutdownTcpIpInterface(void) {
   }
 }
 
-EipStatus GetAttributeSingleTcpIpInterface(
-  CipInstance *const RESTRICT instance,
-  CipMessageRouterRequest *const RESTRICT message_router_request,
-  CipMessageRouterResponse *const RESTRICT message_router_response,
-  const struct sockaddr *originator_address,
-  const int encapsulation_session) {
-
-  EipUint16 attribute_number = message_router_request->request_path
-                               .attribute_number;
-
-  /* Use common handler for all attributes except attribute 9. */
-  if (9 != attribute_number) {
-    return GetAttributeSingle(instance,
-                              message_router_request,
-                              message_router_response,
-                              originator_address,
-                              encapsulation_session);
-  }
-
-  { /* attribute 9 can not be easily handled with the default mechanism therefore we will do it by hand */
-    EipByte *message = message_router_response->data;
-
-    message_router_response->data_length = 0;
-    message_router_response->reply_service = (0x80
-                                              | message_router_request->service);
-    message_router_response->size_of_additional_status = 0;
-    message_router_response->general_status = kCipErrorAttributeNotSupported;
-
-    uint8_t get_bit_mask = 0;
-    if (kGetAttributeAll == message_router_request->service) {
-      get_bit_mask = (instance->cip_class->get_all_bit_mask[CalculateIndex(
-                                                              attribute_number)]);
-      message_router_response->general_status = kCipErrorSuccess;
-    } else {
-      get_bit_mask = (instance->cip_class->get_single_bit_mask[CalculateIndex(
-                                                                 attribute_number)
-                      ]);
-    }
-
-    if ( 0 != ( get_bit_mask & ( 1 << (attribute_number % 8) ) ) ) {
-      OPENER_TRACE_INFO("getAttribute %d\n",
-                        message_router_request->request_path.attribute_number);
-
-      /* create a reply message containing the data*/
-      message_router_response->data_length += EncodeData(
-        kCipUsint, &(g_tcpip.mcast_config.alloc_control), &message);
-      message_router_response->data_length += EncodeData(
-        kCipUsint, &(g_tcpip.mcast_config.reserved_shall_be_zero),
-        &message);
-      message_router_response->data_length += EncodeData(
-        kCipUint,
-        &(g_tcpip.mcast_config.number_of_allocated_multicast_addresses),
-        &message);
-
-      CipUdint multicast_address = ntohl(
-        g_tcpip.mcast_config.starting_multicast_address);
-
-      message_router_response->data_length += EncodeData(kCipUdint,
-                                                         &multicast_address,
-                                                         &message);
-      message_router_response->general_status = kCipErrorSuccess;
-    }
-  }
-
-  return kEipStatusOkSend;
-}
-
-EipStatus GetAttributeAllTcpIpInterface(
-  CipInstance *instance,
-  CipMessageRouterRequest *message_router_request,
-  CipMessageRouterResponse *message_router_response,
-  const struct sockaddr *originator_address,
-  const int encapsulation_session) {
-
-  EipUint8 *response = message_router_response->data; /* pointer into the reply */
-  CipAttributeStruct *attribute = instance->attributes;
-
-  for (int j = 0; j < instance->cip_class->number_of_attributes; j++) /* for each instance attribute of this class */
-  {
-    int attribute_number = attribute->attribute_number;
-    if (attribute_number < 32) /* only return attributes that are flagged as being part of GetAttributeALl */
-    {
-      message_router_request->request_path.attribute_number = attribute_number;
-
-      if (8 == attribute_number) { /* insert 6 zeros for the required empty safety network number according to Table 5-3.10 */
-        memset(message_router_response->data, 0, 6);
-        message_router_response->data += 6;
-      }
-
-      if ( kEipStatusOkSend
-           != GetAttributeSingleTcpIpInterface(instance, message_router_request,
-                                               message_router_response,
-                                               originator_address,
-                                               encapsulation_session) ) {
-        message_router_response->data = response;
-        return kEipStatusError;
-      }
-      message_router_response->data += message_router_response->data_length;
-
-      if (9 == attribute_number) {
-        /* returning default value for unimplemented attributes 10,11 and 12 */
-
-        /* attribute 10, type: BOOL, default value: 0 */
-        message_router_response->data += 6;
-        *(message_router_response->data) = 0;
-        message_router_response->data += 1;
-
-        /* attribute 11, type: STRUCT OF USINT, ARRAY of 6 USINTs, ARRAY of 28 USINTs default value: 0 */
-        memset(message_router_response->data, 0, 29);
-        message_router_response->data += 29;
-
-        /* attribute 12, type: BOOL default value: 0 */
-        *(message_router_response->data) = 0;
-        message_router_response->data += 1;
-      }
-
-    }
-    attribute++;
-  }
-  message_router_response->data_length = message_router_response->data
-                                         - response;
-  message_router_response->data = response;
-
-  return kEipStatusOkSend;
-}
-
 /**
  *  This function calculates the multicast base address to be used for CIP
  *  connections from the current IP setting. The algorithm is implemented
  *  according to CIP spec Volume 2,
  *  section 3-5.3 "Multicast Address Allocation for EtherNet/IP"
  */
-void CipTcpIpCalculateMulticastIp(CipTcpIpObject *const tcpip)
-{
+void CipTcpIpCalculateMulticastIp(CipTcpIpObject *const tcpip) {
   /* Multicast base address according to spec: 239.192.1.0 */
   static const CipUdint cip_mcast_base_addr = 0xEFC00100;
 
   /* Calculate the CIP multicast address. The multicast address is calculated, not input */
   CipUdint host_id = ntohl(tcpip->interface_configuration.ip_address) &
-                    ~ntohl(tcpip->interface_configuration.network_mask);
+                     ~ntohl(tcpip->interface_configuration.network_mask);
   host_id -= 1;
   host_id &= 0x3ff;
 
   tcpip->mcast_config.starting_multicast_address =
-    htonl(cip_mcast_base_addr + (host_id << 5));
+    htonl(cip_mcast_base_addr + (host_id << 5) );
 }
 
 

+ 1 - 0
source/src/cip/ciptcpipinterface.h

@@ -57,6 +57,7 @@ typedef struct {
 
   /** #9 The multicast configuration for this device */
   MulticastAddressConfiguration mcast_config;
+  CipBool select_acd; /**< attribute #10 - Is ACD enabled? */
 
   /** #13 Number of seconds of inactivity before TCP connection is closed */
   CipUint encapsulation_inactivity_timeout;

+ 62 - 11
source/src/cip/ciptypes.h

@@ -55,8 +55,9 @@ typedef enum cip_data_types {
   kCip6Usint = 0xA2, /**< Struct for MAC Address (six USINTs)*/
   kCipMemberList = 0xA3, /**< */
   kCipByteArray = 0xA4, /**< */
-  kInternalUint6 = 0xF0 /**< bogus hack, for port class attribute 9, TODO
-                           figure out the right way to handle it */
+  kInternalUint6 = 0xF0, /**< bogus hack, for port class attribute 9, TODO
+                            figure out the right way to handle it */
+  kCipStringI
 } CipDataType;
 
 /** @brief Definition of CIP service codes
@@ -111,6 +112,7 @@ typedef enum { /* TODO: Rework */
   kSetAndGetAble = 0x07, /**< both set and get-able */
   kGetableSingleAndAll = 0x03, /**< both single and all */
   /* Flags to control the usage of callbacks per attribute from the Get* and Set* services */
+  kGetableAllDummy = 0x08, /**< Get-able but a dummy Attribute */
   kPreGetFunc = 0x10, /**< enable pre get callback */
   kPostGetFunc = 0x20,  /**< enable post get callback */
   kPreSetFunc = 0x40, /**< enable pre set callback */
@@ -145,15 +147,59 @@ typedef struct {
  */
 typedef struct {
   EipUint16 length; /**< Length of the String (16 bit value) */
-  EipByte *string; /**< Pointer to the string data */
+  CipByte *string; /**< Pointer to the string data */
 } CipString;
 
+/** @brief CIP String2
+ *
+ */
+typedef struct {
+  EipUint16 length; /**< Length of the String (16 bit value) */
+  CipWord *string; /**< Pointer to the string data */
+} CipString2;
+
+/** @brief CIP String with variable symbol size
+ *
+ */
 typedef struct {
-  EipUint16 size;
+  EipUint16 size; /**< Amount of bytes per symbol */
   EipUint16 length; /**< Length of the String (16 bit value) */
   EipByte *string; /**< Pointer to the string data */
 } CipStringN;
 
+/** @brief STRINGI definition
+ *
+ */
+typedef struct cip_type_string_i_struct CipStringIStruct;
+
+typedef struct cip_string_i {
+  CipUsint number_of_strings;
+  CipStringIStruct *array_of_string_i_structs;
+} CipStringI;
+
+typedef enum cip_type_string_i_character_set {
+  kCipStringICharSet_ISO_8859_1_1987 = 4,
+  kCipStringICharSet_ISO_8859_2_1987 = 5,
+  kCipStringICharSet_ISO_8859_3_1988 = 6,
+  kCipStringICharSet_ISO_8859_4_1988 = 7,
+  kCipStringICharSet_ISO_8859_5_1988 = 8,
+  kCipStringICharSet_ISO_8859_6_1987 = 9,
+  kCipStringICharSet_ISO_8859_7_1987 = 10,
+  kCipStringICharSet_ISO_8859_8_1989 = 11,
+  kCipStringICharSet_ISO_8859_9_1989 = 12,
+  kCipStringICharSet_ISO_10646_UCS_2 = 1000,
+  kCipStringICharSet_ISO_10646_UCS_4 = 1001
+} CipStringICharacterSet;
+
+typedef struct cip_type_string_i_struct {
+  CipUsint language_char_1;
+  CipUsint language_char_2;
+  CipUsint language_char_3;
+  CipUint char_string_struct;   /**< EPath Either 0xD0, 0xD5, 0xD9, or 0xDA */
+  CipUint character_set;   /**< Character set of the string */
+  CipOctet *string;   /**< Pointer to the string data */
+} CipStringIStruct;
+
 /** @brief Struct for padded EPATHs
  *
  * Here the class code is referenced as class ID - see Vol. 1 C-1.4.2
@@ -205,6 +251,8 @@ typedef struct {
 
 #define MAX_SIZE_OF_ADD_STATUS 2 /* for now we support extended status codes up to 2 16bit values there is mostly only one 16bit value used */
 
+typedef struct enip_message ENIPMessage;
+
 /** @brief CIP Message Router Response
  *
  */
@@ -219,16 +267,19 @@ typedef struct {
   EipUint16 additional_status[MAX_SIZE_OF_ADD_STATUS]; /**< Array of 16 bit words; Additional status;
                                                           If SizeOfAdditionalStatus is 0. there is no
                                                           Additional Status */
-  EipInt16 data_length; /**< Supportative non-CIP variable, gives length of data segment */
-  CipOctet *data; /**< Array of octet; Response data per object definition from
-                     request */
+  ENIPMessage message; /* The constructed message */
 } CipMessageRouterResponse;
 
+/** @brief self-describing data encoding for CIP types */
+typedef void (*CipAttributeEncodeInMessage)(const void *const data,
+                                            ENIPMessage *const outgoing_message);
+
 /** @brief Structure to describe a single CIP attribute of an object
-*/
+ */
 typedef struct {
   EipUint16 attribute_number; /**< The attribute number of this attribute. */
   EipUint8 type;  /**< The @ref CipDataType of this attribute. */
+  CipAttributeEncodeInMessage encode; /**< Self-describing its data encoding */
   CIPAttributeFlag attribute_flags; /**< See @ref CIPAttributeFlag declaration for valid values. */
   void *data;
 } CipAttributeStruct;
@@ -290,15 +341,15 @@ typedef struct cip_class {
   struct cip_service_struct *services; /**< pointer to the array of services */
   char *class_name; /**< class name */
   /** Is called in GetAttributeSingle* before the response is assembled from
-  * the object's attributes */
+   * the object's attributes */
   CipGetSetCallback PreGetCallback;
   /** Is called in GetAttributeSingle* after the response has been sent. */
   CipGetSetCallback PostGetCallback;
   /** Is called in SetAttributeSingle* before the received data is moved
-  * to the object's attributes */
+   * to the object's attributes */
   CipGetSetCallback PreSetCallback;
   /** Is called in SetAttributeSingle* after the received data was set
-  * in the object's attributes. */
+   * in the object's attributes. */
   CipGetSetCallback PostSetCallback;
 } CipClass;
 

+ 119 - 177
source/src/enet_encap/cpf.c

@@ -15,21 +15,29 @@
 #include "cipconnectionmanager.h"
 #include "trace.h"
 #include "encap.h"
+#include "enipmessage.h"
 
-const size_t item_count_field_size = 2; /**< The size of the item count field in the message */
-const size_t item_data_type_id_field_length = 2; /**< The size of the item count field in the message */
+const size_t kItemCountFieldSize = 2; /**< The size of the item count field in the message */
+const size_t KItemDataTypeIdFieldLength = 2; /**< The size of the item count field in the message */
 
-const size_t sequenced_address_item_length = 8;
+const size_t kSequencedAddressItemLength = 8;
 
 CipCommonPacketFormatData g_common_packet_format_data_item; /**< CPF global data items */
 
+static void InitializeMessageRouterResponse(
+  CipMessageRouterResponse *const message_router_response) {
+  memset(message_router_response, 0, sizeof(*message_router_response) );
+  InitializeENIPMessage(&message_router_response->message);
+}
+
 EipStatus NotifyCommonPacketFormat
 (
   const EncapsulationData *const received_data,
   const struct sockaddr *const originator_address,
-  ENIPMessage *const outgoing_message)
-{
+  ENIPMessage *const outgoing_message) {
   EipStatus return_value = kEipStatusError;
+  CipMessageRouterResponse message_router_response;
+  InitializeMessageRouterResponse(&message_router_response);
 
   if (kEipStatusError == ( return_value = CreateCommonPacketFormatStructure(
                              received_data->
@@ -47,24 +55,28 @@ EipStatus NotifyCommonPacketFormat
         return_value = NotifyMessageRouter(
           g_common_packet_format_data_item.data_item.data,
           g_common_packet_format_data_item.data_item.length,
+          &message_router_response,
           originator_address,
           received_data->session_handle);
         if (return_value != kEipStatusError) {
           SkipEncapsulationHeader(outgoing_message);
-          /* TODO: Here we lose a possible kEipStatusError from AssembleLinearMessage().
+          /* TODO: Here we get the status. What to do? kEipStatusError from AssembleLinearMessage().
            *  Its not clear how to transport this error information to the requester. */
-          int response_len = AssembleLinearMessage(
-            &g_message_router_response, &g_common_packet_format_data_item,
+          EipStatus status = AssembleLinearMessage(
+            &message_router_response,
+            &g_common_packet_format_data_item,
             outgoing_message);
 
+          /* Save pointer and move to start for Encapusulation Header */
           CipOctet *buffer = outgoing_message->current_message_position;
           outgoing_message->current_message_position =
             outgoing_message->message_buffer;
           GenerateEncapsulationHeader(received_data,
-                                      response_len,
+                                      outgoing_message->used_message_length,
                                       received_data->session_handle,
                                       kEncapsulationProtocolSuccess,
                                       outgoing_message);
+          /* Move pointer back to last octet */
           outgoing_message->current_message_position = buffer;
           return_value = kEipStatusOkSend;
         }
@@ -151,9 +163,12 @@ EipStatus NotifyConnectedCommonPacketFormat(
 
           ConnectionObjectResetInactivityWatchdogTimerValue(connection_object);
 
+          CipMessageRouterResponse message_router_response;
+          InitializeMessageRouterResponse(&message_router_response);
           return_value = NotifyMessageRouter(
             buffer,
             g_common_packet_format_data_item.data_item.length - 2,
+            &message_router_response,
             originator_address,
             received_data->session_handle);
 
@@ -162,17 +177,17 @@ EipStatus NotifyConnectedCommonPacketFormat(
             .connection_identifier = connection_object
                                      ->cip_produced_connection_id;
             SkipEncapsulationHeader(outgoing_message);
-            /* TODO: Here we lose a possible kEipStatusError from AssembleLinearMessage().
+            /* TODO: Here we get the status. What to do? kEipStatusError from AssembleLinearMessage().
              *  Its not clear how to transport this error information to the requester. */
-            int response_len = AssembleLinearMessage(
-              &g_message_router_response, &g_common_packet_format_data_item,
+            EipStatus status = AssembleLinearMessage(
+              &message_router_response, &g_common_packet_format_data_item,
               outgoing_message);
 
             CipOctet *buffer = outgoing_message->current_message_position;
             outgoing_message->current_message_position =
               outgoing_message->message_buffer;
             GenerateEncapsulationHeader(received_data,
-                                        response_len,
+                                        outgoing_message->used_message_length,
                                         received_data->session_handle,
                                         kEncapsulationProtocolSuccess,
                                         outgoing_message);
@@ -197,7 +212,9 @@ EipStatus NotifyConnectedCommonPacketFormat(
     }
   }
   // return outgoing_message->used_message_length;
-  return (0 != outgoing_message->used_message_length ? kEipStatusOkSend : kEipStatusOk); /* TODO: What would the right EipStatus to return? */
+  return (0 !=
+          outgoing_message->used_message_length ? kEipStatusOkSend :
+          kEipStatusOk);                                                                 /* TODO: What would the right EipStatus to return? */
 }
 
 /**
@@ -299,39 +316,27 @@ EipStatus CreateCommonPacketFormatStructure(
 /**
  * @brief Encodes a Null Address Item into the message frame
  * @param outgoing_message The outgoing message object
- *
- * @return The new size of the message frame after encoding
  */
-int EncodeNullAddressItem(ENIPMessage *const outgoing_message) {
-  outgoing_message->used_message_length += AddIntToMessage(
-    kCipItemIdNullAddress,
-    &outgoing_message->current_message_position);
+void EncodeNullAddressItem(ENIPMessage *const outgoing_message) {
+  AddIntToMessage(kCipItemIdNullAddress, outgoing_message);
   /* null address item -> address length set to 0 */
-  outgoing_message->used_message_length += AddIntToMessage(0,
-                                                           &outgoing_message->current_message_position);
-  return outgoing_message->used_message_length;
+  AddIntToMessage(0, outgoing_message);
 }
 
 /**
  * Encodes a Connected Address Item into the message frame
  * @param common_packet_format_data_item The Common Packet Format data structure from which the message is constructed
  * @param outgoing_message The outgoing message object
- *
- * @return The new size of the message frame after encoding
  */
-int EncodeConnectedAddressItem(
+void EncodeConnectedAddressItem(
   const CipCommonPacketFormatData *const common_packet_format_data_item,
   ENIPMessage *const outgoing_message) {
   /* connected data item -> address length set to 4 and copy ConnectionIdentifier */
-  outgoing_message->used_message_length += AddIntToMessage(
-    kCipItemIdConnectionAddress,
-    &outgoing_message->current_message_position);
-  outgoing_message->used_message_length += AddIntToMessage(4,
-                                                           &outgoing_message->current_message_position);
-  outgoing_message->used_message_length += AddDintToMessage(
+  AddIntToMessage(kCipItemIdConnectionAddress, outgoing_message);
+  AddIntToMessage(4, outgoing_message);
+  AddDintToMessage(
     common_packet_format_data_item->address_item.data.connection_identifier,
-    &outgoing_message->current_message_position);
-  return outgoing_message->used_message_length;
+    outgoing_message);
 }
 
 /**
@@ -339,26 +344,19 @@ int EncodeConnectedAddressItem(
  *
  * @param common_packet_format_data_item Common Packet Format item which is used in the encoding
  * @param outgoing_message The outgoing message object
- *
- * @return New message size after encoding
  */
-int EncodeSequencedAddressItem(
+void EncodeSequencedAddressItem(
   const CipCommonPacketFormatData *const common_packet_format_data_item,
   ENIPMessage *const outgoing_message) {
   /* sequenced address item -> address length set to 8 and copy ConnectionIdentifier and SequenceNumber */
-  outgoing_message->used_message_length += AddIntToMessage(
-    kCipItemIdSequencedAddressItem,
-    &outgoing_message->current_message_position);
-  outgoing_message->used_message_length += AddIntToMessage(
-    sequenced_address_item_length,
-    &outgoing_message->current_message_position);
-  outgoing_message->used_message_length += AddDintToMessage(
+  AddIntToMessage(kCipItemIdSequencedAddressItem, outgoing_message);
+  AddIntToMessage(kSequencedAddressItemLength, outgoing_message);
+  AddDintToMessage(
     common_packet_format_data_item->address_item.data.connection_identifier,
-    &outgoing_message->current_message_position);
-  outgoing_message->used_message_length += AddDintToMessage(
+    outgoing_message);
+  AddDintToMessage(
     common_packet_format_data_item->address_item.data.sequence_number,
-    &outgoing_message->current_message_position);
-  return outgoing_message->used_message_length;
+    outgoing_message);
 }
 
 /**
@@ -366,16 +364,11 @@ int EncodeSequencedAddressItem(
  *
  * @param common_packet_format_data_item The Common Packet Format data structure from which the message is constructed
  * @param outgoing_message The outgoing message object
- *
- * @return The new size of the message frame after encoding
  */
-int EncodeItemCount(
+void EncodeItemCount(
   const CipCommonPacketFormatData *const common_packet_format_data_item,
   ENIPMessage *const outgoing_message) {
-  outgoing_message->used_message_length += AddIntToMessage(
-    common_packet_format_data_item->item_count,
-    &outgoing_message->current_message_position);                                                                                                    /* item count */
-  return outgoing_message->used_message_length;
+  AddIntToMessage(common_packet_format_data_item->item_count, outgoing_message); /* item count */
 }
 
 /**
@@ -383,16 +376,12 @@ int EncodeItemCount(
  *
  * @param common_packet_format_data_item The Common Packet Format data structure from which the message is constructed
  * @param outgoing_message The outgoing message object
- *
- * @return The new size of the message frame after encoding
  */
-int EncodeDataItemType(
+void EncodeDataItemType(
   const CipCommonPacketFormatData *const common_packet_format_data_item,
   ENIPMessage *const outgoing_message) {
-  outgoing_message->used_message_length += AddIntToMessage(
-    common_packet_format_data_item->data_item.type_id,
-    &outgoing_message->current_message_position);
-  return outgoing_message->used_message_length;
+  AddIntToMessage(common_packet_format_data_item->data_item.type_id,
+                  outgoing_message);
 }
 
 /**
@@ -400,16 +389,12 @@ int EncodeDataItemType(
  *
  * @param common_packet_format_data_item The Common Packet Format data structure from which the message is constructed
  * @param outgoing_message The outgoing message object
- *
- * @return The new size of the message frame after encoding
  */
-int EncodeDataItemLength(
+void EncodeDataItemLength(
   const CipCommonPacketFormatData *const common_packet_format_data_item,
   ENIPMessage *const outgoing_message) {
-  outgoing_message->used_message_length += AddIntToMessage(
-    common_packet_format_data_item->data_item.length,
-    &outgoing_message->current_message_position);
-  return outgoing_message->used_message_length;
+  AddIntToMessage(common_packet_format_data_item->data_item.length,
+                  outgoing_message);
 }
 
 /**
@@ -417,19 +402,17 @@ int EncodeDataItemLength(
  *
  * @param common_packet_format_data_item The Common Packet Format data structure from which the message is constructed
  * @param outgoing_message The outgoing message object
- *
- * @return The new size of the message frame after encoding
  */
-int EncodeDataItemData(
+void EncodeDataItemData(
   const CipCommonPacketFormatData *const common_packet_format_data_item,
   ENIPMessage *const outgoing_message) {
-  for (size_t i = 0; i < common_packet_format_data_item->data_item.length;
-       i++) {
-    outgoing_message->used_message_length += AddSintToMessage(
-      *(common_packet_format_data_item->data_item.data + i),
-      &outgoing_message->current_message_position);
-  }
-  return outgoing_message->used_message_length;
+  memcpy(outgoing_message->current_message_position,
+         common_packet_format_data_item->data_item.data,
+         common_packet_format_data_item->data_item.length);
+  outgoing_message->current_message_position +=
+    common_packet_format_data_item->data_item.length;
+  outgoing_message->used_message_length +=
+    common_packet_format_data_item->data_item.length;
 }
 
 /**
@@ -437,18 +420,17 @@ int EncodeDataItemData(
  *
  * @param message_router_response The Router Response message which shall be answered
  * @param outgoing_message The outgoing message object
- *
- * @return The new size of the message buffer
  */
 
-int EncodeConnectedDataItemLength(
+void EncodeConnectedDataItemLength(
   const CipMessageRouterResponse *const message_router_response,
   ENIPMessage *const outgoing_message) {
-  outgoing_message->used_message_length += AddIntToMessage(
-    (EipUint16) ( message_router_response->data_length + 4 + 2  /* TODO: Magic numbers */
-                  + (2 * message_router_response->size_of_additional_status) ),
-    &outgoing_message->current_message_position);
-  return outgoing_message->used_message_length;
+  AddIntToMessage( (EipUint16) ( message_router_response->message.
+                                 used_message_length + 4 + 2                                  /* TODO: Magic numbers */
+                                 + (2 *
+                                    message_router_response->
+                                    size_of_additional_status) ),
+                   outgoing_message );
 }
 
 /**
@@ -456,18 +438,13 @@ int EncodeConnectedDataItemLength(
  *
  * @param common_packet_format_data_item
  * @param outgoing_message The outgoing message object
- *
- * @return The new size of the message buffer
- *
  */
-int EncodeSequenceNumber(
+void EncodeSequenceNumber(
   const CipCommonPacketFormatData *const common_packet_format_data_item,
   ENIPMessage *const outgoing_message) {
-  outgoing_message->used_message_length += AddIntToMessage(
-    (EipUint16) common_packet_format_data_item->address_item.data
-    .sequence_number,
-    &outgoing_message->current_message_position);
-  return outgoing_message->used_message_length;
+  AddIntToMessage(
+     (EipUint16) common_packet_format_data_item->address_item.data.sequence_number,
+    outgoing_message );
 }
 
 /**
@@ -475,16 +452,11 @@ int EncodeSequenceNumber(
  *
  * @param message_router_response The router response message data structure to be processed
  * @param outgoing_message The outgoing message object
- *
- * @return The new size of the message buffer
  */
-int EncodeReplyService(
+void EncodeReplyService(
   const CipMessageRouterResponse *const message_router_response,
   ENIPMessage *const outgoing_message) {
-  outgoing_message->used_message_length += AddSintToMessage(
-    message_router_response->reply_service,
-    &outgoing_message->current_message_position);
-  return outgoing_message->used_message_length;
+  AddSintToMessage(message_router_response->reply_service, outgoing_message);
 }
 
 /**
@@ -492,16 +464,11 @@ int EncodeReplyService(
  *
  * @param message_router_response Router Response message to be processed
  * @param outgoing_message The outgoing message object
- *
- * @return New size of the message buffer
  */
-int EncodeReservedFieldOfLengthByte(
+void EncodeReservedFieldOfLengthByte(
   const CipMessageRouterResponse *const message_router_response,
   ENIPMessage *const outgoing_message) {
-  outgoing_message->used_message_length += AddSintToMessage(
-    message_router_response->reserved,
-    &outgoing_message->current_message_position);
-  return outgoing_message->used_message_length;
+  AddSintToMessage(message_router_response->reserved, outgoing_message);
 }
 
 /**
@@ -509,16 +476,11 @@ int EncodeReservedFieldOfLengthByte(
  *
  * @param message_router_response Router Response message to be processed
  * @param outgoing_message The outgoing message object
- *
- * @return New size of the message buffer
  */
-int EncodeGeneralStatus(
+void EncodeGeneralStatus(
   const CipMessageRouterResponse *const message_router_response,
   ENIPMessage *const outgoing_message) {
-  outgoing_message->used_message_length += AddSintToMessage(
-    message_router_response->general_status,
-    &outgoing_message->current_message_position);
-  return outgoing_message->used_message_length;
+  AddSintToMessage(message_router_response->general_status, outgoing_message);
 }
 
 /**
@@ -526,17 +488,13 @@ int EncodeGeneralStatus(
  *
  * @param message_router_response Router Response message to be processed
  * @param outgoing_message The outgoing message object
- *
- * @return New size of the message buffer
  */
 
-int EncodeExtendedStatusLength(
+void EncodeExtendedStatusLength(
   const CipMessageRouterResponse *const message_router_response,
   ENIPMessage *const outgoing_message) {
-  outgoing_message->used_message_length += AddSintToMessage(
-    message_router_response->size_of_additional_status,
-    &outgoing_message->current_message_position);
-  return outgoing_message->used_message_length;
+  AddSintToMessage(message_router_response->size_of_additional_status,
+                   outgoing_message);
 }
 
 /**
@@ -544,20 +502,16 @@ int EncodeExtendedStatusLength(
  *
  * @param message_router_response Router Response message to be processed
  * @param outgoing_message The outgoing message object
- *
- * @return New size of the message buffer
  */
-size_t EncodeExtendedStatusDataItems(
+void EncodeExtendedStatusDataItems(
   const CipMessageRouterResponse *const message_router_response,
   ENIPMessage *const outgoing_message) {
   for (size_t i = 0;
        i < message_router_response->size_of_additional_status &&
        i < MAX_SIZE_OF_ADD_STATUS; i++) {
-    outgoing_message->used_message_length += AddIntToMessage(
-      message_router_response->additional_status[i],
-      &outgoing_message->current_message_position);
+    AddIntToMessage(message_router_response->additional_status[i],
+                    outgoing_message);
   }
-  return outgoing_message->used_message_length;
 }
 
 /**
@@ -568,17 +522,13 @@ size_t EncodeExtendedStatusDataItems(
  *
  * @param message_router_response Router Response message to be processed
  * @param outgoing_message The outgoing message object
- *
- * @return New size of the message buffer
  */
 
-int EncodeExtendedStatus(
+void EncodeExtendedStatus(
   const CipMessageRouterResponse *const message_router_response,
   ENIPMessage *const outgoing_message) {
   EncodeExtendedStatusLength(message_router_response, outgoing_message);
   EncodeExtendedStatusDataItems(message_router_response, outgoing_message);
-
-  return outgoing_message->used_message_length;
 }
 
 /**
@@ -587,16 +537,16 @@ int EncodeExtendedStatus(
  * @param message_router_response Router Response message to be processed
  * @param outgoing_message The outgoing message object
  *
- * @return New size of the message buffer
  */
-int EncodeUnconnectedDataItemLength(
+void EncodeUnconnectedDataItemLength(
   const CipMessageRouterResponse *const message_router_response,
   ENIPMessage *const outgoing_message) {
-  outgoing_message->used_message_length += AddIntToMessage(
-    (EipUint16) ( message_router_response->data_length + 4  /* TODO: Magic number */
-                  + (2 * message_router_response->size_of_additional_status) ),
-    &outgoing_message->current_message_position);
-  return outgoing_message->used_message_length;
+  AddIntToMessage( (EipUint16) ( message_router_response->message.
+                                 used_message_length + 4                                  /* TODO: Magic number */
+                                 + (2 *
+                                    message_router_response->
+                                    size_of_additional_status) ),
+                   outgoing_message );
 }
 
 /**
@@ -605,15 +555,17 @@ int EncodeUnconnectedDataItemLength(
  * @param message_router_response Router Response message to be processed
  * @param outgoing_message The outgoing message object
  */
-int EncodeMessageRouterResponseData(
+void EncodeMessageRouterResponseData(
   const CipMessageRouterResponse *const message_router_response,
   ENIPMessage *const outgoing_message) {
-  for (size_t i = 0; i < message_router_response->data_length; i++) {
-    outgoing_message->used_message_length +=
-      AddSintToMessage( (message_router_response->data)[i],
-                        &outgoing_message->current_message_position );
-  }
-  return outgoing_message->used_message_length;
+  memcpy(outgoing_message->current_message_position,
+         message_router_response->message.message_buffer,
+         message_router_response->message.used_message_length);
+
+  outgoing_message->current_message_position +=
+    message_router_response->message.used_message_length;
+  outgoing_message->used_message_length +=
+    message_router_response->message.used_message_length;
 }
 
 /**
@@ -622,19 +574,15 @@ int EncodeMessageRouterResponseData(
  * @param item_type
  * @param common_packet_format_data_item The Common Packet Format data structure from which the message is constructed
  * @param outgoing_message The outgoing message object
- *
- * @return New size of the message buffer
  */
-int EncodeSockaddrInfoItemTypeId(
+void EncodeSockaddrInfoItemTypeId(
   int item_type,
   const CipCommonPacketFormatData *const common_packet_format_data_item,
   ENIPMessage *const outgoing_message) {
   OPENER_ASSERT(item_type == 0 || item_type == 1);
-  outgoing_message->used_message_length += AddIntToMessage(
+  AddIntToMessage(
     common_packet_format_data_item->address_info_item[item_type].type_id,
-    &outgoing_message->current_message_position);
-
-  return outgoing_message->used_message_length;
+    outgoing_message);
 }
 
 /**
@@ -643,30 +591,25 @@ int EncodeSockaddrInfoItemTypeId(
  * @param item_type
  * @param common_packet_format_data_item The Common Packet Format data structure from which the message is constructed
  * @param outgoing_message The outgoing message object
- *
- * @return New size of the message buffer
  */
-int EncodeSockaddrInfoLength(
+void EncodeSockaddrInfoLength(
   int item_type,
   const CipCommonPacketFormatData *const common_packet_format_data_item,
   ENIPMessage *const outgoing_message) {
-  outgoing_message->used_message_length += AddIntToMessage(
+  AddIntToMessage(
     common_packet_format_data_item->address_info_item[item_type].length,
-    &outgoing_message->current_message_position);
-  return outgoing_message->used_message_length;
+    outgoing_message);
 }
 
-int AssembleLinearMessage(
+EipStatus AssembleLinearMessage(
   const CipMessageRouterResponse *const message_router_response,
   const CipCommonPacketFormatData *const common_packet_format_data_item,
   ENIPMessage *const outgoing_message) {
 
   if (message_router_response) {
     /* add Interface Handle and Timeout = 0 -> only for SendRRData and SendUnitData necessary */
-    outgoing_message->used_message_length += AddDintToMessage(0,
-                                                              &outgoing_message->current_message_position);
-    outgoing_message->used_message_length += AddIntToMessage(0,
-                                                             &outgoing_message->current_message_position);
+    AddDintToMessage(0, outgoing_message);
+    AddIntToMessage(0, outgoing_message);
   }
 
   EncodeItemCount(common_packet_format_data_item, outgoing_message);
@@ -750,24 +693,23 @@ int AssembleLinearMessage(
         EncodeSockaddrInfoLength(j,common_packet_format_data_item,
                                  outgoing_message);
 
-        outgoing_message->used_message_length += EncapsulateIpAddress(
+        EncapsulateIpAddress(
           common_packet_format_data_item->address_info_item[j].sin_port,
           common_packet_format_data_item->address_info_item[j].sin_addr,
-          &outgoing_message->current_message_position);
+          outgoing_message);
 
-        outgoing_message->used_message_length +=
-          FillNextNMessageOctetsWithValueAndMoveToNextPosition(
-            0, 8, &outgoing_message->current_message_position);
+        FillNextNMessageOctetsWithValueAndMoveToNextPosition(
+          0, 8, outgoing_message);
         break;
       }
     }
   }
-  return outgoing_message->used_message_length;
+  return kEipStatusOk;
 }
 
-int AssembleIOMessage(
+void AssembleIOMessage(
   const CipCommonPacketFormatData *const common_packet_format_data_item,
   ENIPMessage *const outgoing_message) {
-  return AssembleLinearMessage(0, common_packet_format_data_item,
-                               outgoing_message);
+  AssembleLinearMessage(0, common_packet_format_data_item,
+                        outgoing_message);
 }

+ 2 - 2
source/src/enet_encap/cpf.h

@@ -121,7 +121,7 @@ EipStatus CreateCommonPacketFormatStructure(
  * @return length of modification in bytes
  *     kEipStatusError .. error
  */
-int AssembleIOMessage(
+void AssembleIOMessage(
   const CipCommonPacketFormatData *const common_packet_format_data_item,
   ENIPMessage *const message);
 
@@ -136,7 +136,7 @@ int AssembleIOMessage(
  * @return length of modification in bytes
  *         kEipStatusError .. error
  */
-int AssembleLinearMessage(
+EipStatus AssembleLinearMessage(
   const CipMessageRouterResponse *const message_router_response,
   const CipCommonPacketFormatData *const common_packet_format_data_item,
   ENIPMessage *const outgoing_message);

+ 42 - 83
source/src/enet_encap/encap.c

@@ -106,7 +106,7 @@ int GetFreeSessionIndex(void);
 SessionStatus CheckRegisteredSessions(
   const EncapsulationData *const receive_data);
 
-void DetermineDelayTime(const EipByte *const buffer_start,
+void DetermineDelayTime(const EipByte *buffer_start,
                         DelayedEncapsulationMessage *const delayed_message_buffer);
 
 /*   @brief Initializes session list and interface information. */
@@ -300,8 +300,8 @@ EipStatus HandleReceivedExplictUdpData
 }
 
 void SkipEncapsulationHeader(ENIPMessage *const outgoing_message) {
-  MoveMessageNOctets(ENCAPSULATION_HEADER_LENGTH,
-                     (const CipOctet **)&outgoing_message->current_message_position);
+  /* Move pointer over Header, but do not add to size */
+  outgoing_message->current_message_position += ENCAPSULATION_HEADER_LENGTH;
 }
 
 void GenerateEncapsulationHeader(const EncapsulationData *const receive_data,
@@ -309,23 +309,15 @@ void GenerateEncapsulationHeader(const EncapsulationData *const receive_data,
                                  const size_t session_handle,
                                  const EncapsulationProtocolErrorCode encapsulation_protocol_status,
                                  ENIPMessage *const outgoing_message) {
-  outgoing_message->used_message_length += AddIntToMessage(
-    receive_data->command_code,
-    &outgoing_message->current_message_position);
-  outgoing_message->used_message_length += AddIntToMessage(
-    command_specific_data_length,
-    &outgoing_message->current_message_position);
-  outgoing_message->used_message_length += AddDintToMessage(session_handle,
-                                                            &outgoing_message->current_message_position); //Session handle
-  outgoing_message->used_message_length += AddDintToMessage(
-    encapsulation_protocol_status,
-    &outgoing_message->current_message_position);                                                         //Status
+  AddIntToMessage(receive_data->command_code, outgoing_message);
+  AddIntToMessage(command_specific_data_length, outgoing_message);
+  AddDintToMessage(session_handle, outgoing_message); //Session handle
+  AddDintToMessage(encapsulation_protocol_status, outgoing_message); //Status
   memcpy(outgoing_message->current_message_position,
          receive_data->sender_context, kSenderContextSize);                // sender context
   outgoing_message->current_message_position += kSenderContextSize;
   outgoing_message->used_message_length += kSenderContextSize;
-  outgoing_message->used_message_length += AddDintToMessage(0,
-                                                            &outgoing_message->current_message_position); // options
+  AddDintToMessage(0, outgoing_message); // options
 }
 
 /** @brief generate reply with "Communications Services" + compatibility Flags.
@@ -347,23 +339,18 @@ void HandleReceivedListServicesCommand(
                               outgoing_message);
 
   /* Command specific data copy Interface data to msg for sending */
-  outgoing_message->used_message_length += AddIntToMessage(1,
-                                                           &outgoing_message->current_message_position); // Item count
-  outgoing_message->used_message_length += AddIntToMessage(
-    g_service_information.type_code,
-    &outgoing_message->current_message_position);
-  outgoing_message->used_message_length += AddIntToMessage(
-    (EipUint16) (g_service_information.length - 4),
-    &outgoing_message->current_message_position);
-  outgoing_message->used_message_length += AddIntToMessage(
-    g_service_information.encapsulation_protocol_version,
-    &outgoing_message->current_message_position);
-  outgoing_message->used_message_length += AddIntToMessage(
-    g_service_information.capability_flags,
-    &outgoing_message->current_message_position);
+  AddIntToMessage(1, outgoing_message); // Item count
+  AddIntToMessage(g_service_information.type_code, outgoing_message);
+  AddIntToMessage( (EipUint16) (g_service_information.length - 4),
+                   outgoing_message );
+  AddIntToMessage(g_service_information.encapsulation_protocol_version,
+                  outgoing_message);
+  AddIntToMessage(g_service_information.capability_flags, outgoing_message);
   memcpy(outgoing_message->current_message_position,
          g_service_information.name_of_service,
          sizeof(g_service_information.name_of_service) );
+  outgoing_message->current_message_position +=
+    sizeof(g_service_information.name_of_service);
   outgoing_message->used_message_length +=
     sizeof(g_service_information.name_of_service);
 }
@@ -381,8 +368,7 @@ void HandleReceivedListInterfacesCommand(
                               kEncapsulationProtocolSuccess,
                               outgoing_message);
   /* Command specific data */
-  outgoing_message->used_message_length += AddIntToMessage(0x0000,
-                                                           &outgoing_message->current_message_position); /* Set Item Count to 0: no Target Items follow. */
+  AddIntToMessage(0x0000, outgoing_message); /* Set Item Count to 0: no Target Items follow. */
 }
 
 void HandleReceivedListIdentityCommandTcp(
@@ -432,59 +418,36 @@ CipUint ListIdentityGetCipIdentityItemLength() {
 void EncodeListIdentityCipIdentityItem(ENIPMessage *const outgoing_message) {
   /* Item ID*/
   const CipUint kItemIDCipIdentity = 0x0C;
-  outgoing_message->used_message_length += AddIntToMessage(
-    kItemIDCipIdentity,
-    &outgoing_message->current_message_position);
+  AddIntToMessage(kItemIDCipIdentity, outgoing_message);
 
-  outgoing_message->used_message_length += AddIntToMessage(
-    ListIdentityGetCipIdentityItemLength(),
-    &outgoing_message->current_message_position);
+  AddIntToMessage(ListIdentityGetCipIdentityItemLength(), outgoing_message);
 
-  outgoing_message->used_message_length += AddIntToMessage(
-    kSupportedProtocolVersion,
-    &outgoing_message->current_message_position);
+  AddIntToMessage(kSupportedProtocolVersion, outgoing_message);
 
-  outgoing_message->used_message_length += EncapsulateIpAddress(
-    htons(kOpenerEthernetPort), g_network_status.ip_address,
-    &outgoing_message->current_message_position);
+  EncapsulateIpAddress(htons(kOpenerEthernetPort),
+                       g_tcpip.interface_configuration.ip_address,
+                       outgoing_message);
 
   /** Array of USINT - length 8 shall be set to zero */
-  memset(outgoing_message->current_message_position, 0, 8);
-  outgoing_message->used_message_length += MoveMessageNOctets(8,
-                                                              (const CipOctet **) &outgoing_message->current_message_position);
-
-  outgoing_message->used_message_length += AddIntToMessage(g_identity.vendor_id,
-                                                           &outgoing_message->current_message_position);
-  outgoing_message->used_message_length += AddIntToMessage(
-    g_identity.device_type,
-    &outgoing_message->current_message_position);
-  outgoing_message->used_message_length += AddIntToMessage(
-    g_identity.product_code,
-    &outgoing_message->current_message_position);
-  *(outgoing_message->current_message_position)++ =
-    g_identity.revision.major_revision;
-  outgoing_message->used_message_length++;
-  *(outgoing_message->current_message_position)++ =
-    g_identity.revision.minor_revision;
-  outgoing_message->used_message_length++;
-  outgoing_message->used_message_length += AddIntToMessage(g_identity.status,
-                                                           &outgoing_message->current_message_position);
-  outgoing_message->used_message_length += AddDintToMessage(
-    g_identity.serial_number,
-    &outgoing_message->current_message_position);
-  *outgoing_message->current_message_position++ =
-    (unsigned char) g_identity.product_name.length;
-  outgoing_message->used_message_length++;
-
+  FillNextNMessageOctetsWithValueAndMoveToNextPosition(0, 8, outgoing_message);
+
+  AddIntToMessage(g_identity.vendor_id, outgoing_message);
+  AddIntToMessage(g_identity.device_type, outgoing_message);
+  AddIntToMessage(g_identity.product_code, outgoing_message);
+  AddSintToMessage(g_identity.revision.major_revision, outgoing_message);
+  AddSintToMessage(g_identity.revision.minor_revision, outgoing_message);
+  AddIntToMessage(g_identity.status, outgoing_message);
+  AddDintToMessage(g_identity.serial_number, outgoing_message);
+  AddSintToMessage( (unsigned char) g_identity.product_name.length,
+                    outgoing_message );
+//TODO Change to EncodeCipString
   memcpy(outgoing_message->current_message_position,
          g_identity.product_name.string,
          g_identity.product_name.length);
   outgoing_message->current_message_position += g_identity.product_name.length;
   outgoing_message->used_message_length += g_identity.product_name.length;
 
-  *outgoing_message->current_message_position++ = g_identity.state;
-  outgoing_message->used_message_length++;
-
+  AddSintToMessage(g_identity.state, outgoing_message);
 }
 
 void EncapsulateListIdentityResponseMessage(
@@ -502,17 +465,16 @@ void EncapsulateListIdentityResponseMessage(
                               kEncapsulationProtocolSuccess,
                               outgoing_message);
 
-  outgoing_message->used_message_length += AddIntToMessage(1,
-                                                           &outgoing_message->current_message_position); /* Item count: one item */
+  AddIntToMessage(1, outgoing_message); /* Item count: one item */
   EncodeListIdentityCipIdentityItem(outgoing_message);
 
 }
 
-void DetermineDelayTime(const EipByte *const buffer_start,
+void DetermineDelayTime(const EipByte *buffer_start,
                         DelayedEncapsulationMessage *const delayed_message_buffer)
 {
 
-  MoveMessageNOctets(12, (const CipOctet **) &buffer_start);       /* start of the sender context */
+  buffer_start += 12;             /* start of the sender context */
   EipUint16 maximum_delay_time = GetIntFromMessage(
     (const EipUint8 **const ) &buffer_start);
 
@@ -541,11 +503,8 @@ void EncapsulateRegisterSessionCommandResponseMessage(
                               encapsulation_protocol_status,
                               outgoing_message);
 
-  outgoing_message->used_message_length += AddIntToMessage(1,
-                                                           &outgoing_message->current_message_position); /* protocol version*/
-  outgoing_message->used_message_length += AddIntToMessage(
-    0,
-    &outgoing_message->current_message_position);                     /* Options flag, shall be set to zero */
+  AddIntToMessage(1, outgoing_message); /* protocol version*/
+  AddIntToMessage(0, outgoing_message); /* Options flag, shall be set to zero */
 }
 
 /* @brief Check supported protocol, generate session handle, send replay back to originator.

+ 66 - 77
source/src/enet_encap/endianconv.c

@@ -100,13 +100,12 @@ CipUdint GetUdintFromMessage(const CipOctet **const buffer_address) {
  * @param data value to be written
  * @param buffer pointer where data should be written.
  */
-int AddSintToMessage(const EipUint8 data,
-                     EipUint8 **const buffer) {
-  unsigned char *p = (unsigned char *) *buffer;
+void AddSintToMessage(const EipUint8 data,
+                      ENIPMessage *const outgoing_message) {
 
-  p[0] = (unsigned char) data;
-  *buffer += 1;
-  return 1;
+  outgoing_message->current_message_position[0] = (unsigned char) data;
+  outgoing_message->current_message_position += 1;
+  outgoing_message->used_message_length += 1;
 }
 
 /**
@@ -114,14 +113,13 @@ int AddSintToMessage(const EipUint8 data,
  * @param data value to be written
  * @param buffer pointer where data should be written.
  */
-int AddIntToMessage(const EipUint16 data,
-                    EipUint8 **const buffer) {
-  unsigned char *p = (unsigned char *) *buffer;
+void AddIntToMessage(const EipUint16 data,
+                     ENIPMessage *const outgoing_message) {
 
-  p[0] = (unsigned char) data;
-  p[1] = (unsigned char) (data >> 8);
-  *buffer += 2;
-  return 2;
+  outgoing_message->current_message_position[0] = (unsigned char) data;
+  outgoing_message->current_message_position[1] = (unsigned char) (data >> 8);
+  outgoing_message->current_message_position += 2;
+  outgoing_message->used_message_length += 2;
 }
 
 /**
@@ -129,17 +127,15 @@ int AddIntToMessage(const EipUint16 data,
  * @param data value to be written
  * @param buffer pointer where data should be written.
  */
-int AddDintToMessage(const EipUint32 data,
-                     EipUint8 **const buffer) {
-  unsigned char *p = (unsigned char *) *buffer;
-
-  p[0] = (unsigned char) data;
-  p[1] = (unsigned char) (data >> 8);
-  p[2] = (unsigned char) (data >> 16);
-  p[3] = (unsigned char) (data >> 24);
-  *buffer += 4;
-
-  return 4;
+void AddDintToMessage(const EipUint32 data,
+                      ENIPMessage *const outgoing_message) {
+  outgoing_message->current_message_position[0] = (unsigned char) data;
+  outgoing_message->current_message_position[1] = (unsigned char) (data >> 8);
+  outgoing_message->current_message_position[2] = (unsigned char) (data >> 16);
+  outgoing_message->current_message_position[3] = (unsigned char) (data >> 24);
+
+  outgoing_message->current_message_position += 4;
+  outgoing_message->used_message_length += 4;
 }
 
 #ifdef OPENER_SUPPORT_64BIT_DATATYPES
@@ -175,59 +171,51 @@ EipUint64 GetLintFromMessage(const EipUint8 **const buffer) {
  * @param data value to be written
  * @param buffer pointer where data should be written.
  */
-int AddLintToMessage(const EipUint64 data,
-                     EipUint8 **const buffer) {
-  EipUint8 *buffer_address = *buffer;
-  buffer_address[0] = (EipUint8) (data >> 56) & 0xFF;
-  buffer_address[1] = (EipUint8) (data >> 48) & 0xFF;
-  buffer_address[2] = (EipUint8) (data >> 40) & 0xFF;
-  buffer_address[3] = (EipUint8) (data >> 32) & 0xFF;
-  buffer_address[4] = (EipUint8) (data >> 24) & 0xFF;
-  buffer_address[5] = (EipUint8) (data >> 16) & 0xFF;
-  buffer_address[6] = (EipUint8) (data >> 8) & 0xFF;
-  buffer_address[7] = (EipUint8) (data) & 0xFF;
-  (*buffer) += 8;
-
-  return 8;
+void AddLintToMessage(const EipUint64 data,
+                      ENIPMessage *const outgoing_message) {
+
+  outgoing_message->current_message_position[0] = (EipUint8) (data);
+  outgoing_message->current_message_position[1] = (EipUint8) (data >> 8);
+  outgoing_message->current_message_position[2] = (EipUint8) (data >> 16);
+  outgoing_message->current_message_position[3] = (EipUint8) (data >> 24);
+  outgoing_message->current_message_position[4] = (EipUint8) (data >> 32);
+  outgoing_message->current_message_position[5] = (EipUint8) (data >> 40);
+  outgoing_message->current_message_position[6] = (EipUint8) (data >> 48);
+  outgoing_message->current_message_position[7] = (EipUint8) (data >> 56);
+  outgoing_message->current_message_position += 8;
+  outgoing_message->used_message_length += 8;
 }
 
 #endif
 
 
-int EncapsulateIpAddress(EipUint16 port,
-                         EipUint32 address,
-                         EipByte **communication_buffer) {
-  int size = 0;
+void EncapsulateIpAddress(EipUint16 port,
+                          EipUint32 address,
+                          ENIPMessage *const outgoing_message) {
   if (kOpENerEndianessLittle == g_opener_platform_endianess) {
-    size += AddIntToMessage(htons(AF_INET), communication_buffer);
-    size += AddIntToMessage(port, communication_buffer);
-    size += AddDintToMessage(address, communication_buffer);
+    AddIntToMessage(htons(AF_INET), outgoing_message);
+    AddIntToMessage(port, outgoing_message);
+    AddDintToMessage(address, outgoing_message);
 
   } else {
     if (kOpENerEndianessBig == g_opener_platform_endianess) {
-      (*communication_buffer)[0] = (unsigned char) (AF_INET >> 8);
-      (*communication_buffer)[1] = (unsigned char) AF_INET;
-      *communication_buffer += 2;
-      size += 2;
-
-      (*communication_buffer)[0] = (unsigned char) (port >> 8);
-      (*communication_buffer)[1] = (unsigned char) port;
-      *communication_buffer += 2;
-      size += 2;
-
-      (*communication_buffer)[3] = (unsigned char) address;
-      (*communication_buffer)[2] = (unsigned char) (address >> 8);
-      (*communication_buffer)[1] = (unsigned char) (address >> 16);
-      (*communication_buffer)[0] = (unsigned char) (address >> 24);
-      *communication_buffer += 4;
-      size += 4;
+
+      AddIntToMessage(htons(AF_INET), outgoing_message);
+
+      AddSintToMessage( (unsigned char) (port >> 8), outgoing_message );
+      AddSintToMessage( (unsigned char) port, outgoing_message );
+
+      AddSintToMessage( (unsigned char) address, outgoing_message );
+      AddSintToMessage( (unsigned char) (address >> 8), outgoing_message );
+      AddSintToMessage( (unsigned char) (address >> 16), outgoing_message );
+      AddSintToMessage( (unsigned char) (address >> 24), outgoing_message );
+
     } else {
       fprintf(stderr,
               "No endianess detected! Probably the DetermineEndianess function was not executed!");
       exit (EXIT_FAILURE);
     }
   }
-  return size;
 }
 
 /**
@@ -255,24 +243,25 @@ int GetEndianess() {
   return g_opener_platform_endianess;
 }
 
-int MoveMessageNOctets(const int amount_of_bytes_moved,
-                       const CipOctet **message_runner) {
-  (*message_runner) += amount_of_bytes_moved;
-  return amount_of_bytes_moved;
+void MoveMessageNOctets(const int amount_of_bytes_moved,
+                        ENIPMessage *const outgoing_message) {
+  outgoing_message->current_message_position += amount_of_bytes_moved;
+  outgoing_message->used_message_length += amount_of_bytes_moved;
 }
 
-int FillNextNMessageOctetsWith(CipOctet value,
-                               unsigned int amount_of_bytes_written,
-                               CipOctet **message) {
-  memset(*message, value, amount_of_bytes_written);
-  return amount_of_bytes_written;
+void FillNextNMessageOctetsWith(CipOctet value,
+                                unsigned int amount_of_bytes_written,
+                                ENIPMessage *const outgoing_message) {
+  memset(outgoing_message->current_message_position,
+         value,
+         amount_of_bytes_written);
 }
 
-int FillNextNMessageOctetsWithValueAndMoveToNextPosition(CipOctet value,
-                                                         unsigned int amount_of_filled_bytes,
-                                                         CipOctet **message) {
-  FillNextNMessageOctetsWith(value, amount_of_filled_bytes, message);
-  MoveMessageNOctets(amount_of_filled_bytes, (const CipOctet **)message);
-  return amount_of_filled_bytes;
+void FillNextNMessageOctetsWithValueAndMoveToNextPosition(CipOctet value,
+                                                          unsigned int amount_of_filled_bytes,
+                                                          ENIPMessage *const outgoing_message)
+{
+  FillNextNMessageOctetsWith(value, amount_of_filled_bytes, outgoing_message);
+  MoveMessageNOctets(amount_of_filled_bytes, outgoing_message);
 }
 

+ 21 - 20
source/src/enet_encap/endianconv.h

@@ -7,6 +7,7 @@
 #define OPENER_ENDIANCONV_H_
 
 #include "typedefs.h"
+#include "ciptypes.h"
 
 /** @file endianconv.h
  * @brief Responsible for Endianess conversion
@@ -57,8 +58,8 @@ CipUdint GetUdintFromMessage(const CipOctet **const buffer_address);
  * @param data value to be written
  * @param buffer pointer where data should be written.
  */
-int AddSintToMessage(const EipUint8 data,
-                     EipUint8 **const buffer);
+void AddSintToMessage(const EipUint8 data,
+                      ENIPMessage *const outgoing_message);
 
 /** @ingroup ENCAP
  *
@@ -68,8 +69,8 @@ int AddSintToMessage(const EipUint8 data,
  *
  * @return Length in bytes of the encoded message
  */
-int AddIntToMessage(const EipUint16 data,
-                    EipUint8 **const buffer);
+void AddIntToMessage(const EipUint16 data,
+                     ENIPMessage *const outgoing_message);
 
 /** @ingroup ENCAP
  *
@@ -79,8 +80,8 @@ int AddIntToMessage(const EipUint16 data,
  *
  * @return Length in bytes of the encoded message
  */
-int AddDintToMessage(const EipUint32 data,
-                     EipUint8 **const buffer);
+void AddDintToMessage(const EipUint32 data,
+                      ENIPMessage *const outgoing_message);
 
 #ifdef OPENER_SUPPORT_64BIT_DATATYPES
 
@@ -92,10 +93,9 @@ EipUint64 GetLintFromMessage(const EipUint8 **const buffer);
  * @param data value to write
  * @param buffer pointer to the network buffer array. This pointer will be incremented by 8!
  *
- * @return Length in bytes of the encoded message
  */
-int AddLintToMessage(const EipUint64 pa_unData,
-                     EipUint8 **const buffer);
+void AddLintToMessage(const EipUint64 pa_unData,
+                      ENIPMessage *const outgoing_message);
 
 #endif
 
@@ -107,9 +107,9 @@ int AddLintToMessage(const EipUint64 pa_unData,
  * @param address IP address of the socket, has to be provided in big-endian
  * @param communication_buffer The message buffer for sending the message
  */
-int EncapsulateIpAddress(EipUint16 port,
-                         EipUint32 address,
-                         EipByte **communication_buffer);
+void EncapsulateIpAddress(EipUint16 port,
+                          EipUint32 address,
+                          ENIPMessage *const outgoing_message);
 
 /** Identify if we are running on a big or little endian system and set
  * variable.
@@ -124,14 +124,15 @@ void DetermineEndianess(void);
  */
 int GetEndianess(void);
 
-int MoveMessageNOctets(const int n,
-                       const CipOctet **message_runner);
+void MoveMessageNOctets(const int amount_of_bytes_moved,
+                        ENIPMessage *const outgoing_message);
+
+void FillNextNMessageOctetsWith(CipOctet value,
+                                unsigned int amount_of_bytes_written,
+                                ENIPMessage *const outgoing_message);
 
-int FillNextNMessageOctetsWith(CipOctet value,
-                               unsigned int n,
-                               CipOctet **message);
+void FillNextNMessageOctetsWithValueAndMoveToNextPosition(CipOctet value,
+                                                          unsigned int amount_of_filled_bytes,
+                                                          ENIPMessage *const outgoing_message);
 
-int FillNextNMessageOctetsWithValueAndMoveToNextPosition(CipOctet value,
-                                                         unsigned int n,
-                                                         CipOctet **message);
 #endif /* OPENER_ENDIANCONV_H_ */

+ 84 - 16
source/src/opener_api.h

@@ -45,7 +45,8 @@ EipStatus IfaceGetConfiguration
  *  @return                   kEipStatusOk: all fine
  *                            kEipStatusError: failure, errno set
  */
-EipStatus IfaceGetMacAddress(const char *iface, uint8_t *const physical_address);
+EipStatus IfaceGetMacAddress(const char *iface,
+                             uint8_t *const physical_address);
 
 /** @ingroup CIP_API
  * @brief Wait for the network interface having an IP address
@@ -100,7 +101,7 @@ void SetDeviceStatus(const CipWord status);
  * @param unique_connection_id value passed to Connection_Manager_Init() to form
  * a "per boot" unique connection ID.
  */
-void CipStackInit(const EipUint16 unique_connection_id);
+EipStatus CipStackInit(const EipUint16 unique_connection_id);
 
 /** @ingroup CIP_API
  * @brief Shutdown of the CIP stack
@@ -229,13 +230,15 @@ CipInstance *AddCipInstance(CipClass *RESTRICT const cip_class_to_add_instance,
  *  @param cip_instance Pointer to CIP class instance (Instance 0)
  *  @param attribute_number Number of attribute to be inserted.
  *  @param cip_data_type Type of attribute to be inserted.
+ *  @param encode_function Function pointer to the encoding function
  *  @param cip_data Pointer to data of attribute.
  *  @param cip_flags Flags to indicate set-ability and get-ability of attribute.
  */
-void InsertAttribute(CipInstance *const cip_instance,
+void InsertAttribute(CipInstance *const instance,
                      const EipUint16 attribute_number,
-                     const EipUint8 cip_data_type,
-                     void *const cip_data,
+                     const EipUint8 cip_type,
+                     CipAttributeEncodeInMessage encode_function,
+                     void *const data,
                      const EipByte cip_flags);
 
 
@@ -292,9 +295,11 @@ void InsertGetSetCallback
 (
   CipClass *const cip_class,
   CipGetSetCallback callback_function,
-  CIPAttributeFlag  callbacks_to_install
+  CIPAttributeFlag callbacks_to_install
 );
 
+
+//TODO: Update documentation
 /** @ingroup CIP_API
  * @brief Produce the data according to CIP encoding onto the message buffer.
  *
@@ -302,13 +307,78 @@ void InsertGetSetCallback
  * requester (e.g., getAttributeSingle for special structs).
  *  @param cip_data_type the cip type to encode
  *  @param cip_data pointer to data value.
- *  @param cip_message pointer to memory where response should be written
- *  @return length of attribute in bytes
- *          -1 .. error
+ *  @param message_router_response The message router response construct
  */
-int EncodeData(const EipUint8 cip_data_type,
-               const void *const cip_data,
-               EipUint8 **cip_message);
+
+
+void EncodeCipBool(const CipBool *const data,
+                   ENIPMessage *const outgoing_message);
+
+void EncodeCipByte(const CipByte *const data,
+                   ENIPMessage *const outgoing_message);
+
+void EncodeCipWord(const CipWord *const data,
+                   ENIPMessage *const outgoing_message);
+
+void EncodeCipDword(const CipDword *const data,
+                    ENIPMessage *const outgoing_message);
+
+void EncodeCipLword(const CipLword *const data,
+                    ENIPMessage *const outgoing_message);
+
+void EncodeCipUsint(const CipUsint *const data,
+                    ENIPMessage *const outgoing_message);
+
+void EncodeCipUint(const CipUint *const data,
+                   ENIPMessage *const outgoing_message);
+
+void EncodeCipUdint(const CipUdint *const data,
+                    ENIPMessage *const outgoing_message);
+
+void EncodeCipUlint(const CipUlint *const data,
+                    ENIPMessage *const outgoing_message);
+
+void EncodeCipSint(const CipSint *const data,
+                   ENIPMessage *const outgoing_message);
+
+void EncodeCipInt(const CipInt *const data,
+                  ENIPMessage *const outgoing_message);
+
+void EncodeCipDint(const CipDint *const data,
+                   ENIPMessage *const outgoing_message);
+
+void EncodeCipLint(const CipLint *const data,
+                   ENIPMessage *const outgoing_message);
+
+void EncodeCipReal(const CipReal *const data,
+                   ENIPMessage *const outgoing_message);
+
+void EncodeCipLreal(const CipLreal *const data,
+                    ENIPMessage *const outgoing_message);
+
+void EncodeCipShortString(const CipShortString *const data,
+                          ENIPMessage *const outgoing_message);
+
+void EncodeCipString(const CipString *const data,
+                     ENIPMessage *const outgoing_message);
+
+void EncodeCipString2(const CipString2 *const data,
+                      ENIPMessage *const outgoing_message);
+
+void EncodeCipStringN(const CipStringN *const data,
+                      ENIPMessage *const outgoing_message);
+
+void EncodeCipStringI(const CipStringI *const data,
+                      ENIPMessage *const outgoing_message);
+
+void EncodeCipByteArray(const CipByteArray *const data,
+                        ENIPMessage *const outgoing_message);
+
+void EncodeCipEPath(const CipEpath *const data,
+                    ENIPMessage *const outgoing_message);
+
+void EncodeCipEthernetLinkPhyisicalAddress(const void *const data,
+                                           ENIPMessage *const outgoing_message);
 
 /** @ingroup CIP_API
  * @brief Retrieve the given data according to CIP encoding from the message
@@ -745,15 +815,13 @@ int CreateUdpSocket(UdpCommuncationDirection communication_direction,
  *
  * @param socket_data Pointer to the "send to" address
  * @param socket_handle Socket descriptor to send on
- * @param data Pointer to the data to send
- * @param data_length Length of the data to send
+ * @param outgoing message The constructed outgoing message
  * @return kEipStatusOk on success
  */
 EipStatus
 SendUdpData(struct sockaddr_in *socket_data,
             int socket_handle,
-            EipUint8 *data,
-            EipUint16 data_length);
+            const ENIPMessage *const outgoing_message);
 
 /** @ingroup CIP_CALLBACK_API
  * @brief Close the given socket and clean up the stack

+ 1 - 0
source/src/ports/MINGW/CMakeLists.txt

@@ -26,6 +26,7 @@ if( OpENer_HAS_ADDITIONAL_OBJECT )
   message(STATUS "Additional activated objects: ${OpENer_ADD_CIP_OBJECTS}")
   string(REPLACE " " ";" OpENer_ADD_CIP_OBJECTS_LIST ${OpENer_ADD_CIP_OBJECTS} )
   foreach(CIP_OBJECT IN LISTS OpENer_ADD_CIP_OBJECTS_LIST)
+    include_directories(${${CIP_OBJECT}_SOURCE_DIR})
     target_link_libraries( OpENer ${CIP_OBJECT} )
   endforeach()
 else()

+ 11 - 9
source/src/ports/MINGW/main.c

@@ -49,7 +49,8 @@ static DWORD executeEventLoop(LPVOID thread_arg);
 volatile int g_end_stack = 0;
 
 /******************************************************************************/
-int main(int argc, char *arg[]) {
+int main(int argc,
+         char *arg[]) {
 
   if (argc != 2) {
     fprintf(stderr, "Wrong number of command line parameters!\n");
@@ -64,7 +65,7 @@ int main(int argc, char *arg[]) {
   /* Fetch MAC address from the platform. This tests also if the interface
    *  is present. */
   uint8_t iface_mac[6];
-  if (kEipStatusError == IfaceGetMacAddress(arg[1], iface_mac)) {
+  if (kEipStatusError == IfaceGetMacAddress(arg[1], iface_mac) ) {
     printf("Network interface %s not found.\n", arg[1]);
     exit(EXIT_FAILURE);
   }
@@ -94,15 +95,15 @@ int main(int argc, char *arg[]) {
    *  After that any NV data values are loaded to change the attribute contents
    *  to the stored configuration.
    */
-  if (kEipStatusError == NvdataLoad()) {
+  if (kEipStatusError == NvdataLoad() ) {
     OPENER_TRACE_WARN("Loading of some NV data failed. Maybe the first start?\n");
   }
 
   /* Bring up network interface or start DHCP client ... */
   EipStatus status = BringupNetwork(arg[1],
-                       g_tcpip.config_control,
-                       &g_tcpip.interface_configuration,
-                       &g_tcpip.hostname);
+                                    g_tcpip.config_control,
+                                    &g_tcpip.interface_configuration,
+                                    &g_tcpip.hostname);
   if (status < 0) {
     OPENER_TRACE_ERR("BringUpNetwork() failed\n");
   }
@@ -114,7 +115,8 @@ int main(int argc, char *arg[]) {
   signal(SIGTERM, LeaveStack);
 
   /* Next actions depend on the set network configuration method. */
-  CipDword network_config_method = g_tcpip.config_control & kTcpipCfgCtrlMethodMask;
+  CipDword network_config_method = g_tcpip.config_control &
+                                   kTcpipCfgCtrlMethodMask;
   if (kTcpipCfgCtrlStaticIp == network_config_method) {
     OPENER_TRACE_INFO("Static network configuration done\n");
   }
@@ -137,7 +139,7 @@ int main(int argc, char *arg[]) {
 
 
   /* The network initialization of the EIP stack for the NetworkHandler. */
-  if (!g_end_stack && kEipStatusOk == NetworkHandlerInitialize()) {
+  if (!g_end_stack && kEipStatusOk == NetworkHandlerInitialize() ) {
 
     (void) executeEventLoop(NULL);
 
@@ -153,7 +155,7 @@ int main(int argc, char *arg[]) {
 
   if(0 != g_end_stack) {
     printf("OpENer aborted by signal %d.\n", g_end_stack);
-    return RET_SHOW_SIGNAL+g_end_stack;
+    return RET_SHOW_SIGNAL + g_end_stack;
   }
 
   return EXIT_SUCCESS;

+ 1 - 0
source/src/ports/POSIX/CMakeLists.txt

@@ -49,6 +49,7 @@ if( OpENer_HAS_ADDITIONAL_OBJECT )
   message(STATUS "Additional activated objects: ${OpENer_ADD_CIP_OBJECTS}")
   string(REPLACE " " ";" OpENer_ADD_CIP_OBJECTS_LIST ${OpENer_ADD_CIP_OBJECTS} )
   foreach(CIP_OBJECT IN LISTS OpENer_ADD_CIP_OBJECTS_LIST)
+    include_directories(${${CIP_OBJECT}_SOURCE_DIR})
     target_link_libraries( OpENer ${CIP_OBJECT} )
   endforeach()
 else()

+ 23 - 18
source/src/ports/POSIX/main.c

@@ -56,7 +56,8 @@ static void *executeEventLoop(void *pthread_arg);
 volatile int g_end_stack = 0;
 
 /******************************************************************************/
-int main(int argc, char *arg[]) {
+int main(int argc,
+         char *arg[]) {
 
   cap_t capabilities;
   cap_value_t capabilities_list[1];
@@ -100,7 +101,7 @@ int main(int argc, char *arg[]) {
   /* Fetch MAC address from the platform. This tests also if the interface
    *  is present. */
   uint8_t iface_mac[6];
-  if (kEipStatusError == IfaceGetMacAddress(arg[1], iface_mac)) {
+  if (kEipStatusError == IfaceGetMacAddress(arg[1], iface_mac) ) {
     printf("Network interface %s not found.\n", arg[1]);
     exit(EXIT_FAILURE);
   }
@@ -115,7 +116,7 @@ int main(int argc, char *arg[]) {
 
   /* Setup the CIP Layer. All objects are initialized with the default
    * values for the attribute contents. */
-  CipStackInit(unique_connection_id);
+  EipStatus eip_status = CipStackInit(unique_connection_id);
 
   CipEthernetLinkSetMac(iface_mac);
 
@@ -130,16 +131,16 @@ int main(int argc, char *arg[]) {
    *  After that any NV data values are loaded to change the attribute contents
    *  to the stored configuration.
    */
-  if (kEipStatusError == NvdataLoad()) {
+  if (kEipStatusError == NvdataLoad() ) {
     OPENER_TRACE_WARN("Loading of some NV data failed. Maybe the first start?\n");
   }
 
   /* Bring up network interface or start DHCP client ... */
-  EipStatus status = BringupNetwork(arg[1],
-                       g_tcpip.config_control,
-                       &g_tcpip.interface_configuration,
-                       &g_tcpip.hostname);
-  if (status < 0) {
+  eip_status = BringupNetwork(arg[1],
+                              g_tcpip.config_control,
+                              &g_tcpip.interface_configuration,
+                              &g_tcpip.hostname);
+  if (eip_status < 0) {
     OPENER_TRACE_ERR("BringUpNetwork() failed\n");
   }
 
@@ -149,7 +150,8 @@ int main(int argc, char *arg[]) {
   signal(SIGINT, LeaveStack); /* needed to be able to abort with ^C */
 
   /* Next actions depend on the set network configuration method. */
-  CipDword network_config_method = g_tcpip.config_control & kTcpipCfgCtrlMethodMask;
+  CipDword network_config_method = g_tcpip.config_control &
+                                   kTcpipCfgCtrlMethodMask;
   if (kTcpipCfgCtrlStaticIp == network_config_method) {
     OPENER_TRACE_INFO("Static network configuration done\n");
   }
@@ -157,14 +159,17 @@ int main(int argc, char *arg[]) {
     OPENER_TRACE_INFO("DHCP network configuration started\n");
     /* DHCP should already have been started with BringupNetwork(). Wait
      * here for IP present (DHCP done) or abort through g_end_stack. */
-    status = IfaceWaitForIp(arg[1], -1, &g_end_stack);
-    OPENER_TRACE_INFO("DHCP wait for interface: status %d, g_end_stack=%d\n",
-                      status, g_end_stack);
-    if (kEipStatusOk == status && 0 == g_end_stack) {
+    eip_status = IfaceWaitForIp(arg[1], -1, &g_end_stack);
+    OPENER_TRACE_INFO(
+      "DHCP wait for interface: eip_status %d, g_end_stack=%d\n",
+      eip_status,
+      g_end_stack);
+    if (kEipStatusOk == eip_status && 0 == g_end_stack) {
       /* Read IP configuration received via DHCP from interface and store in
        *  the TCP/IP object.*/
-      status = IfaceGetConfiguration(arg[1], &g_tcpip.interface_configuration);
-      if (status < 0) {
+      eip_status = IfaceGetConfiguration(arg[1],
+                                         &g_tcpip.interface_configuration);
+      if (eip_status < 0) {
         OPENER_TRACE_WARN("Problems getting interface configuration\n");
       }
     }
@@ -172,7 +177,7 @@ int main(int argc, char *arg[]) {
 
 
   /* The network initialization of the EIP stack for the NetworkHandler. */
-  if (!g_end_stack && kEipStatusOk == NetworkHandlerInitialize()) {
+  if (!g_end_stack && kEipStatusOk == NetworkHandlerInitialize() ) {
 #ifdef OPENER_RT
     int ret;
 
@@ -247,7 +252,7 @@ int main(int argc, char *arg[]) {
 
   if(0 != g_end_stack) {
     printf("OpENer aborted by signal %d.\n", g_end_stack);
-    return RET_SHOW_SIGNAL+g_end_stack;
+    return RET_SHOW_SIGNAL + g_end_stack;
   }
 
   return EXIT_SUCCESS;

+ 1 - 1
source/src/ports/POSIX/sample_application/sampleapplication.c

@@ -102,7 +102,7 @@ EipStatus ApplicationInitialization(void) {
     {
       CipAttributeStruct *p_eth_link_attr;
       CipInstance *p_eth_link_inst =
-        GetCipInstance(p_eth_link_class, idx+1);
+        GetCipInstance(p_eth_link_class, idx + 1);
       OPENER_ASSERT(p_eth_link_inst);
 
       /* Interface counters attribute */

+ 1 - 0
source/src/ports/WIN32/CMakeLists.txt

@@ -26,6 +26,7 @@ if( OpENer_HAS_ADDITIONAL_OBJECT )
   message(STATUS "Additional activated objects: ${OpENer_ADD_CIP_OBJECTS}")
   string(REPLACE " " ";" OpENer_ADD_CIP_OBJECTS_LIST ${OpENer_ADD_CIP_OBJECTS} )
   foreach(CIP_OBJECT IN LISTS OpENer_ADD_CIP_OBJECTS_LIST)
+    include_directories(${${CIP_OBJECT}_SOURCE_DIR})
     target_link_libraries( OpENer ${CIP_OBJECT} )
   endforeach()
 else()

+ 19 - 14
source/src/ports/generic_networkhandler.c

@@ -217,7 +217,7 @@ EipStatus NetworkHandlerInitialize(void) {
     int error_code = GetSocketErrorNumber();
     char *error_message = GetErrorMessage(error_code);
     OPENER_TRACE_ERR( "error with UDP unicast bind: %d - %s\n",
-                     error_code, error_message);
+                      error_code, error_message);
     FreeErrorMessage(error_message);
     return kEipStatusError;
   }
@@ -617,8 +617,7 @@ void CheckAndHandleUdpUnicastSocket(void) {
 
 EipStatus SendUdpData(struct sockaddr_in *address,
                       int socket_handle,
-                      EipUint8 *data,
-                      EipUint16 data_length) {
+                      const ENIPMessage *const outgoing_message) {
 
 
 
@@ -626,23 +625,29 @@ EipStatus SendUdpData(struct sockaddr_in *address,
   UDPHeader header = {
     .source_port = 2222,
     .destination_port = ntohs(address->sin_port),
-    .packet_length = kUdpHeaderLength + data_length,
+    .packet_length = kUdpHeaderLength + outgoing_message->used_message_length,
     .checksum = 0
   };
 
   char complete_message[PC_OPENER_ETHERNET_BUFFER_SIZE];
-  memcpy(complete_message + kUdpHeaderLength, data, data_length);
+  memcpy(complete_message + kUdpHeaderLength,
+         outgoing_message->message_buffer,
+         outgoing_message->used_message_length);
   UDPHeaderGenerate(&header, (char *)complete_message);
   UDPHeaderSetChecksum(&header,
                        htons(UDPHeaderCalculateChecksum(complete_message,
-                                                        8 + data_length,
-                                                        g_network_status.ip_address,
+                                                        8 +
+                                                        outgoing_message->
+                                                        used_message_length,
+                                                        g_tcpip.
+                                                        interface_configuration
+                                                        .ip_address,
                                                         address->sin_addr.s_addr) ) );
   UDPHeaderGenerate(&header, (char *)complete_message);
 
   int sent_length = sendto( socket_handle,
                             (char *) complete_message,
-                            data_length + kUdpHeaderLength,
+                            outgoing_message->used_message_length + kUdpHeaderLength,
                             0,
                             (struct sockaddr *) address,
                             sizeof(*address) );
@@ -658,11 +663,11 @@ EipStatus SendUdpData(struct sockaddr_in *address,
     return kEipStatusError;
   }
 
-  if (sent_length != data_length + kUdpHeaderLength) {
+  if (sent_length != outgoing_message->used_message_length + kUdpHeaderLength) {
     OPENER_TRACE_WARN(
       "data length sent_length mismatch; probably not all data was sent in SendUdpData, sent %d of %d\n",
       sent_length,
-      data_length);
+      outgoing_message->used_message_length);
     return kEipStatusError;
   }
 
@@ -729,7 +734,7 @@ EipStatus HandleDataOnTcpSocket(int socket) {
       OPENER_TRACE_INFO(
         "Entering consumption loop, remaining data to receive: %ld\n",
         data_sent);
-      number_of_read_bytes = recv(socket, NWBUF_CAST &incoming_message[0],
+      number_of_read_bytes = recv(socket, NWBUF_CAST & incoming_message[0],
                                   data_sent, 0);
 
       if (number_of_read_bytes == 0) /* got error or connection closed by client */
@@ -766,7 +771,7 @@ EipStatus HandleDataOnTcpSocket(int socket) {
     return kEipStatusOk;
   }
 
-  number_of_read_bytes = recv(socket, NWBUF_CAST &incoming_message[4],
+  number_of_read_bytes = recv(socket, NWBUF_CAST & incoming_message[4],
                               data_size, 0);
 
   if (0 == number_of_read_bytes) /* got error or connection closed by client */
@@ -958,7 +963,7 @@ int CreateUdpSocket(UdpCommuncationDirection communication_direction,
         == g_tcpip.mcast_config.starting_multicast_address) {
       if (1 != g_tcpip.mcast_ttl_value) { /* we need to set a TTL value for the socket */
         if ( setsockopt(new_socket, IPPROTO_IP, IP_MULTICAST_TTL,
-                        NWBUF_CAST &g_tcpip.mcast_ttl_value,
+                        NWBUF_CAST & g_tcpip.mcast_ttl_value,
                         sizeof(g_tcpip.mcast_ttl_value) ) < 0 ) {
           int error_code = GetSocketErrorNumber();
           char *error_message = GetErrorMessage(error_code);
@@ -976,7 +981,7 @@ int CreateUdpSocket(UdpCommuncationDirection communication_direction,
         struct in_addr my_addr =
         { .s_addr = g_network_status.ip_address };
         if ( setsockopt(new_socket, IPPROTO_IP, IP_MULTICAST_IF,
-                        NWBUF_CAST &my_addr.s_addr,
+                        NWBUF_CAST & my_addr.s_addr,
                         sizeof my_addr.s_addr ) < 0 ) {
           int error_code = GetSocketErrorNumber();
           char *error_message = GetErrorMessage(error_code);

+ 52 - 229
source/tests/cip/cipcommontests.cpp

@@ -10,257 +10,80 @@
 
 extern "C" {
 
-#include "cipcommon.h"
+#include "opener_api.h"
 
 }
 
-TEST_GROUP(CipCommon) {
-
-};
-
-TEST(CipCommon, GetSizeOfAttributeCipBool) {
-  CipAttributeStruct attribute;
-  attribute.type = kCipBool;
-  CHECK_EQUAL(sizeof(CipBool), GetSizeOfAttribute(&attribute) );
-}
-
-TEST(CipCommon, GetSizeOfAttributeCipSint) {
-  CipAttributeStruct attribute;
-  attribute.type = kCipSint;
-  CHECK_EQUAL(sizeof(CipSint), GetSizeOfAttribute(&attribute) );
-}
-
-TEST(CipCommon, GetSizeOfAttributeCipInt) {
-  CipAttributeStruct attribute;
-  attribute.type = kCipInt;
-  CHECK_EQUAL(sizeof(CipInt), GetSizeOfAttribute(&attribute) );
-}
-
-TEST(CipCommon, GetSizeOfAttributeCipDint) {
-  CipAttributeStruct attribute;
-  attribute.type = kCipDint;
-  CHECK_EQUAL(sizeof(CipDint), GetSizeOfAttribute(&attribute) );
-}
-
-TEST(CipCommon, GetSizeOfAttributeCipUsint) {
-  CipAttributeStruct attribute;
-  attribute.type = kCipUsint;
-  CHECK_EQUAL(sizeof(CipUsint), GetSizeOfAttribute(&attribute) );
-}
-
-TEST(CipCommon, GetSizeOfAttributeCipUint) {
-  CipAttributeStruct attribute;
-  attribute.type = kCipUint;
-  CHECK_EQUAL(sizeof(CipUint), GetSizeOfAttribute(&attribute) );
-}
-
-TEST(CipCommon, GetSizeOfAttributeCipUdint) {
-  CipAttributeStruct attribute;
-  attribute.type = kCipUdint;
-  CHECK_EQUAL(sizeof(CipUdint), GetSizeOfAttribute(&attribute) );
-}
-
-TEST(CipCommon, GetSizeOfAttributeCipReal) {
-  CipAttributeStruct attribute;
-  attribute.type = kCipReal;
-  CHECK_EQUAL(sizeof(CipReal), GetSizeOfAttribute(&attribute) );
-}
-
-#ifdef OPENER_SUPPORT_64BIT_DATATYPES
-TEST(CipCommon, GetSizeOfAttributeCipLreal) {
-  CipAttributeStruct attribute;
-  attribute.type = kCipLreal;
-  CHECK_EQUAL(sizeof(CipLreal), GetSizeOfAttribute(&attribute) );
-}
-
-TEST(CipCommon, GetSizeOfAttributeCipUlint) {
-  CipAttributeStruct attribute;
-  attribute.type = kCipUlint;
-  CHECK_EQUAL(sizeof(CipUlint), GetSizeOfAttribute(&attribute) );
-}
-
-TEST(CipCommon, GetSizeOfAttributeCipLint) {
-  CipAttributeStruct attribute;
-  attribute.type = kCipLint;
-  CHECK_EQUAL(sizeof(CipLint), GetSizeOfAttribute(&attribute) );
-}
-
-TEST(CipCommon, GetSizeOfAttributeCipLword) {
-  CipAttributeStruct attribute;
-  attribute.type = kCipLword;
-  CHECK_EQUAL(sizeof(CipLword), GetSizeOfAttribute(&attribute) );
-}
+ENIPMessage message; /**< Test variable holds ENIP message*/
 
-TEST(CipCommon, GetSizeOfAttributeCipLtime) {
-  CipAttributeStruct attribute;
-  attribute.type = kCipLtime;
-  CHECK_EQUAL(sizeof(CipLint), GetSizeOfAttribute(&attribute) );
-}
-#endif /* OPENER_SUPPORT_64BIT_DATATYPES */
-
-TEST(CipCommon, GetSizeOfAttributeCipStime) {
-  CipAttributeStruct attribute;
-  attribute.type = kCipStime;
-  CHECK_EQUAL(sizeof(CipDint), GetSizeOfAttribute(&attribute) );
-}
-
-TEST(CipCommon, GetSizeOfAttributeCipData) {
-  CipAttributeStruct attribute;
-  attribute.type = kCipDate;
-  CHECK_EQUAL(sizeof(CipUint), GetSizeOfAttribute(&attribute) );
-}
-
-TEST(CipCommon, GetSizeOfAttributeCipTimeOfDay) {
-  CipAttributeStruct attribute;
-  attribute.type = kCipTimeOfDay;
-  CHECK_EQUAL(sizeof(CipUdint), GetSizeOfAttribute(&attribute) );
-}
-
-TEST(CipCommon, GetSizeOfAttributeCipDateAndTime) {
-  CipAttributeStruct attribute;
-  attribute.type = kCipDateAndTime;
-  CHECK_EQUAL(sizeof(CipUdint) + sizeof(CipUint),
-              GetSizeOfAttribute(&attribute) );
-}
-
-TEST(CipCommon, GetSizeOfAttributeCipString) {
-  CipAttributeStruct attribute;
-  char demo_string[] = "Hello World!";
-  CipString test_string =
-  { .length = sizeof(demo_string), .string = (EipByte *)demo_string };
-  attribute.type = kCipString;
-  attribute.data = (void *)&test_string;
-
-  CHECK_EQUAL(
-    sizeof(test_string.length) + test_string.length * sizeof(CipOctet),
-    GetSizeOfAttribute(&attribute) );
-}
-
-TEST(CipCommon, GetSizeOfAttributeCipByte) {
-  CipAttributeStruct attribute;
-  attribute.type = kCipByte;
-  CHECK_EQUAL(sizeof(CipByte), GetSizeOfAttribute(&attribute) );
-}
-
-TEST(CipCommon, GetSizeOfAttributeCipWord) {
-  CipAttributeStruct attribute;
-  attribute.type = kCipWord;
-  CHECK_EQUAL(sizeof(CipWord), GetSizeOfAttribute(&attribute) );
-}
-
-TEST(CipCommon, GetSizeOfAttributeCipDword) {
-  CipAttributeStruct attribute;
-  attribute.type = kCipDword;
-  CHECK_EQUAL(sizeof(CipDword), GetSizeOfAttribute(&attribute) );
-}
-
-TEST(CipCommon, GetSizeOfAttributeCipString2) {
-  CipAttributeStruct attribute;
-  char demo_string[] = "H e l l o   W o r l d !"; /* \0 termination symbol is seen as second byte for ! */
-  CipString test_string =
-  { .length = sizeof(demo_string) / 2, .string = (EipByte *)demo_string };
-  attribute.type = kCipString;
-  attribute.data = (void *)&test_string;
-
-  CHECK_EQUAL(
-    sizeof(test_string.length) + test_string.length * sizeof(CipOctet),
-    GetSizeOfAttribute(&attribute) );
-}
-
-TEST(CipCommon, GetSizeOfAttributeCipFtime) {
-  CipAttributeStruct attribute;
-  attribute.type = kCipFtime;
-  CHECK_EQUAL(sizeof(CipDint), GetSizeOfAttribute(&attribute) );
-}
+TEST_GROUP(CipCommon) {
 
-TEST(CipCommon, GetSizeOfAttributeCipItime) {
-  CipAttributeStruct attribute;
-  attribute.type = kCipItime;
-  CHECK_EQUAL(sizeof(CipInt), GetSizeOfAttribute(&attribute) );
-}
+  void setup() {
+    InitializeENIPMessage(&message);
+  }
 
-TEST(CipCommon, GetSizeOfAttributeCipStringN) {
-  CipAttributeStruct attribute;
-  char demo_string[] = "Hello World!";
-  CipStringN test_string =
-  { .size = 1, .length = sizeof(demo_string),
-    .string = (EipByte *) demo_string };
-  attribute.type = kCipStringN;
-  attribute.data = (void *) &test_string;
+};
 
-  CHECK_EQUAL(
-    sizeof(test_string.size) + sizeof(test_string.length) + test_string.size * test_string.length *
-    sizeof(CipOctet),
-    GetSizeOfAttribute(
-      &attribute) );
+TEST(CipCommon, EncodeCipBool) {
+  const CipBool value = false;
+  EncodeCipBool(&value, &message);
+  CHECK_EQUAL(0, *(CipBool *)message.message_buffer);
+  POINTERS_EQUAL(message.message_buffer + 1, message.current_message_position);
 }
 
-TEST(CipCommon, GetSizeOfAttributeCipTime) {
-  CipAttributeStruct attribute;
-  attribute.type = kCipTime;
-  CHECK_EQUAL(sizeof(CipDint), GetSizeOfAttribute(&attribute) );
+TEST(CipCommon, EncodeCipByte) {
+  const CipByte value = 173U;
+  EncodeCipBool(&value, &message);
+  CHECK_EQUAL(value, *(CipByte *)message.message_buffer);
+  POINTERS_EQUAL(message.message_buffer + 1, message.current_message_position);
 }
 
-TEST(CipCommon, GetSizeOfAttributeCipEpath) {
-  /* TODO: Fix me */
-  CipAttributeStruct attribute;
-  attribute.type = kCipItime;
-  CHECK_EQUAL(sizeof(CipInt), GetSizeOfAttribute(&attribute) );
+TEST(CipCommon, EncodeCipWord) {
+  const CipWord value = 53678U;
+  EncodeCipWord(&value, &message);
+  CHECK_EQUAL(value, *(CipWord *)(message.message_buffer) );
+  POINTERS_EQUAL(message.message_buffer + 2, message.current_message_position);
 }
 
-TEST(CipCommon, GetSizeOfAttributeCipEngUnit) {
-  CipAttributeStruct attribute;
-  attribute.type = kCipEngUnit;
-  CHECK_EQUAL(sizeof(CipUint), GetSizeOfAttribute(&attribute) );
+TEST(CipCommon, EncodeCipDword) {
+  const CipDword value = 5357678U;
+  EncodeCipDword(&value, &message);
+  CHECK_EQUAL(value, *(CipDword *)(message.message_buffer) );
+  POINTERS_EQUAL(message.message_buffer + 4, message.current_message_position);
 }
 
-TEST(CipCommon, GetSizeOfAttributeCipUsintUsint) {
-  CipAttributeStruct attribute;
-  attribute.type = kCipUsintUsint;
-  CHECK_EQUAL(2 * sizeof(CipUsint), GetSizeOfAttribute(&attribute) );
+TEST(CipCommon, EncodeCipLword) {
+  const CipLword value = 8353457678U;
+  EncodeCipLword(&value, &message);
+  CHECK_EQUAL(value, *(CipLword *)(message.message_buffer) );
+  POINTERS_EQUAL(message.message_buffer + 8, message.current_message_position);
 }
 
-TEST(CipCommon, GetSizeOfAttributeCipUdintUdintUdintUdintUdintString) {
-  CipTcpIpInterfaceConfiguration config;
-  char domain_name[] = "www.github.com/EIPStackGroup/OpENer";
-  config.domain_name.length = sizeof(domain_name);
-  config.domain_name.string = (EipByte *)domain_name;
-  CipAttributeStruct attribute;
-  attribute.type = kCipUdintUdintUdintUdintUdintString;
-  attribute.data = (void *)&config;
-  CHECK_EQUAL(
-    5 * sizeof(CipUdint) + sizeof(CipUint) + sizeof(domain_name) *
-    sizeof(EipByte),
-    GetSizeOfAttribute(&attribute) );
-}
 
-TEST(CipCommon, GetSizeOfAttributeCip6Usint) {
-  CipAttributeStruct attribute;
-  attribute.type = kCip6Usint;
-  CHECK_EQUAL(6 * sizeof(CipUsint), GetSizeOfAttribute(&attribute) );
+TEST(CipCommon, EncodeCipUsint) {
+  const CipUsint value = 212U;
+  EncodeCipBool(&value, &message);
+  CHECK_EQUAL(value, *(CipUsint *)message.message_buffer);
+  POINTERS_EQUAL(message.message_buffer + 1, message.current_message_position);
 }
 
-TEST(CipCommon, GetSizeOfAttributeCipMemberList) {
-  CipAttributeStruct attribute;
-  attribute.type = kCipMemberList;
-  CHECK_EQUAL(0, GetSizeOfAttribute(&attribute) );
-  /* Currently not implemented */
+TEST(CipCommon, EncodeCipUint) {
+  const CipUint value = 42568U;
+  EncodeCipUint(&value, &message);
+  CHECK_EQUAL(value, *(CipUint *)(message.message_buffer) );
+  POINTERS_EQUAL(message.message_buffer + 2, message.current_message_position);
 }
 
-TEST(CipCommon, GetSizeOfAttributeCipByteArray) {
-  CipByte data_array[] = {1,2,3,4,5,6,7,8,9};
-  CipByteArray array;
-  array.data = (EipByte *)&data_array;
-  array.length = sizeof(data_array);
-  CipAttributeStruct attribute;
-  attribute.type = kCipByteArray;
-  attribute.data = (void *)&array;
-  CHECK_EQUAL(sizeof(CipUint) + array.length * sizeof(CipByte),
-              GetSizeOfAttribute(&attribute) );
+TEST(CipCommon, EncodeCipUdint) {
+  const CipUdint value = 1653245U;
+  EncodeCipUdint(&value, &message);
+  CHECK_EQUAL(value, *(CipUdint *)(message.message_buffer) );
+  POINTERS_EQUAL(message.message_buffer + 4, message.current_message_position);
 }
 
-TEST(CipCommon, GetSizeOfAttributeInternalUint6) {
-  CipAttributeStruct attribute;
-  attribute.type = kInternalUint6;
-  CHECK_EQUAL(6 * sizeof(CipUint), GetSizeOfAttribute(&attribute) );
+TEST(CipCommon, EncodeCipUlint) {
+  const CipUlint value = 5357678U;
+  EncodeCipUlint(&value, &message);
+  CHECK_EQUAL(value, *(CipUlint *)(message.message_buffer) );
+  POINTERS_EQUAL(message.message_buffer + 8, message.current_message_position);
 }

+ 58 - 55
source/tests/enet_encap/endianconvtest.cpp

@@ -65,92 +65,95 @@ TEST(EndianConversion, GetLintFromMessage) {
 
 TEST(EndianConversion, AddIntToMessage) {
   CipUint value_to_add_to_message = 0x5499;
-  CipOctet message[2];
-  CipOctet *message_pointer = message;
+  ENIPMessage message;
+  InitializeENIPMessage(&message);
 
-  AddIntToMessage(value_to_add_to_message, &message_pointer);
+  AddIntToMessage(value_to_add_to_message, &message);
 
-  BYTES_EQUAL(0x99, message[0]);
-  BYTES_EQUAL(0x54, message[1]);
+  BYTES_EQUAL(0x99, message.message_buffer[0]);
+  BYTES_EQUAL(0x54, message.message_buffer[1]);
 
-  POINTERS_EQUAL(message + 2, message_pointer)
+  POINTERS_EQUAL(message.message_buffer + 2, message.current_message_position)
 }
 
 TEST(EndianConversion, AddDintToMessage) {
   CipUdint value_to_add_to_message = 0x25E0C459;
-  CipOctet message[4];
-  CipOctet *message_pointer = message;
+  ENIPMessage message;
+  InitializeENIPMessage(&message);
 
-  AddDintToMessage(value_to_add_to_message, &message_pointer);
+  AddDintToMessage(value_to_add_to_message, &message);
 
-  BYTES_EQUAL(0x59, message[0]);
-  BYTES_EQUAL(0xC4, message[1]);
-  BYTES_EQUAL(0xE0, message[2]);
-  BYTES_EQUAL(0x25, message[3]);
+  BYTES_EQUAL(0x59, message.message_buffer[0]);
+  BYTES_EQUAL(0xC4, message.message_buffer[1]);
+  BYTES_EQUAL(0xE0, message.message_buffer[2]);
+  BYTES_EQUAL(0x25, message.message_buffer[3]);
 
-  POINTERS_EQUAL(message + 4, message_pointer)
+  POINTERS_EQUAL(message.message_buffer + 4, message.current_message_position)
 }
 
 TEST(EndianConversion, AddLintToMessage) {
   CipLint value_to_add_to_message = 0x2D2AEF0B84095230;
-  CipOctet message[8];
-  CipOctet *message_pointer = message;
+  ENIPMessage message;
+  InitializeENIPMessage(&message);
 
-  AddLintToMessage(value_to_add_to_message, &message_pointer);
+  AddLintToMessage(value_to_add_to_message, &message);
 
   /* Expected message from highest to lowest byte [30][52][09][84][0B][EF][2A][2D] */
-  BYTES_EQUAL(0x2D, message[0]);
-  BYTES_EQUAL(0x2A, message[1]);
-  BYTES_EQUAL(0xEF, message[2]);
-  BYTES_EQUAL(0x0B, message[3]);
-  BYTES_EQUAL(0x84, message[4]);
-  BYTES_EQUAL(0x09, message[5]);
-  BYTES_EQUAL(0x52, message[6]);
-  BYTES_EQUAL(0x30, message[7]);
-
-  POINTERS_EQUAL(message + 8, message_pointer)
+  BYTES_EQUAL(0x30, message.message_buffer[0]);
+  BYTES_EQUAL(0x52, message.message_buffer[1]);
+  BYTES_EQUAL(0x09, message.message_buffer[2]);
+  BYTES_EQUAL(0x84, message.message_buffer[3]);
+  BYTES_EQUAL(0x0B, message.message_buffer[4]);
+  BYTES_EQUAL(0xEF, message.message_buffer[5]);
+  BYTES_EQUAL(0x2A, message.message_buffer[6]);
+  BYTES_EQUAL(0x2D, message.message_buffer[7]);
+
+  POINTERS_EQUAL(message.message_buffer + 8, message.current_message_position)
 }
 
 TEST(EndianConversion, EncapsulateIpAddress) {
-  CipOctet ip_message[8];
-  CipOctet *ip_message_ponter = ip_message;
+  ENIPMessage message;
+  InitializeENIPMessage(&message);
 
   DetermineEndianess();
 
-  EncapsulateIpAddress(0xAF12, 0x25E0C459, &ip_message_ponter);
+  EncapsulateIpAddress(0xAF12, 0x25E0C459, &message);
 
-  BYTES_EQUAL(AF_INET >> 8, ip_message[0]);
-  BYTES_EQUAL(AF_INET, ip_message[1]);
-  BYTES_EQUAL(0x12, ip_message[2]);
-  BYTES_EQUAL(0xAF, ip_message[3]);
-  BYTES_EQUAL(0x59, ip_message[4]);
-  BYTES_EQUAL(0xC4, ip_message[5]);
-  BYTES_EQUAL(0xE0, ip_message[6]);
-  BYTES_EQUAL(0x25, ip_message[7]);
+  BYTES_EQUAL(AF_INET >> 8, message.message_buffer[0]);
+  BYTES_EQUAL(AF_INET, message.message_buffer[1]);
+  BYTES_EQUAL(0x12, message.message_buffer[2]);
+  BYTES_EQUAL(0xAF, message.message_buffer[3]);
+  BYTES_EQUAL(0x59, message.message_buffer[4]);
+  BYTES_EQUAL(0xC4, message.message_buffer[5]);
+  BYTES_EQUAL(0xE0, message.message_buffer[6]);
+  BYTES_EQUAL(0x25, message.message_buffer[7]);
+
+  POINTERS_EQUAL(message.message_buffer + 8, message.current_message_position)
 }
 
 TEST(EndianConversion, MoveMessageNOctets) {
-  const CipOctet message[] = "This is a test message";
-  const CipOctet *message_runner = message;
+  ENIPMessage message;
+  InitializeENIPMessage(&message);
 
-  MoveMessageNOctets(4, &message_runner);
+  MoveMessageNOctets(4, &message);
 
-  POINTERS_EQUAL(message + 4, message_runner);
+  POINTERS_EQUAL(message.message_buffer + 4, message.current_message_position);
 }
 
 TEST(EndianConversion, FillNextNMEssageOctetsWith) {
-  CipOctet message[8];
-  CipOctet *message_runner = message;
-  memset(message, 15, 8);
-
-  FillNextNMessageOctetsWith(0, 8, &message_runner);
-  BYTES_EQUAL(0, message_runner[0]);
-  BYTES_EQUAL(0, message_runner[1]);
-  BYTES_EQUAL(0, message_runner[2]);
-  BYTES_EQUAL(0, message_runner[3]);
-  BYTES_EQUAL(0, message_runner[4]);
-  BYTES_EQUAL(0, message_runner[5]);
-  BYTES_EQUAL(0, message_runner[6]);
-  BYTES_EQUAL(0, message_runner[7]);
+  ENIPMessage message;
+  InitializeENIPMessage(&message);
+  memset(message.message_buffer, 15, 8);
+
+  FillNextNMessageOctetsWith(0, 8, &message);
+  BYTES_EQUAL(0, message.message_buffer[0]);
+  BYTES_EQUAL(0, message.message_buffer[1]);
+  BYTES_EQUAL(0, message.message_buffer[2]);
+  BYTES_EQUAL(0, message.message_buffer[3]);
+  BYTES_EQUAL(0, message.message_buffer[4]);
+  BYTES_EQUAL(0, message.message_buffer[5]);
+  BYTES_EQUAL(0, message.message_buffer[6]);
+  BYTES_EQUAL(0, message.message_buffer[7]);
+  POINTERS_EQUAL(message.message_buffer, message.current_message_position);
 
 }

+ 10 - 0
source/tests/ports/socket_timer_tests.cpp

@@ -30,6 +30,16 @@ TEST(SocketTimer, NoEmptySocketTimerAvailable) {
   POINTERS_EQUAL( NULL, SocketTimerArrayGetEmptySocketTimer(timers, 10) );
 }
 
+TEST(SocketTimer, SetSocket) {
+  SocketTimer timer = {
+    socket : -1,
+    last_update : 0
+  };
+  SocketTimerSetSocket(&timer, 1);
+  CHECK_EQUAL( 1, timer.socket );
+}
+
+
 TEST(SocketTimer, UpdateSocketTimer) {
   SocketTimer timer = {
     socket : -1,