📄 cm_targt.c
字号:
/****************************************************************************
*****************************************************************************
**
** File Name
** ---------
**
** CM_TARGT.C
**
*****************************************************************************
*****************************************************************************
**
** Description
** -----------
**
** Target portion of the Connection Manager object.
**
*****************************************************************************
*****************************************************************************
**
** Source Change Indices
** ---------------------
**
** Porting: <none>0----<major> Customization: <none>0----<major>
**
*****************************************************************************
*****************************************************************************
** **
** ETHERNET/IP EXAMPLE CODE **
** COPYRIGHT (c) 2000-2005 ODVA (Open DeviceNet Vendor Association) **
** & ControlNet International Ltd. **
** **
** All rights reserved, except as specifically licensed in writing. **
** Use of the Ethernet/IP Example Protocol Software is subject to **
** ODVA's and ControlNet International's Terms of Use Agreement. **
** The following work constitutes example program code and is intended **
** merely to illustrate useful programming techniques. The user is **
** responsible for applying the code correctly. The code is provided **
** AS IS without warranty and is in no way guaranteed to be error-free. **
** **
*****************************************************************************
*****************************************************************************
*/
/****************************************************************************
*****************************************************************************
**
** Change Log
** ----------
**
**
*****************************************************************************
*****************************************************************************
*/
/*
** Determine if this object is to be included.
*/
#include "ab_env.h"
#ifdef CORE_OBJECTS
#include "cd.h" /* Communications Device public interfaces */
#include "mr.h" /* Message Router Public Interfaces */
#include "um.h" /* UCMM Client request interfaces */
#include "cm.h" /* Connection Manager public interfaces */
#include "cm_targt.h" /* Connection Manager Target private interfaces */
#include "id.h"
#include "ad.h" /* September,15th 2005, H.F. */
#include "bf.h" /* September,15th 2005, H.F. */
#include "sy.h" /* September,15th 2005, H.F. */
#include "sy_obj.h" /* September,15th 2005, H.F. */
#include "ECUserDefined.h" /* September,9th 2005, H.F.
#include "ECInterface.h" */
/****************************************************************************
**
** Public data
**
*****************************************************************************
*/
GS_MsgQueueType CM_xQid;
/****************************************************************************
**
** Private data
**
*****************************************************************************
*/
cm_DataType cm_s;
/****************************************************************************
**
** Public Services
**
*****************************************************************************
*/
/*---------------------------------------------------------------------------
** CM_DecodeTimePerTickAndTicks()
**---------------------------------------------------------------------------
*/
GS_MSecType CM_DecodeTimePerTickAndTicks( UINT8 bTimePerTick , UINT8 bNumTicks )
{
return( ( ( GS_MSecType ) 1 << ( bTimePerTick & CM_PTT_TICKTIME_MASK ) ) * bNumTicks );
} /* end of CM_DecodeTimePerTickAndTicks() */
/*---------------------------------------------------------------------------
** CM_EncodeTimePerTickAndTicks()
**---------------------------------------------------------------------------
*/
BOOL CM_EncodeTimePerTickAndTicks( GS_MSecType nTimeout, UINT8 *pbTimePerTick , UINT8 *pbNumTicks )
{
UINT8 bTimePerTick;
/*
** Given a time in milli-seconds, calulate the the number of ticks and time per tick.
** See Chapter 4, section 4.2.6 of the ControlNet spec.
*/
bTimePerTick = 0;
/*
** Note that the ( 8 + bTimePerTick ) is used because *pbNumTicks is an 8 bit value.
*/
while( nTimeout >= ((GS_MSecType)( 1L << ( 8 + bTimePerTick ) ) ) )
{
bTimePerTick++;
if( bTimePerTick > CM_PTT_TICKTIME_MASK )
{
break;
}
}
if( bTimePerTick <= CM_PTT_TICKTIME_MASK )
{
/*
** OR in value so that priority does not get overwritten
*/
*pbTimePerTick &= ~CM_PTT_TICKTIME_MASK;
*pbTimePerTick |= bTimePerTick;
*pbNumTicks = (unsigned char/* jjw 11/1/9*/ )( nTimeout / ( 1L << bTimePerTick ) );
return( TRUE );
}
else
{
/*
** TimePerTick Error
*/
return( FALSE );
}
} /* end of CM_EncodeTimePerTickAndTicks() */
/*---------------------------------------------------------------------------
** CM_Init()
**---------------------------------------------------------------------------
*/
StatusType CM_Init( UINT16 iOptions )
{
GS_TaskSeedType sSeed;
MR_RegistrationTrrblType *pMrTrrbl;
/*
** Allocate/Create all resources (except for tasks).
*/
if( iOptions & AB_CREATE_RESOURCE )
{
/*
** Create the task's request queue.
*/
CM_xQid = GS_NewMsgQueue();
}
/*
** Initialize all internal data structures.
*/
if( iOptions & AB_INIT_RESOURCE )
{
/*
** Initialize (empty) the connection record list.
** Initialize the connection ID counter.
*/
cm_s.fAllowConn = TRUE;
LL_Init( &cm_s.sRecordList );
cm_s.iConnSn = 1;
cm_s.fConnSnWrapped = FALSE;
}
/*
** Create the task & associate it with the message queue created earlier.
*/
if( iOptions & AB_CREATE_TASK )
{
sSeed.pRoutine = cm_ObjectTask;
sSeed.pParameter = NULL;
sSeed.pStack = NULL;
sSeed.iStackSize = CM_STACK_SIZE;
sSeed.nPrio = CM_TASK_PRIO;
sSeed.pTaskName = "CM ";
GS_AssociateTaskAndQueues( GS_NewTask( &sSeed ), CM_xQid, GS_NO_QUEUE );
}
/*
** Final initialization after tasks are running.
*/
if( iOptions & AB_INIT_TASK )
{
/*
** Register ourselves with the message router.
*/
pMrTrrbl = GS_NewTrrbl( MR_RegistrationTrrblType );
pMrTrrbl->eRequest = TREQ_REGISTER_OBJECT;
pMrTrrbl->iClass = CM_CLASS_NUMBER;
pMrTrrbl->iInstance = MR_CLASS_AND_INSTANCE_1;
pMrTrrbl->iPort = MR_ALL_PORTS;
pMrTrrbl->xQ = CM_xQid;
GS_PutTrrbl( MR_xQid, pMrTrrbl );
}
return( SUCCESS );
} /* end of CM_Init() */
/****************************************************************************
**
** Private services
**
*****************************************************************************
*/
/*---------------------------------------------------------------------------
** cm_BuildFwdErrorReply()
**---------------------------------------------------------------------------
*/
void cm_BuildFwdErrorReply( CB_ComBufType *pComBuf,
LeUINT16 iLeOrigConnectionSn,
LeUINT16 iLeOrigVendorId,
LeUINT32 lLeOrigDeviceSn,
UINT8 bPathSize,
UINT8 bServiceCode,
UINT8 bGRC,
UINT16 iERC )
{
CM_LeFwdOpenErrorReplyType* pLeFwdReply;
/*
** Build general forward open/close error reply packet.
** Good forward close reply is the same format.
*/
CB_ClearAndExpandComBuf( pComBuf, sizeof( CM_LeFwdOpenErrorReplyType ) );
pLeFwdReply = CB_GetDataPtrComBuf( pComBuf );
pLeFwdReply->lLeOrigDeviceSn = lLeOrigDeviceSn;
pLeFwdReply->iLeOrigVendorId = iLeOrigVendorId;
pLeFwdReply->iLeOrigConnectionSn = iLeOrigConnectionSn;
pLeFwdReply->bPathSize = bPathSize;
pLeFwdReply->bReserved = 0;
/*
** Build a good or bad reply header based on the status codes.
*/
CI_PrependReplyHeader( pComBuf, bServiceCode, bGRC, iERC );
} /* end of cm_BuildFwdErrorReply() */
/*---------------------------------------------------------------------------
** cm_CloseConnection()
**---------------------------------------------------------------------------
*/
void cm_CloseConnection( CM_CloseTrrblType *pTrrbl, BOOL fTimeout )
{
StatusType eStatus;
cm_ConnectionRecordType *psConnRecord;
/*
** start edits: September,29th 2005, H.F.
*/
cm_ConnectionRecordType *psParallelConnRecord;
CM_CloseTrrblType *pTrrblClose;
/*
** end edits: September,29th 2005, H.F.
*/
/*
** Find the connection to close.
*/
psConnRecord = cm_FindConnection( pTrrbl->iConnectionSn, 0, 0, 0, 0, 0, 0, 0, 0 );
if( ( psConnRecord == NULL ) || ( psConnRecord->iState & CM_PS_CLOSING ) )
{
/*
** No such connection or connection already being closed.
** Just return the tribble.
*/
pTrrbl->eStatus = CM_CONNECTION_NOT_FOUND;
GS_ReturnTrrbl( pTrrbl );
}
else
{
/*
** Connection found. Mark it as being closed.
** Record an appropriate error for a timed out connection.
** Save the close request tribble for controlled closes (non-timeout).
*/
psConnRecord->iState |= CM_PS_CLOSING;
if( fTimeout )
{
psConnRecord->sPublic.bGRC = CI_GRC_FAILURE;
psConnRecord->sPublic.iERC = CM_ERC_CONN_TIMED_OUT;
eStatus = ( ( psConnRecord->sPublic.bClassTrigger & CM_TCT_CLASS_MASK ) == CM_TCT_CLASS_1 )
? CM_CONNECTION_CLASS_1_TIMEOUT : CM_CONNECTION_CLASS_3_TIMEOUT;
GS_LogEvent( eStatus, psConnRecord->sPublic.iConnectionSn, 0, SEVERE );
GS_ReturnTrrbl( pTrrbl );
/*
** start edits: September,29th 2005, H.F.
**
** if the timed out connection is an exclusive owner connection,
** any other connection with the same producer connection point
** must be closed, too. Otherwise the Originator of the exclusive
** owner connection would not be signalled that the O->T data is
** no longer being received by the target device, as the target
** device would further produce data on the same Multicast address
** and Connection ID.
*/
/* check, if an exclusive owner connection timed out */
if( psConnRecord->sPublic.bExclusiveOwnerConn )
{
/*
** Scan the connection record list for connections with the
** same Producer Connection Point
*/
psParallelConnRecord = LL_FirstEntry( &cm_s.sRecordList );
while( !LL_EndOfList( &cm_s.sRecordList, psParallelConnRecord ) )
{
if( psParallelConnRecord->sPublic.iProConnPoint
== psConnRecord->sPublic.iProConnPoint )
{
/*
** Found a connection with the same Producer
** Connection Point, tell CM to close it.
*/
pTrrblClose = GS_NewTrrbl( CM_CloseTrrblType );
pTrrblClose->eRequest = TREQ_CLOSE_CONNECTION;
pTrrblClose->xUserHandle = NULL;
pTrrblClose->iConnectionSn = psParallelConnRecord->sPublic.iConnectionSn;
pTrrblClose->fUnrequestedClose = FALSE;
pTrrblClose->pCombuf = NULL;
GS_PutTrrbl( CM_xQid, pTrrblClose );
}
psParallelConnRecord = LL_NextEntry( psParallelConnRecord );
}
}
/*
** end edits: September,29th 2005, H.F.
*/
}
else
{
psConnRecord->pTrrblClose = pTrrbl;
}
/*
** Continue the close process.
*/
cm_ContinueProcessing( psConnRecord );
}
} /* end of cm_CloseConnection() */
/*---------------------------------------------------------------------------
** cm_ContinueClosing()
**---------------------------------------------------------------------------
*/
void cm_ContinueClosing( cm_ConnectionRecordType *psConnRecord )
{
CD_TransportTrrblType *pTrrbl;
ID_TrrblType *pIdTrrbl;
/*
** start edits: September,9th 2005, H.F.
*/
t_UserDefinedAssemblyInstance *aConsumerAssemblyInstance;
/*
** end edits: September,9th 2005, H.F.
*/
/*
** start edits: September,20th 2005, H.F.
*/
t_UserDefinedAssemblyInstance *aProducerAssemblyInstance;
t_UserDefinedAssemblyInstance *aConfigAssemblyInstance;
/*
** end edits: September,20th 2005, H.F.
*/
/*----------------------------------------------------------
** Before closeing this connection, make sure any opening
** requests that have been issued, have returned.
**----------------------------------------------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -