Przeglądaj źródła

added support for production inhibit time network segment

Alois Zoitl 14 lat temu
rodzic
commit
3b477356d4

+ 0 - 1
ChangeLog.txt

@@ -1,6 +1,5 @@
 2011-11-21  alil
 
-	* .:
 	* : updated documentation for upcoming release
 
 2011-11-18  alil

+ 142 - 109
src/cip/cipconnectionmanager.c

@@ -37,11 +37,8 @@ extern S_CIP_Revision Revison;
 
 #define CIP_CONN_TYPE_MASK 0x6000   /*Bit 13&14 true*/
 
-#define CIP_CONN_PRODUCTION_TRIGGER_MASK 0x70
-#define CIP_CONN_CYCLIC_CONNECTION       0x0
-#define CIP_CONN_COS_TRIGGERED_CONNECTION 0x10
-#define CIP_CONN_APLICATION_TRIGGERED_CONNECTION 0x20
 
+#define CIP_CONN_PIT_NETWORK_SEGEMENT_ID  0x43  /* identifier indicating a production inhibit time network segment */
 
 #define FORWARD_OPEN_HEADER_LENGTH 36         /* the length in bytes of the forward open command specific data till the start of the connection path (including con path size)*/
 #define EQLOGICALPATH(x,y) (((x)&0xfc)==(y))
@@ -202,8 +199,7 @@ Connection_Manager_Init(EIP_UINT16 pa_nUniqueConnID)
 
   g_nIncarnationID = ((EIP_UINT32) pa_nUniqueConnID) << 16;
 
-  addConnectableObject(CIP_MESSAGE_ROUTER_CLASS_CODE,
-      establishClass3Connection);
+  addConnectableObject(CIP_MESSAGE_ROUTER_CLASS_CODE, establishClass3Connection);
   addConnectableObject(CIP_ASSEMBLY_CLASS_CODE, establishIOConnction);
 
   return EIP_OK;
@@ -223,7 +219,8 @@ handleReceivedConnectedData(EIP_UINT8 * pa_pnData, int pa_nDataLength,
     {
       /* check if connected address item or sequenced address item  received, otherwise it is no connected message and should not be here */
       if ((g_stCPFDataItem.stAddr_Item.TypeID == CIP_ITEM_ID_CONNECTIONBASED)
-          || (g_stCPFDataItem.stAddr_Item.TypeID == CIP_ITEM_ID_SEQUENCEDADDRESS))
+          || (g_stCPFDataItem.stAddr_Item.TypeID
+              == CIP_ITEM_ID_SEQUENCEDADDRESS))
         { /* found connected address item or found sequenced address item -> for now the sequence number will be ignored */
           if (g_stCPFDataItem.stDataI_Item.TypeID
               == CIP_ITEM_ID_CONNECTIONTRANSPORTPACKET)
@@ -241,14 +238,14 @@ handleReceivedConnectedData(EIP_UINT8 * pa_pnData, int pa_nDataLength,
                   if (SEQ_GEQ32(g_stCPFDataItem.stAddr_Item.Data.SequenceNumber, pstConnectionObject->EIPSequenceCountConsuming))
                     {
                       /* reset the watchdog timer */
-                      pstConnectionObject->InnacitvityWatchdogTimer =
-                          (pstConnectionObject->O_to_T_RPI / 1000)
+                      pstConnectionObject->InnacitvityWatchdogTimer
+                          = (pstConnectionObject->O_to_T_RPI / 1000)
                               << (2
                                   + pstConnectionObject->ConnectionTimeoutMultiplier);
 
                       /* only inform assembly object if the sequence counter is greater or equal */
-                      pstConnectionObject->EIPSequenceCountConsuming =
-                          g_stCPFDataItem.stAddr_Item.Data.SequenceNumber;
+                      pstConnectionObject->EIPSequenceCountConsuming
+                          = g_stCPFDataItem.stAddr_Item.Data.SequenceNumber;
 
                       if (NULL != pstConnectionObject->m_pfReceiveDataFunc)
                         {
@@ -294,11 +291,11 @@ ForwardOpen(S_CIP_Instance *pa_pstInstance, S_CIP_MR_Request *pa_MRRequest,
   g_stDummyConnectionObject.Priority_Timetick = *pa_MRRequest->Data++;
   g_stDummyConnectionObject.Timeoutticks = *pa_MRRequest->Data++;
   /* O_to_T Conn ID */
-  g_stDummyConnectionObject.CIPConsumedConnectionID = ltohl(
-      &pa_MRRequest->Data);
+  g_stDummyConnectionObject.CIPConsumedConnectionID
+      = ltohl(&pa_MRRequest->Data);
   /* T_to_O Conn ID */
-  g_stDummyConnectionObject.CIPProducedConnectionID = ltohl(
-      &pa_MRRequest->Data);
+  g_stDummyConnectionObject.CIPProducedConnectionID
+      = ltohl(&pa_MRRequest->Data);
   g_stDummyConnectionObject.ConnectionSerialNumber = ltohs(&pa_MRRequest->Data);
   g_stDummyConnectionObject.OriginatorVendorID = ltohs(&pa_MRRequest->Data);
   g_stDummyConnectionObject.OriginatorSerialNumber = ltohl(&pa_MRRequest->Data);
@@ -308,8 +305,8 @@ ForwardOpen(S_CIP_Instance *pa_pstInstance, S_CIP_MR_Request *pa_MRRequest,
       /* TODO this test is  incorrect, see CIP spec 3-5.5.2 re: duplicate forward open
        it should probably be testing the connection type fields
        TODO think on how a reconfigurationrequest could be handled correctly */
-      if ((0 == g_stDummyConnectionObject.CIPConsumedConnectionID)
-          && (0 == g_stDummyConnectionObject.CIPProducedConnectionID))
+      if ((0 == g_stDummyConnectionObject.CIPConsumedConnectionID) && (0
+          == g_stDummyConnectionObject.CIPProducedConnectionID))
         {
           /*TODO implement reconfiguration of connection*/
 
@@ -342,8 +339,8 @@ ForwardOpen(S_CIP_Instance *pa_pstInstance, S_CIP_MR_Request *pa_MRRequest,
   tmp = g_stDummyConnectionObject.T_to_O_RPI % (OPENER_TIMER_TICK * 1000);
   if (tmp > 0)
     {
-      g_stDummyConnectionObject.T_to_O_RPI =
-          (EIP_UINT32) (g_stDummyConnectionObject.T_to_O_RPI
+      g_stDummyConnectionObject.T_to_O_RPI
+          = (EIP_UINT32) (g_stDummyConnectionObject.T_to_O_RPI
               / (OPENER_TIMER_TICK * 1000)) * (OPENER_TIMER_TICK * 1000)
               + (OPENER_TIMER_TICK * 1000);
     }
@@ -354,10 +351,9 @@ ForwardOpen(S_CIP_Instance *pa_pstInstance, S_CIP_MR_Request *pa_MRRequest,
   /*check if Network connection paramters are ok */
   if ((CIP_CONN_TYPE_MASK
       == (g_stDummyConnectionObject.O_to_T_NetworkConnectionParameter
-          & CIP_CONN_TYPE_MASK))
-      || (CIP_CONN_TYPE_MASK
-          == (g_stDummyConnectionObject.T_to_O_NetworkConnectionParameter
-              & CIP_CONN_TYPE_MASK)))
+          & CIP_CONN_TYPE_MASK)) || (CIP_CONN_TYPE_MASK
+      == (g_stDummyConnectionObject.T_to_O_NetworkConnectionParameter
+          & CIP_CONN_TYPE_MASK)))
     {
       return assembleFWDOpenResponse(&g_stDummyConnectionObject, pa_MRResponse,
           CIP_ERROR_CONNECTION_FAILURE,
@@ -447,8 +443,8 @@ generalConnectionConfiguration(S_CIP_ConnectionObject *pa_pstConnObj)
 
   if ((pa_pstConnObj->TransportClassTrigger & 0x80) == 0x00)
     { /* Client Type Connection requested */
-      pa_pstConnObj->ExpectedPacketRate =
-          (EIP_UINT16) ((pa_pstConnObj->T_to_O_RPI) / 1000);
+      pa_pstConnObj->ExpectedPacketRate
+          = (EIP_UINT16) ((pa_pstConnObj->T_to_O_RPI) / 1000);
       /* As soon as we are ready we should produce the connection. With the 0 here we will produce with the next timer tick
        * which should be sufficient. */
       pa_pstConnObj->TransmissionTriggerTimer = 0;
@@ -456,24 +452,25 @@ generalConnectionConfiguration(S_CIP_ConnectionObject *pa_pstConnObj)
   else
     {
       /* Server Type Connection requested */
-      pa_pstConnObj->ExpectedPacketRate =
-          (EIP_UINT16) ((pa_pstConnObj->O_to_T_RPI) / 1000);
+      pa_pstConnObj->ExpectedPacketRate
+          = (EIP_UINT16) ((pa_pstConnObj->O_to_T_RPI) / 1000);
     }
 
-  pa_pstConnObj->m_unProductionInhibitTime = pa_pstConnObj->m_unProductionInhibitTime = 0;
+  pa_pstConnObj->m_unProductionInhibitTime
+      = pa_pstConnObj->m_unProductionInhibitTime = 0;
 
   /*setup the preconsuption timer: max(ConnectionTimeoutMultiplier * EpectetedPacketRate, 10s) */
-  pa_pstConnObj->InnacitvityWatchdogTimer =
-      ((((pa_pstConnObj->O_to_T_RPI) / 1000)
-          << (2 + pa_pstConnObj->ConnectionTimeoutMultiplier)) > 10000) ? (((pa_pstConnObj->O_to_T_RPI)
-          / 1000) << (2 + pa_pstConnObj->ConnectionTimeoutMultiplier)) :
-          10000;
+  pa_pstConnObj->InnacitvityWatchdogTimer
+      = ((((pa_pstConnObj->O_to_T_RPI) / 1000) << (2
+          + pa_pstConnObj->ConnectionTimeoutMultiplier)) > 10000) ? (((pa_pstConnObj->O_to_T_RPI)
+          / 1000) << (2 + pa_pstConnObj->ConnectionTimeoutMultiplier))
+          : 10000;
 
-  pa_pstConnObj->ConsumedConnectionSize =
-      pa_pstConnObj->O_to_T_NetworkConnectionParameter & 0x01FF;
+  pa_pstConnObj->ConsumedConnectionSize
+      = pa_pstConnObj->O_to_T_NetworkConnectionParameter & 0x01FF;
 
-  pa_pstConnObj->ProducedConnectionSize =
-      pa_pstConnObj->T_to_O_NetworkConnectionParameter & 0x01FF;
+  pa_pstConnObj->ProducedConnectionSize
+      = pa_pstConnObj->T_to_O_NetworkConnectionParameter & 0x01FF;
 
 }
 
@@ -490,8 +487,8 @@ ForwardClose(S_CIP_Instance *pa_pstInstance, S_CIP_MR_Request * pa_MRRequest,
   (void) pa_pstInstance;
 
   /* check connection serial number && Vendor ID && OriginatorSerialNr if connection is established */
-  nConnectionStatus =
-      CIP_CON_MGR_ERROR_CONNECTION_NOT_FOUND_AT_TARGET_APPLICATION;
+  nConnectionStatus
+      = CIP_CON_MGR_ERROR_CONNECTION_NOT_FOUND_AT_TARGET_APPLICATION;
   pstRunner = g_pstActiveConnectionList;
 
   /* set AddressInfo Items to invalid TypeID to prevent assembleLinearMsg to read them */
@@ -508,15 +505,14 @@ ForwardClose(S_CIP_Instance *pa_pstInstance, S_CIP_MR_Request * pa_MRRequest,
   while (NULL != pstRunner)
     {
       /* this check should not be necessary as only established connections should be in the active connection list */
-      if ((pstRunner->State == CONN_STATE_ESTABLISHED)
-          || (pstRunner->State == CONN_STATE_TIMEDOUT))
+      if ((pstRunner->State == CONN_STATE_ESTABLISHED) || (pstRunner->State
+          == CONN_STATE_TIMEDOUT))
         {
           if ((pstRunner->ConnectionSerialNumber == ConnectionSerialNr)
               && (pstRunner->OriginatorVendorID == OriginatorVendorID)
               && (pstRunner->OriginatorSerialNumber == OriginatorSerialNr))
             {
-              /* found the corresponding connection object -> close it */
-              OPENER_ASSERT(NULL != pstRunner->m_pfCloseFunc);
+              /* found the corresponding connection object -> close it */OPENER_ASSERT(NULL != pstRunner->m_pfCloseFunc);
               pstRunner->m_pfCloseFunc(pstRunner);
               nConnectionStatus = CIP_CON_MGR_SUCCESS;
               break;
@@ -574,17 +570,20 @@ manageConnections(void)
           if (CONN_STATE_ESTABLISHED == pstRunner->State)
             {
               /* client connection */
-              if((pstRunner->ExpectedPacketRate != 0)
-                  && (EIP_INVALID_SOCKET != pstRunner->sockfd[PRODUCING])) /* only produce for the master connection */
+              if ((pstRunner->ExpectedPacketRate != 0) && (EIP_INVALID_SOCKET
+                  != pstRunner->sockfd[PRODUCING])) /* only produce for the master connection */
                 {
-                  if (CIP_CONN_CYCLIC_CONNECTION != (pstRunner->TransportClassTrigger & CIP_CONN_PRODUCTION_TRIGGER_MASK))
-                  {
-                    /* non cyclic connections have to decrement production inhibit timer */
-                    if(0 <= pstRunner->m_nProductionInhibitTimer)
-                      {
-                        pstRunner->m_nProductionInhibitTimer -= OPENER_TIMER_TICK;
-                      }
-                  }
+                  if (CIP_CONN_CYCLIC_CONNECTION
+                      != (pstRunner->TransportClassTrigger
+                          & CIP_CONN_PRODUCTION_TRIGGER_MASK))
+                    {
+                      /* non cyclic connections have to decrement production inhibit timer */
+                      if (0 <= pstRunner->m_nProductionInhibitTimer)
+                        {
+                          pstRunner->m_nProductionInhibitTimer
+                              -= OPENER_TIMER_TICK;
+                        }
+                    }
                   pstRunner->TransmissionTriggerTimer -= OPENER_TIMER_TICK;
                   if (pstRunner->TransmissionTriggerTimer <= 0)
                     { /* need to send package */
@@ -596,12 +595,15 @@ manageConnections(void)
                               "sending of UDP data in manage Connection failed\n");
                         }
                       /* reload the timer value */
-                      pstRunner->TransmissionTriggerTimer =
-                          pstRunner->ExpectedPacketRate;
-                      if (CIP_CONN_CYCLIC_CONNECTION != (pstRunner->TransportClassTrigger & CIP_CONN_PRODUCTION_TRIGGER_MASK))
+                      pstRunner->TransmissionTriggerTimer
+                          = pstRunner->ExpectedPacketRate;
+                      if (CIP_CONN_CYCLIC_CONNECTION
+                          != (pstRunner->TransportClassTrigger
+                              & CIP_CONN_PRODUCTION_TRIGGER_MASK))
                         {
                           /* non cyclic connections have to reload the production inhibit timer */
-                          pstRunner->m_nProductionInhibitTimer = pstRunner->m_unProductionInhibitTime;
+                          pstRunner->m_nProductionInhibitTimer
+                              = pstRunner->m_unProductionInhibitTime;
                         }
                     }
                 }
@@ -833,7 +835,8 @@ checkElectronicKeyData(EIP_UINT8 pa_nKeyFormat, S_CIP_KeyData *pa_pstKeyData,
                     }
                   else
                     {
-                      if ((pa_pstKeyData->MajorRevision != Revison.MajorRevision)
+                      if ((pa_pstKeyData->MajorRevision
+                          != Revison.MajorRevision)
                           || ((pa_pstKeyData->MajorRevision
                               == Revison.MajorRevision)
                               && (pa_pstKeyData->MinorRevision
@@ -907,9 +910,9 @@ parseConnectionPath(S_CIP_ConnectionObject *pa_pstConnObj,
               pa_pstConnObj->ElectronicKey.KeyData.MajorRevision,
               pa_pstConnObj->ElectronicKey.KeyData.MinorRevision);
 
-          if (EIP_OK
-              != checkElectronicKeyData(pa_pstConnObj->ElectronicKey.KeyFormat,
-                  &(pa_pstConnObj->ElectronicKey.KeyData), pa_pnExtendedError))
+          if (EIP_OK != checkElectronicKeyData(
+              pa_pstConnObj->ElectronicKey.KeyFormat,
+              &(pa_pstConnObj->ElectronicKey.KeyData), pa_pnExtendedError))
             {
               return CIP_ERROR_CONNECTION_FAILURE;
             }
@@ -930,13 +933,13 @@ parseConnectionPath(S_CIP_ConnectionObject *pa_pstConnObj,
               if (pa_pstConnObj->ConnectionPath.ClassID >= 0xC8) /*reserved range of class ids */
 
                 {
-                  *pa_pnExtendedError =
-                      CIP_CON_MGR_ERROR_INVALID_SEGMENT_TYPE_IN_PATH;
+                  *pa_pnExtendedError
+                      = CIP_CON_MGR_ERROR_INVALID_SEGMENT_TYPE_IN_PATH;
                 }
               else
                 {
-                  *pa_pnExtendedError =
-                      CIP_CON_MGR_ERROR_INVALID_CONNECTION_POINT;
+                  *pa_pnExtendedError
+                      = CIP_CON_MGR_ERROR_INVALID_CONNECTION_POINT;
                 }
               return CIP_ERROR_CONNECTION_FAILURE;
             }OPENER_TRACE_INFO("classid %lx (%s)\n",
@@ -951,21 +954,21 @@ parseConnectionPath(S_CIP_ConnectionObject *pa_pstConnObj,
 
       if (EQLOGICALPATH(*pnMsg,0x24))
         { /* store the configuration ID for later checking in the application connection types */
-          pa_pstConnObj->ConnectionPath.ConnectionPoint[2] =
-              GETPADDEDLOGICALPATH(&pnMsg);
+          pa_pstConnObj->ConnectionPath.ConnectionPoint[2]
+              = GETPADDEDLOGICALPATH(&pnMsg);
           OPENER_TRACE_INFO("Configuration instance id %ld\n", pa_pstConnObj->ConnectionPath.ConnectionPoint[2]);
-          if (NULL
-              == getCIPInstance(pstClass,
-                  pa_pstConnObj->ConnectionPath.ConnectionPoint[2]))
+          if (NULL == getCIPInstance(pstClass,
+              pa_pstConnObj->ConnectionPath.ConnectionPoint[2]))
             {
               /*according to the test tool we should respond with this extended error code */
-              *pa_pnExtendedError =
-                  CIP_CON_MGR_ERROR_INVALID_SEGMENT_TYPE_IN_PATH;
+              *pa_pnExtendedError
+                  = CIP_CON_MGR_ERROR_INVALID_SEGMENT_TYPE_IN_PATH;
               return CIP_ERROR_CONNECTION_FAILURE;
             }
           /* 1 or 2 16Bit words for the configuration instance part of the path  */
-          nRemainingPathSize -=
-              (pa_pstConnObj->ConnectionPath.ConnectionPoint[2] > 0xFF) ? 2 : 1;
+          nRemainingPathSize
+              -= (pa_pstConnObj->ConnectionPath.ConnectionPoint[2] > 0xFF) ? 2
+                  : 1;
         }
       else
         {
@@ -979,7 +982,8 @@ parseConnectionPath(S_CIP_ConnectionObject *pa_pstConnObj,
             {
               OPENER_TRACE_WARN(
                   "Too much data in connection path for class 3 connection\n");
-              *pa_pnExtendedError = CIP_CON_MGR_ERROR_INVALID_SEGMENT_TYPE_IN_PATH;
+              *pa_pnExtendedError
+                  = CIP_CON_MGR_ERROR_INVALID_SEGMENT_TYPE_IN_PATH;
               return CIP_ERROR_CONNECTION_FAILURE;
             }
 
@@ -991,8 +995,8 @@ parseConnectionPath(S_CIP_ConnectionObject *pa_pstConnObj,
               *pa_pnExtendedError = CIP_CON_MGR_ERROR_INVALID_CONNECTION_POINT;
               return CIP_ERROR_CONNECTION_FAILURE;
             }
-          pa_pstConnObj->ConnectionPath.ConnectionPoint[0] =
-              pa_pstConnObj->ConnectionPath.ConnectionPoint[2];
+          pa_pstConnObj->ConnectionPath.ConnectionPoint[0]
+              = pa_pstConnObj->ConnectionPath.ConnectionPoint[2];
         }
       else
         { /* we have an IO connection */
@@ -1034,27 +1038,26 @@ parseConnectionPath(S_CIP_ConnectionObject *pa_pstConnObj,
             {
               if (EQLOGICALPATH(*pnMsg,0x24) || EQLOGICALPATH(*pnMsg,0x2C)) /* Connection Point interpreted as InstanceNr -> only in Assembly Objects */
                 { /* InstanceNR */
-                  pa_pstConnObj->ConnectionPath.ConnectionPoint[i] =
-                      GETPADDEDLOGICALPATH(&pnMsg);
+                  pa_pstConnObj->ConnectionPath.ConnectionPoint[i]
+                      = GETPADDEDLOGICALPATH(&pnMsg);
                   OPENER_TRACE_INFO("connection point %lu\n",
                       pa_pstConnObj->ConnectionPath.ConnectionPoint[i]);
-                  if (0
-                      == getCIPInstance(pstClass,
-                          pa_pstConnObj->ConnectionPath.ConnectionPoint[i]))
+                  if (0 == getCIPInstance(pstClass,
+                      pa_pstConnObj->ConnectionPath.ConnectionPoint[i]))
                     {
-                      *pa_pnExtendedError =
-                          CIP_CON_MGR_ERROR_INVALID_CONNECTION_POINT;
+                      *pa_pnExtendedError
+                          = CIP_CON_MGR_ERROR_INVALID_CONNECTION_POINT;
                       return CIP_ERROR_CONNECTION_FAILURE;
                     }
                   /* 1 or 2 16Bit word for the connection point part of the path */
-                  nRemainingPathSize -=
-                      (pa_pstConnObj->ConnectionPath.ConnectionPoint[i] > 0xFF) ? 2 :
-                          1;
+                  nRemainingPathSize
+                      -= (pa_pstConnObj->ConnectionPath.ConnectionPoint[i]
+                          > 0xFF) ? 2 : 1;
                 }
               else
                 {
-                  *pa_pnExtendedError =
-                      CIP_CON_MGR_ERROR_INVALID_SEGMENT_TYPE_IN_PATH;
+                  *pa_pnExtendedError
+                      = CIP_CON_MGR_ERROR_INVALID_SEGMENT_TYPE_IN_PATH;
                   return CIP_ERROR_CONNECTION_FAILURE;
                 }
             }
@@ -1062,21 +1065,46 @@ parseConnectionPath(S_CIP_ConnectionObject *pa_pstConnObj,
           g_unConfigDataLen = 0;
           g_pnConfigDataBuffer = NULL;
 
-          if (nRemainingPathSize > 0)
+          /* with 256 we mark that we haven't got a PIT segment */
+          pa_pstConnObj->m_unProductionInhibitTime = 256;
+
+          while (nRemainingPathSize > 0)
             { /* have something left in the path should be configuration data */
-              if (0x80 == *pnMsg)
-                { /* we have a simple data segment
-                 TODO do we have to handle ANSI extended symbol data segments too? */
-                  g_unConfigDataLen = pnMsg[1] * 2; /*data segments store length 16-bit word wise */
-                  g_pnConfigDataBuffer = &(pnMsg[2]);
-                }
-              else
+
+              switch (*pnMsg)
                 {
-                  OPENER_TRACE_WARN(
-                      "No data segment identifier found for the configuration data\n");
-                  *pa_pnExtendedError = pa_pstConnObj->ConnectionPathSize
-                      - nRemainingPathSize; /*offset in 16Bit words where within the connection path the error happend*/
-                  return 0x04; /*status code for invalid segment type*/
+              case 0x80:
+                /* we have a simple data segment */
+                g_unConfigDataLen = pnMsg[1] * 2; /*data segments store length 16-bit word wise */
+                g_pnConfigDataBuffer = &(pnMsg[2]);
+                nRemainingPathSize -= (g_unConfigDataLen + 2);
+                pnMsg += (g_unConfigDataLen + 2);
+                break;
+                /*TODO do we have to handle ANSI extended symbol data segments too? */
+              case CIP_CONN_PIT_NETWORK_SEGEMENT_ID:
+                if (CIP_CONN_CYCLIC_CONNECTION
+                    != (pa_pstConnObj->TransportClassTrigger
+                        & CIP_CONN_PRODUCTION_TRIGGER_MASK))
+                  {
+                    /* only non cyclic connections may have a production inhibit */
+                    pa_pstConnObj->m_unProductionInhibitTime = pnMsg[1];
+                    pnMsg += 2;
+                    nRemainingPathSize -= 2;
+                  }
+                else
+                  {
+                    *pa_pnExtendedError = pa_pstConnObj->ConnectionPathSize
+                        - nRemainingPathSize; /*offset in 16Bit words where within the connection path the error happend*/
+                    return 0x04; /*status code for invalid segment type*/
+                  }
+                break;
+              default:
+                OPENER_TRACE_WARN(
+                    "No data segment identifier found for the configuration data\n");
+                *pa_pnExtendedError = pa_pstConnObj->ConnectionPathSize
+                    - nRemainingPathSize; /*offset in 16Bit words where within the connection path the error happend*/
+                return 0x04; /*status code for invalid segment type*/
+                break;
                 }
             }
         }
@@ -1171,8 +1199,8 @@ addConnectableObject(EIP_UINT32 pa_nClassId, TConnOpenFunc pa_pfOpenFunc)
   /*parsing is now finished all data is available and check now establish the connection */
   for (i = 0; i < scg_nNumConnectableObjects; ++i)
     {
-      if ((0 == g_astConnMgmList[i].m_nClassID)
-          || (pa_nClassId == g_astConnMgmList[i].m_nClassID))
+      if ((0 == g_astConnMgmList[i].m_nClassID) || (pa_nClassId
+          == g_astConnMgmList[i].m_nClassID))
         {
           g_astConnMgmList[i].m_nClassID = pa_nClassId;
           g_astConnMgmList[i].m_pfOpenFunc = pa_pfOpenFunc;
@@ -1203,20 +1231,25 @@ getConnMgmEntry(EIP_UINT32 pa_nClassId)
 }
 
 EIP_STATUS
-triggerConnections(unsigned int pa_unOutputAssembly, unsigned int pa_unInputAssembly)
+triggerConnections(unsigned int pa_unOutputAssembly,
+    unsigned int pa_unInputAssembly)
 {
   EIP_STATUS nRetVal = EIP_ERROR;
 
   S_CIP_ConnectionObject *pstRunner = g_pstActiveConnectionList;
   while (NULL != pstRunner)
     {
-      if((pa_unOutputAssembly == pstRunner->ConnectionPath.ConnectionPoint[0]) &&
-          (pa_unInputAssembly == pstRunner->ConnectionPath.ConnectionPoint[1]))
+      if ((pa_unOutputAssembly == pstRunner->ConnectionPath.ConnectionPoint[0])
+          && (pa_unInputAssembly
+              == pstRunner->ConnectionPath.ConnectionPoint[1]))
         {
-          if (CIP_CONN_APLICATION_TRIGGERED_CONNECTION == (pstRunner->TransportClassTrigger & CIP_CONN_PRODUCTION_TRIGGER_MASK))
+          if (CIP_CONN_APLICATION_TRIGGERED_CONNECTION
+              == (pstRunner->TransportClassTrigger
+                  & CIP_CONN_PRODUCTION_TRIGGER_MASK))
             {
               /* produce at the next allowed occurrence */
-              pstRunner->TransmissionTriggerTimer = pstRunner->m_nProductionInhibitTimer;
+              pstRunner->TransmissionTriggerTimer
+                  = pstRunner->m_nProductionInhibitTimer;
               nRetVal = EIP_OK;
             }
           break;

+ 5 - 0
src/cip/cipconnectionmanager.h

@@ -39,6 +39,11 @@
 #define CIP_CON_MGR_ERROR_INVALID_SEGMENT_TYPE_IN_PATH 0x0315
 #define CIP_CON_MGR_TARGET_OBJECT_OUT_OF_CONNECTIONS 0x011A
 
+#define CIP_CONN_PRODUCTION_TRIGGER_MASK 0x70
+#define CIP_CONN_CYCLIC_CONNECTION       0x0
+#define CIP_CONN_COS_TRIGGERED_CONNECTION 0x10
+#define CIP_CONN_APLICATION_TRIGGERED_CONNECTION 0x20
+
 /*macros for comparing sequence numbers according to CIP spec vol 2 3-4.2*/
 #define SEQ_LEQ32(a, b) ((int)((a) - (b)) <= 0)
 #define SEQ_GEQ32(a, b) ((int)((a) - (b)) >= 0)

+ 21 - 0
src/cip/cipioconnection.c

@@ -97,6 +97,27 @@ establishIOConnction(struct CIP_ConnectionObject *pa_pstConnObjData,
 
   //TODO add check for transport type trigger
 
+  if (CIP_CONN_CYCLIC_CONNECTION != (pstIOConnObj->TransportClassTrigger
+      & CIP_CONN_PRODUCTION_TRIGGER_MASK))
+    {
+      if (256 == pstIOConnObj->m_unProductionInhibitTime)
+        {
+          /* there was no PIT segment in the connection path set PIT to one fourth of RPI */
+          pstIOConnObj->m_unProductionInhibitTime
+              = ((EIP_UINT16) (pstIOConnObj->T_to_O_RPI) / 4000);
+        }
+      else
+        {
+          /* if production inhibit time has been provided it needs to be smaller than the RPI */
+          if (pstIOConnObj->m_unProductionInhibitTime
+              > ((EIP_UINT16) ((pstIOConnObj->T_to_O_RPI) / 1000)))
+            {
+              /* see section C-1.4.3.3 */
+              *pa_pnExtendedError = 0x111;
+              return 0x01;
+            }
+        }
+    }
   /* set the connection call backs */
   pstIOConnObj->m_pfCloseFunc = closeIOConnection;
   pstIOConnObj->m_pfTimeOutFunc = handleIOConnectionTimeOut;