Explorar el Código

Add example using mingw

 .gitignore has added .idea/ to avoid checking in Clion project files

 README.md has got a description of how to build for mingw

 source/CMakeLists.txt has got one more platform, and the compiler options
 are added to avoid warnings from the gcc compiler.

 doublylinkedlist.c has got an added #include nedded when no tracing is
 enabled to avoid undefined NULL constant.

 The rest is the application. ConfigureNetworkInterface() is modified to
 ues the IP address as parameter, so the
 opener.exe can be started with ip address as argument and not interface
 number. The windows version also has
 several errors and could not be compiled. The
 DEMO_APP_CONFIG_ASSEMBLY_NUM has been changed from 151 to 1 in order
 to be tested against my PLS.

 Jan Kare Vatne (jkvatne@online.no)
Jan Kåre Vatne hace 7 años
padre
commit
25af5fa768

+ 1 - 0
.gitignore

@@ -10,3 +10,4 @@ source/src/cip_objects/
 *~
 CMakeCache.txt
 *.patch
+.idea/

+ 15 - 1
README.md

@@ -81,7 +81,21 @@ Compile for Windows XP/7/8:
 		OpENer interface_index
 
 		e.g. OpENer 3
- 
+		
+Compile for MinGW on Windows 10
+-------------------------------
+1. Make sure 64 bit mingw is installed. (Test with gcc --version, should show x86_64-posix-seh-rev1)
+2. Make sure Cmake is installed. (Test with cmake --version, should be version 3.xx)
+3. Change to <opener install dir>/bin/mingw
+4. Run the command `setup_mingw.bat` in a dos command line. (Not a bash shell). If tracing is desired, 
+use the following (where the cmake parameter must be enclosed in quotes) or change the ./source/CMakeList.txt file.
+    ```
+    setup_mingw.bat "-DOpENer_TRACES:BOOL=TRUE"
+    ```
+5. Run the command "make" from the same directory (./bin/mingw)
+6. The opener.exe is now found in <opener install dir>\bin\mingw\src\ports\MINGW
+7. Start it like this: "opener 192.168.250.22", where the ip address is the local computer's address on the nettwork you want to use.
+		
 Directory structure:
 --------------------
 - bin ...  The resulting binaries and make files for different ports

+ 5 - 2
source/CMakeLists.txt

@@ -18,7 +18,7 @@ set( OpENer_Device_Config_Device_Name "OpENer PC" CACHE STRING "Device Name")
 set( OpENer_VERSION_MAJOR 2 )
 set( OpENer_VERSION_MINOR 1 )
 
-configure_file( 
+configure_file(  
 	"${PROJECT_SOURCE_DIR}/src/ports/devicedata.h.in"
 	"${PROJECT_BINARY_DIR}/src/ports/devicedata.h"
 	)
@@ -42,7 +42,7 @@ endif()
 #######################################
 # Platform switches                   #
 #######################################
-set( OpENer_KNOWN_PLATFORMS "POSIX" "WIN32" )
+set( OpENer_KNOWN_PLATFORMS "POSIX" "WIN32" "MINGW")
 
 set( OpENer_PLATFORM CACHE STRINGS "Platform OpENer will be built for" )
 set_property(CACHE OpENer_PLATFORM PROPERTY STRINGS ${OpENer_KNOWN_PLATFORMS} )
@@ -88,6 +88,9 @@ endif( OpENer_TESTS )
 # OpENer C flags                      #
 #######################################
 set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall" )
+# The following extra flags are needed to compile without warnings on mingw
+# TODO: Fix the root problems and remove this line
+set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-unused-variable -Wno-incompatible-pointer-types -Wno-pointer-sign -Wno-format -Wno-discarded-qualifiers -Wno-unknown-pragmas" )
 
 ####################################################
 # Internal cache holding the available CIP objects #

+ 6 - 0
source/buildsupport/MINGW/OpENer_PLATFORM_INCLUDES.cmake

@@ -0,0 +1,6 @@
+macro(opener_platform_spec)
+  #find_path( MSINTTYPES_DIR inttypes.h ${PROJECT_SOURCE_DIR}/contrib/msinttypes)
+  include_directories(${PORTS_SRC_DIR}/${OpENer_PLATFORM} ${PORTS_SRC_DIR}/${OpENer_PLATFORM}/sample_application )
+  set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DRESTRICT=__restrict -DWIN32" )
+endmacro(opener_platform_spec)
+

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

@@ -0,0 +1,21 @@
+add_subdirectory(sample_application)
+
+set( PLATFORM_SPEC_SRC networkhandler.c opener_error.c networkconfig.c)
+
+#######################################
+# Add common includes                 #
+#######################################
+opener_common_includes()
+
+#######################################
+# Add platform specific things        #
+#######################################
+opener_platform_support("INCLUDES")
+
+set (PLATFORMLIBNAME ${OpENer_PLATFORM}PLATFORM)
+
+add_library( ${PLATFORMLIBNAME} ${PLATFORM_SPEC_SRC}) 
+
+add_executable(OpENer main.c)
+
+target_link_libraries( OpENer PLATFORM_GENERIC ${PLATFORMLIBNAME} CIP Utils  SAMPLE_APP ENET_ENCAP ws2_32 IPHLPAPI ${OpENer_CIP_OBJECTS} )

+ 285 - 0
source/src/ports/MINGW/Makefile

@@ -0,0 +1,285 @@
+# CMAKE generated file: DO NOT EDIT!
+# Generated by "MinGW Makefiles" Generator, CMake Version 3.12
+
+# Default target executed when no arguments are given to make.
+default_target: all
+
+.PHONY : default_target
+
+# Allow only one "make -f Makefile2" at a time, but pass parallelism.
+.NOTPARALLEL:
+
+
+#=============================================================================
+# Special targets provided by cmake.
+
+# Disable implicit rules so canonical targets will work.
+.SUFFIXES:
+
+
+# Remove some rules from gmake that .SUFFIXES does not remove.
+SUFFIXES =
+
+.SUFFIXES: .hpux_make_needs_suffix_list
+
+
+# Suppress display of executed commands.
+$(VERBOSE).SILENT:
+
+
+# A target that is always out of date.
+cmake_force:
+
+.PHONY : cmake_force
+
+#=============================================================================
+# Set environment variables for the build.
+
+SHELL = cmd.exe
+
+# The CMake executable.
+CMAKE_COMMAND = "C:\Program Files\JetBrains\CLion 2018.2.4\bin\cmake\win\bin\cmake.exe"
+
+# The command to remove a file.
+RM = "C:\Program Files\JetBrains\CLion 2018.2.4\bin\cmake\win\bin\cmake.exe" -E remove -f
+
+# Escaping for special characters.
+EQUALS = =
+
+# The top-level source directory on which CMake was run.
+CMAKE_SOURCE_DIR = C:\Doc\opener-jkvatne\source
+
+# The top-level build directory on which CMake was run.
+CMAKE_BINARY_DIR = C:\Doc\opener-jkvatne\source
+
+#=============================================================================
+# Targets provided globally by CMake.
+
+# Special rule for the target edit_cache
+edit_cache:
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "No interactive CMake dialog available..."
+	"C:\Program Files\JetBrains\CLion 2018.2.4\bin\cmake\win\bin\cmake.exe" -E echo "No interactive CMake dialog available."
+.PHONY : edit_cache
+
+# Special rule for the target edit_cache
+edit_cache/fast: edit_cache
+
+.PHONY : edit_cache/fast
+
+# Special rule for the target rebuild_cache
+rebuild_cache:
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake to regenerate build system..."
+	"C:\Program Files\JetBrains\CLion 2018.2.4\bin\cmake\win\bin\cmake.exe" -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)
+.PHONY : rebuild_cache
+
+# Special rule for the target rebuild_cache
+rebuild_cache/fast: rebuild_cache
+
+.PHONY : rebuild_cache/fast
+
+# The main all target
+all: cmake_check_build_system
+	cd /d C:\Doc\opener-jkvatne\source && $(CMAKE_COMMAND) -E cmake_progress_start C:\Doc\opener-jkvatne\source\CMakeFiles C:\Doc\opener-jkvatne\source\src\ports\WIN32\CMakeFiles\progress.marks
+	cd /d C:\Doc\opener-jkvatne\source && $(MAKE) -f CMakeFiles\Makefile2 src/ports/WIN32/all
+	$(CMAKE_COMMAND) -E cmake_progress_start C:\Doc\opener-jkvatne\source\CMakeFiles 0
+.PHONY : all
+
+# The main clean target
+clean:
+	cd /d C:\Doc\opener-jkvatne\source && $(MAKE) -f CMakeFiles\Makefile2 src/ports/WIN32/clean
+.PHONY : clean
+
+# The main clean target
+clean/fast: clean
+
+.PHONY : clean/fast
+
+# Prepare targets for installation.
+preinstall: all
+	cd /d C:\Doc\opener-jkvatne\source && $(MAKE) -f CMakeFiles\Makefile2 src/ports/WIN32/preinstall
+.PHONY : preinstall
+
+# Prepare targets for installation.
+preinstall/fast:
+	cd /d C:\Doc\opener-jkvatne\source && $(MAKE) -f CMakeFiles\Makefile2 src/ports/WIN32/preinstall
+.PHONY : preinstall/fast
+
+# clear depends
+depend:
+	cd /d C:\Doc\opener-jkvatne\source && $(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles\Makefile.cmake 1
+.PHONY : depend
+
+# Convenience name for target.
+src/ports/WIN32/CMakeFiles/WIN32PLATFORM.dir/rule:
+	cd /d C:\Doc\opener-jkvatne\source && $(MAKE) -f CMakeFiles\Makefile2 src/ports/WIN32/CMakeFiles/WIN32PLATFORM.dir/rule
+.PHONY : src/ports/WIN32/CMakeFiles/WIN32PLATFORM.dir/rule
+
+# Convenience name for target.
+WIN32PLATFORM: src/ports/WIN32/CMakeFiles/WIN32PLATFORM.dir/rule
+
+.PHONY : WIN32PLATFORM
+
+# fast build rule for target.
+WIN32PLATFORM/fast:
+	cd /d C:\Doc\opener-jkvatne\source && $(MAKE) -f src\ports\WIN32\CMakeFiles\WIN32PLATFORM.dir\build.make src/ports/WIN32/CMakeFiles/WIN32PLATFORM.dir/build
+.PHONY : WIN32PLATFORM/fast
+
+# Convenience name for target.
+src/ports/WIN32/CMakeFiles/OpENer.dir/rule:
+	cd /d C:\Doc\opener-jkvatne\source && $(MAKE) -f CMakeFiles\Makefile2 src/ports/WIN32/CMakeFiles/OpENer.dir/rule
+.PHONY : src/ports/WIN32/CMakeFiles/OpENer.dir/rule
+
+# Convenience name for target.
+OpENer: src/ports/WIN32/CMakeFiles/OpENer.dir/rule
+
+.PHONY : OpENer
+
+# fast build rule for target.
+OpENer/fast:
+	cd /d C:\Doc\opener-jkvatne\source && $(MAKE) -f src\ports\WIN32\CMakeFiles\OpENer.dir\build.make src/ports/WIN32/CMakeFiles/OpENer.dir/build
+.PHONY : OpENer/fast
+
+main.obj: main.c.obj
+
+.PHONY : main.obj
+
+# target to build an object file
+main.c.obj:
+	cd /d C:\Doc\opener-jkvatne\source && $(MAKE) -f src\ports\WIN32\CMakeFiles\OpENer.dir\build.make src/ports/WIN32/CMakeFiles/OpENer.dir/main.c.obj
+.PHONY : main.c.obj
+
+main.i: main.c.i
+
+.PHONY : main.i
+
+# target to preprocess a source file
+main.c.i:
+	cd /d C:\Doc\opener-jkvatne\source && $(MAKE) -f src\ports\WIN32\CMakeFiles\OpENer.dir\build.make src/ports/WIN32/CMakeFiles/OpENer.dir/main.c.i
+.PHONY : main.c.i
+
+main.s: main.c.s
+
+.PHONY : main.s
+
+# target to generate assembly for a file
+main.c.s:
+	cd /d C:\Doc\opener-jkvatne\source && $(MAKE) -f src\ports\WIN32\CMakeFiles\OpENer.dir\build.make src/ports/WIN32/CMakeFiles/OpENer.dir/main.c.s
+.PHONY : main.c.s
+
+networkconfig.obj: networkconfig.c.obj
+
+.PHONY : networkconfig.obj
+
+# target to build an object file
+networkconfig.c.obj:
+	cd /d C:\Doc\opener-jkvatne\source && $(MAKE) -f src\ports\WIN32\CMakeFiles\WIN32PLATFORM.dir\build.make src/ports/WIN32/CMakeFiles/WIN32PLATFORM.dir/networkconfig.c.obj
+.PHONY : networkconfig.c.obj
+
+networkconfig.i: networkconfig.c.i
+
+.PHONY : networkconfig.i
+
+# target to preprocess a source file
+networkconfig.c.i:
+	cd /d C:\Doc\opener-jkvatne\source && $(MAKE) -f src\ports\WIN32\CMakeFiles\WIN32PLATFORM.dir\build.make src/ports/WIN32/CMakeFiles/WIN32PLATFORM.dir/networkconfig.c.i
+.PHONY : networkconfig.c.i
+
+networkconfig.s: networkconfig.c.s
+
+.PHONY : networkconfig.s
+
+# target to generate assembly for a file
+networkconfig.c.s:
+	cd /d C:\Doc\opener-jkvatne\source && $(MAKE) -f src\ports\WIN32\CMakeFiles\WIN32PLATFORM.dir\build.make src/ports/WIN32/CMakeFiles/WIN32PLATFORM.dir/networkconfig.c.s
+.PHONY : networkconfig.c.s
+
+networkhandler.obj: networkhandler.c.obj
+
+.PHONY : networkhandler.obj
+
+# target to build an object file
+networkhandler.c.obj:
+	cd /d C:\Doc\opener-jkvatne\source && $(MAKE) -f src\ports\WIN32\CMakeFiles\WIN32PLATFORM.dir\build.make src/ports/WIN32/CMakeFiles/WIN32PLATFORM.dir/networkhandler.c.obj
+.PHONY : networkhandler.c.obj
+
+networkhandler.i: networkhandler.c.i
+
+.PHONY : networkhandler.i
+
+# target to preprocess a source file
+networkhandler.c.i:
+	cd /d C:\Doc\opener-jkvatne\source && $(MAKE) -f src\ports\WIN32\CMakeFiles\WIN32PLATFORM.dir\build.make src/ports/WIN32/CMakeFiles/WIN32PLATFORM.dir/networkhandler.c.i
+.PHONY : networkhandler.c.i
+
+networkhandler.s: networkhandler.c.s
+
+.PHONY : networkhandler.s
+
+# target to generate assembly for a file
+networkhandler.c.s:
+	cd /d C:\Doc\opener-jkvatne\source && $(MAKE) -f src\ports\WIN32\CMakeFiles\WIN32PLATFORM.dir\build.make src/ports/WIN32/CMakeFiles/WIN32PLATFORM.dir/networkhandler.c.s
+.PHONY : networkhandler.c.s
+
+opener_error.obj: opener_error.c.obj
+
+.PHONY : opener_error.obj
+
+# target to build an object file
+opener_error.c.obj:
+	cd /d C:\Doc\opener-jkvatne\source && $(MAKE) -f src\ports\WIN32\CMakeFiles\WIN32PLATFORM.dir\build.make src/ports/WIN32/CMakeFiles/WIN32PLATFORM.dir/opener_error.c.obj
+.PHONY : opener_error.c.obj
+
+opener_error.i: opener_error.c.i
+
+.PHONY : opener_error.i
+
+# target to preprocess a source file
+opener_error.c.i:
+	cd /d C:\Doc\opener-jkvatne\source && $(MAKE) -f src\ports\WIN32\CMakeFiles\WIN32PLATFORM.dir\build.make src/ports/WIN32/CMakeFiles/WIN32PLATFORM.dir/opener_error.c.i
+.PHONY : opener_error.c.i
+
+opener_error.s: opener_error.c.s
+
+.PHONY : opener_error.s
+
+# target to generate assembly for a file
+opener_error.c.s:
+	cd /d C:\Doc\opener-jkvatne\source && $(MAKE) -f src\ports\WIN32\CMakeFiles\WIN32PLATFORM.dir\build.make src/ports/WIN32/CMakeFiles/WIN32PLATFORM.dir/opener_error.c.s
+.PHONY : opener_error.c.s
+
+# Help Target
+help:
+	@echo The following are some of the valid targets for this Makefile:
+	@echo ... all (the default if no target is provided)
+	@echo ... clean
+	@echo ... depend
+	@echo ... WIN32PLATFORM
+	@echo ... OpENer
+	@echo ... edit_cache
+	@echo ... rebuild_cache
+	@echo ... main.obj
+	@echo ... main.i
+	@echo ... main.s
+	@echo ... networkconfig.obj
+	@echo ... networkconfig.i
+	@echo ... networkconfig.s
+	@echo ... networkhandler.obj
+	@echo ... networkhandler.i
+	@echo ... networkhandler.s
+	@echo ... opener_error.obj
+	@echo ... opener_error.i
+	@echo ... opener_error.s
+.PHONY : help
+
+
+
+#=============================================================================
+# Special targets to cleanup operation of make.
+
+# Special rule to run CMake to check the build system integrity.
+# No rule that depends on this can have commands that come from listfiles
+# because they might be regenerated.
+cmake_check_build_system:
+	cd /d C:\Doc\opener-jkvatne\source && $(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles\Makefile.cmake 0
+.PHONY : cmake_check_build_system
+

+ 93 - 0
source/src/ports/MINGW/main.c

@@ -0,0 +1,93 @@
+/*******************************************************************************
+ * Copyright (c) 2009, Rockwell Automation, Inc.
+ * All rights reserved.
+ *
+ ******************************************************************************/
+
+#include "generic_networkhandler.h"
+#include "opener_api.h"
+#include "cipcommon.h"
+#include "trace.h"
+#include "networkconfig.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+
+extern int newfd;
+
+/******************************************************************************/
+/*!\brief Signal handler function for ending stack execution
+ *
+ * @param pa_nSig the signal we received
+ */
+void
+LeaveStack(int pa_nSig);
+
+/*****************************************************************************/
+/*! \brief Flag indicating if the stack should end its execution
+ */
+int g_end_stack = 0;
+
+/******************************************************************************/
+int main(int argc,
+         char *arg[]) {
+  EipUint16 nUniqueConnectionID;
+
+  if (argc != 2) {
+    printf("Wrong number of command line parameters!\n");
+    printf("The correct command line parameters are:\n");
+    printf(
+      "./OpENer ip-address\n");
+    printf(
+      "    e.g. ./OpENer 192.168.259.22\n");
+    exit(0);
+  } else {
+    DoublyLinkedListInitialize(&connection_list,
+                               CipConnectionObjectListArrayAllocator,
+                               CipConnectionObjectListArrayFree);
+    /* fetch Internet address info from the platform */
+    ConfigureDomainName(arg[1] );
+    ConfigureHostName();
+    ConfigureNetworkInterface(arg[1] );
+  }
+
+  /*for a real device the serial number should be unique per device */
+  SetDeviceSerialNumber(123456789);
+
+  /* nUniqueConnectionID should be sufficiently random or incremented and stored
+   *  in non-volatile memory each time the device boots.
+   */
+  nUniqueConnectionID = rand();
+
+  /* Setup the CIP Layer */
+  CipStackInit(nUniqueConnectionID);
+
+  /* Setup Network Handles */
+  if ( kEipStatusOk == NetworkHandlerInitialize() ) {
+    g_end_stack = 0;
+#ifndef WIN32
+    /* register for closing signals so that we can trigger the stack to end */
+    signal(SIGHUP, LeaveStack);
+#endif
+
+    /* The event loop. Put other processing you need done continually in here */
+    while (1 != g_end_stack) {
+      if ( kEipStatusOk != NetworkHandlerProcessOnce() ) {
+        break;
+      }
+    }
+
+    /* clean up network state */
+    NetworkHandlerFinish();
+  }
+  /* close remaining sessions and connections, cleanup used data */
+  ShutdownCipStack();
+
+  return -1;
+}
+
+void LeaveStack(int pa_nSig) {
+  (void) pa_nSig; /* kill unused parameter warning */
+  OPENER_TRACE_STATE("got signal HUP\n");
+  g_end_stack = 1;
+}

+ 256 - 0
source/src/ports/MINGW/networkconfig.c

@@ -0,0 +1,256 @@
+/*******************************************************************************
+ * Copyright (c) 2009, Rockwell Automation, Inc.
+ * All rights reserved.
+ *
+ ******************************************************************************/
+#define WIN32_LEAN_AND_MEAN
+#include "ciptcpipinterface.h"
+#include "networkconfig.h"
+#include "cipcommon.h"
+#include "ciperror.h"
+#include "opener_api.h"
+#include "trace.h"
+#include "cipethernetlink.h"
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <winsock2.h>
+#include <windows.h>
+#include <Ws2tcpip.h>
+#include <iphlpapi.h>
+
+#define WORKING_BUFFER_SIZE 15000
+#define MAX_TRIES 3
+
+
+EipStatus ConfigureNetworkInterface(const char *const network_interface) {
+
+  PIP_ADAPTER_INFO pAdapterInfo;
+  PIP_ADAPTER_INFO pAdapter = NULL;
+  CipDword dwRetVal = 0;
+
+  CipUdint ulOutBufLen = sizeof(IP_ADAPTER_INFO);
+  pAdapterInfo = (IP_ADAPTER_INFO *)CipCalloc(1,sizeof(IP_ADAPTER_INFO) );
+  if (pAdapterInfo == NULL) {
+    printf("Error allocating memory needed to call GetAdaptersinfo\n");
+    return kEipStatusError;
+  }
+  // Make an initial call to GetAdaptersInfo to get
+  // the necessary size into the ulOutBufLen variable
+  if (GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) == ERROR_BUFFER_OVERFLOW) {
+    CipFree(pAdapterInfo);
+    pAdapterInfo = (IP_ADAPTER_INFO *)CipCalloc(ulOutBufLen,sizeof(CipUdint) );
+    if (pAdapterInfo == NULL) {
+      printf("Error allocating memory needed to call GetAdaptersinfo\n");
+      return kEipStatusError;
+    }
+  }
+
+
+  if ( (dwRetVal = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) ) == NO_ERROR ) {
+    pAdapter = pAdapterInfo;
+    while (pAdapter) {
+      if (strcmp( pAdapter->IpAddressList.IpAddress.String, network_interface) == 0) {
+        for (int i = 0; i < 6; i++) {
+          memcpy(&g_ethernet_link.physical_address, pAdapter->Address,
+                 6 * sizeof(CipUsint) );
+        }
+
+        interface_configuration_.ip_address = inet_addr(
+          pAdapter->IpAddressList.IpAddress.String);
+        interface_configuration_.network_mask = inet_addr(
+          pAdapter->IpAddressList.IpMask.String);
+        interface_configuration_.gateway = inet_addr(
+          pAdapter->GatewayList.IpAddress.String);
+
+        CipUdint host_id = ntohl(interface_configuration_.ip_address)
+                           & ~ntohl(interface_configuration_.network_mask);              /* see CIP spec 3-5.3 for multicast address algorithm*/
+        host_id -= 1;
+        host_id &= 0x3ff;
+
+        g_multicast_configuration.starting_multicast_address = htonl(
+          ntohl(inet_addr("239.192.1.0") ) + (host_id << 5) );
+      }
+      pAdapter = pAdapter->Next;
+    }
+  }
+  else {
+    printf("GetAdaptersInfo failed with error: %d\n", dwRetVal);
+
+  }
+  CipFree(pAdapterInfo);
+  CipFree(pAdapter);
+  return kEipStatusOk;
+}
+
+void ConfigureDomainName() {
+  // This was a parameter!
+  int interface_index = 0;
+
+  CipDword dwSize = 0;
+  int i = 0;
+  // Set the flags to pass to GetAdaptersAddresses
+  CipUdint flags = GAA_FLAG_INCLUDE_PREFIX;
+  CipDword dwRetVal = 0;
+  // default to unspecified address family (both)
+  CipUdint family = AF_UNSPEC;
+
+  LPVOID lpMsgBuf = NULL;
+
+  PIP_ADAPTER_ADDRESSES pAddresses = NULL;
+  PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL;
+  IP_ADAPTER_DNS_SERVER_ADDRESS *pDnServer = NULL;
+  CipUdint outBufLen = 0;
+  CipUdint tries = 0;
+
+  family = AF_INET;
+  // Allocate a 15 KB buffer to start with.
+  outBufLen = WORKING_BUFFER_SIZE;
+
+  do {
+
+    pAddresses = (IP_ADAPTER_ADDRESSES *)CipCalloc(1,outBufLen);
+    if (pAddresses == NULL) {
+      printf
+        ("Memory allocation failed for IP_ADAPTER_ADDRESSES struct\n");
+      exit(1);
+    }
+
+    dwRetVal =
+      GetAdaptersAddresses(family, flags, NULL, pAddresses, &outBufLen);
+
+    if (dwRetVal == ERROR_BUFFER_OVERFLOW) {
+      CipFree(pAddresses);
+      pAddresses = NULL;
+    }
+    else {
+      break;
+    }
+
+    tries++;
+
+  } while ( (dwRetVal == ERROR_BUFFER_OVERFLOW) && (tries < MAX_TRIES) );
+
+  if (dwRetVal == NO_ERROR) {
+    // If successful, output some information from the data we received
+    pCurrAddresses = pAddresses;
+    while (pCurrAddresses) {
+      if (interface_index == pCurrAddresses->IfIndex) {
+        pDnServer = pCurrAddresses->FirstDnsServerAddress;
+        if (pDnServer) {
+          for (i = 0; pDnServer != NULL; i++) {
+            pDnServer = pDnServer->Next;
+          }
+        }
+
+        char pStringBuf[INET_ADDRSTRLEN];
+        if (i != 0) {
+
+          if (NULL != interface_configuration_.domain_name.string) {
+            /* if the string is already set to a value we have to free the resources
+             * before we can set the new value in order to avoid memory leaks.
+             */
+            CipFree(interface_configuration_.domain_name.string);
+          }
+          interface_configuration_.domain_name.length = strlen(
+            pCurrAddresses->DnsSuffix);
+          if (interface_configuration_.domain_name.length) {
+            interface_configuration_.domain_name.string = (CipByte *)CipCalloc(
+              interface_configuration_.domain_name.length + 1,
+              sizeof(CipUsint) );
+            strcpy(interface_configuration_.domain_name.string,
+                   pCurrAddresses->DnsSuffix);
+          }
+          else {
+            interface_configuration_.domain_name.string = NULL;
+          }
+/*
+          inet_ntop(AF_INET,
+                   pCurrAddresses->FirstDnsServerAddress->Address.lpSockaddr->sa_data + 2,
+                   interface_configuration_.name_server,
+                   sizeof(interface_configuration_.name_server) );
+          inet_ntop(AF_INET,
+                   pCurrAddresses->FirstDnsServerAddress->Next->Address.lpSockaddr->sa_data + 2,
+                   interface_configuration_.name_server_2,
+                   sizeof(interface_configuration_.name_server_2) );
+*/
+        }
+        else{ interface_configuration_.domain_name.length = 0;}
+
+      }
+      pCurrAddresses = pCurrAddresses->Next;
+    }
+  }
+  else {
+    OPENER_TRACE_INFO("Call to GetAdaptersAddresses failed with error: %d\n",
+                      dwRetVal);
+    if (dwRetVal == ERROR_NO_DATA) {
+      OPENER_TRACE_INFO(
+        "\tNo addresses were found for the requested parameters\n");
+    }
+    else {
+
+      if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+                        FORMAT_MESSAGE_FROM_SYSTEM |
+                        FORMAT_MESSAGE_IGNORE_INSERTS,
+                        NULL, dwRetVal,
+                        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+                        // Default language
+                        (LPTSTR)&lpMsgBuf, 0, NULL) ) {
+        OPENER_TRACE_INFO("\tError: %s", lpMsgBuf);
+        CipFree(lpMsgBuf);
+        if (pAddresses) {
+          CipFree(pAddresses);
+        }
+        exit(1);
+      }
+    }
+  }
+
+  if (pAddresses) {
+    CipFree(pAddresses);
+  }
+
+
+}
+
+void ConfigureHostName(void) {
+  CipWord wVersionRequested;
+  WSADATA wsaData;
+  int err;
+
+  /* Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */
+  wVersionRequested = MAKEWORD(2, 2);
+
+  err = WSAStartup(wVersionRequested, &wsaData);
+  if (err != 0) {
+    /* Tell the user that we could not find a usable */
+    /* Winsock DLL.                                  */
+    printf("WSAStartup failed with error: %d\n", err);
+    return;
+  }
+
+  char hostname[256] = "";
+  gethostname(hostname, sizeof(hostname) );
+
+  //WSACleanup();
+
+
+
+
+  if (NULL != hostname_.string) {
+    /* if the string is already set to a value we have to free the resources
+     * before we can set the new value in order to avoid memory leaks.
+     */
+    CipFree(hostname_.string);
+  }
+  hostname_.length = strlen(hostname);
+  if (hostname_.length) {
+    hostname_.string = (CipByte *) CipCalloc( hostname_.length + 1,
+                                              sizeof(CipByte) );
+    strcpy(hostname_.string, hostname);
+  } else {
+    hostname_.string = NULL;
+  }
+}

+ 0 - 0
source/src/ports/MINGW/networkconfig.h


+ 53 - 0
source/src/ports/MINGW/networkhandler.c

@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * Copyright (c) 2009, Rockwell Automation, Inc.
+ * All rights reserved.
+ *
+ ******************************************************************************/
+#define WIN32_LEAN_AND_MEAN
+#include <string.h>
+#include <stdlib.h>
+#include <winsock2.h>
+#include <windows.h>
+#include <Ws2tcpip.h>
+
+#include "networkhandler.h"
+
+#include "generic_networkhandler.h"
+
+MicroSeconds getMicroSeconds() {
+  LARGE_INTEGER performance_counter;
+  LARGE_INTEGER performance_frequency;
+
+  QueryPerformanceCounter(&performance_counter);
+  QueryPerformanceFrequency(&performance_frequency);
+
+  return (MicroSeconds) (performance_counter.QuadPart * 1000000LL
+                         / performance_frequency.QuadPart);
+}
+
+MilliSeconds GetMilliSeconds(void) {
+  return (MilliSeconds) (getMicroSeconds() / 1000ULL);
+}
+
+EipStatus NetworkHandlerInitializePlatform(void) {
+  WSADATA wsaData;
+  const WORD wVersionRequested = MAKEWORD(2, 2);
+  WSAStartup(wVersionRequested, &wsaData);
+
+  return kEipStatusOk;
+}
+
+void CloseSocketPlatform(int socket_handle) {
+  closesocket(socket_handle);
+}
+
+int SetSocketToNonBlocking(int socket_handle) {
+  u_long iMode = 1;
+  return ioctlsocket(socket_handle, FIONBIO, &iMode);
+}
+
+int SetQosOnSocket(int socket,
+                   CipUsint qos_value) {
+  CipUsint set_tos = qos_value;
+  return setsockopt(socket, IPPROTO_IP, IP_TOS, &set_tos, sizeof(set_tos) );
+}

+ 43 - 0
source/src/ports/MINGW/networkhandler.h

@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 2009, Rockwell Automation, Inc.
+ * All rights reserved.
+ *
+ ******************************************************************************/
+#ifndef NETWORKHANDLER_H_
+#define NETWORKHANDLER_H_
+
+#include "winsock2.h"
+#include "typedefs.h"
+#include <Ws2tcpip.h>
+
+#define OPENER_SOCKET_WOULD_BLOCK WSAEWOULDBLOCK
+
+// THis type is defined in Ws2tcpip.h!
+//typedef unsigned long socklen_t;
+
+EipStatus NetworkHandlerInitializePlatform(void);
+
+/** @brief Platform dependent code to close a socket
+ *
+ *  @param socket_handle The socket handle to be closed
+ */
+void CloseSocketPlatform(int socket_handle);
+
+int SetSocketToNonBlocking(int socket_handle);
+
+/** @brief This function shall return the current time in microseconds relative to epoch, and shall be implemented in a port specific networkhandler
+ *
+ *  @return Current time relative to epoch as MicroSeconds
+ */
+MicroSeconds GetMicroSeconds(void);
+
+/** @brief This function shall return the current time in milliseconds relative to epoch, and shall be implemented in a port specific networkhandler
+ *
+ *  @return Current time relative to epoch as MilliSeconds
+ */
+MilliSeconds GetMilliSeconds(void);
+
+int SetQosOnSocket(int socket,
+                   CipUsint qos_value);
+
+#endif /*NETWORKHANDLER_H_*/

+ 36 - 0
source/src/ports/MINGW/opener_error.c

@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 2009, Rockwell Automation, Inc.
+ * All rights reserved.
+ *
+ ******************************************************************************/
+
+/** @file opener_error.c
+ *  @author Martin Melik Merkumians
+ *  @brief This file includes the prototypes for error resolution functions like strerror or WSAGetLastError
+ *
+ */
+
+ #include <windows.h>
+
+ #include "opener_error.h"
+
+int GetSocketErrorNumber() {
+  return WSAGetLastError();
+}
+
+char *GetErrorMessage(int error_number) {
+  char *error_message = NULL;
+  FormatMessage(
+    FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+    NULL,
+    error_number,
+    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+    &error_message,
+    0,
+    NULL);
+  return error_message;
+}
+
+void FreeErrorMessage(char *error_message) {
+  LocalFree(error_message);
+}

+ 14 - 0
source/src/ports/MINGW/sample_application/CMakeLists.txt

@@ -0,0 +1,14 @@
+#######################################
+# Add common includes                 #
+#######################################
+opener_common_includes()
+
+#######################################
+# Add platform specific things        #
+#######################################
+
+opener_platform_support("INCLUDES")
+
+opener_platform_support("INCLUDES")
+
+add_library(SAMPLE_APP sampleapplication.c)

+ 179 - 0
source/src/ports/MINGW/sample_application/Makefile

@@ -0,0 +1,179 @@
+# CMAKE generated file: DO NOT EDIT!
+# Generated by "MinGW Makefiles" Generator, CMake Version 3.12
+
+# Default target executed when no arguments are given to make.
+default_target: all
+
+.PHONY : default_target
+
+# Allow only one "make -f Makefile2" at a time, but pass parallelism.
+.NOTPARALLEL:
+
+
+#=============================================================================
+# Special targets provided by cmake.
+
+# Disable implicit rules so canonical targets will work.
+.SUFFIXES:
+
+
+# Remove some rules from gmake that .SUFFIXES does not remove.
+SUFFIXES =
+
+.SUFFIXES: .hpux_make_needs_suffix_list
+
+
+# Suppress display of executed commands.
+$(VERBOSE).SILENT:
+
+
+# A target that is always out of date.
+cmake_force:
+
+.PHONY : cmake_force
+
+#=============================================================================
+# Set environment variables for the build.
+
+SHELL = cmd.exe
+
+# The CMake executable.
+CMAKE_COMMAND = "C:\Program Files\JetBrains\CLion 2018.2.4\bin\cmake\win\bin\cmake.exe"
+
+# The command to remove a file.
+RM = "C:\Program Files\JetBrains\CLion 2018.2.4\bin\cmake\win\bin\cmake.exe" -E remove -f
+
+# Escaping for special characters.
+EQUALS = =
+
+# The top-level source directory on which CMake was run.
+CMAKE_SOURCE_DIR = C:\Doc\opener-jkvatne\source
+
+# The top-level build directory on which CMake was run.
+CMAKE_BINARY_DIR = C:\Doc\opener-jkvatne\source
+
+#=============================================================================
+# Targets provided globally by CMake.
+
+# Special rule for the target edit_cache
+edit_cache:
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "No interactive CMake dialog available..."
+	"C:\Program Files\JetBrains\CLion 2018.2.4\bin\cmake\win\bin\cmake.exe" -E echo "No interactive CMake dialog available."
+.PHONY : edit_cache
+
+# Special rule for the target edit_cache
+edit_cache/fast: edit_cache
+
+.PHONY : edit_cache/fast
+
+# Special rule for the target rebuild_cache
+rebuild_cache:
+	@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake to regenerate build system..."
+	"C:\Program Files\JetBrains\CLion 2018.2.4\bin\cmake\win\bin\cmake.exe" -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)
+.PHONY : rebuild_cache
+
+# Special rule for the target rebuild_cache
+rebuild_cache/fast: rebuild_cache
+
+.PHONY : rebuild_cache/fast
+
+# The main all target
+all: cmake_check_build_system
+	cd /d C:\Doc\opener-jkvatne\source && $(CMAKE_COMMAND) -E cmake_progress_start C:\Doc\opener-jkvatne\source\CMakeFiles C:\Doc\opener-jkvatne\source\src\ports\WIN32\sample_application\CMakeFiles\progress.marks
+	cd /d C:\Doc\opener-jkvatne\source && $(MAKE) -f CMakeFiles\Makefile2 src/ports/WIN32/sample_application/all
+	$(CMAKE_COMMAND) -E cmake_progress_start C:\Doc\opener-jkvatne\source\CMakeFiles 0
+.PHONY : all
+
+# The main clean target
+clean:
+	cd /d C:\Doc\opener-jkvatne\source && $(MAKE) -f CMakeFiles\Makefile2 src/ports/WIN32/sample_application/clean
+.PHONY : clean
+
+# The main clean target
+clean/fast: clean
+
+.PHONY : clean/fast
+
+# Prepare targets for installation.
+preinstall: all
+	cd /d C:\Doc\opener-jkvatne\source && $(MAKE) -f CMakeFiles\Makefile2 src/ports/WIN32/sample_application/preinstall
+.PHONY : preinstall
+
+# Prepare targets for installation.
+preinstall/fast:
+	cd /d C:\Doc\opener-jkvatne\source && $(MAKE) -f CMakeFiles\Makefile2 src/ports/WIN32/sample_application/preinstall
+.PHONY : preinstall/fast
+
+# clear depends
+depend:
+	cd /d C:\Doc\opener-jkvatne\source && $(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles\Makefile.cmake 1
+.PHONY : depend
+
+# Convenience name for target.
+src/ports/WIN32/sample_application/CMakeFiles/SAMPLE_APP.dir/rule:
+	cd /d C:\Doc\opener-jkvatne\source && $(MAKE) -f CMakeFiles\Makefile2 src/ports/WIN32/sample_application/CMakeFiles/SAMPLE_APP.dir/rule
+.PHONY : src/ports/WIN32/sample_application/CMakeFiles/SAMPLE_APP.dir/rule
+
+# Convenience name for target.
+SAMPLE_APP: src/ports/WIN32/sample_application/CMakeFiles/SAMPLE_APP.dir/rule
+
+.PHONY : SAMPLE_APP
+
+# fast build rule for target.
+SAMPLE_APP/fast:
+	cd /d C:\Doc\opener-jkvatne\source && $(MAKE) -f src\ports\WIN32\sample_application\CMakeFiles\SAMPLE_APP.dir\build.make src/ports/WIN32/sample_application/CMakeFiles/SAMPLE_APP.dir/build
+.PHONY : SAMPLE_APP/fast
+
+sampleapplication.obj: sampleapplication.c.obj
+
+.PHONY : sampleapplication.obj
+
+# target to build an object file
+sampleapplication.c.obj:
+	cd /d C:\Doc\opener-jkvatne\source && $(MAKE) -f src\ports\WIN32\sample_application\CMakeFiles\SAMPLE_APP.dir\build.make src/ports/WIN32/sample_application/CMakeFiles/SAMPLE_APP.dir/sampleapplication.c.obj
+.PHONY : sampleapplication.c.obj
+
+sampleapplication.i: sampleapplication.c.i
+
+.PHONY : sampleapplication.i
+
+# target to preprocess a source file
+sampleapplication.c.i:
+	cd /d C:\Doc\opener-jkvatne\source && $(MAKE) -f src\ports\WIN32\sample_application\CMakeFiles\SAMPLE_APP.dir\build.make src/ports/WIN32/sample_application/CMakeFiles/SAMPLE_APP.dir/sampleapplication.c.i
+.PHONY : sampleapplication.c.i
+
+sampleapplication.s: sampleapplication.c.s
+
+.PHONY : sampleapplication.s
+
+# target to generate assembly for a file
+sampleapplication.c.s:
+	cd /d C:\Doc\opener-jkvatne\source && $(MAKE) -f src\ports\WIN32\sample_application\CMakeFiles\SAMPLE_APP.dir\build.make src/ports/WIN32/sample_application/CMakeFiles/SAMPLE_APP.dir/sampleapplication.c.s
+.PHONY : sampleapplication.c.s
+
+# Help Target
+help:
+	@echo The following are some of the valid targets for this Makefile:
+	@echo ... all (the default if no target is provided)
+	@echo ... clean
+	@echo ... depend
+	@echo ... SAMPLE_APP
+	@echo ... edit_cache
+	@echo ... rebuild_cache
+	@echo ... sampleapplication.obj
+	@echo ... sampleapplication.i
+	@echo ... sampleapplication.s
+.PHONY : help
+
+
+
+#=============================================================================
+# Special targets to cleanup operation of make.
+
+# Special rule to run CMake to check the build system integrity.
+# No rule that depends on this can have commands that come from listfiles
+# because they might be regenerated.
+cmake_check_build_system:
+	cd /d C:\Doc\opener-jkvatne\source && $(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles\Makefile.cmake 0
+.PHONY : cmake_check_build_system
+

+ 34 - 0
source/src/ports/MINGW/sample_application/cmake_install.cmake

@@ -0,0 +1,34 @@
+# Install script for directory: C:/Doc/opener-jkvatne/source/src/ports/WIN32/sample_application
+
+# Set the install prefix
+if(NOT DEFINED CMAKE_INSTALL_PREFIX)
+  set(CMAKE_INSTALL_PREFIX "C:/Program Files (x86)/OpENer")
+endif()
+string(REGEX REPLACE "/$" "" CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}")
+
+# Set the install configuration name.
+if(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME)
+  if(BUILD_TYPE)
+    string(REGEX REPLACE "^[^A-Za-z0-9_]+" ""
+           CMAKE_INSTALL_CONFIG_NAME "${BUILD_TYPE}")
+  else()
+    set(CMAKE_INSTALL_CONFIG_NAME "")
+  endif()
+  message(STATUS "Install configuration: \"${CMAKE_INSTALL_CONFIG_NAME}\"")
+endif()
+
+# Set the component getting installed.
+if(NOT CMAKE_INSTALL_COMPONENT)
+  if(COMPONENT)
+    message(STATUS "Install component: \"${COMPONENT}\"")
+    set(CMAKE_INSTALL_COMPONENT "${COMPONENT}")
+  else()
+    set(CMAKE_INSTALL_COMPONENT)
+  endif()
+endif()
+
+# Is this installation the result of a crosscompile?
+if(NOT DEFINED CMAKE_CROSSCOMPILING)
+  set(CMAKE_CROSSCOMPILING "FALSE")
+endif()
+

+ 151 - 0
source/src/ports/MINGW/sample_application/opener_user_conf.h

@@ -0,0 +1,151 @@
+/*******************************************************************************
+ * Copyright (c) 2009, Rockwell Automation, Inc.
+ * All rights reserved.
+ *
+ ******************************************************************************/
+#ifndef OPENER_USER_CONF_H_
+#define OPENER_USER_CONF_H_
+
+/** @file
+ * @brief OpENer configuration setup
+ *
+ * This file contains the general application specific configuration for OpENer.
+ *
+ * Furthermore you have to specific platform specific network include files.
+ * OpENer needs definitions for the following data-types
+ * and functions:
+ *    - struct sockaddr_in
+ *    - AF_INET
+ *    - INADDR_ANY
+ *    - htons
+ *    - ntohl
+ *    - inet_addr
+ */
+
+typedef unsigned short in_port_t;
+
+/** @brief Identity configuration of the device */
+#include "devicedata.h"
+
+/** @brief Define the number of objects that may be used in connections
+ *
+ *  This number needs only to consider additional objects. Connections to
+ *  the connection manager object as well as to the assembly object are supported
+ *  in any case.
+ */
+#define OPENER_CIP_NUM_APPLICATION_SPECIFIC_CONNECTABLE_OBJECTS 1
+
+/** @brief Define the number of supported explicit connections.
+ *  According to ODVA's PUB 70 this number should be greater than 6.
+ */
+#define OPENER_CIP_NUM_EXPLICIT_CONNS 6
+
+/** @brief Define the number of supported exclusive owner connections.
+ *  Each of these connections has to be configured with the function
+ *  void configureExclusiveOwnerConnectionPoint(unsigned int pa_unConnNum, unsigned int pa_unOutputAssembly, unsigned int pa_unInputAssembly, unsigned int pa_unConfigAssembly)
+ *
+ */
+#define OPENER_CIP_NUM_EXLUSIVE_OWNER_CONNS 1
+
+/** @brief Define the number of supported input only connections.
+ *  Each of these connections has to be configured with the function
+ *  void configureInputOnlyConnectionPoint(unsigned int pa_unConnNum, unsigned int pa_unOutputAssembly, unsigned int pa_unInputAssembly, unsigned int pa_unConfigAssembly)
+ *
+ */
+#define OPENER_CIP_NUM_INPUT_ONLY_CONNS 1
+
+/** @brief Define the number of supported input only connections per connection path
+ */
+#define OPENER_CIP_NUM_INPUT_ONLY_CONNS_PER_CON_PATH 3
+
+/** @brief Define the number of supported listen only connections.
+ *  Each of these connections has to be configured with the function
+ *  void configureListenOnlyConnectionPoint(unsigned int pa_unConnNum, unsigned int pa_unOutputAssembly, unsigned int pa_unInputAssembly, unsigned int pa_unConfigAssembly)
+ *
+ */
+#define OPENER_CIP_NUM_LISTEN_ONLY_CONNS 1
+
+/** @brief Define the number of supported Listen only connections per connection path
+ */
+#define OPENER_CIP_NUM_LISTEN_ONLY_CONNS_PER_CON_PATH   3
+
+/** @brief The number of bytes used for the buffer that will be used for generating any
+ *  reply data of messages. There are two uses in OpENer:
+ *    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
+ */
+#define OPENER_MESSAGE_DATA_REPLY_BUFFER 100
+
+/** @brief Number of sessions that can be handled at the same time
+ */
+#define OPENER_NUMBER_OF_SUPPORTED_SESSIONS 20
+
+/** @brief  The time in ms of the timer used in this implementations
+ */
+static const int kOpenerTimerTickInMilliSeconds = 10;
+
+/** @brief Define if RUN IDLE data is sent with consumed data
+ */
+static const int kOpenerConsumedDataHasRunIdleHeader = 1;
+
+/** @brief Define if RUN IDLE data is to be sent with produced data
+ *
+ * Per default we don't send run idle headers with produced data
+ */
+static const int kOpenerProducedDataHasRunIdleHeader = 0;
+
+#ifdef OPENER_WITH_TRACES
+/* If we have tracing enabled provide print tracing macro */
+#include <stdio.h>
+
+#define LOG_TRACE(...)  fprintf(stderr,__VA_ARGS__)
+
+/*#define PRINT_TRACE(args...)  fprintf(stderr,args);*/
+
+/** @brief A specialized assertion command that will log the assertion and block
+ *  further execution in an while(1) loop.
+ */
+#define OPENER_ASSERT(assertion) \
+  do { \
+    if( !(assertion) ) { \
+      LOG_TRACE("Assertion \"%s\" failed: file \"%s\", line %d\n", \
+                # assertion, \
+                __FILE__, \
+                __LINE__); \
+      while(1) {;} \
+    } \
+  } while(0)
+
+/* else use standard assert() */
+//#include <assert.h>
+//#include <stdio.h>
+//#define OPENER_ASSERT(assertion) assert(assertion)
+#else
+
+/* for release builds execute the assertion, but don't test it */
+//#define OPENER_ASSERT(assertion) (assertion)
+
+/* the above may result in "statement with no effect" warnings.
+ *  If you do not use assert()s to run functions, the an empty
+ *  macro can be used as below
+ */
+#define OPENER_ASSERT(assertion)
+/* else if you still want assertions to stop execution but without tracing, use the following */
+//#define OPENER_ASSERT(assertion) do { if(!(assertion)) { while(1){;} } } while (0)
+/* else use standard assert() */
+//#include <assert.h>
+//#include <stdio.h>
+//#define OPENER_ASSERT(assertion) assert(assertion)
+
+#endif
+
+/** @brief The number of bytes used for the Ethernet message buffer on
+ * the pc port. For different platforms it may makes sense to
+ * have more than one buffer.
+ *
+ *  This buffer size will be used for any received message.
+ *  The same buffer is used for the replied explicit message.
+ */
+#define PC_OPENER_ETHERNET_BUFFER_SIZE 512
+
+#endif /*OPENER_USER_CONF_H_*/

+ 149 - 0
source/src/ports/MINGW/sample_application/sampleapplication.c

@@ -0,0 +1,149 @@
+/*******************************************************************************
+ * Copyright (c) 2012, Rockwell Automation, Inc.
+ * All rights reserved.
+ *
+ ******************************************************************************/
+
+#include "opener_api.h"
+#include "appcontype.h"
+#include <string.h>
+#include <stdlib.h>
+
+#define DEMO_APP_INPUT_ASSEMBLY_NUM                100 //0x064
+#define DEMO_APP_OUTPUT_ASSEMBLY_NUM               150 //0x096
+#define DEMO_APP_CONFIG_ASSEMBLY_NUM               1 //0x001
+#define DEMO_APP_HEARTBEAT_INPUT_ONLY_ASSEMBLY_NUM  152 //0x098
+#define DEMO_APP_HEARTBEAT_LISTEN_ONLY_ASSEMBLY_NUM 153 //0x099
+#define DEMO_APP_EXPLICT_ASSEMBLY_NUM              154 //0x09A
+
+/* global variables for demo application (4 assembly data fields)  ************/
+
+extern CipUint g_encapsulation_inactivity_timeout;
+
+EipUint8 g_assembly_data064[40]; /* Input */
+EipUint8 g_assembly_data096[40]; /* Output */
+EipUint8 g_assembly_data097[10]; /* Config */
+EipUint8 g_assembly_data09A[32]; /* Explicit */
+
+EipStatus ApplicationInitialization(void) {
+  /* create 3 assembly object instances*/
+  /*INPUT*/
+  CreateAssemblyObject( DEMO_APP_INPUT_ASSEMBLY_NUM, &g_assembly_data064[0],
+                        sizeof(g_assembly_data064) );
+
+  /*OUTPUT*/
+  CreateAssemblyObject( DEMO_APP_OUTPUT_ASSEMBLY_NUM, &g_assembly_data096[0],
+                        sizeof(g_assembly_data096) );
+
+  /*CONFIG*/
+  CreateAssemblyObject( DEMO_APP_CONFIG_ASSEMBLY_NUM, &g_assembly_data097[0],
+                        sizeof(g_assembly_data097) );
+
+  /*Heart-beat output assembly for Input only connections */
+  CreateAssemblyObject(DEMO_APP_HEARTBEAT_INPUT_ONLY_ASSEMBLY_NUM, 0, 0);
+
+  /*Heart-beat output assembly for Listen only connections */
+  CreateAssemblyObject(DEMO_APP_HEARTBEAT_LISTEN_ONLY_ASSEMBLY_NUM, 0, 0);
+
+  /* assembly for explicit messaging */
+  CreateAssemblyObject( DEMO_APP_EXPLICT_ASSEMBLY_NUM, &g_assembly_data09A[0],
+                        sizeof(g_assembly_data09A) );
+
+  ConfigureExclusiveOwnerConnectionPoint(0, DEMO_APP_OUTPUT_ASSEMBLY_NUM,
+                                         DEMO_APP_INPUT_ASSEMBLY_NUM,
+                                         DEMO_APP_CONFIG_ASSEMBLY_NUM);
+  ConfigureInputOnlyConnectionPoint(0,
+                                    DEMO_APP_HEARTBEAT_INPUT_ONLY_ASSEMBLY_NUM,
+                                    DEMO_APP_INPUT_ASSEMBLY_NUM,
+                                    DEMO_APP_CONFIG_ASSEMBLY_NUM);
+  ConfigureListenOnlyConnectionPoint(0,
+                                     DEMO_APP_HEARTBEAT_LISTEN_ONLY_ASSEMBLY_NUM,
+                                     DEMO_APP_INPUT_ASSEMBLY_NUM,
+                                     DEMO_APP_CONFIG_ASSEMBLY_NUM);
+
+  return kEipStatusOk;
+}
+
+void HandleApplication(void) {
+  /* check if application needs to trigger an connection */
+}
+
+void CheckIoConnectionEvent(unsigned int pa_unOutputAssembly,
+                            unsigned int pa_unInputAssembly,
+                            IoConnectionEvent pa_eIOConnectionEvent) {
+  /* maintain a correct output state according to the connection state*/
+
+  (void) pa_unOutputAssembly; /* suppress compiler warning */
+  (void) pa_unInputAssembly; /* suppress compiler warning */
+  (void) pa_eIOConnectionEvent; /* suppress compiler warning */
+}
+
+EipStatus AfterAssemblyDataReceived(CipInstance *pa_pstInstance) {
+  EipStatus nRetVal = kEipStatusOk;
+
+  /*handle the data received e.g., update outputs of the device */
+  switch (pa_pstInstance->instance_number) {
+    case DEMO_APP_OUTPUT_ASSEMBLY_NUM:
+      /* Data for the output assembly has been received.
+       * Mirror it to the inputs */
+      memcpy( &g_assembly_data064[0], &g_assembly_data096[0],
+              sizeof(g_assembly_data064) );
+      break;
+    case DEMO_APP_EXPLICT_ASSEMBLY_NUM:
+      /* do something interesting with the new data from
+       * the explicit set-data-attribute message */
+      break;
+    case DEMO_APP_CONFIG_ASSEMBLY_NUM:
+      /* Add here code to handle configuration data and check if it is ok
+       * The demo application does not handle config data.
+       * However in order to pass the test we accept any data given.
+       * EIP_ERROR
+       */
+      nRetVal = kEipStatusOk;
+      break;
+  }
+  return nRetVal;
+}
+
+EipBool8 BeforeAssemblyDataSend(CipInstance *pa_pstInstance) {
+  /*update data to be sent e.g., read inputs of the device */
+  /*In this sample app we mirror the data from out to inputs on data receive
+   * therefore we need nothing to do here. Just return true to inform that
+   * the data is new.
+   */
+
+  if (pa_pstInstance->instance_number == DEMO_APP_EXPLICT_ASSEMBLY_NUM) {
+    /* do something interesting with the existing data
+     * for the explicit get-data-attribute message */
+  }
+  return true;
+}
+
+EipStatus ResetDevice(void) {
+  /* add reset code here*/
+  CloseAllConnections();
+  return kEipStatusOk;
+}
+
+EipStatus ResetDeviceToInitialConfiguration(void) {
+  /*rest the parameters */
+  g_encapsulation_inactivity_timeout = 120;
+  /*than perform device reset*/
+  ResetDevice();
+  return kEipStatusOk;
+}
+
+void *
+CipCalloc(size_t pa_nNumberOfElements,
+          size_t pa_nSizeOfElement) {
+  return calloc(pa_nNumberOfElements, pa_nSizeOfElement);
+}
+
+void CipFree(void *pa_poData) {
+  free(pa_poData);
+}
+
+void RunIdleChanged(EipUint32 pa_nRunIdleValue) {
+  (void) pa_nRunIdleValue;
+}
+

+ 1 - 0
source/src/utils/doublylinkedlist.c

@@ -7,6 +7,7 @@
 #include "doublylinkedlist.h"
 
 #include "opener_user_conf.h"
+#include <stdio.h>  // Needed to define NULL
 
 void DoublyLinkedListInitialize(DoublyLinkedList *list,
                                 NodeMemoryAllocator allocator,