Parcourir la source

Adds first part of LM3S8962 port files

CapXilinx il y a 12 ans
Parent
commit
36378d4e44

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

@@ -0,0 +1,21 @@
+add_subdirectory(sample_application)
+
+set( PLATFORM_SPEC_SRC networkhandler.c basiccip.c)
+
+#######################################
+# Add common includes                 #
+#######################################
+opener_common_includes()
+
+#######################################
+# Add platform-specific includes      #
+#######################################
+opener_platform_support("INCLUDES")
+
+set (PLATFORMLIBNAME ${OpENer_PLATFORM}PLATFORM)
+
+add_library( ${PLATFORMLIBNAME} ${PLATFORM_SPEC_SRC})
+
+add_executable(OpENer main.c)
+
+target_link_libraries( OpENer ${PLATFORMLIBNAME} CIP SAMPLE_APP ENET_ENCAP ${PLATFORM_SPEC_LIBS} ${OpENer_ADD_CIP_OBJECTS})

+ 35 - 0
source/src/ports/LM3S8962/archnw.h

@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2009, Rockwell Automation, Inc.
+ * All rights reserved.
+ *
+ ******************************************************************************/
+
+#ifndef ARCHNW_H_
+#define ARCHNW_H_
+
+#include "lwiplib.h"
+
+#include "local.h"
+
+extern void *mycalloc(unsigned);
+#define cip_calloc(x,y) mycalloc((unsigned)((x)*(y)))
+
+#define INLINE inline
+
+#define SOCKET_ERROR -1
+
+#define TIMERTICK 10 /* time between calls of manageConnections() in Milliseconds */
+
+// define the socket address structure -- it is different between Berkley sockets and LWIP
+
+typedef unsigned short int sa_family_t;
+typedef unsigned short int in_port_t;
+typedef unsigned int in_addr_t;
+
+#define PF_INET         2					// protocol family
+#define AF_INET         PF_INET					// address family
+#define SOCK_DGRAM	2
+#define SHUT_RDWR	2
+#define INADDR_ANY	0
+
+#endif /*ARCHNW_H_*/

+ 148 - 0
source/src/ports/LM3S8962/basiccip.c

@@ -0,0 +1,148 @@
+/*******************************************************************************
+ * Copyright (c) 2009, Rockwell Automation, Inc.
+ * All rights reserved. 
+ *
+ ******************************************************************************/
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "networkhandler.h"
+#include "opener_api.h"
+#include "cipcommon.h"
+#include "trace.h"
+
+#define DEMO_APP_INPUT_ASSEMBLY_NUM                0x301
+#define DEMO_APP_OUTPUT_ASSEMBLY_NUM               0x302
+#define DEMO_APP_CONFIG_ASSEMBLY_NUM               0x303
+#define DEMO_APP_HEARBEAT_INPUT_ONLY_ASSEMBLY_NUM  0x304
+#define DEMO_APP_HEARBEAT_LISTEN_ONLY_ASSEMBLY_NUM 0x305
+#define DEMO_APP_EXPLICT_ASSEMBLY_NUM              0x306
+
+
+/* global variables for demo application (4 assembly data fields) */
+EIP_UINT8 g_assemblydata301[32]; /* Input */
+EIP_UINT8 g_assemblydata302[32]; /* Output */
+EIP_UINT8 g_assemblydata303[10]; /* Config */
+EIP_UINT8 g_assemblydata306[32]; /* Explicit */
+
+extern int newfd;
+
+
+EIP_STATUS
+IApp_Init(void)
+{
+//  CIP_Motion_Init();
+
+  /* create 3 assembly object instances*/
+  /*INPUT*/
+  createAssemblyObject(DEMO_APP_INPUT_ASSEMBLY_NUM, &g_assemblydata301[0], sizeof(g_assemblydata301));
+
+  /*OUTPUT*/
+  createAssemblyObject(DEMO_APP_OUTPUT_ASSEMBLY_NUM, &g_assemblydata302[0], sizeof(g_assemblydata302));
+
+  /*CONFIG*/
+  createAssemblyObject(DEMO_APP_CONFIG_ASSEMBLY_NUM, &g_assemblydata303[0], sizeof(g_assemblydata303));
+
+  /*Heart-beat output assembly for Input only connections */
+  createAssemblyObject(DEMO_APP_HEARBEAT_INPUT_ONLY_ASSEMBLY_NUM, 0, 0);
+
+  /*Heart-beat output assembly for Listen only connections */
+  createAssemblyObject(DEMO_APP_HEARBEAT_LISTEN_ONLY_ASSEMBLY_NUM, 0, 0);
+
+  /* assembly for explicit messaging */
+  createAssemblyObject(DEMO_APP_EXPLICT_ASSEMBLY_NUM, &g_assemblydata306[0], sizeof(g_assemblydata306));
+
+  configureExclusiveOwnerConnectionPoint(0, DEMO_APP_OUTPUT_ASSEMBLY_NUM, DEMO_APP_INPUT_ASSEMBLY_NUM, DEMO_APP_CONFIG_ASSEMBLY_NUM);
+  configureInputOnlyConnectionPoint(0, DEMO_APP_HEARBEAT_INPUT_ONLY_ASSEMBLY_NUM, DEMO_APP_INPUT_ASSEMBLY_NUM, DEMO_APP_CONFIG_ASSEMBLY_NUM);
+  configureListenOnlyConnectionPoint(0, DEMO_APP_HEARBEAT_LISTEN_ONLY_ASSEMBLY_NUM, DEMO_APP_INPUT_ASSEMBLY_NUM, DEMO_APP_CONFIG_ASSEMBLY_NUM);
+
+  return EIP_OK;
+}
+
+void
+IApp_IOConnectionEvent(unsigned int pa_unOutputAssembly,
+    unsigned int pa_unInputAssembly, EIOConnectionEvent pa_eIOConnectionEvent)
+{
+  /* maintain a correct output state according to the connection state*/
+
+  (void) pa_unOutputAssembly; /* suppress compiler warning */
+  pa_unInputAssembly = pa_unInputAssembly; /* suppress compiler warning */
+  pa_eIOConnectionEvent = pa_eIOConnectionEvent; /* suppress compiler warning */
+}
+
+EIP_STATUS
+IApp_AfterAssemblyDataReceived(S_CIP_Instance *pa_pstInstance)
+{
+  /*handle the data received e.g., update outputs of the device */
+
+  if (pa_pstInstance->nInstanceNr == DEMO_APP_OUTPUT_ASSEMBLY_NUM)
+    {
+      /* Data for the output assembly has been received.
+       * Mirror it to the inputs */
+      memcpy(&g_assemblydata301[0], &g_assemblydata302[0], sizeof(g_assemblydata301));
+    }
+  else if (pa_pstInstance->nInstanceNr == DEMO_APP_EXPLICT_ASSEMBLY_NUM)
+    {
+      /* do something interesting with the new data from
+       * the explicit set-data-attribute message */
+    }
+
+  return EIP_OK;
+}
+
+EIP_BOOL8
+IApp_BeforeAssemblyDataSend(S_CIP_Instance *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->nInstanceNr == DEMO_APP_EXPLICT_ASSEMBLY_NUM)
+    {
+      /* do something interesting with the existing data
+       * for the explicit get-data-attribute message */
+    }
+  return true;
+}
+
+EIP_STATUS
+IApp_ResetDevice(void)
+{
+  /* add reset code here*/
+  return EIP_OK;
+}
+
+EIP_STATUS
+IApp_ResetDeviceToInitialConfiguration(void)
+{
+  /*rest the parameters and than perform device reset*/
+  return EIP_OK;
+}
+
+void *
+IApp_CipCalloc(unsigned pa_nNumberOfElements, unsigned pa_nSizeOfElement)
+{
+  return mem_calloc(pa_nNumberOfElements, pa_nSizeOfElement);
+}
+
+void
+IApp_CipFree(void *pa_poData)
+{
+  mem_free(pa_poData);
+}
+
+void
+IApp_RunIdleChanged(EIP_UINT32 pa_nRunIdleValue)
+{
+  (void) pa_nRunIdleValue;
+}
+
+void
+IApp_HandleApplication(void)
+{
+  /* check if application needs to trigger an connection */
+}
+

+ 426 - 0
source/src/ports/LM3S8962/networkhandler.c

@@ -0,0 +1,426 @@
+/*******************************************************************************
+ * Copyright (c) 2009, Rockwell Automation, Inc.
+ * All rights reserved.
+ *
+ ******************************************************************************/
+
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "networkhandler.h"
+#include "cipcommon.h"
+#include "cipconnectionmanager.h"
+
+#include "encap.h"
+#include <trace.h>
+
+#define EIP_VERBOSE	2
+#define EIP_VVERBOSE	3
+#define EIP_TERSE	1
+
+#define MAX_RECEIVE_SIZE 512
+#define MAX_SEND_SIZE 512
+
+static EIP_UINT8 rxbuf[MAX_RECEIVE_SIZE]; // this appears to be the EIP command buffer
+EIP_UINT8 eip_reply_buf[MAX_SEND_SIZE]; // this appears to be the EthernetIP reply buffer
+
+extern void
+dump(unsigned char *p, int size);
+
+static struct tcp_pcb *TCPlistener;
+static struct udp_pcb *UDPlistener;
+
+#define MAX_NO_OF_TCP_SOCKETS 10
+
+struct sockaddr_in my_addr;
+
+struct tcp_pcb *g_pstCurrentTCP_PCB = NULL;
+
+// UDP UNSOLICITED DATA RECEIVE CALLBACK
+// The callback function is responsible for deallocating the pbuf.
+
+void
+udp_unsolicited_receive_callback(void * arg, // arg specified when the callback was registered
+    struct udp_pcb * pcb, // pcb handling the receive
+    struct pbuf * p, // the packet
+    struct ip_addr * addr, // source IP address
+    u16_t port) // source UDP port number
+{
+  EIP_UINT8 *rxp; // pointer into the receive buf
+  int rxlen; // size of the received message
+  int bytesleft; // bytes left (allows for multiple messages per packet)
+  int replylen;
+  err_t status;
+  struct pbuf * r; // reply buffer
+  struct sockaddr_in stFrom;
+
+  assert(p->tot_len <= sizeof(rxbuf)); // TODO this needs to be hardened
+  pbuf_copy_partial(p, rxbuf, sizeof(rxbuf), 0); // copy the packet into a contiguous receive buffer
+  rxlen = p->tot_len; // size of the received message
+  pbuf_free(p); // we no longer need the packet buffer
+
+  if (EIP_DEBUG > EIP_VVERBOSE)
+    {
+      OPENER_TRACE_INFO("Data received on UDP:\n");
+      dump(rxbuf, rxlen);
+    }
+
+  rxp = &rxbuf[0]; // point to the start of the message
+  do
+    {
+      stFrom.sin_family = AF_INET;
+      stFrom.sin_port = port;
+      stFrom.sin_addr.s_addr = addr->addr;
+      memset(&stFrom.sin_zero, 0, sizeof(stFrom.sin_zero));
+
+      replylen = handleReceivedExplictUDPData((unsigned) pcb, // bogus a socket fd (use the pcb address cast to an int)
+          &stFrom, rxp, rxlen, &bytesleft);
+
+      rxp += rxlen - bytesleft; // bump the buffer pointer by the amount of data that was eaten
+      rxlen = bytesleft; // dec the data size by the same amount
+
+      if (replylen > 0)
+        {
+          if (EIP_DEBUG >= EIP_VVERBOSE)
+            {
+              OPENER_TRACE_INFO("reply sent:\n");
+              dump(eip_reply_buf, replylen);
+            }
+
+          r = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_REF);
+          assert(r != 0); // TODO harden
+          //r->payload = &eip_reply_buf[0];
+          r->payload = &rxbuf[0];
+          r->len = r->tot_len = replylen;
+          status = udp_sendto(pcb, r, (struct ip_addr *) &addr->addr, port);
+          assert(status == 0); // TODO check for non-fatal status response?
+          pbuf_free(r); // reference counting makes sure the header does not get freed prematurely, but what about the replybuf?
+        }
+    }
+  while (rxlen > 0);
+}
+
+// UDP CONNECTED DATA CALLBACK
+
+void
+udp_registered_receive_callback(void * arg, // arg specified when the callback was registered
+    struct udp_pcb * pcb, // pcb handling the receive
+    struct pbuf * pbuf, // the packet
+    struct ip_addr * addr, // source IP address
+    u16_t port) // source UDP port number
+{
+  EIP_UINT8 *rxp; // pointer into the receive buf
+  int rxlen; // size of the received message
+  struct sockaddr_in stFrom;
+
+  //assert(pbuf->len == pbuf->tot_len);
+  assert(pbuf->tot_len <= MAX_RECEIVE_SIZE); // TODO this needs to be hardened
+  rxlen = pbuf_copy_partial(pbuf, rxbuf, MAX_RECEIVE_SIZE, 0); // copy the packet into a contiguous receive buffer
+  //assert(rxlen == pbuf->tot_len);
+  rxp = &rxbuf[0]; // point to the start of the message
+  pbuf_free(pbuf); // we no longer need the packet buffer
+
+  if (rxlen == 0)
+    {
+      OPENER_TRACE_ERR("connection closed by client\n");
+      udp_disconnect(pcb); /* close socket */
+      udp_remove(pcb);
+      return;
+    }
+  if (rxlen <= 0)
+    {
+      OPENER_TRACE_ERR("networkhandler: error on recv");
+      udp_disconnect(pcb); /* close socket */
+      udp_remove(pcb);
+      return;
+    }
+
+  stFrom.sin_family = AF_INET;
+  stFrom.sin_port = port;
+  stFrom.sin_addr.s_addr = addr->addr;
+  memset(&stFrom.sin_zero, 0, sizeof(stFrom.sin_zero));
+
+  handleReceivedConnectedData(rxbuf, rxlen, &stFrom);
+}
+
+// TCP DATA SENT CALLBACK
+
+err_t
+tcp_sent_callback(void * arg, struct tcp_pcb * tpcb, u16_t len)
+{
+  // TODO unlock the reply buf?
+
+  return ERR_OK;
+}
+
+
+
+// TCP DATA RECEIVE CALLBACK
+
+err_t
+tcp_receive_callback(void * arg, // arg specified earlier
+    struct tcp_pcb *pcb, // pcb that is delivering the data
+    struct pbuf *pbuf, // the packet
+    err_t err) // TCP uses this to tell us what's happening to the connection perhaps?
+{
+  EIP_UINT8 *rxp;
+  int rxlen;
+  int bytesread;
+  int bytesleft;
+  int replylen;
+  int txspace;
+  int rxoff = 0;
+  err_t status;
+
+  if (err != ERR_OK)
+    return err; // don't try to receive if error
+
+  if (pbuf == 0) // check if connection is closing
+    {
+      tcp_close(pcb); // close out end
+      return ERR_OK;
+    }
+
+  while (rxoff < pbuf->tot_len)
+    {
+      rxlen = pbuf_copy_partial(pbuf, rxbuf, 4, rxoff); // copy the first four words into the contiguous receive buffer
+      assert(rxlen == 4); //need at least four bytes of the header at this point
+      rxp = &rxbuf[2]; // at this place EIP stores the data length
+      rxlen = ltohs(&rxp) + ENCAPSULATION_HEADER_LENGTH - 4; // -4 is for the 4 bytes we have already read
+      // (NOTE this advances the buffer pointer)
+
+      if (rxlen + 4 > MAX_RECEIVE_SIZE)
+        { //TODO can this be handled in a better way?
+          OPENER_TRACE_ERR("too large packet received will be ignored\n"); // this may corrupt the connection ???
+          return EIP_ERROR;
+        }
+
+      bytesread = pbuf_copy_partial(pbuf, &rxbuf[4], rxlen, rxoff + 4); // copy the rest of the message into the contiguous receive buffer
+      assert(bytesread == rxlen);
+      rxlen += 4;
+      rxoff += rxlen;
+      tcp_recved(pcb, rxlen); // tell TCP we have received the data
+
+      if (EIP_DEBUG >= EIP_VVERBOSE)
+        {
+          OPENER_TRACE_INFO("Data received on tcp:\n");
+          dump(rxbuf, rxlen);
+        }
+
+      g_pstCurrentTCP_PCB = pcb;
+      replylen = handleReceivedExplictTCPData((unsigned) pcb, // bogus a socket fd (use the pcb address cast to an int) -- I do not think this is used anywhere
+          rxbuf, rxlen, &bytesleft);
+      g_pstCurrentTCP_PCB = NULL;
+      assert(bytesleft == 0);
+
+      if (replylen > 0)
+        {
+          if (EIP_DEBUG >= EIP_VVERBOSE)
+            {
+              OPENER_TRACE_INFO("reply sent:\n");
+              dump(eip_reply_buf, replylen);
+            }
+
+          txspace = tcp_sndbuf(pcb); // see how much data can be sent
+          assert(txspace >= replylen); // TODO harden this
+
+          status = tcp_write(pcb, rxbuf, replylen, TCP_WRITE_FLAG_COPY); // TODO need to examine serial reuse of the reply buf
+          if (status != ERR_OK)
+            {
+              OPENER_TRACE_ERR("TCP response was not sent OK: %d\n", status);
+            }
+          tcp_output(pcb); // push the data out
+        }
+    }
+
+  pbuf_free(pbuf); // we no longer need the packet buffer
+
+  return ERR_OK;
+}
+
+// TCP CONNECTION ACCEPT CALLBACK
+
+err_t
+tcp_connection_accept_callback(void *arg, // arg registered for this listener (ignored in this case)
+    struct tcp_pcb *newpcb, // pcb for new tcp connection
+    err_t err)
+{
+  OPENER_TRACE_INFO("networkhandler: new TCP connection\n");
+
+  tcp_accepted(TCPlistener); // tell the listener that the call was accepted
+
+  tcp_recv(newpcb, tcp_receive_callback); // set the callback for received data on the new connection
+  tcp_sent(newpcb, tcp_sent_callback); // set the callback for transmitted data on the new connection
+
+  return ERR_OK;
+}
+
+/* INT8 Start_NetworkHandler()
+ * 	start a TCP listening socket, accept connections, receive data in select loop, call manageConnections periodicaly.
+ * 	return status
+ * 			-1 .. error
+ */
+
+EIP_STATUS
+Start_NetworkHandler()
+{
+  err_t status;
+
+  my_addr.sin_family = AF_INET;
+  my_addr.sin_port = htons(OPENER_ETHERNET_PORT);
+  my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+  memset(&my_addr.sin_zero, 0, sizeof(my_addr.sin_zero));
+
+  /* create a new TCP listener socket */
+  TCPlistener = tcp_new();
+  assert(TCPlistener != 0);
+  status = tcp_bind(TCPlistener, INADDR_ANY, OPENER_ETHERNET_PORT);
+  assert(status == 0);
+  TCPlistener = tcp_listen(TCPlistener);
+  assert(TCPlistener != 0);
+  tcp_accept(TCPlistener, tcp_connection_accept_callback);
+
+  /* create a new UDP listener socket */
+  UDPlistener = udp_new();
+  assert(UDPlistener != 0);
+  udp_bind(UDPlistener, INADDR_ANY, OPENER_ETHERNET_PORT);
+  udp_recv(UDPlistener, udp_unsolicited_receive_callback, 0); // set the callback
+
+  return EIP_OK;
+}
+
+static elapsedtime = 0;
+
+// this gets called every 10 ms from the lwiptick handler, which is called from an Ethernet controller interrupt (SYSTICKHZ = 100)
+void
+CIPtick(int delta) // time since last tick in ms, probably 10
+{
+  /* call manage_connections() in connection manager every TIMERTICK ms */
+  elapsedtime += delta;
+  if (elapsedtime >= TIMERTICK)
+    {
+      manageConnections();
+      elapsedtime = 0;
+    }
+}
+
+/* INT8 registerCallbackFunc(int sockfd, struct sockaddr_in pa_addr, S_CIP_Class *p_stObject, INT8 (*pt2func)(S_CIP_Class *p_stObject, INT8 *data, UINT16 datalength))
+ *  register a callbackfuntion with the corresponding CIP object and socket handle.
+ * 	sockfd		sockethandle
+ * 	pa_addr		remote address for sending UDP packets
+ * 	p_stObject	pointer to CIP object which is to be registered
+ * 	(*pt2func)()	pointer to callbackfunktion which will be called if data arrive on sockfd
+ *
+ *	return status	0 .. success
+ * 			-1 .. error
+ */
+
+EIP_STATUS
+registerCallbackFunc(int sockfd, struct sockaddr_in *pa_addr,
+    S_CIP_Instance *pa_pstInstance, TCIPServiceFunc pa_ptfuncReceiveData)
+{
+  return EIP_OK;
+}
+
+EIP_STATUS
+unregisterCallbackFunc(S_CIP_Instance * pa_pstInstance)
+{
+  return EIP_OK;
+}
+
+/* INT8 sendUDPData(struct sockaddr_in pa_addr, int sockfd, INT8 *pa_data, UINT16 pa_datalength)
+ * send udp datagram to pa_addr on socket sockfd.
+ * 	 pa_addr	remote address
+ * 	 sockfd		sockethandle
+ * 	 pa_data	pointer to data which will be sent
+ * 	 pa_datalength	length of data ind pa_data
+ *
+ * return status	0 .. success
+ * 			-1 .. error
+ */
+
+EIP_STATUS
+IApp_SendUDPData(struct sockaddr_in *pa_addr, int sockfd, EIP_UINT8 *pa_data,
+    EIP_UINT16 pa_datalength)
+{
+  struct pbuf *r;
+  err_t status;
+  struct udp_pcb *pcb;
+
+  pcb = (struct udp_pcb *) sockfd;
+  r = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_REF);
+  assert(r != 0); // TODO harden
+  r->payload = pa_data;
+  r->len = r->tot_len = pa_datalength;
+  status = udp_sendto(pcb, r, (struct ip_addr *) &pa_addr->sin_addr,
+      htons(pa_addr->sin_port));
+  assert(status == 0); // TODO check for non-fatal status response?
+  pbuf_free(r); // reference counting make sure the header does not get freed prematurely, but what about the replybuf?
+
+  return EIP_OK;
+}
+
+// create a new UDP socket for the connection manager
+// returns the fd if successful, else -1
+
+int
+IApp_CreateUDPSocket(int pa_nDirection, // direction: CONSUMING or PRODUCING
+    struct sockaddr_in *pa_pstAddr) // bind address, used for producing only
+{
+  struct udp_pcb *pcb;
+
+  /* create a new UDP socket */
+  pcb = udp_new();
+  if (pcb == 0)
+    {
+      OPENER_TRACE_ERR("networkhandler: cannot create UDP socket\n");
+      return -1;
+    } OPENER_TRACE_INFO("networkhandler: created UDP socket %x\n", pcb);
+
+  /* check if it is sending or receiving */
+  if (pa_nDirection == CONSUMING)
+    { /* bind is only for consuming necessary */
+      struct ip_addr addr;
+
+      addr.addr = htonl(pa_pstAddr->sin_addr.s_addr);
+      if (udp_bind(pcb, &addr, htons(pa_pstAddr->sin_port)) != ERR_OK)
+        {
+          OPENER_TRACE_INFO("networkhandler: error on bind udp\n");
+          return -1;
+        }
+
+      OPENER_TRACE_INFO("networkhandler: bind UDP socket %08x port %d\n", pcb,
+          pa_pstAddr->sin_port);
+      udp_recv(pcb, udp_registered_receive_callback, 0); // set the callback
+    }
+
+
+  if ((pa_nDirection == CONSUMING) || (0 == pa_pstAddr->sin_addr.s_addr))
+    {
+      /* store the originators address */
+      pa_pstAddr->sin_addr.s_addr =  g_pstCurrentTCP_PCB->remote_ip.addr;
+    }
+
+  return (int) pcb;
+}
+
+void IApp_CloseSocket_udp(int fd)
+{
+  struct udp_pcb *pcb;
+
+  OPENER_TRACE_INFO("networkhandler: shutdown UDP socket %x\n", pcb);
+  pcb = (struct udp_pcb *) fd;
+  udp_remove(pcb);
+}
+
+void IApp_CloseSocket_tcp(int fd)
+{
+  struct tcp_pcb *pcb;
+
+  OPENER_TRACE_INFO("networkhandler: shutdown TCP socket %x\n", pcb);
+  pcb = (struct tcp_pcb *) fd;
+  tcp_close(pcb);
+}
+

+ 18 - 0
source/src/ports/LM3S8962/networkhandler.h

@@ -0,0 +1,18 @@
+/*******************************************************************************
+ * Copyright (c) 2009, Rockwell Automation, Inc.
+ * All rights reserved. 
+ *
+ ******************************************************************************/
+#ifndef NETWORKHANDLER_H_
+#define NETWORKHANDLER_H_
+
+#include "typedefs.h"
+
+
+/*! Start a TCP/UDP listening socket, accept connections, receive data in select loop, call manageConnections periodically.
+ *  @return status
+ *          EIP_ERROR .. error
+ */
+EIP_STATUS Start_NetworkHandler(void);
+
+#endif /*NETWORKHANDLER_H_*/

+ 506 - 0
source/src/ports/LM3S8962/sample_application/main.c

@@ -0,0 +1,506 @@
+// Scraps of this module were pulled from the following demo program:
+
+//*****************************************************************************
+//
+// enet_lwip.c - Sample WebServer Application using lwIP.
+//
+// Copyright (c) 2007-2008 Luminary Micro, Inc.  All rights reserved.
+// Software License Agreement
+//
+// Luminary Micro, Inc. (LMI) is supplying this software for use solely and
+// exclusively on LMI's microcontroller products.
+//
+// The software is owned by LMI and/or its suppliers, and is protected under
+// applicable copyright laws.  All rights are reserved.  You may not combine
+// this software with "viral" open-source software in order to form a larger
+// program.  Any use in violation of the foregoing restrictions may subject
+// the user to criminal sanctions under applicable laws, as well as to civil
+// liability for the breach of the terms and conditions of this license.
+//
+// THIS SOFTWARE IS PROVIDED "AS IS".  NO WARRANTIES, WHETHER EXPRESS, IMPLIED
+// OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
+// LMI SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR
+// CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
+//
+// This is part of revision 3618 of the EK-LM3S6965 Rev C Firmware Package.
+//
+//*****************************************************************************
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include "hw_ints.h"
+#include "hw_memmap.h"
+#include "hw_nvic.h"
+#include "hw_types.h"
+#include "driverlib/ethernet.h"
+#include "driverlib/flash.h"
+#include "driverlib/gpio.h"
+#include "driverlib/interrupt.h"
+#include "driverlib/sysctl.h"
+#include "driverlib/systick.h"
+#include "lwiplib.h"
+
+#include "local.h"
+#include "flashmgr.h"
+#include "networkhandler.h"
+#include <opener_api.h>
+#include "cipcommon.h"
+#include "random.h"
+#include <trace.h>
+#include "../../cip_energy/ElEnergyData.h"
+#include "eminterface.h"
+
+int callocsize = CALLOCSIZE;
+char callocmem[CALLOCSIZE];
+
+//define here instead of ptpd.h
+volatile unsigned long g_ulSystemTimeSeconds;
+volatile unsigned long g_ulSystemTimeNanoSeconds;
+
+// cast an int as a struct_inaddr (check the "inet_ntoa" man page -- it wants a struct_inaddr passed by value, not an int)
+// static IP-Address?
+//#define useStaticIP 1
+#define useStaticIP 0
+
+struct parm
+{
+  int useStatic; // 1 use static IP address, 0 use DHCP
+  unsigned long ip; // my ip address
+  unsigned long nm; // net mask
+  unsigned long gw; // gateway ip address
+};
+
+
+//*****************************************************************************
+//
+// Defines for setting up the system clock.
+//
+//*****************************************************************************
+#define SYSTICKHZ               100
+#define SYSTICKMS               (1000 / SYSTICKHZ)
+#define SYSTICKUS               (1000000 / SYSTICKHZ)
+#define SYSTICKNS               (1000000000 / SYSTICKHZ)
+
+
+//*****************************************************************************
+//
+// Interrupt priority definitions.  The top 3 bits of these values are
+// significant with lower values indicating higher priority interrupts.
+//
+//*****************************************************************************
+#define SYSTICK_INT_PRIORITY    0xF0
+#define ETHERNET_INT_PRIORITY   0xC2
+
+//*****************************************************************************
+//
+// The error routine that is called if the driver library encounters an error.
+//
+//*****************************************************************************
+#ifdef DEBUG
+void
+__error__(char *pcFilename, unsigned long ulLine)
+  {
+  }
+#endif
+
+void DisplayIPAddress(unsigned long ipaddr, unsigned long ulCol,
+                 unsigned long ulRow);
+void DisplayOdo(EIP_INT64 pa_nValue, unsigned long pa_nRow);
+
+
+void DisplayRealVal(double pa_fValue, const char *pcPrefix, const char *pcPostfix, unsigned long pa_nRow, unsigned long pa_nCol);
+
+
+// change my IP address etc.
+void
+setCIPaddress(unsigned long addr, // my IP address, in network order
+    unsigned long mask, // netmask, in network order
+    unsigned long gw) // gateway, in network order
+{
+  struct in_addr inAddr;
+  inAddr.s_addr = addr;
+  char acIPAddr[16];
+  strncpy(acIPAddr, inet_ntoa(inAddr), 16);
+  inAddr.s_addr = mask;
+  char acNetMask[16];
+  strncpy(acNetMask, inet_ntoa(inAddr), 16);
+  inAddr.s_addr = gw;
+  char acGW[16];
+  strncpy(acGW, inet_ntoa(inAddr), 16);
+
+  configureNetworkInterface(acIPAddr, acNetMask, acGW);
+  configureDomainName("test");
+  configureHostName("karl");
+}
+
+// this gets called every 100 usec by the lwip timer handler
+void
+lwIPHostTimerHandler(void)
+{
+  static unsigned long ulLastIPAddress = 0;
+  unsigned long ulIPAddress;
+  unsigned long ulNetmask;
+  unsigned long ulGateway;
+
+  ulIPAddress = lwIPLocalIPAddrGet();
+
+  if (ulLastIPAddress != ulIPAddress)
+    {
+      ulLastIPAddress = ulIPAddress;
+      ulNetmask = lwIPLocalNetMaskGet();
+      ulGateway = lwIPLocalGWAddrGet();
+      setCIPaddress(ulIPAddress, ulNetmask, ulGateway);
+      DisplayIPAddress((ulIPAddress), 36, 8);
+    }
+}
+
+int
+main(void)
+{
+  int i;
+  unsigned long ulUser0, ulUser1;
+  unsigned char pucMACArray[8];
+
+  unsigned long ip, nm, gw;
+  int valid;
+
+  struct parm parm;
+  struct parm *p;
+  unsigned long *pl;
+
+  IntPriorityGroupingSet(4);
+
+  //
+  // Set the clocking to run directly from the crystal.
+  //
+  SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN
+                  | SYSCTL_XTAL_8MHZ);
+
+  SysCtlPeripheralEnable(SYSCTL_PERIPH_ETH);
+  SysCtlPeripheralReset(SYSCTL_PERIPH_ETH);
+
+  // Enable Port F for Ethernet LEDs.
+  //  LED0        Bit 3   Output
+  //  LED1        Bit 2   Output
+  //
+  SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);
+  SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
+  GPIODirModeSet(GPIO_PORTF_BASE, GPIO_PIN_2 | GPIO_PIN_3, GPIO_DIR_MODE_HW);
+  GPIOPadConfigSet(GPIO_PORTF_BASE, GPIO_PIN_2 | GPIO_PIN_3,
+                  GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD);
+
+  //
+  // Configure the GPIOs used to read the state of the on-board push buttons.
+  //
+  GPIOPinTypeGPIOInput(GPIO_PORTE_BASE, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2
+                  | GPIO_PIN_3);
+  GPIOPadConfigSet(GPIO_PORTE_BASE, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2
+                  | GPIO_PIN_3, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD_WPU);
+  GPIOPinTypeGPIOInput(GPIO_PORTF_BASE, GPIO_PIN_1);
+  GPIOPadConfigSet(GPIO_PORTF_BASE, GPIO_PIN_1, GPIO_STRENGTH_2MA,
+                  GPIO_PIN_TYPE_STD_WPU);
+
+  // configure the user LED output
+  GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_0);
+  GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_0, 0);
+
+
+
+  //
+  // Configure SysTick for a 100 Hz (10 ms) interrupt.
+  //
+  SysTickPeriodSet(SysCtlClockGet() / SYSTICKHZ);
+  SysTickEnable();
+  SysTickIntEnable();
+
+  //
+  // Initialize ADC
+  //
+  EMInterfaceInit();
+  //
+  // Enable processor interrupts.
+  //
+  IntMasterEnable();
+
+
+
+  //
+  // Configure the hardware MAC address for Ethernet Controller filtering of
+  // incoming packets.
+  //
+  // For the LM3S6965 Evaluation Kit, the MAC address will be stored in the
+  // non-volatile USER0 and USER1 registers.  These registers can be read
+  // using the FlashUserGet function, as illustrated below.
+  //
+  FlashUserGet(&ulUser0, &ulUser1);
+  if ((ulUser0 == 0xffffffff) || (ulUser1 == 0xffffffff))
+    {
+      //
+      // We should never get here.  This is an error if the MAC address has
+      // not been programmed into the device.  Exit the program.
+      //
+
+      while (1)
+        {
+        }
+    }
+
+  //
+  // Convert the 24/24 split MAC address from NV ram into a 32/16 split MAC
+  // address needed to program the hardware registers, then program the MAC
+  // address into the Ethernet Controller registers.
+  //
+
+  pucMACArray[0] = ((ulUser0 >> 0) & 0xff);
+  pucMACArray[1] = ((ulUser0 >> 8) & 0xff);
+  pucMACArray[2] = ((ulUser0 >> 16) & 0xff);
+  pucMACArray[3] = ((ulUser1 >> 0) & 0xff);
+  pucMACArray[4] = ((ulUser1 >> 8) & 0xff);
+  pucMACArray[5] = ((ulUser1 >> 16) & 0xff);
+
+  //////////////////////////////////////////////////////////
+  // YOU MUST SET THESE TO VALID VALUES FOR YOUR LOCATION //
+  //////////////////////////////////////////////////////////
+  configureMACAddress(pucMACArray);
+
+  //
+  // Initialze the lwIP library
+  //
+
+
+  pl = parmFind();
+  p = (struct parm *) (pl + 1);
+
+  if (useStaticIP)
+    {
+      OPENER_TRACE_INFO("using static IP address\n");
+
+      ip = 0x8083BAC9; //128.130.200.201
+//      ip = 0x8083BACB; //128.130.200.203
+      nm = 0xFFFFFF00;
+      gw = 0x8083BA01;
+      valid = 7;
+      lwIPInit(pucMACArray, ip, nm, gw, IPADDR_USE_STATIC);
+    }
+  else
+    {
+      //
+      // Initialze the lwIP library, using DHCP.
+      //
+      OPENER_TRACE_INFO("using DHCP\n");
+      valid = 0; //0
+      lwIPInit(pucMACArray, 0, 0, 0, IPADDR_USE_DHCP);
+    }
+
+
+  // Set the interrupt priorities.  We set the SysTick interrupt to a higher
+    // priority than the Ethernet interrupt to ensure that the file system
+    // tick is processed if SysTick occurs while the Ethernet handler is being
+    // processed.  This is very likely since all the TCP/IP and HTTP work is
+    // done in the context of the Ethernet interrupt.
+    //
+    //
+    // Initialize the OLED display.
+    //
+    RIT128x96x4Init(1000000);
+    RIT128x96x4StringDraw("OpENer w/ CIP-Energy", 4, 0, 15);
+    RIT128x96x4StringDraw("-----------------------", 0, 14, 15);
+    RIT128x96x4StringDraw("IP:   ", 0, 8, 15);
+    DisplayIPAddress(htonl(ip), 36, 8);
+
+    RIT128x96x4StringDraw("  TWh GWh MWh kWh  Wh  ", 0, 20, 15);
+
+    RIT128x96x4StringDraw("factor 1000 applies    ", 0, 54, 10);
+    RIT128x96x4StringDraw("to metered values     ", 0, 62, 10);
+    //change time-interval value for call of updateElMeasuringAndMeteringData
+    //in SysTickIntHandler-method to show/provide correct values (see line 370)
+
+  IntPrioritySet(INT_ETH, ETHERNET_INT_PRIORITY);
+  IntPrioritySet(FAULT_SYSTICK, SYSTICK_INT_PRIORITY);
+
+  /*for a real device the serial number should be unique per device */
+  setDeviceSerialNumber(123456789);
+
+  /* Setup the CIP Layer */
+  CIP_Init(365);
+  IntMasterDisable();
+  CIP_BaseEnergy_Init();
+  CIP_ElEnergy_Init();
+
+  IntMasterEnable();
+  Start_NetworkHandler();
+
+  // this is a simple command interpreter which reads from serial port 0
+  // it is used to set a static IP address
+  while (1)
+    {
+
+    }
+}
+
+/* implement missing functions rand and srand */
+int _EXFUN(rand,(_VOID))
+{
+  return RandomNumber();
+}
+
+_VOID   _EXFUN(srand,(unsigned __seed))
+{
+  RandomAddEntropy(__seed);
+  RandomSeed();
+}
+
+
+
+//*****************************************************************************
+//
+// The interrupt handler for the SysTick interrupt.
+// Entry here directly from the interrupt vector
+// This interrupt occurs once every 10 milliseconds
+//*****************************************************************************
+void SysTickIntHandler(void) {
+
+  //
+  // Update internal time and set PPS output, if needed.
+  //
+  g_ulSystemTimeNanoSeconds += SYSTICKNS;
+  if(g_ulSystemTimeNanoSeconds >= 1000000000) //1 second interval
+      {
+          //GPIOPinWrite(PPS_GPIO_BASE, PPS_GPIO_PIN, PPS_GPIO_PIN); ???
+          g_ulSystemTimeNanoSeconds -= 1000000000;
+          g_ulSystemTimeSeconds += 1;
+
+          //TODO: set interval back to 1 second
+          updateElMeasuringAndMeteringData(1000.0, EMInterfaceGetVoltage(), EMInterfaceGetCurrent());
+
+          RIT128x96x4StringDraw("N", 0, 28, 15);
+          DisplayOdo(g_nBE_TotalEnergyValue, 28);
+
+          RIT128x96x4StringDraw("C", 0, 36, 15);
+          DisplayOdo(g_nBE_ConsumedEnergyValue, 36);
+
+          RIT128x96x4StringDraw("P", 0, 44, 15);
+          DisplayOdo(g_nBE_ProducedEnergyValue, 44);
+
+          DisplayRealVal(g_astEE_ObjInstanceAttribs[eELEL1Current].m_nAttribValue.m_fReal, "I:", "A", 74, 0);
+          DisplayRealVal(g_astEE_ObjInstanceAttribs[eELEL1toNVoltage].m_nAttribValue.m_fReal, "U:", "V", 74, 66);
+
+          DisplayRealVal(g_astEE_ObjInstanceAttribs[eELELineFrequency].m_nAttribValue.m_fReal, "f:", "Hz", 82, 0);
+          DisplayRealVal(g_astEE_ObjInstanceAttribs[eELEL1RealPower].m_nAttribValue.m_fReal, "P:", "W", 82, 66);
+
+      }
+
+
+  //
+  // Call the lwIP timer handler.
+  //
+  lwIPTimer(SYSTICKMS);
+}
+
+
+//*****************************************************************************
+//
+// Display an lwIP type IP Address.
+//
+//*****************************************************************************
+void
+DisplayIPAddress(unsigned long ipaddr, unsigned long ulCol,
+                 unsigned long ulRow)
+{
+    char pucBuf[16];
+    unsigned char *pucTemp = (unsigned char *)&ipaddr;
+
+    //
+    // Convert the IP Address into a string.
+    //
+    sprintf(pucBuf, "%d.%d.%d.%d", pucTemp[0], pucTemp[1], pucTemp[2],
+             pucTemp[3]);
+
+    //
+    // Display the string.
+    //
+    RIT128x96x4StringDraw(pucBuf, ulCol, ulRow, 15);
+}
+
+
+//*****************************************************************************
+//
+// Display a 5 digit odometer
+//
+//*****************************************************************************
+void
+DisplayOdo(EIP_INT64 pa_nValue, unsigned long pa_nRow) {
+  char pucBuf[23];
+  char pucSign[2];
+  UINT16 odoMeter[5] = {0,0,0,0,0};
+  int i = 0;
+
+
+  if (0 > pa_nValue) {
+    pa_nValue = pa_nValue * (-1);
+    sprintf(pucSign,"-");
+  } else {
+    sprintf(pucSign," ");
+  }
+  RIT128x96x4StringDraw(pucSign, 6, pa_nRow, 15);
+
+
+  for (i=0; i<5;++i) {
+      odoMeter[i] = pa_nValue % 1000;
+      pa_nValue /= 1000;
+  }
+
+  sprintf(pucBuf, "%03d,%03d,%03d,%03d,%03d", odoMeter[4], odoMeter[3],
+      odoMeter[2], odoMeter[1], odoMeter[0]);
+
+  RIT128x96x4StringDraw(pucBuf, 12, pa_nRow, 15);
+
+}
+
+
+//*****************************************************************************
+//
+// Split double value at decimal-point and provide integer values
+// for both values. the value after the decimal point is limited to 3 digits
+//
+//*****************************************************************************
+void
+splitDecimal(double pa_fValue, char* pa_pSign, int* pa_pFull, int* pa_pMilli){
+  if (0 <= pa_fValue) {
+      *pa_pSign = ' ';
+      *pa_pFull = floor(pa_fValue);
+      *pa_pMilli = floor(fmod(pa_fValue, 1.0)*1000);
+  } else {
+      *pa_pSign = '-';
+      *pa_pFull = floor(-1.0 * pa_fValue);
+      *pa_pMilli = floor(fmod(pa_fValue * (-1.0), 1.0)*1000);
+  }
+}
+
+
+
+//*****************************************************************************
+//
+// Print the given double-value, preceeded by pre-fix and followed by post-fix
+// at given position of OLED-display
+//
+//*****************************************************************************
+void
+DisplayRealVal(double pa_fValue, const char *pcPrefix, const char *pcPostfix, unsigned long pa_nRow, unsigned long pa_nCol) {
+  char pucBuf[23];
+
+  int Val;
+  int milliVal;
+  char sign;
+
+  splitDecimal(pa_fValue, &sign, &Val, &milliVal);
+//TODO: minor bug: values between -1 and 0 have incorrect sign at output (there is no integer value with -0)
+  sprintf(pucBuf, "%s%c%2d.%03d%s", pcPrefix, sign, Val, milliVal, pcPostfix);
+  RIT128x96x4StringDraw(pucBuf, pa_nCol, pa_nRow, 15);
+}
+

+ 194 - 0
source/src/ports/LM3S8962/sample_application/opener_user_conf.h

@@ -0,0 +1,194 @@
+/*******************************************************************************
+ * 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
+ */
+
+
+#include "lwiplib.h"
+#include "archnw.h"
+
+/* members are in network byte order */
+struct sockaddr_in {
+  u8_t sin_len;
+  u8_t sin_family;
+  u16_t sin_port;
+  struct in_addr sin_addr;
+  char sin_zero[8];
+};
+
+struct sockaddr {
+  u8_t sa_len;
+  u8_t sa_family;
+  char sa_data[14];
+};
+
+#ifndef socklen_t
+#define socklen_t u32_t
+#endif
+
+
+#define SOCK_STREAM     1
+#define  SOL_SOCKET  0xfff    /* options for socket level */
+#define  SO_BROADCAST   0x0020 /* Unimplemented: permit sending of broadcast msgs */
+
+/*! Identity configuration of the device */
+#define OPENER_DEVICE_VENDOR_ID           1
+#define OPENER_DEVICE_TYPE               43
+#define OPENER_DEVICE_PRODUCT_CODE      0x01
+#define OPENER_DEVICE_MAJOR_REVISION      1
+#define OPENER_DEVICE_MINOR_REVISION      2
+#define OPENER_DEVICE_NAME      "OpENer Energy"
+
+/*! 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
+
+/*! 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
+
+/*! 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
+
+/*! 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
+
+/*! Define the number of supported input only connections per connection path
+ */
+#define OPENER_CIP_NUM_INPUT_ONLY_CONNS_PER_CON_PATH 1
+
+
+/*! 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
+
+/*! Define the number of supported Listen only connections per connection path
+ */
+#define OPENER_CIP_NUM_LISTEN_ONLY_CONNS_PER_CON_PATH   1
+
+
+/*! 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 250
+
+/*! Number of sessions that can be handled at the same time
+ */ 
+#define OPENER_NUMBER_OF_SUPPORTED_SESSIONS 4
+
+/*! The time in ms of the timer used in this implementations
+ */ 
+#define OPENER_TIMER_TICK 10 
+
+
+/*! Define if RUN IDLE data is sent with consumed data
+ */ 
+#define OPENER_CONSUMED_DATA_HAS_RUN_IDLE_HEADER 1
+
+/*! Define if RUN IDLE data is to be sent with produced data
+ *
+ * Per default we don't send run idle headers with produced data
+ */
+#define OPENER_PRODUCED_DATA_HAS_RUN_IDLE_HEADER 0
+
+#ifdef OPENER_WITH_TRACES
+/* If we have tracing enabled provide print tracing macro */
+#include <stdio.h>
+
+#define LOG_TRACE(args...)  fprintf(stderr,args)
+
+/*#define PRINT_TRACE(args...)  fprintf(stderr,args);*/
+
+
+/*! 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
+
+/*! 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
+
+
+/*! If this define is here opener will enable 64Bit data type support.
+ *
+ */
+#define OPENER_SUPPORT_64BIT_DATATYPES 1
+
+
+#endif /*OPENER_USER_CONF_H_*/