📄 ad_util.c
字号:
** 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 + -