SIMPLICI TI 的网络层数据队列管理

根据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 的网络层数据队列管理_第1张图片

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;
}

 

你可能感兴趣的:(SIMPLICI,TI)