这里首先介绍是第一种方式,采用 Blocking 的方式,在一个 main loop 中发送数据。
第一步:调用 tlc_init 方法,进行TRDP协议栈初始化。
/** Initialize the TRDP stack.
*
* tlc_init initializes the memory subsystem and takes a function pointer to an output function for logging.
*
* @param[in] pPrintDebugString Pointer to debug print function
* @param[in] pRefCon user context
* @param[in] pMemConfig Pointer to memory configuration
*
* @retval TRDP_NO_ERR no error
* @retval TRDP_MEM_ERR memory allocation failed
* @retval TRDP_PARAM_ERR initialization error
*/
EXT_DECL TRDP_ERR_T tlc_init (
const TRDP_PRINT_DBG_T pPrintDebugString,
void *pRefCon,
const TRDP_MEM_CONFIG_T *pMemConfig)
第二步:调用 tlc_openSession 方法,取得 类型为TRDP_APP_SESSION_T 的TRDP协议栈的唯一的Handle。
/** Open a session with the TRDP stack.
*
* tlc_openSession returns in pAppHandle a unique handle to be used in further calls to the stack.
*
* @param[out] pAppHandle A handle for further calls to the trdp stack
* @param[in] ownIpAddr Own IP address, can be different for each process in multihoming systems,
* if zero, the default interface / IP will be used.
* @param[in] leaderIpAddr IP address of redundancy leader
* @param[in] pMarshall Pointer to marshalling configuration
* @param[in] pPdDefault Pointer to default PD configuration
* @param[in] pMdDefault Pointer to default MD configuration
* @param[in] pProcessConfig Pointer to process configuration
* only option parameter is used here to define session behavior
* all other parameters are only used to feed statistics
*
* @retval TRDP_NO_ERR no error
* @retval TRDP_INIT_ERR not yet inited
* @retval TRDP_PARAM_ERR parameter error
* @retval TRDP_SOCK_ERR socket error
*/
EXT_DECL TRDP_ERR_T tlc_openSession (
TRDP_APP_SESSION_T *pAppHandle,
TRDP_IP_ADDR_T ownIpAddr,
TRDP_IP_ADDR_T leaderIpAddr,
const TRDP_MARSHALL_CONFIG_T *pMarshall,
const TRDP_PD_CONFIG_T *pPdDefault,
const TRDP_MD_CONFIG_T *pMdDefault,
const TRDP_PROCESS_CONFIG_T *pProcessConfig)
第三步:调用 tlp_publish方法,对过程数据 PD 的 Handle 进行相关的必要的配置,如comID,目标IP地址,发送的初始数据等。
/** Prepare for sending PD messages.
* Queue a PD message, it will be send when tlc_publish has been called
*
* @param[in] appHandle the handle returned by tlc_openSession
* @param[out] pPubHandle returned handle for related re/unpublish
* @param[in] pUserRef user supplied value returned within the info structure of callback function
* @param[in] pfCbFunction Pointer to pre-send callback function, NULL if not used
* @param[in] serviceId optional serviceId this telegram belongs to (default = 0)
* @param[in] comId comId of packet to send
* @param[in] etbTopoCnt ETB topocount to use, 0 if consist local communication
* @param[in] opTrnTopoCnt operational topocount, != 0 for orientation/direction sensitive communication
* @param[in] srcIpAddr own IP address, 0 - srcIP will be set by the stack
* @param[in] destIpAddr where to send the packet to
* @param[in] interval frequency of PD packet (>= 10ms) in usec
* @param[in] redId 0 - Non-redundant, > 0 valid redundancy group
* @param[in] pktFlags OPTION:
* TRDP_FLAGS_DEFAULT, TRDP_FLAGS_NONE, TRDP_FLAGS_MARSHALL, TRDP_FLAGS_CALLBACK
* @param[in] pSendParam optional pointer to send parameter, NULL - default parameters are used
* @param[in] pData optional pointer to data packet / dataset, NULL if sending starts later with tlp_put()
* @param[in] dataSize size of data packet >= 0 and <= TRDP_MAX_PD_DATA_SIZE
*
* @retval TRDP_NO_ERR no error
* @retval TRDP_PARAM_ERR parameter error
* @retval TRDP_MEM_ERR could not insert (out of memory)
* @retval TRDP_NOINIT_ERR handle invalid
*/
EXT_DECL TRDP_ERR_T tlp_publish (
TRDP_APP_SESSION_T appHandle,
TRDP_PUB_T *pPubHandle,
const void *pUserRef,
TRDP_PD_CALLBACK_T pfCbFunction,
UINT32 serviceId,
UINT32 comId,
UINT32 etbTopoCnt,
UINT32 opTrnTopoCnt,
TRDP_IP_ADDR_T srcIpAddr,
TRDP_IP_ADDR_T destIpAddr,
UINT32 interval,
UINT32 redId,
TRDP_FLAGS_T pktFlags,
const TRDP_SEND_PARAM_T *pSendParam,
const UINT8 *pData,
UINT32 dataSize)
{
PD_ELE_T *pNewElement = NULL;
TRDP_TIME_T nextTime;
TRDP_TIME_T tv_interval;
TRDP_ERR_T ret = TRDP_NO_ERR;
TRDP_MSG_T msgType = TRDP_MSG_PD;
TRDP_SOCK_TYPE_T sockType = TRDP_SOCK_PD;
第四步:调用 tlc_updateSession 方法,完成初始的设置,它应该在订阅者和收发者添加进来之后调用。
/** Update a session.
*
* tlc_updateSession signals the end of the set-up phase to the stack. It shall be called after the last publisher
* and subscriber was added and will create and compute the index tables to be used by the high-performance targets.
* This function is currently a no-op on standard targets.
*
* @param[in] appHandle A handle for further calls to the trdp stack
*
* @retval TRDP_NO_ERR no error
* @retval TRDP_INIT_ERR not yet inited
* @retval TRDP_PARAM_ERR parameter error
*/
EXT_DECL TRDP_ERR_T tlc_updateSession (
TRDP_APP_SESSION_T appHandle)
第五步:进入一个主循环 main loop,在这个主循环里需要做的事情有计算最小的 select 超时时间,调用 select,然后 process,和设置发送的数据。
/*
Enter the main processing loop.
*/
while (1)
{
TRDP_FDS_T rfds;
INT32 noDesc;
TRDP_TIME_T tv;
const TRDP_TIME_T max_tv = {0, 1000000};
const TRDP_TIME_T min_tv = {0, TRDP_PROCESS_DEFAULT_CYCLE_TIME};
/*
Prepare the file descriptor set for the select call.
Additional descriptors can be added here.
*/
FD_ZERO(&rfds);
/* FD_SET(pd_fd, &rfds); */
/*
Compute the min. timeout value for select.
This way we can guarantee that PDs are sent in time
with minimum CPU load and minimum jitter.
*/
tlc_getInterval(appHandle, &tv, &rfds, &noDesc);
/*
The wait time for select must consider cycle times and timeouts of
the PD packets received or sent.
If we need to poll something faster than the lowest PD cycle,
we need to set the maximum time out our self.
*/
if (vos_cmpTime(&tv, &max_tv) > 0)
{
tv = max_tv;
}
else if (vos_cmpTime(&tv, &min_tv) < 0)
{
tv = min_tv;
}
/*
Select() will wait for ready descriptors or time out,
what ever comes first.
*/
rv = vos_select(noDesc + 1, &rfds, NULL, NULL, &tv);
/*
Check for overdue PDs (sending and receiving)
Send any pending PDs if it's time...
Detect missing PDs...
'rv' will be updated to show the handled events, if there are
more than one...
The callback function will be called from within the tlc_process
function (in it's context and thread)!
*/
(void) tlc_process(appHandle, &rfds, &rv);
/* Handle other ready descriptors... */
if (rv > 0)
{
vos_printLogStr(VOS_LOG_USR, "other descriptors were ready\n");
}
else
{
fprintf(stdout, ".");
fflush(stdout);
}
if (outputBuffer != NULL && strlen((char *)outputBuffer) != 0)
{
sprintf((char *)outputBuffer, "Just a Counter: %08d", hugeCounter++);
outputBufferSize = (UINT32) strlen((char *)outputBuffer);
}
err = tlp_put(appHandle, pubHandle, outputBuffer, outputBufferSize);
if (err != TRDP_NO_ERR)
{
vos_printLogStr(VOS_LOG_ERROR, "put pd error\n");
rv = 1;
break;
}
}
第六步:主循环之外的清理工作。
tlp_unpublish(appHandle, pubHandle);
tlc_closeSession(appHandle);
tlc_terminate();