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

📄 ad_util.c

📁 基于EthernetIP协议的应用程序,可以读取AB公司Controllogix系列Ethernetip协议PLC数据. 此软件代码可用于工业控制.
💻 C
📖 第 1 页 / 共 2 页
字号:
   ** lower priority tasks to use critical sections appropriately when
   ** messing with the data and associated data structures).
   */

   /*
   ** Look up the details for this AppDataArea. Bail if it's empty.
   */

   eStatus = BF_GetActiveSubList( eAppDataAreaId, fCon, TRUE, &psActiveEntryFirst, &iEntriesTotal );

   if( ( eStatus != SUCCESS ) || ( iEntriesTotal == 0 ) )
   {
      return;
   }

   /*
   ** Walk the active entry sub-list, copying any and all pieces in the list.
   ** The copy direction is determined by the producer/consumer flag.
   ** The source and destination addresses are prepared properly based on
   ** that information.
   */

   /*********************************************/
   /*** PORTING ALERT!                        ***/
   /*** ADD APPROPRIATE HANDSHAKING AND OTHER ***/
   /*** PLATFORM SPECIFIC COPY STUFF HERE     ***/
   /*** BEFORE/DURING/AFTER COPY AS NEEDED.   ***/
   /***                                       ***/
   /*** PROBABLY WANT TO REPLACE THIS LOOP    ***/
   /*** WITH TIGHTLY CODED ASSEMBLY...        ***/
   /*********************************************/

   psActiveEntry = psActiveEntryFirst;
   iEntries      = iEntriesTotal;

   while( iEntries )
   {

      if( !fCon ) EC_BeforeSyncOfSendDataCB( EC_FindUserDefinedAssemblyInstanceNoByAppDataAreaId( eAppDataAreaId ) );

      UC_CopyMem( psActiveEntry->pDestination, psActiveEntry->pSource, psActiveEntry->iResyncSize );

      if( fCon ) EC_AfterSyncOfReceiveDataCB( EC_FindUserDefinedAssemblyInstanceNoByAppDataAreaId( eAppDataAreaId ) );

      psActiveEntry++;
      iEntries--;
   }

   /*
   ** After the copy operation has been completed as quickly as possible,
   ** and ownership of the application memory (possibly shared or dual port)
   ** has been handed back, update the buffer ownership and freshness
   ** indications. We only need to do this for produced buffers.
   */

   if( !fCon )
   {
      psActiveEntry = psActiveEntryFirst;
      iEntries      = iEntriesTotal;

#ifdef CD_EN_OBJECTS
    /*
    ** Ethernet uses a single transport buffer for tx data.  We lock access to it before
    ** we write/read it with the GetTransportBuffer call.  Then we unlock it using the
    ** put transport call.  When we unlock it with the put transport the data is sent
    ** via immediately if change of state. Or at the next RPI interval if not COS.
    */

      iTransportId = psActiveEntry->iTransportId;
      iPort = psActiveEntry->iPort;
      if( iPort == CD_ETHERNET_PORT )
      {
		  /*
		  ** start edits: November,7th 2005, H.F.
		  **
		  ** It can happen (and sometimes actually does during a GetTransportBuffer
		  ** call), that 'psActiveEntryFirst' and 'psActiveEntry' might have changed
		  ** in the meantime. Therefore it is possible, that psActiveEntry does not 
		  ** point to a producer any longer. In this case a GetTransportBuffer call
		  ** does not make sense and must be avoided to avoid an succeeding access
		  ** violation.
		  **
		  ** NOTE: This is just a workaround to avoid an access violation!
		  */

		  /* store Transport ID to assure that the correct transport buffer
		     will be put later */
		  iGetTransportId = iTransportId;

		  /* check, if the Transport ID belongs to a Consumer and not to a Producer */
		  if( iGetTransportId < EN_CD_FIRST_C1P_TRANSPORT )
			  iGetTransportId = 0; /* indicates that a GetTransportBuffer call 
									  has not been executed */
		  else

		  /*
		  ** end edits: November,7th 2005, H.F.
		  */

		  
          (CD_s[  iPort  ].GetTransportBuffer)( iTransportId );
      }
#endif

      while( iEntries )
      {
         /*
         ** Prepend whatever status information is appropriate for each
         ** connection, then toss the buffer back to the transport for
         ** transmission and grab the stale buffer from the transport.
         */

         iTransportId = psActiveEntry->iTransportId;


		if( psActiveEntry->pAddStatus!=NULL ) /* !?! sometimes access violation because of pAddStatus==NULL war. !?! ! !! !!! !!!! */
		{
			/*
			** start edits: September,27th 2005, H.F.
			**
			** pass the run/idle state of the producer assembly with the function
			** call
			**

			psActiveEntry->pAddStatus( psActiveEntry->pDestination, psActiveEntry->iTranBufOffset, iTransportId );

			**
			*/

			/* get the producer assembly instance */
			aProducerAssemblyInstanceNo = EC_FindUserDefinedAssemblyInstanceNoByAppDataAreaId(eAppDataAreaId);
			if( aProducerAssemblyInstance=EC_FindUserDefinedAssemblyInstance( aProducerAssemblyInstanceNo ) )
			{
				/* run? */
				if( aProducerAssemblyInstance->itsState & 0x0001 )
					bRunIdleState = TRUE;
				else
					bRunIdleState = FALSE;

				psActiveEntry->pAddStatus( psActiveEntry->pDestination, psActiveEntry->iTranBufOffset, iTransportId, bRunIdleState );
			}


			/*
			** end edits: September,27th 2005, H.F.
			*/
		}

#ifdef CD_EN_OBJECTS
        if( psActiveEntry->iPort != CD_ETHERNET_PORT )
#endif
        {
			/*
			** start edits: November,7th 2005, H.F.
			**
			** I think this case should normally not occur. Therefore it does
			** not make sense to execute any code here, as definitely something
			** went wrong...?
			**

           if( CD_s[ psActiveEntry->iPort ].PutTransportBuffer!=NULL ) /* !?! sometimes access violation because of CD_s[ psActiveEntry->iPort ].PutTransportBuffer==NULL !?! ! !! !!! !!!! *//*
              (CD_s[ psActiveEntry->iPort ].PutTransportBuffer)( iTransportId );
           if( CD_s[ psActiveEntry->iPort ].GetTransportBuffer!=NULL ) /* !?! check to avoid access violation *//*
              BF_UpdateMapping( iTransportId, (CD_s[ psActiveEntry->iPort ].GetTransportBuffer)( iTransportId ) );

			**
			** end edits: November,7th 2005, H.F.
			*/
        }

         psActiveEntry++;
         iEntries--;

         /*
         ** Check to see if this entrie belongs to a new transport, or
         ** the same transport we are currently servicing.  If it is a new transport
         ** we will put the buffer, and send it on its way.  If it is the
         ** same transport hold on till we fill in more information
         */

         if ( iEntries )
         {
            /*
            ** Update port information to new entry we have incremented to
            */
            iPort = psActiveEntry->iPort;
            if( iPort == CD_ETHERNET_PORT )
            {
               if ( psActiveEntry->iTransportId != iTransportId )
               {
               /*
               ** New transport, send the last one on its way.
               */
				   /*
				   ** start edits: November,7th 2005, H.F.
				   ** 
				   ** assure, that the correct transport buffer will be put
				   **
				   
				   (CD_s[ iPort ].PutTransportBuffer)( iTransportId );

				   */
				   if( iGetTransportId )
					   (CD_s[ iPort ].PutTransportBuffer)( iGetTransportId );

				   /*
				   ** end edits: November,7th 2005, H.F.
				   */
				   

                  iTransportId = psActiveEntry->iTransportId;


				  /*
				  ** start edits: November,7th 2005, H.F.
				  **
				  ** It can happen (and sometimes actually does during a GetTransportBuffer
				  ** call), that 'psActiveEntryFirst' and 'psActiveEntry' might have changed
				  ** in the meantime. Therefore it is possible, that psActiveEntry does not 
				  ** point to a producer any longer. In this case a GetTransportBuffer call
				  ** does not make sense and must be avoided to avoid an succeeding access
				  ** violation.
				  **
				  ** NOTE: This is just a workaround to avoid an access violation!
				  */

				  /* store Transport ID to assure that the correct transport buffer
				     will be put later */
				  iGetTransportId = iTransportId;

				  /* check, if the Transport ID belongs to a Consumer and not to a Producer */
				  if( iGetTransportId < EN_CD_FIRST_C1P_TRANSPORT )
					  iGetTransportId = 0; /* indicates that a GetTransportBuffer call 
											  has not been executed */
				  else

				  /*
				  ** end edits: November,7th 2005, H.F.
				  */


                  (CD_s[  iPort  ].GetTransportBuffer)( iTransportId );
               } /* if different transport */
            } /* if ethernet port */
         } /* if entries left to service */
         else
         {

         /*
         ** We have serviced the last entry.  Put the buffer and send
         ** the data on its way
         */
         if( iPort == CD_ETHERNET_PORT )
		 {
			 /*
			 ** start edits: November,7th 2005, H.F.
			 ** 
			 ** assure, that the correct transport buffer will be put
			 **

			 (CD_s[ iPort ].PutTransportBuffer)( iTransportId );

			 */
			 if( iGetTransportId )
				 (CD_s[ iPort ].PutTransportBuffer)( iGetTransportId );

			 /*
			 ** end edits: November,7th 2005, H.F.
			 */
		 }
         } /* end else, no more entries */
      } /* end while entries */
   }  /* end if producer transport */

#ifdef CD_EN_OBJECTS
   /*
   ** Since Ethernet uses a single transport buffer note that the same iPort is
   ** used for both GetTransportBuffer and PutTransportBuffer.
   */

#endif

} /* end of ad_ResyncCommAndAppBufs() */



/*---------------------------------------------------------------------------
** ad_Task()
**---------------------------------------------------------------------------
*/

TASKRETURN ad_Task( TASKPARAM )
{
   ad_upsTrrblType upsTrrbl;
   unsigned int i;

   /*
   ** Stay here forever.
   */

   while( 1 )
   {
      /*
      ** Process forwarded access request tribbles.
      */

      upsTrrbl.Generic = GS_TakeTrrbl( AD_xQid );
      switch( upsTrrbl.Generic->eRequest )
      {

      case TREQ_BIT_MSG:

         switch( upsTrrbl.BitMsg->iBitMsg )
         {
         case AD_BIT_MSG_TIMER:
            /*
            ** Periodic application timer went off.
            ** Do a portion of the demo loopback.
            ** Resync producer data in case it changed or we have a
            ** producer only connection to service.
            */

            ad_DemoLoopback( AD_DEMOLOOP_PERIODIC );

			/*
			** start edits: October,14th 2005, H.F.
			** 
			** resync producer data only in case of AD_BIT_MSG_SENT_PRO
			**

			/* ! *//*
			if( gUserDefinedAssembly!=NULL )
				for( i=0; i<gUserDefinedAssembly->itsInstancesCount; i++ )
					switch( gUserDefinedAssembly->itsInstances[i].itsSYType ){
						case PRODUCER:
						case STATUSIN: ad_ResyncCommAndAppBufs( gUserDefinedAssembly->itsInstances[i].itsAppDataAreaId, FALSE ); break;
					}

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

            break;


         case AD_BIT_MSG_SCHEDULED_CON:
            /*
            ** New scheduled data consumed.
            ** Resync the consumed data data area with the transport buffers.
            ** Do the demo loopback as appropriate.
            ** Resync the produced app data area with the transport buffers.
            */

GS_EnterCritical();

			if( gUserDefinedAssembly!=NULL )
				for( i=0; i<gUserDefinedAssembly->itsInstancesCount; i++ )
					if( gUserDefinedAssembly->itsInstances[i].itsSYType==CONSUMER )
						ad_ResyncCommAndAppBufs( gUserDefinedAssembly->itsInstances[i].itsAppDataAreaId, TRUE  );

            ad_DemoLoopback( AD_DEMOLOOP_SCHED );

			/*
			** start edits: October,13th 2005, H.F.
			**
			** the produced app data area is resynced with the transport buffers
			** in case of the AD_BIT_MSG_TIMER
			**

			if( gUserDefinedAssembly!=NULL )
				for( i=0; i<gUserDefinedAssembly->itsInstancesCount; i++ )
					switch( gUserDefinedAssembly->itsInstances[i].itsSYType ){
						case PRODUCER:
						case STATUSIN: ad_ResyncCommAndAppBufs( gUserDefinedAssembly->itsInstances[i].itsAppDataAreaId, FALSE ); break;
					}

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

GS_ExitCritical();

            break;


		/*
		** start edits: October,14th 2005, H.F.
		*/

         case AD_BIT_MSG_SENT_PRO:
            /*
            ** Data has just been produced.
            ** Do the demo loopback as appropriate.
            ** Resync the produced app data area with the transport buffers.
			** NOTE: if you find a way to do it before production, change it!!!
            */

            ad_DemoLoopback( AD_DEMOLOOP_SENT_PRO );

			/* ! */
			if( gUserDefinedAssembly!=NULL )
				for( i=0; i<gUserDefinedAssembly->itsInstancesCount; i++ )
					switch( gUserDefinedAssembly->itsInstances[i].itsSYType ){
						case PRODUCER:
						case STATUSIN: ad_ResyncCommAndAppBufs( gUserDefinedAssembly->itsInstances[i].itsAppDataAreaId, FALSE ); break;
					}

            break;


		/*
		** end edits: October,14th 2005, H.F.
		*/
         }
         break;


      case TREQ_ACCESS_MAPPED_DATA:

         /*
         ** Unscheduled access.
         ** Process the request then do the demo loopback in case this
         ** request wrote new data.
         */

         ad_ProcessAccessRequest( upsTrrbl.Access );
         ad_DemoLoopback( AD_DEMOLOOP_UNSCHED );
         break;

      default:

         GS_LogEvent( GS_UNSUPPORTED_TRIBBLE_REQUEST, upsTrrbl.Generic->eRequest, upsTrrbl.Generic, FATAL );
         break;
      }

      /*
      ** Return the request tribble back to the sender.
      */

      GS_ReturnTrrbl( upsTrrbl.Generic );
   }

} /* end of ad_Task() */



/****************************************************************************
*****************************************************************************
**
** End of AD_Util.C
**
*****************************************************************************
****************************************************************************/

⌨️ 快捷键说明

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