Part Number: CC2652P
Other Parts Discussed in Thread: Z-STACK
AF_DataRequest发送超过82字节的数据包,目标端口0xFF,可以发送给Silicon Labs的zigbee芯片,但是无法发给自己同类型芯片,SDK 8.30。
不是这个问题,我使用AF_DataRequest发送一包数据到协调器,dstAddr->shortAddr = 0x0000, dstAddr->endPoint = 0xFF, len = 100. 协调器就不能接收该包数据,但是把len改成80或者把dstAddr->endPoint的值改成0x01,协调器就能接收这包数据。
有可能是TI Z-Stack对广播端点的分片限制,您把dstAddr->endPoint改为特定的端点,而不是广播端点
如果是TI Z-Stack对广播端点的分片限制,那这样就不合理。如果分片传输只是禁止短地址广播是合理的,但是如果是端点广播,目标地址是单播,不应该限制这种使用方式。我在Z-stack 3.0.2的aps_frag.c中发现,函数APSF_AllocRxObj只筛选aff->DstEndPoint为本机注册端点,未考虑aff->DstEndPoint等于0xFF的情况。我想提供一种思路,aff->DstEndPoint为0xFF时,把pRx->taskID赋值为APSF_taskID,分片接收完毕后把AF_INCOMING_MSG_CMD消息先发给APSF_ProcessEvent任务,在APSF_ProcessEvent任务中再增加一次处理,把AF_INCOMING_MSG_CMD按照注册端点数量进行复制,再发给各个端点对应的Task。
所以你们能否提供一下SDK 8.30的aps_frag.c文件,就像之前对nl_mede_cb.c中对APS Retry缓存溢出不能触发DATA CONFIRM的修复方式那样。
以下只是参考意见
/**************************************************************************************************
Filename: aps_frag.c
Revised: $Date: 2013-09-27 11:56:40 -0700 (Fri, 27 Sep 2013) $
Revision: $Revision: 35472 $
Description: Implements APS Application Data Unit Fragmentation
Copyright 2006-2013 Texas Instruments Incorporated. All rights reserved.
IMPORTANT: Your use of this Software is limited to those specific rights
granted under the terms of a software license agreement between the user
who downloaded the software, his/her employer (which must be your employer)
and Texas Instruments Incorporated (the "License"). You may not use this
Software unless you agree to abide by the terms of the License. The License
limits your use, and you acknowledge, that the Software may not be modified,
copied or distributed unless embedded on a Texas Instruments microcontroller
or used solely and exclusively in conjunction with a Texas Instruments radio
frequency transceiver, which is integrated into your product. Other than for
the foregoing purpose, you may not use, reproduce, copy, prepare derivative
works of, modify, distribute, perform, display or sell this Software and/or
its documentation for any purpose.
YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE
PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED,
INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE,
NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL
TEXAS INSTRUMENTS OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT,
NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER
LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES
INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE
OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT
OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES
(INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS.
Should you have any questions regarding your right to use this Software,
contact Texas Instruments Incorporated at www.TI.com.
**************************************************************************************************/
/*********************************************************************
* INCLUDES
*/
#include "OSAL.h"
#include "AF.h"
#include "ZDApp.h"
#include "aps_frag.h"
#include "aps_util.h"
#include "hal_assert.h"
#include "nwk_util.h"
#include "ZGlobals.h"
/*********************************************************************
* MACROS
*/
// Time to wait for an ackknowledgement
#define APSF_ACK_WAIT (100 * _NIB.MaxDepth * zgApsAckWaitMultiplier)
// Time to wait for retrys before timing out the reception
#define APSF_RX_TOUT (APSF_ACK_WAIT + APSF_ACK_WAIT * zgApscMaxFrameRetries)
// Object list type
#define APSF_TX_TYPE 1
#define APSF_RX_TYPE 2
/*********************************************************************
* CONSTANTS
*/
#define APSF_DEF_FRAME_DELAY 50
#define APSF_DEF_WINDOW_SIZE 3
#define APSF_ZCL_WINDOW_SIZE 1
/*********************************************************************
* TYPEDEFS
*/
typedef struct _apsf_hdr_t {
uint16 timeStamp;
uint16 duration;
uint16 shortAddr;
uint8 type;
uint8 apsCount;
uint8 numBlocks;
struct _apsf_hdr_t *pNext;
} APSF_Header_t;
typedef struct {
APSF_Header_t hdr;
APSDE_DataReq_t dataReq;
uint8 blockSize;
uint8 firstBlk; // First block in the window
uint8 sendMask; // Mask of sent blocks (1=sent)
uint8 ackBits; // Mask of acked blocks (1=ack)
uint8 retry;
uint8 windowSize;
uint8 frameDelay;
uint16 len;
uint8 *pData;
} APSF_TxObj_t;
typedef struct {
APSF_Header_t hdr;
uint8 taskID;
uint8 ackBits;
uint8 fragSize;
uint8 firstBlk; // First block in the window
uint8 windowSize;
afIncomingMSGPacket_t *pMsg;
} APSF_RxObj_t;
/*********************************************************************
* GLOBAL VARIABLES
*/
uint8 APSF_taskID = 0xff;
/*********************************************************************
* EXTERNAL VARIABLES
*/
extern uint8 zgApsAckWaitMultiplier;
/*********************************************************************
* EXTERNAL FUNCTIONS
*/
/*********************************************************************
* LOCAL VARIABLES
*/
static APSF_Header_t *APSF_ObjList;
/*********************************************************************
* LOCAL FUNCTIONS
*/
static void APSF_AddObj(APSF_Header_t *pHdr, uint8 type);
static APSF_Header_t *APSF_FindObj(uint8 apsCount, uint16 shortAddr, uint8 type);
static APSF_Header_t *APSF_FreeObj(APSF_Header_t *pHdr);
static void APSF_TxNextFrame(APSF_TxObj_t *pTx);
static void APSF_Schedule( void );
static APSF_Header_t *APSF_AllocRxObj(aps_FrameFormat_t *aff, zAddrType_t *SrcAddress,
NLDE_Signal_t *sig, uint8 SecurityUse, uint32 timestamp );
static void APSF_IncomingData(aps_FrameFormat_t *aff, zAddrType_t *SrcAddress,
NLDE_Signal_t *sig, uint8 SecurityUse, uint32 timestamp);
uint8 (*pAPSF_IgnoreBlock)( uint8 block ) = (void*)NULL;
/*********************************************************************
* PUBLIC FUNCTIONS
*/
/*********************************************************************
* @fn APSF_Init
*
* @brief Initialization function for the Task.
* This is called during initialization and should contain
* any application specific initialization (ie. hardware
* initialization/setup, table initialization, power up
* notificaiton ... ).
*
* @param task_id - the ID assigned by OSAL. This ID should be
* used to send messages and set timers.
*
* @return none
*/
void APSF_Init(uint8 task_id)
{
// Record the task ID
APSF_taskID = task_id;
// Setup the entry points
apsfSendFragmented = &APSF_SendFragmented;
apsfProcessAck = &APSF_ProcessAck;
apsfSendOsalMsg = &APSF_SendOsalMsg;
}
/*********************************************************************
* @fn APSF_AddObj
*
* @brief Adds a block message to the list of TX and RX messages.
*
* @param pObj - Pointer to type dpecific data to store in the block.
* type - The block represents an RX or TX.
*
* @return none
*/
static void APSF_AddObj(APSF_Header_t *pHdr, uint8 type)
{
APSF_Header_t *pTmp;
HAL_ASSERT(pHdr);
// Insert the block message in the list
if (!APSF_ObjList)
APSF_ObjList = pHdr;
else
{
pTmp = APSF_ObjList;
while (pTmp->pNext)
pTmp = pTmp->pNext;
pTmp->pNext = pHdr;
}
// Initialize the header
pHdr->pNext = NULL;
pHdr->type = type;
}
/*********************************************************************
* @fn APSF_FindObj
*
* @brief Finds a block message in the list of TX and RX messages.
*
* @param apsCount - The APS Count ID of the fragmented data.
* type - The opject represents an RX or TX.
*
* @return none
*/
static APSF_Header_t *APSF_FindObj(uint8 apsCount, uint16 shortAddr, uint8 type)
{
APSF_Header_t *pHdr = APSF_ObjList;
while (pHdr)
{
if ((pHdr->apsCount == apsCount) &&
(pHdr->shortAddr == shortAddr) &&
(pHdr->type == type))
return pHdr;
pHdr = pHdr->pNext;
}
return NULL;
}
/*********************************************************************
* @fn APSF_FreeObj
*
* @brief Frees a block message from the list of TX and RX messages.
*
* @param pHdr - Block to free.
*
* @return Block previous to pHdr.
*/
static APSF_Header_t *APSF_FreeObj(APSF_Header_t *pHdr)
{
APSF_Header_t *pTmp = APSF_ObjList;
// Remove the object from the list
if (pHdr == APSF_ObjList)
pTmp = APSF_ObjList = APSF_ObjList->pNext;
else
{
while (pTmp)
{
if (pTmp->pNext == pHdr)
{
pTmp->pNext = pHdr->pNext;
break;
}
pTmp = pTmp->pNext;
}
}
// Free the object
osal_mem_free(pHdr);
return pTmp;
}
/*********************************************************************
* @fn APSF_SendFragmented
*
* @brief Puts a afMultiHdr into the list of block messages.
*
* @param p_hdr - afMultiHdr_t to be transmitted.
* profileID - The profile ID of the endpoint
*
* @return none
*/
afStatus_t APSF_SendFragmented(APSDE_DataReq_t *pReq)
{
APSF_TxObj_t *pTx;
afDataReqMTU_t mtu;
uint16 dstAddr;
if ( pReq->dstAddr.addrMode == AddrNotPresent ||
pReq->dstAddr.addrMode == AddrGroup ||
NLME_IsAddressBroadcast(pReq->dstAddr.addr.shortAddr) != ADDR_NOT_BCAST )
{
return afStatus_INVALID_PARAMETER;
}
// Find out the destination short address
if ( pReq->dstAddr.addrMode == Addr64Bit )
{
if ( APSME_LookupNwkAddr( pReq->dstAddr.addr.extAddr, &dstAddr ) == FALSE )
{
return afStatus_INVALID_PARAMETER;
}
}
else
{
dstAddr = pReq->dstAddr.addr.shortAddr;
}
// Allocate a TX object
pTx = osal_mem_alloc(sizeof(APSF_TxObj_t) + pReq->asduLen);
if (pTx)
{
afAPSF_Config_t cfg;
// Initialize the pTx
osal_memset(pTx, 0, sizeof(APSF_TxObj_t));
afAPSF_ConfigGet(pReq->srcEP, &cfg);
pTx->frameDelay = cfg.frameDelay;
pTx->windowSize = cfg.windowSize;
// Add the TX object to the list
APSF_AddObj((APSF_Header_t*) pTx, APSF_TX_TYPE);
// Copy the data request information
osal_memcpy(&pTx->dataReq, pReq, sizeof(APSDE_DataReq_t));
// Copy the msg data
pTx->pData = (uint8*) (pTx + 1);
pTx->len = pReq->asduLen;
osal_memcpy(pTx->pData, pReq->asdu, pReq->asduLen);
pTx->hdr.shortAddr = dstAddr;
pTx->hdr.apsCount = APS_Counter++;
pTx->hdr.timeStamp = (uint16) osal_GetSystemClock();
pTx->sendMask = pTx->ackBits = 0xff << pTx->windowSize;
mtu.kvp = FALSE;
if (pReq->txOptions & APS_TX_OPTIONS_SECURITY_ENABLE)
mtu.aps.secure = TRUE;
else
mtu.aps.secure = FALSE;
pTx->blockSize = afDataReqMTU(&mtu) - APS_XFRAME_CTRL_FIELD_LEN - APS_BLOCK_CNT_FIELD_LEN;
// Set the total number of blocks
pTx->hdr.numBlocks = pTx->len / pTx->blockSize;
if (pTx->len % pTx->blockSize)
{
pTx->hdr.numBlocks++;
}
// Enable fragmentation permitted tx option
pTx->dataReq.txOptions |= APS_TX_OPTIONS_PERMIT_FRAGMENT;
// Kick the scheduler
osal_set_event(APSF_taskID, APSF_SCHED_EVT);
return afStatus_SUCCESS;
}
return afStatus_MEM_FAIL;
}
/*********************************************************************
* @fn APSF_TxNextFrame
*
* @brief Goes through the list of block messages and transmits
* the next frame.
*
* @param none
*
* @return none
*/
static void APSF_TxNextFrame(APSF_TxObj_t *pTx)
{
uint16 len;
uint8 block;
uint8 i;
pTx->hdr.timeStamp = (uint16) osal_GetSystemClock();
if (pTx->retry < zgApscMaxFrameRetries)
{
if (pTx->sendMask == 0xff)
{
// No ack received. Retry
pTx->retry++;
pTx->sendMask = pTx->ackBits;
}
// Determine the block to send
block = pTx->firstBlk;
for ( i = 0; i < pTx->windowSize; i++ )
{
if ( (pTx->sendMask ^ 0xFF) & (1 << i) )
{
block += i;
pTx->sendMask |= (1 << i);
break;
}
}
// Calculate the block length
len = pTx->len - (block * pTx->blockSize);
if (len >= pTx->blockSize)
{
len = pTx->blockSize;
}
else
{
// Last block, fill in all bits in the sent mask
pTx->sendMask = 0xff;
}
if (pTx->sendMask == 0xff)
{
// Last block in the window. Request an ack
pTx->hdr.duration = APSF_ACK_WAIT;
}
else
{
pTx->hdr.duration = pTx->frameDelay;
}
if (block == 0)
{
// First fragment
pTx->dataReq.txOptions |= APS_TX_OPTIONS_FIRST_FRAGMENT;
// blkCount contains total number of blocks
pTx->dataReq.blkCount = pTx->hdr.numBlocks;
// Set pReq asdu ptr to beginnning
pTx->dataReq.asdu = pTx->pData;
}
else
{
// Not first fragment
pTx->dataReq.txOptions &= ~APS_TX_OPTIONS_FIRST_FRAGMENT;
// Set the block
pTx->dataReq.blkCount = block;
// Set pReq asdu ptr to data to send
pTx->dataReq.asdu = pTx->pData + block * pTx->blockSize;
}
pTx->dataReq.apsCount = pTx->hdr.apsCount;
pTx->dataReq.asduLen = (uint8) len;
// For error testing
if ( pAPSF_IgnoreBlock && pAPSF_IgnoreBlock( block ) )
return; // Don't send the packet
// Send the block
APSDE_DataReq(&pTx->dataReq);
}
else
{
// Max retry reached, send DATA.confirm failure
afDataConfirm(pTx->dataReq.srcEP, pTx->dataReq.transID, ZMacNoACK);
APSF_FreeObj((APSF_Header_t*) pTx);
}
}
/*********************************************************************
* @fn APSF_Schedule
*
* @brief Goes through the list of block messages, picks the next
* block to transmit, and timeout any old RX block messages.
*
* @param none
*
* @return none
*/
static void APSF_Schedule( void )
{
APSF_Header_t *pHdr = APSF_ObjList;
uint16 sysClk = (uint16) osal_GetSystemClock();
uint16 nextTime = 0xffff;
uint16 duration;
// Go through list
while (pHdr)
{
duration = sysClk - pHdr->timeStamp;
if (duration >= pHdr->duration)
{
// RX or TX Object
if (pHdr->type == APSF_RX_TYPE)
{
APSF_RxObj_t *pRx = (APSF_RxObj_t*) pHdr;
// The task owns the pMsg id the rx completed sucessfully, else free the pMsg
if (pRx->taskID != 0xff)
{
osal_msg_deallocate((uint8*) pRx->pMsg);
}
// Free the RX Obj
APSF_FreeObj(pHdr);
}
else
{
// Handle TX timeout
APSF_TxNextFrame((APSF_TxObj_t*) pHdr);
}
// Only process one Object at a time without context switch
osal_set_event(APSF_taskID, APSF_SCHED_EVT);
return;
}
else
{
// Keep track of smallest time for next scheduled event
if (pHdr->duration - duration < nextTime)
nextTime = pHdr->duration - duration;
}
pHdr = pHdr->pNext;
}
// Start timer for next escheduled event
if (nextTime != 0xffff)
osal_start_timerEx(APSF_taskID, APSF_SCHED_EVT, nextTime);
}
/*********************************************************************
* @fn APSF_ProccessAck
*
* @brief Processes an ack on Fragmented APS data.
*
* @param aff - Frame format.
* status - The status of the operation.
*
* @return none
*/
void APSF_ProcessAck(aps_FrameFormat_t *aff, uint16 srcAddr, uint8 status)
{
APSF_TxObj_t *pTx = (APSF_TxObj_t*) APSF_FindObj(aff->ApsCounter, srcAddr, APSF_TX_TYPE);
if (pTx && status == ZSuccess)
{
// Verify the ack matches the window
if (aff->BlkCount != pTx->firstBlk)
return;
if ((aff->BlkCount + pTx->windowSize >= pTx->hdr.numBlocks) &&
(aff->AckBits == 0xff))
{
// TX complete. Send data confirm and free the TX object
afDataConfirm(pTx->dataReq.srcEP, pTx->dataReq.transID, status);
APSF_FreeObj((APSF_Header_t*) pTx);
}
else
{
// Check if we are moving to the next window
if (aff->AckBits == 0xff)
{
pTx->ackBits = pTx->sendMask = 0xff << pTx->windowSize;
pTx->firstBlk += pTx->windowSize;
pTx->retry = 0;
}
else
{
// Record the ack
pTx->ackBits = aff->AckBits;
pTx->sendMask = aff->AckBits;
}
// Set the delay
pTx->hdr.timeStamp = (uint16) osal_GetSystemClock();
pTx->hdr.duration = pTx->frameDelay;
// Kick the scheduler
osal_set_event(APSF_taskID, APSF_SCHED_EVT);
}
}
}
/*********************************************************************
* @fn APSF_AllocRxObj
*
* @brief Allocates an object used to track the RX fragmented data.
*
* @param aff - APS frame format
* SrcAddress - Source address of data.
* sig - Link quality of received data.
* SecurityUse - Passed in from APS
* timestamp - when the message arrived
*
* @return none
*/
static APSF_Header_t *APSF_AllocRxObj(aps_FrameFormat_t *aff, zAddrType_t *SrcAddress,
NLDE_Signal_t *sig, uint8 SecurityUse, uint32 timestamp )
{
uint16 msgLen;
afIncomingMSGPacket_t *MSGpkt;
endPointDesc_t *epDesc = NULL;
APSF_RxObj_t *pRx;
// Discard if the endpoint is not supported
if (aff->DstEndPoint != 0xFF)
{
// Only look for an endpoint if the message is not a broadcast, fixed by Luoyiming 2026-06-08
epDesc = afFindEndPointDesc(aff->DstEndPoint);
if (!epDesc)
return NULL;
}
// Allocate an RX object
pRx = osal_mem_alloc(sizeof(APSF_RxObj_t));
if (pRx)
{
afAPSF_Config_t cfg;
// Initialize the RX Object
osal_memset(pRx, 0, sizeof(APSF_RxObj_t));
afAPSF_ConfigGet(aff->DstEndPoint, &cfg);
pRx->windowSize = cfg.windowSize;
// Add the RX Object to the list
APSF_AddObj((APSF_Header_t*) pRx, APSF_RX_TYPE);
pRx->hdr.shortAddr = SrcAddress->addr.shortAddr;
pRx->hdr.apsCount = aff->ApsCounter;
pRx->ackBits = 0xff << pRx->windowSize;
// Record the task ID
if (aff->DstEndPoint == AF_BROADCAST_ENDPOINT)
{
// If DstEndPoint is a broadcast, set taskID to APSF_taskID and let APSF_ProcessEvent
// send the message to all matching endpoints. Fixed by Luoyiming 2026-06-08
pRx->taskID = APSF_taskID;
}
else
{
pRx->taskID = *epDesc->task_id;
}
// The block count on the first fragment contians the total number of blocks
// The asduLength contains the length of each block ( not clear in spec ??? )
pRx->fragSize = aff->asduLength;
msgLen = sizeof(afIncomingMSGPacket_t) + aff->BlkCount * pRx->fragSize;
pRx->pMsg = MSGpkt = (afIncomingMSGPacket_t*) osal_msg_allocate( msgLen );
if (MSGpkt)
{
MSGpkt->hdr.event = AF_INCOMING_MSG_CMD;
MSGpkt->hdr.status = afStatus_SUCCESS;
MSGpkt->groupId = 0;
MSGpkt->clusterId = aff->ClusterID;
// Make an AF source address
afCopyAddress ( &(MSGpkt->srcAddr), SrcAddress );
MSGpkt->srcAddr.endPoint = aff->SrcEndPoint;
// A fragmented message could not have been received via Inter-PAN.
MSGpkt->srcAddr.panId = _NIB.nwkPanId;
MSGpkt->macSrcAddr = aff->macSrcAddr;
MSGpkt->macDestAddr = aff->macDestAddr;
MSGpkt->endPoint = aff->DstEndPoint;
MSGpkt->wasBroadcast = aff->wasBroadcast;
MSGpkt->LinkQuality = sig->LinkQuality;
MSGpkt->correlation = sig->correlation;
MSGpkt->rssi = sig->rssi;
MSGpkt->SecurityUse = SecurityUse;
MSGpkt->timestamp = timestamp;
MSGpkt->cmd.Data = (uint8 *) (MSGpkt + 1);
MSGpkt->cmd.TransSeqNumber = aff->transID;
}
else
{
APSF_FreeObj((APSF_Header_t*)pRx);
pRx = NULL;
}
}
return ( (APSF_Header_t*) pRx );
}
/*********************************************************************
* @fn APSF_IncomingData
*
* @brief Processes incomming fragmented APS data
*
* @param aff - APS frame format
* SrcAddress - Source address of data.
* sig - Link quality of received data.
*
* @return none
*/
static void APSF_IncomingData(aps_FrameFormat_t *aff, zAddrType_t *SrcAddress,
NLDE_Signal_t *sig, uint8 SecurityUse, uint32 timestamp)
{
// Find or add header to the list
APSF_RxObj_t *pRx;
uint8 lastBlk = FALSE;
uint8 block = aff->BlkCount;
// For error testing
if ( pAPSF_IgnoreBlock && pAPSF_IgnoreBlock( block ) )
return; // Don't receive the packet
pRx = (APSF_RxObj_t*) APSF_FindObj(aff->ApsCounter,
SrcAddress->addr.shortAddr,
APSF_RX_TYPE);
if (pRx == NULL)
{
// Add to list if first fragment
if (aff->XtndFrmCtrl & APS_XFC_FIRST_FRAG)
{
pRx = (APSF_RxObj_t*) APSF_AllocRxObj(aff, SrcAddress, sig,
SecurityUse, timestamp);
if (pRx)
{
// First fragment blkCount contains total number of blocks
pRx->hdr.numBlocks = block;
// Kick the scheduler
osal_set_event(APSF_taskID, APSF_SCHED_EVT);
}
}
}
if (pRx)
{
// Record if last block of the transfer
if (block == pRx->hdr.numBlocks - 1)
{
lastBlk = TRUE;
}
if (pRx->taskID != 0xff)
{
// Set block count to zero on first fragment
if (aff->XtndFrmCtrl & APS_XFC_FIRST_FRAG)
{
block = 0;
}
// Check if the window has moved
if (block >= pRx->firstBlk + pRx->windowSize)
{
pRx->firstBlk += pRx->windowSize;
pRx->ackBits = 0xff << pRx->windowSize;
}
// Copy the data
osal_memcpy(pRx->pMsg->cmd.Data + block * pRx->fragSize,
aff->asdu, aff->asduLength);
// Set the ack bit
pRx->ackBits |= 1 << (block % pRx->windowSize);
if (lastBlk)
{
// Fill in all unused ack bits
pRx->ackBits |= 0xff << ((block % pRx->windowSize) + 1);
// Calcualte the actual length of the message
pRx->pMsg->cmd.DataLength = pRx->fragSize * block + aff->asduLength;
}
// Check if the transfer is complete
if (lastBlk && pRx->ackBits == 0xff)
{
// Send message to endpoint task
osal_msg_send(pRx->taskID, (uint8*) pRx->pMsg);
// The RX object must persist incase the last ack was lost.
// Set the task ID to 0xff indicating the rx process is complete
// then free the RX object in the timeout
pRx->taskID = 0xff;
}
else
{
// Reset timer for RX timeout error
pRx->hdr.timeStamp = (uint16) osal_GetSystemClock();
pRx->hdr.duration = APSF_RX_TOUT;
}
}
// Send ack on last block in the window, retry is complete, or on last block in transfer
if (block == pRx->firstBlk + pRx->windowSize - 1 || pRx->ackBits == 0xff || lastBlk)
{
aff->BlkCount = pRx->firstBlk;
aff->AckBits = pRx->ackBits;
apsGenerateAck(SrcAddress->addr.shortAddr, aff);
}
}
}
/*********************************************************************
* @fn APSF_SendOsalMsg
*
* @brief Sends a message to the APSF_Task
*
* @param msgPtr - Message
*
* @return none
*/
void APSF_SendOsalMsg(uint8 *msgPtr)
{
osal_msg_send(APSF_taskID, msgPtr);
}
/*********************************************************************
* @fn Sim_ProcessEvent
*
* @brief Task event processor. This function
* is called to process all events for the task. Events
* include timers, messages and any other user defined events.
*
* @param task_id - The OSAL assigned task ID.
* @param events - events to process. This is a bit map and can
* contain more than one event.
*
* @return none
*/
UINT16 APSF_ProcessEvent(uint8 task_id, UINT16 events)
{
afIncomingMSGPacket_t *MSGpkt;
apsInMsg_t *pData;
(void)task_id; // Intentionally unreferenced parameter
if (events & SYS_EVENT_MSG)
{
while ((MSGpkt = (afIncomingMSGPacket_t*) osal_msg_receive(APSF_taskID)) != NULL)
{
switch (MSGpkt->hdr.event)
{
case APS_INCOMING_MSG:
pData = (apsInMsg_t*) MSGpkt;
APSF_IncomingData(&pData->aff, &pData->SrcAddress,
&(pData->sig), pData->SecurityUse, pData->timestamp);
break;
case AF_INCOMING_MSG_CMD:
{
// If the message is a broadcast, send it to all endpoints that match the profile ID, fixed by Luoyiming 2026-06-08
if (MSGpkt->endPoint == AF_BROADCAST_ENDPOINT)
{
// Broadcast message
epList_t *pList = epList;
while (pList)
{
if ( (pList->epDesc->AppProfId == aff->ProfileID) ||
((pList->epDesc->endPoint != ZDO_EP) && ( aff->ProfileID == ZDO_WILDCARD_PROFILE_ID )) )
{
afIncomingMSGPacket_t *pNewMsg = (afIncomingMSGPacket_t*) osal_msg_allocate( OSAL_MSG_LEN(MSGpkt) );
if (pNewMsg)
{
osal_memcpy(pNewMsg, MSGpkt, OSAL_MSG_LEN(MSGpkt));
osal_msg_send(*pList->epDesc->task_id, (uint8*) pNewMsg);
}
}
pList = pList->next;
}
}
}
break;
default:
break;
}
osal_msg_deallocate((uint8*) MSGpkt);
}
// Return unprocessed events
return (events ^ SYS_EVENT_MSG);
}
if (events & APSF_SCHED_EVT)
{
APSF_Schedule();
return (events ^ APSF_SCHED_EVT);
}
// Discard unknown events
return 0;
}
/**************************************************************************************************
*/