根据simplici TI说明,网络层数据队列分为输入队列和输出队列,输入队列用于存储从射频层取回的数据帧,输出队列用于暂存等待发送的数据帧,它们使用了LRU淘汰机制。
单个队列数据队列单元如下所示:
其中fi_usage代表数据单元使用状况,一共有如下几种状态,FI_AVAILABLE代表数据单元可用,FI_INUSE_UNTIL_DEL表示等待释放存储空间,FI_INUSE_UNTIL_TX表示等待发送,FI_INUSE_UNTIL_FWD表示等待AP转发,FI_INUSE_TRANSITION表示取回,不在中断中删除。
oderStamp个人理解用于表示数据在队列中停留时间,mrfiPkt当然就是射频数据包
存储结构如图所示:
Simplici Ti针对队列管理主要提供如下API:
void nwk_QInit(void) |
队列初始化 |
frameInfo_t *nwk_QfindSlot(uint8_t which) | 找到一个位置用于从射频取回帧数据 |
void nwk_QadjustOrder(uint8_t which, uint8_t stamp) | 调整队列 |
frameInfo_t *nwk_QfindOldest(uint8_t which, rcvContext_t *rcv, uint8_t fi_usage) | 查看帧队列并查找停留在队列时间最长的可用帧 |
frameInfo_t *nwk_getQ(uint8_t which) | 获取指定帧队列的地址 |
nwk_QInit:队列初始化的功能是将数据存储单元清零,所有fi_usage设置为FI_AVAILABLE,即数据单元可用,所有oderStamp为0.
void nwk_QInit(void)
{
#if SIZE_INFRAME_Q > 0
memset(sInFrameQ, 0, sizeof(sInFrameQ));
#endif // SIZE_INFRAME_Q > 0
memset(sOutFrameQ, 0, sizeof(sOutFrameQ));
}
nwk_QfindSlot:首先遍历队列,遍历队列主要寻找空闲位置和队列数据单元暂用个数,以及占用stamp值最小的位置,如果队列有空闲位置,给空闲位置stamp赋值暂用单元个数+1,如果未找到可用数据单元,将stamp值最小的位置返回
frameInfo_t *nwk_QfindSlot(uint8_t which)
{
frameInfo_t *pFI, *oldest= 0, *newFI = 0;
uint8_t i, num, newOrder = 0, orderTest;
if (INQ == which)
{
pFI = sInFrameQ;//输入队列指针
num = SIZE_INFRAME_Q;//输入队列容量
}
else
{
pFI = sOutFrameQ;//输出队列指针
num = SIZE_OUTFRAME_Q;//输出队列容量
}
orderTest = num + 1;
for (i=0; ifi_usage != FI_AVAILABLE)//不可用
{
/*支队输入队列操作,输出队列不做操作*/
if (INQ == which) /* TODO: do cast-out for Tx as well */
{
/* need to know the number of occupied slots so we know the age value
* for the unoccupied slot (if there is one).
*/
//需要知道占用位置的数量,所以我们需要直到未占用位置的年龄
newOrder++;//占用的个数
/* make sure nwk_retrieveFrame() is not processing this frame */
if (FI_INUSE_TRANSITION == pFI->fi_usage)
{
continue;
}
/* is this frame older than any we've seen? */
if (orderTest > pFI->orderStamp)
{
/* yes. */
oldest = pFI;//最早存进来的
orderTest = pFI->orderStamp;//最小对的stamp值
}
}
}
else//可用FI_AVALIABLE
{
if (OUTQ == which) /* TODO: do cast-out for Tx as well */
{
return pFI;//输出队列的话直接返回
}
newFI = pFI;//先把FI_AVALIABLE 的空间赋值给newFI
}
}
/* did we find anything? */
if (!newFI)//如果没返回,则队列已满
{
/* queue was full. cast-out happens here...unless... */
if (!oldest)//
{
/* This can happen if the queue is only of size 1 or 2 and all
* the frames are in transition when the Rx interrupt occurs.
*/
return (frameInfo_t *)0;
}
newFI = oldest;
nwk_QadjustOrder(which, newFI->orderStamp);
newFI->orderStamp = i;
}
else
{
/* mark the available slot. */
newFI->orderStamp = ++newOrder;
}
return newFI;
}
nwk_QadjustOrder:把所有非空闲且大于某个stamp值的缓冲区stamp值减1
void nwk_QadjustOrder(uint8_t which, uint8_t stamp)
{
frameInfo_t *pFI;
uint8_t i, num;
bspIState_t intState;
//只对输入队列操作
if (INQ == which)
{
pFI = sInFrameQ;
num = SIZE_INFRAME_Q;
}
else
{
/* pFI = sOutFrameQ; */
/* num = SIZE_OUTFRAME_Q; */
return;
}
BSP_ENTER_CRITICAL_SECTION(intState);
for (i=0; ifi_usage != FI_AVAILABLE) && (pFI->orderStamp > stamp))
{
pFI->orderStamp--;//就是把各个缓冲区的orderstamp值减1
}
}
BSP_EXIT_CRITICAL_SECTION(intState);
return;
}
nwk_QfindOldest:
frameInfo_t *nwk_QfindOldest(uint8_t which, rcvContext_t *rcv, uint8_t fi_usage)
{
uint8_t i, oldest, num, port;
uint8_t uType, addr12Compare;
bspIState_t intState;
frameInfo_t *fPtr = 0, *wPtr;
connInfo_t *pCInfo = 0;
uint8_t *pAddr1 = 0, *pAddr2 = 0, *pAddr3 = 0;
//只用于输入队列
if (INQ == which)
{
wPtr = sInFrameQ;
num = SIZE_INFRAME_Q;
oldest = SIZE_INFRAME_Q+1;
}
else
{
/* pFI = sOutFrameQ; */
/* num = SIZE_OUTFRAME_Q; */
return 0;
}
if (RCV_APP_LID == rcv->type)//如果接收到的是APP_LID
{
pCInfo = nwk_getConnInfo(rcv->t.lid);//获取连接信息根据lid
if (!pCInfo)//如果如连接信息,返回NULL
{
return (frameInfo_t *)0;
}
port = pCInfo->portRx;//接收端口
pAddr2 = pCInfo->peerAddr;//对方地址
}
else if (RCV_NWK_PORT == rcv->type)//如果接收到的是端口
{
port = rcv->t.port;//接收端口
}
#ifdef ACCESS_POINT
else if (RCV_RAW_POLL_FRAME == rcv->type)
{
port = *(MRFI_P_PAYLOAD(rcv->t.pkt)+F_APP_PAYLOAD_OS+M_POLL_PORT_OS);//获取接收端口
pAddr2 = MRFI_P_SRC_ADDR(rcv->t.pkt);//获取源地址
pAddr3 = MRFI_P_PAYLOAD(rcv->t.pkt)+F_APP_PAYLOAD_OS+M_POLL_ADDR_OS;//获取轮询地址
}
#endif
else
{
return (frameInfo_t *)0;//三种类型把都不是
}
uType = (USAGE_NORMAL == fi_usage) ? FI_INUSE_UNTIL_DEL : FI_INUSE_UNTIL_FWD;//直到删除/直到转发
for (i=0; ifi_usage)
{
wPtr->fi_usage = FI_INUSE_TRANSITION;//变为直到取出帧
BSP_EXIT_CRITICAL_SECTION(intState); /* release hold */
/* message sent to this device? */
if (GET_FROM_FRAME(MRFI_P_PAYLOAD(&wPtr->mrfiPkt), F_PORT_OS) == port)//获取端口信息
{
/* Port matches. If the port of interest is a NWK applicaiton we're a
* match...the NWK applications are not connection-based. If it is a
* NWK application we need to check the source address for disambiguation.
* Also need to check source address if it's a raw frame lookup (S&F frame)
*/
//端口相匹配。 如果相关端口是NWK应用程序,是匹配的... NWK应用程序不是基于连接的。 如果它是NWK应用程序,我们需要检查源地址以消除歧义。 还需要检查源地址是否是原始帧查找(S&F帧)
if (RCV_APP_LID == rcv->type)
{
if (SMPL_PORT_USER_BCAST == port)
{
/* guarantee a match... */
pAddr1 = pCInfo->peerAddr;
}
else
{
pAddr1 = MRFI_P_SRC_ADDR(&wPtr->mrfiPkt);
}
}
#ifdef ACCESS_POINT
else if (RCV_RAW_POLL_FRAME == rcv->type)
{
pAddr1 = MRFI_P_DST_ADDR(&wPtr->mrfiPkt);
}
#endif
addr12Compare = memcmp(pAddr1, pAddr2, NET_ADDR_SIZE);
if ( (RCV_NWK_PORT == rcv->type) ||
(!pAddr3 && !addr12Compare) ||
(pAddr3 && !memcmp(pAddr3, MRFI_P_SRC_ADDR(&wPtr->mrfiPkt), NET_ADDR_SIZE))
)
{
if (wPtr->orderStamp < oldest)
{
if (fPtr)
{
/* restore previous oldest one */
fPtr->fi_usage = uType;
}
oldest = wPtr->orderStamp;
fPtr = wPtr;
continue;
}
else
{
/* not oldest. restore state */
wPtr->fi_usage = uType;
}
}
else
{
/* not a match. restore state */
wPtr->fi_usage = uType;
}
}
else
{
/* wrong port. restore state */
wPtr->fi_usage = uType;
}
}
else
{
BSP_EXIT_CRITICAL_SECTION(intState);
}
}
return fPtr;
}
nwk_getQ:返回队列地址
frameInfo_t *nwk_getQ(uint8_t which)
{
return (INQ == which) ? sInFrameQ : sOutFrameQ;
}