/******************************************************************************
 * @fn          nwk_radioControl
 *
 * @brief       Handle radio control functions.
 *
 * input parameters
 * @param   action   - radio operation to perform. currently suppoerted:
 *                         sleep/unsleep
 * output parameters
 *
 * @return   Status of operation.
 */
smplStatus_t nwk_radioControl(ioctlAction_t action, void *val)
{
  smplStatus_t rc = SMPL_SUCCESS;

  if (IOCTL_ACT_RADIO_SLEEP == action)
  {
    /* go to sleep mode. */
    MRFI_RxIdle();
    MRFI_Sleep();
  }
  else if (IOCTL_ACT_RADIO_AWAKE == action)
  {
    MRFI_WakeUp();

#if !defined( END_DEVICE )
    MRFI_RxOn();
#endif

  }
  else if (IOCTL_ACT_RADIO_SIGINFO == action)
  {
    ioctlRadioSiginfo_t *pSigInfo = (ioctlRadioSiginfo_t *)val;
    connInfo_t          *pCInfo   = nwk_getConnInfo(pSigInfo->lid);

    if (!pCInfo)
    {
      return SMPL_BAD_PARAM;
    }
    memcpy(&pSigInfo->sigInfo, &pCInfo->sigInfo, sizeof(pCInfo->sigInfo));
  }
  else if (IOCTL_ACT_RADIO_RSSI == action)
  {
    *((rssi_t *)val) = MRFI_Rssi();
  }
  else if (IOCTL_ACT_RADIO_RXON == action)
  {
    MRFI_RxOn();
  }
  else if (IOCTL_ACT_RADIO_RXIDLE == action)
  {
    MRFI_RxIdle();
  }
#ifdef EXTENDED_API
  else if (IOCTL_ACT_RADIO_SETPWR == action)
  {
    uint8_t idx;

    switch (*(ioctlLevel_t *)val)
    {
      case IOCTL_LEVEL_2:
        idx = 2;
        break;

      case IOCTL_LEVEL_1:
        idx = 1;
        break;

      case IOCTL_LEVEL_0:
        idx = 0;
        break;

      default:
        return SMPL_BAD_PARAM;
    }
    MRFI_SetRFPwr(idx);
    return SMPL_SUCCESS;
  }
#endif  /* EXTENDED_API */
  else
  {
    rc = SMPL_BAD_PARAM;
  }
  return rc;
}
Esempio n. 2
0
smplStatus_t SMPL_Receive(linkID_t lid, uint8_t *msg, uint8_t *len)
{
    connInfo_t  *pCInfo = nwk_getConnInfo(lid);
    smplStatus_t rc = SMPL_BAD_PARAM;
    rcvContext_t rcv;

    if (!pCInfo || ((rc = nwk_checkConnInfo(pCInfo, CHK_RX)) != SMPL_SUCCESS))
    {
        return rc;
    }

    rcv.type  = RCV_APP_LID;
    rcv.t.lid = lid;

#if defined(RX_POLLS)
    {
        uint8_t numChans  = 1;
#    if defined(FREQUENCY_AGILITY)
        freqEntry_t chans[NWK_FREQ_TBL_SIZE];
        uint8_t scannedB4 = 0;
#    endif

        do
        {
            uint8_t radioState = MRFI_GetRadioState();

            /* I'm polling. Do the poll to stimulate the sending of a frame. If the
             * frame has application length of 0 it means there were no frames.  If
             * no reply is received infer that the channel is changed. We then need
             * to scan and then retry the poll on each channel returned.
             */
            if (SMPL_SUCCESS != (rc = nwk_poll(pCInfo->portRx, pCInfo->peerAddr)))
            {
                /* for some reason couldn't send the poll out. */
                return rc;
            }

            /* do this before code block below which may reset it. */
            numChans--;

            /* Wait until there's a frame. if the len is 0 then return SMPL_NO_FRAME
             * to the caller. In the poll case the AP always sends something.
             */
            NWK_CHECK_FOR_SETRX(radioState);
            NWK_REPLY_DELAY();
            NWK_CHECK_FOR_RESTORE_STATE(radioState);

            /* TODO: deal with pending */
            rc = nwk_retrieveFrame(&rcv, msg, len, 0, 0);

#    if defined(FREQUENCY_AGILITY)
            if (SMPL_SUCCESS == rc)
            {
                /* we received something... */
                return (*len) ? SMPL_SUCCESS : SMPL_NO_PAYLOAD;
            }

            /* No reply. scan for other channel(s) if we haven't already. Then set
             * one and try again.
             */
            if (!scannedB4)
            {
                numChans  = nwk_scanForChannels(chans);
                scannedB4 = 1;
            }
            if (numChans)
            {
                nwk_setChannel(&chans[numChans - 1]);
            }
#    else /*  FREQUENCY_AGILITY */
            return (*len) ? rc : ((SMPL_SUCCESS == rc) ? SMPL_NO_PAYLOAD : SMPL_TIMEOUT);
#    endif
        } while (numChans);
    }

#    if defined(FREQUENCY_AGILITY)
    return SMPL_NO_CHANNEL;
#    endif

#else     /* RX_POLLS */
    return nwk_retrieveFrame(&rcv, msg, len, 0, 0);
#endif  /* RX_POLLS */
}
Esempio n. 3
0
/******************************************************************************
 * @fn          nwk_QfindOldest
 *
 * @brief       Look through frame queue and find the oldest available frame
 *              in the context in question. Supports connection-based (user),
 *              non-connection based (NWK applications), and the special case
 *              of store-and-forward.
 *
 * input parameters
 * @param   which      - INQ or OUTQ to adjust
 * @param   rcvContext - context information for finding the oldest
 * @param   usage      - normal usage or store-and-forward usage
 *
 * output parameters
 *
 * @return      Pointer to frame that is the oldsest on the requested port, or
 *              0 if there are none.
 */
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)
  {
    pCInfo = nwk_getConnInfo(rcv->t.lid);
    if (!pCInfo)
    {
      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; i<num; ++i, ++wPtr)
  {

    BSP_ENTER_CRITICAL_SECTION(intState);   /* protect the frame states */

    /* only check entries in use and waiting for this port */
    if (uType == wPtr->fi_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)
         */
        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;
}
Esempio n. 4
0
smplStatus_t SMPL_SendOpt(linkID_t lid, uint8_t *msg, uint8_t len, txOpt_t options)
{
    frameInfo_t  *pFrameInfo;
    connInfo_t   *pCInfo     = nwk_getConnInfo(lid);
    smplStatus_t rc         = SMPL_BAD_PARAM;
    uint8_t radioState = MRFI_GetRadioState();
    uint8_t ackreq     = 0;

#if defined(ACCESS_POINT)
    uint8_t loc;
#endif

    /* we have the connection info for this Link ID. make sure it is valid. */
    if (!pCInfo || ((rc = nwk_checkConnInfo(pCInfo, CHK_TX)) != SMPL_SUCCESS))
    {
        return rc;
    }

    /* parameter sanity check... */
    if (!msg || (len > MAX_APP_PAYLOAD))
    {
        return rc;
    }

    /* Build an outgoing message frame destined for the port from the
     * connection info using the destination address also from the
     * connection info.
     */
    if (SMPL_TXOPTION_NONE == options)
    {
        pFrameInfo = nwk_buildFrame(pCInfo->portTx, msg, len, pCInfo->hops2target);
    }
#if defined(APP_AUTO_ACK)
    else if (options & SMPL_TXOPTION_ACKREQ)
    {
        if (SMPL_LINKID_USER_UUD != lid)
        {
            pFrameInfo = nwk_buildAckReqFrame(pCInfo->portTx, msg, len, pCInfo->hops2target,
                                              &pCInfo->ackTID);
            ackreq     = 1;
        }
        else
        {
            /* can't request an ack on the UUD link ID */
            return SMPL_BAD_PARAM;
        }
    }
#endif  /* APP_AUTO_ACK */
    else
    {
        return SMPL_BAD_PARAM;
    }

    if (!pFrameInfo)
    {
        return SMPL_NOMEM;
    }
    memcpy(MRFI_P_DST_ADDR(&pFrameInfo->mrfiPkt), pCInfo->peerAddr, NET_ADDR_SIZE);

#if defined(SMPL_SECURE)
    {
        uint32_t *pUL = 0;

        if (pCInfo->thisLinkID != SMPL_LINKID_USER_UUD)
        {
            pUL = &pCInfo->connTxCTR;
        }
        nwk_setSecureFrame(&pFrameInfo->mrfiPkt, len, pUL);
    }
#endif  /* SMPL_SECURE */

#if defined(ACCESS_POINT)

    /* If we are an AP trying to send to a polling device, don't do it.
     * See if the target is a store-and-forward client.
     */
    if (nwk_isSandFClient(MRFI_P_DST_ADDR(&pFrameInfo->mrfiPkt), &loc))
    {
        pFrameInfo->fi_usage = FI_INUSE_UNTIL_FWD;
        return SMPL_SUCCESS;
    }
    else
#endif  /* ACCESS_POINT */
    {
        rc = nwk_sendFrame(pFrameInfo, MRFI_TX_TYPE_CCA);
    }

#if !defined(APP_AUTO_ACK)
    /* save a little code space with this #if */
    (void) ackreq;  /* keep compiler happy */
    return rc;
#else
    /* we're done if the send failed or no ack requested. */
    if (SMPL_SUCCESS != rc || !ackreq)
    {
        return rc;
    }

    NWK_CHECK_FOR_SETRX(radioState);
    NWK_REPLY_DELAY();
    NWK_CHECK_FOR_RESTORE_STATE(radioState);

    {
        bspIState_t intState;

        /* If the saved TID hasn't been reset then we never got the ack. */
        BSP_ENTER_CRITICAL_SECTION(intState);
        if (pCInfo->ackTID)
        {
            pCInfo->ackTID = 0;
            rc = SMPL_NO_ACK;
        }
        BSP_EXIT_CRITICAL_SECTION(intState);
    }

    return rc;
#endif  /* APP_AUTO_ACK */
}