⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cd_util.c

📁 基于EthernetIP协议的应用程序,可以读取AB公司Controllogix系列Ethernetip协议PLC数据. 此软件代码可用于工业控制.
💻 C
📖 第 1 页 / 共 5 页
字号:
            else
            {
               /*
               ** This should never happen.  The system could be unstable,
               ** so log a fatal fault.
               */

               GS_LogEvent( CM_INCONSISTENT_STATE, 0, psTrrbl, FATAL );
            }
         }

         /*
         ** Now do the ASIC specific initialization and start up the transport.
         */

#ifdef CD_EN_OBJECTS
         /* For tcpip we have to verify that messages for a given cip connection match
         ** the encap session that it was created on.  We do that by copying the encap
         ** session information into the cip record.
         */

         if( psConnRecord->iPort == CD_ETHERNET_PORT )
         {
            if( ( psConnRecord->iProConnParams & CM_CP_TYPE_MASK ) == CM_CP_TYPE_MULTICAST )
            {
               if( ( psConnRecord->sEce.psMcast = en_cd_AllocMcastAddress() ) == (MCAST_P)NULL )
               {
                  eStatus = CD_TRANSPORT_ALLOC_FAIL;
                  psConnRecord->iERC = CM_ERC_BAD_TRANSPORT;
                  goto Bailout;
               }
            }
            if( psConnRecord->fOriginator == FALSE )
            {
               /*
               ** Save the source Sockaddr multicast or point-to-point address in the connection
               ** and transport record "sEce".  This is so the  T->O tag can be returned with
               ** the FWD_OPEN_REPLY, and so UDP Class1 packets will have the correct Sockaddr for
               ** the "sendto".
               */

                en_cd_SaveSendToAddress( psConnRecord );
            }

            pTr->sEce = psTrrbl->psConnRecord->sEce;

         } /* End if an ethernet port */
#endif
         eStatus = (CD_s[ psConnRecord->iPort ].StartTransport)( pTr );

         if( eStatus != SUCCESS )
         {
            eStatus = CD_TRANSPORT_ALLOC_FAIL;
            psConnRecord->iERC = CM_ERC_BAD_TRANSPORT;
            goto Bailout;
         }
      }  /* end if start */
#ifdef CD_EN_OBJECTS
      /*
      ** The transport was already reserved, we need to add the address to the message
      ** going back so the client can listen in on an existing connections
      */
      else  if (( psTrrbl->eRequest == TREQ_START_TRANSPORTS ) &&
                ( psConnRecord->iPort == CD_ETHERNET_PORT ) )
      {

         if( psConnRecord->fOriginator == FALSE  ||
             (psConnRecord->iProConnParams & CM_CP_TYPE_MASK ) == CM_CP_TYPE_POINT )
         {
         /*
         ** Save the source Sockaddr multicast or point-to-point address in the connection
         ** and transport record "sEce".  This is so the  T->O tag can be returned with
         ** the FWD_OPEN_REPLY, and so UDP Class1 packets will have the correct Sockaddr for
         ** the "sendto".
         */

             psConnRecord->sEce.psMcast = pTr->sEce.psMcast;
             en_cd_SaveSendToAddress( psConnRecord );
         }
      }
#endif


	  /*
	  ** start edits: October,5th 2005, H.F.
	  **
	  ** If a Producer Connection Point is already in use, it shall
	  ** adjust its API timer according to the new requested I/O connection, if
	  ** this needs a lesser API. This will avoid a timeout for the new I/O
	  ** connection.
	  */

	  /*
	  ** check, if the Producer Connection Point uses at least the
	  ** requested API; if not...
	  */
      if( ( psTrrbl->eRequest == TREQ_START_TRANSPORTS )
        && ( pTr->iState & CD_TS_STARTED )
		&& ( pTr->lProApi > psConnRecord->lProApi ) )
	  {
		  /* ...apply new (faster) APIs */
		  pTr->lProApi = pTr->lConApi = psConnRecord->lProApi;
		  pTr->lProInhib = psConnRecord->lProInhib;

		  /* adjust the API timer */
		  pTr->xAPITimer->nRetrigger = pTr->lProApi/1000;

		  /* retrigger API timer */
		  GS_RetriggerTimer(pTr->xAPITimer);
		  en_cd_Class1TxPacket( pTr->pBufA, pTr);

		  /*
		  ** start edits: October,13th 2005, H.F.:
		  **
		  ** update data after transmission
		  ** (NOTE: An ad_ResyncCommAndAppBufs() call before executing
		  ** en_cd_Class1TxPacket() does not work!)
		  */

		  GS_PutMsgQueueBits( AD_xQid, AD_BIT_MSG_SENT_PRO );

		  /*
		  ** end edits: October,13th 2005, H.F.
		  */
	  }

	  /*
	  ** end edits: October,5th 2005, H.F.
	  */


   }  /* end if Class 1 - reserve a producer transport */

   /*
   **-------------------------------------------------------------
   ** Reserve a consumer transport for this connection record
   **-------------------------------------------------------------
   */

   /*
   ** Allocate a transport, if not yet done
   */

   if( psConnRecord->iConTransportId == 0 )
   {
      if( ( eStatus = cd_AllocateTransport( psTrrbl, FALSE ) ) != SUCCESS )
      {
         eStatus = CD_TRANSPORT_ALLOC_FAIL;
         psConnRecord->iERC = CM_ERC_NO_BUFFER;
         goto Bailout;
      }
   }

   /*
   ** TODO: For Ethernet, this check for multicast transport already in use is NOT functional.
   */

   pTr = cd_LookupTransportRecord( psConnRecord->iPort, psConnRecord->iConTransportId );

   if( pTr == NULL )
   {
      eStatus = CD_TRANSPORT_ALLOC_FAIL;
      psConnRecord->iERC = CM_ERC_NO_BUFFER;
      goto Bailout;
   }

   /*
   ** Link the connection serial number to the transport record.
   ** Error out if too many multicast connections.
   */

   bNumLinked = cd_LinkConnSnToTransport( psConnRecord->iConnectionSn, pTr, psConnRecord->iPort );

   if( bNumLinked < 0 )
   {
      eStatus = CD_TRANSPORT_ALLOC_FAIL;
      psConnRecord->iERC = CM_ERC_NO_BUFFER;
      goto Bailout;
   }

   /*
   ** If reserve has not been done or if only one connection record
   ** is linked to the transport, do the reserve.
   **
   ** Note that a second pass is allowed here in case we need to pick
   ** up information that has changed in the connection record.
   ** (e.g. connection ID's that were returned in a FO request)
   */

   if( ( ( pTr->iState & CD_TS_RESERVED ) == 0 )
         || ( bNumLinked == 1 ) )
   {
      pTr->iState |= CD_TS_RESERVED;


      /*
      ** Save the transport type.
      */

      pTr->bTransportType = psConnRecord->bConTransportType;



      /*
      ** Fill in any tags that we select
      ** with our mac id and the transport number.
      */

      if( ( psConnRecord->iConConnParams & CM_CP_TYPE_MASK ) == CM_CP_TYPE_POINT )
      {
         /*
         ** Ethernet uses the module incarnation count for the upper half of
         ** the 32 bit connection ID
         */

      /*
      **   jjw note change of using the transport record transport id rather
      **   than the connection record transport ID.  The connection record id
      **   does not have the radioactive bits, the transport id does.
      */

         if( psConnRecord->iPort == CD_ETHERNET_PORT )
         {
            lConnId = pTr->iTransportId |
                      ( ( UINT32 ) sRadioActiveMasks.nIncarnation << 16 );
         }
         else if( psConnRecord->iPort == CD_CONTROLNET_PORT )
         {
            lConnId = pTr->iTransportId |
                   ( ( UINT32 ) CD_s[ CD_CONTROLNET_PORT ].bMacId << 16 );
         }

         psConnRecord->lLeConConnId = UC_lTOlLe( lConnId );
      }
      else
      {
         lConnId = UC_lLeTOl( psConnRecord->lLeConConnId );
         /*
         ** MCast connection, so reserve space
         */

         if( psTrrbl->eRequest == TREQ_RESERVE_TRANSPORTS )
         {
            if ( ( psConnRecord->sEce.psMcast = ( MCAST_P ) GS_Malloc( sizeof( MCAST ) ) ) == (MCAST_P)NULL )
            {
               eStatus = CD_TRANSPORT_ALLOC_FAIL;
               psConnRecord->iERC = CM_ERC_BAD_TRANSPORT;
               goto Bailout;
            }

            /*
            ** Set mcast addr to 0, so if we free it before it is set up,
            ** we don't erroneously think it is a valid mcast addr.
            */

            psConnRecord->sEce.psMcast->sMc_addr.sin_addr.s_addr = 0;
         }
      }

      /*
      ** Copy the Mac Id and Transport Id from the Conn Id
      */

      if ( psConnRecord->iPort == CD_ETHERNET_PORT )
      {
         /*
         **  Use 4 byte connection record
         */

         *( UINT32 * ) &pTr->abRxTag[0] = UC_lLeTOl( psConnRecord->lLeConConnId );
      }
      else
      {
         pTr->abRxTag[ 0 ] = ( UINT8 ) (lConnId >> 16);
         pTr->abRxTag[ 1 ] = ( UINT8 ) lConnId;
         pTr->abRxTag[ 2 ] = ( UINT8 ) (lConnId >> 8);
      }


      if( iClass == CM_TCT_CLASS_1 )
      {
         /*
         ** Since we are in the consumer section we can't be a producer
         */

         pTr->fServerConsumer = TRUE;

      }


      if( iClass == CM_TCT_CLASS_3 )
      {
      /*
      ** Class 3.
      */

      /*
      ** Fill in producer tag (if we select it)
      ** with our mac id and the Consumer transport id number.
      ** Else, use what was provided in the connection record.
      */

         if( ( psConnRecord->iProConnParams & CM_CP_TYPE_MASK ) == CM_CP_TYPE_MULTICAST )
         {
#ifdef CD_EN_OBJECTS
         /*
         ** Ethernet uses the module incarnation count for the upper half of
         ** the 32 bit connection ID
         */

            if (psConnRecord->iPort == CD_ETHERNET_PORT)
               lConnId = psConnRecord->iConTransportId |
                      ( ( UINT32 ) sRadioActiveMasks.nIncarnation << 16 );
            else
#endif
            lConnId = psConnRecord->iConTransportId |
                      ( ( UINT32 ) CD_s[  psConnRecord->iPort  ].bMacId << 16 );
            psConnRecord->lLeProConnId = UC_lTOlLe( lConnId );
         }
         else
         {
            lConnId = UC_lLeTOl( psConnRecord->lLeProConnId );
         }

         /*
         ** Copy the Mac Id and Transport Id from the Conn Id
         */

         if ( psConnRecord->iPort == CD_ETHERNET_PORT )
         {
            /*
            ** Use 4 byte connection record
            */

            *( UINT32 * ) &pTr->abTxTag[0] = UC_lLeTOl( psConnRecord->lLeProConnId );
         }
         else
         {
            pTr->abTxTag[ 0 ] = ( UINT8 ) (lConnId >> 16);
            pTr->abTxTag[ 1 ] = ( UINT8 ) lConnId;
            pTr->abTxTag[ 2 ] = ( UINT8 ) (lConnId >> 8);
         }


         /*
         ** Use the generic consumer transport that uses the ring queue.
         */

         pTr->fServerConsumer = psConnRecord->bClassTrigger & CM_TCT_CLIENTSERVER_MASK;


         /*
         ** If Client and not bridged,
         ** Create the client retry timer.
         */

         if( !pTr->fServerConsumer && !pTr->fBridged )
         {
            /*
            ** Build the timeout tribble.
            **
            ** But first, check to see if it is already done.
            */

            if( pTr->pRetryTot == NULL )
            {
               pTr->pRetryTot = GS_NewTrrbl( CD_TimeoutTrrblType );
               pTr->pRetryTot->eRequest = TREQ_CLASS3_CLIENT_TIMEOUT;
               pTr->pRetryTot->iId      = psConnRecord->iConTransportId;
               pTr->pRetryTot->iPort    = psTrrbl->psConnRecord->iPort;

               /*
               ** Now build the timer itself.
               */

               pTr->xRetryTimer = GS_NewLinkedMsgTimer( TIMER_ONE_SHOT,
                     psConnRecord->lConApi / 1000L,
                     psConnRecord->lConApi / 1000L,
                     CD_s[ psTrrbl->psConnRecord->iPort ].xTxUnschedHiQid,
                     pTr->pRetryTot );

               if( pTr->xRetryTimer == NULL )
               {
                  GS_Free( pTr->pRetryTot );
                  eStatus = CD_RESOURCE_UNAVAILABLE;
                  psConnRecord->iERC = CM_ERC_NO_BUFFER;
                  goto Bailout;
               }
            }  /* end if pTr->pRetryTot */
         }  /* end if client */
      }  /* end if Class 3 */


      if( iClass == CM_TCT_CLASS_1 )
      {

         /*
         ** If this is and explicit transport reserve request, put information
         ** into the connection record that may be used latter during the
         ** start phase of transport comissioning.
         **
         ** For example, if this is a class 1 bridged connection, a copy
         ** function could be placed into the connection record at this time
         ** and later, during the strart phase, retrived and used,
         ** by the other transport on the other side of the bridge.
         */

         if( psTrrbl->eRequest == TREQ_RESERVE_TRANSPORTS )
         {

            /* For Consumer Transport */
            switch( psConnRecord->bConTransportType & CD_XPORT_TYPE_MASK )
            {
            case CD_XPORT_TYPE_PROVIDE_FUNCTION:

               /*
               ** Provide a copy function that will be called whenever new
               ** data is ready to be Consumed.  That is, the transport
               ** stores the data until the application needs to consume it.
               **
               ** This case is valid for the NetLinx Dualport, which should
               ** have it's own transport commission function.
               ** It is not valid for either ControlNet ASIC, so flag an error.
               */

               eStatus = CD_UNSUPPORTED_TRANSPORT;
               psConnRecord->iERC = CM_ERC_BAD_TRANSPORT;
               goto Bailout;

            case CD_XPORT_TYPE_DEFAULT:
            case CD_XPORT_TYPE_CALL_FUNCTION:

               /*
               ** This case is how the Consumer Xports have worked in the past.
               **
               ** Do nothing here.  Wait for start of transport to get pointer
               ** to function to call.
               */

               break;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -