/******************************************************************************
 * @fn          isDupSandFFrame
 *
 * @brief       Have we already stored this frame on behalf of a client?
 *
 * input parameters
 * @param   frame   - pointer to frame in question
 *
 * output parameters
 *
 * @return      Returns 1 if the frame is a duplicate, otherwise 0.
 */
uint8_t  isDupSandFFrame(mrfiPacket_t *frame)
{
  uint8_t      i, plLen = MRFI_GET_PAYLOAD_LEN(frame);
  frameInfo_t *fiPtr;

  /* check the input queue for duplicate S&F frame. */
  fiPtr = nwk_getQ(INQ);
  for (i=0; i<SIZE_INFRAME_Q; ++i, fiPtr++)
  {
    if (FI_INUSE_UNTIL_FWD == fiPtr->fi_usage)
    {
      /* compare everything except the DEVICE INFO byte. */
      if (MRFI_GET_PAYLOAD_LEN(&fiPtr->mrfiPkt) == plLen                                   &&
          !memcmp(MRFI_P_DST_ADDR(&fiPtr->mrfiPkt), MRFI_P_DST_ADDR(frame), NET_ADDR_SIZE) &&
          !memcmp(MRFI_P_SRC_ADDR(&fiPtr->mrfiPkt), MRFI_P_SRC_ADDR(frame), NET_ADDR_SIZE) &&
          !memcmp(MRFI_P_PAYLOAD(&fiPtr->mrfiPkt), MRFI_P_PAYLOAD(frame), 1)               &&
          !memcmp(MRFI_P_PAYLOAD(&fiPtr->mrfiPkt)+F_TRACTID_OS, MRFI_P_PAYLOAD(frame)+F_TRACTID_OS, plLen-F_TRACTID_OS)
          )
      {
        return 1;
      }
    }
  }
  return 0;
}
Beispiel #2
0
/******************************************************************************
* @fn         mrfiLinkSend
*
* @brief      Send data on the RX link.
*
* @param      pBuf - buffer to be transmitted
*
* @param      len -  number of bytes to be transmitted
*
* @return     Return code indicates success or failure of transmit:
*                  MRFI_TX_RESULT_SUCCESS - transmit succeeded
*                  MRFI_TX_RESULT_FAILED  - transmit failed because CCA or ACK failed
*/
uint8 mrfiLinkSend(uint8 *pBuf, uint8 len, uint8 nRetrans)
{
    uint8 v,i,status;

    v= halIntLock();

    MRFI_SET_PAYLOAD_LEN(&pkt, len+2);
    memcpy(MRFI_P_DST_ADDR(&pkt), dest_addr, 4);
    memcpy(MRFI_P_SRC_ADDR(&pkt), src_addr, 4);

    MRFI_P_PAYLOAD(&pkt)[0]= seqSend;
    MRFI_P_PAYLOAD(&pkt)[1]= MRFI_LINK_DATA;

    memcpy(MRFI_P_PAYLOAD(&pkt)+2, pBuf, len);
    halIntUnlock(v);

    for (i=0;i<nRetrans;i++) {
        status= MRFI_Transmit(&pkt, MRFI_TX_TYPE_CCA);
        if (status==MRFI_TX_RESULT_SUCCESS) {
            if (waitForAck(20)) {
                seqSend++;
                break;
            } else {
                status= MRFI_TX_RESULT_FAILED;
                // wait random time if sending is not successful
                // (20-40 milliseconds)
                halMcuWaitUs( (20000/255*MRFI_RandomByte()) + 20000 );
            }
        }
    }

    return status;

}
smplStatus_t nwk_rawSend(ioctlRawSend_t *info)
{
    frameInfo_t *pOutFrame;
    uint8_t hops;

    /* If we know frame is going to or from the AP then we can reduce the hop
     * count.
     */
    switch (info->port)
    {
        case SMPL_PORT_JOIN:
        case SMPL_PORT_FREQ:
        case SMPL_PORT_MGMT:
            hops = MAX_HOPS_FROM_AP;
            break;

        default:
            hops = MAX_HOPS;
            break;
    }

    if (pOutFrame = nwk_buildFrame(info->port, info->msg, info->len, hops))
    {
        memcpy(MRFI_P_DST_ADDR(&pOutFrame->mrfiPkt), info->addr, NET_ADDR_SIZE);
#ifdef SMPL_SECURE
        nwk_setSecureFrame(&pOutFrame->mrfiPkt, info->len, 0);
#endif  /* SMPL_SECURE */
        return nwk_sendFrame(pOutFrame, MRFI_TX_TYPE_CCA);
    }
    return SMPL_NOMEM;
}
/******************************************************************************
 * @fn          change_channel_cmd_is_valid
 *
 * @brief       Check validity of a change channel command frame.
 *
 * input parameters
 * @param   frame  - pointer to frame with command context
 *
 * @return   Returns non-zero if command is valid, otherwise returns 0.
 *           Command is valid if either:
 *             - frame is directed
 *             - frame is from an AP and we know about that AP
 *
 *           It is possible that either we don't know about an AP or that
 *           we do but this frame comes from another AP in range.
 */
static uint8_t change_channel_cmd_is_valid(mrfiPacket_t *frame)
{
  uint8_t rc = 0;
  addr_t const *apAddr;

  /* If this was a directed frame obey the command. */
  if (!memcmp(MRFI_P_DST_ADDR(frame), nwk_getMyAddress(), NET_ADDR_SIZE))
  {
    rc = 1;
  }
  else
  {
    /* Do we know about an AP? If not assume frame bogus. */
    apAddr = nwk_getAPAddress();
    if (apAddr)
    {
      /* Yes, we know about an AP. Is that who sent it? */
      if (!memcmp(apAddr, MRFI_P_SRC_ADDR(frame), NET_ADDR_SIZE))
      {
        /* OK. We obey. */
        rc = 1;
      }
    }
  }

  return rc;
}
/******************************************************************************
 * @fn          send_ping_reply
 *
 * @brief       Send Frequency application ping reply.
 *
 * input parameters
 * @param   frame     - pointer to frame from pinger.
 *
 * @return   FHS_RELEASE unless this isn't an Access Point. In this case for
 *           flow to et this far it is a Range Extender, so replay the frame
 *           by returning FHW_REPLAY
 */
static fhStatus_t send_ping_reply(mrfiPacket_t *frame)
{
#ifdef ACCESS_POINT
  uint8_t      msg[FREQ_REQ_PING_FRAME_SIZE];
  frameInfo_t *pOutFrame;

  /* original request with reply bit on */
  msg[FB_APP_INFO_OS] = *(MRFI_P_PAYLOAD(frame)+F_APP_PAYLOAD_OS) | NWK_APP_REPLY_BIT;
  msg[FB_TID_OS]      = *(MRFI_P_PAYLOAD(frame)+F_APP_PAYLOAD_OS+FB_TID_OS);

  pOutFrame = nwk_buildFrame(SMPL_PORT_FREQ, msg, sizeof(msg), MAX_HOPS_FROM_AP);
  if (pOutFrame)
  {
    /* destination address is the source address of the received frame. */
    memcpy(MRFI_P_DST_ADDR(&pOutFrame->mrfiPkt), MRFI_P_SRC_ADDR(frame), NET_ADDR_SIZE);
    /* must use transaction ID of source frame */
    PUT_INTO_FRAME(MRFI_P_PAYLOAD(&pOutFrame->mrfiPkt), F_TRACTID_OS, (GET_FROM_FRAME(MRFI_P_PAYLOAD(frame), F_TRACTID_OS)));
#ifdef SMPL_SECURE
    nwk_setSecureFrame(&pOutFrame->mrfiPkt, sizeof(msg), 0);
#endif  /* SMPL_SECURE */
    nwk_sendFrame(pOutFrame, MRFI_TX_TYPE_FORCED);
  }

  return FHS_RELEASE;
#else
  return FHS_REPLAY;
#endif  /* ACCESS_POINT */
}
/******************************************************************************
 * @fn          nwk_getSandFFrame
 *
 * @brief       Get any frame waiting for the client on the port supplied in
 *              the frame payload.
 *              TODO: support returning NWK application frames always. the
 *              port requested in the call should be an user application port.
 *              NWK app ports will never be in the called frame.
 *              TODO: deal with broadcast NWK frames from AP.
 *
 * input parameters
 * @param   frame   - pointer to frame in question
 *
 * output parameters
 *
 * @return      pointer to frame if there is one, otherwise 0.
 */
frameInfo_t *nwk_getSandFFrame(mrfiPacket_t *frame, uint8_t osPort)
{
  uint8_t        i, port = *(MRFI_P_PAYLOAD(frame)+F_APP_PAYLOAD_OS+osPort);
  frameInfo_t *fiPtr;
  rcvContext_t rcv;

  rcv.type  = RCV_RAW_POLL_FRAME;
  rcv.t.pkt = frame;
  /* check the input queue for messages sent by others. */
  if (fiPtr=nwk_QfindOldest(INQ, &rcv, USAGE_FWD))
  {
    return fiPtr;
  }

  /* Check the output queue to see if we ourselves need to send anything.
   * TODO: use the cast-out scheme for output queue so this routine finds
   * the oldest in either queue.
   */
  fiPtr = nwk_getQ(OUTQ);
  for (i=0; i<SIZE_OUTFRAME_Q; ++i, fiPtr++)
  {
    if (FI_INUSE_UNTIL_FWD == fiPtr->fi_usage)
    {
      if (!memcmp(MRFI_P_DST_ADDR(&fiPtr->mrfiPkt), MRFI_P_SRC_ADDR(frame), NET_ADDR_SIZE))
      {
        if (GET_FROM_FRAME(MRFI_P_PAYLOAD(&fiPtr->mrfiPkt), F_PORT_OS) == port)
        {
          return fiPtr;
        }
      }
    }
  }
  return 0;
}
Beispiel #7
0
/******************************************************************************
* @fn          sendAck
*
* @brief       Send an acknowledge packet (no payload)
*
* @param       none
*
* @return      none
*/
static void sendAck(void)
{
    uint8 v;

    v= halIntLock();
    MRFI_SET_PAYLOAD_LEN(&pkt, 2);
    memcpy(MRFI_P_DST_ADDR(&pkt), dest_addr, 4);
    memcpy(MRFI_P_SRC_ADDR(&pkt), src_addr, 4);
    MRFI_P_PAYLOAD(&pkt)[0]= seqRecv;
    MRFI_P_PAYLOAD(&pkt)[1]= MRFI_LINK_ACK;
    halIntUnlock(v);
    MRFI_Transmit(&pkt, MRFI_TX_TYPE_FORCED);

}
/******************************************************************************
 * @fn          nwk_sendAckReply
 *
 * @brief       Send an acknowledgement reply frame.
 *
 * input parameters
 * @param   frame   - pointer to frame with ack request.
 * @param   port    - port on whcih reply expected.
 *
 * output parameters
 *
 * @return      void
 */
void nwk_sendAckReply(mrfiPacket_t *frame, uint8_t port)
{
  mrfiPacket_t dFrame;
  uint8_t      tid = GET_FROM_FRAME(MRFI_P_PAYLOAD(frame), F_TRACTID_OS);

  /* set the type of device sending the frame in the header */
  PUT_INTO_FRAME(MRFI_P_PAYLOAD(&dFrame), F_TX_DEVICE, sMyTxType);

  /* set the listen type of device sending the frame in the header. */
  PUT_INTO_FRAME(MRFI_P_PAYLOAD(&dFrame), F_RX_TYPE, sMyRxType);

  /* destination address from received frame */
  memcpy(MRFI_P_DST_ADDR(&dFrame), MRFI_P_SRC_ADDR(frame), NET_ADDR_SIZE);

  /* source address */
  memcpy(MRFI_P_SRC_ADDR(&dFrame), sMyAddr, NET_ADDR_SIZE);

  /* port is the source the Tx port from the connection object */
  PUT_INTO_FRAME(MRFI_P_PAYLOAD(&dFrame), F_PORT_OS, port);

  /* frame length... */
  MRFI_SET_PAYLOAD_LEN(&dFrame,F_APP_PAYLOAD_OS);

  /* transaction ID taken from source frame */
  PUT_INTO_FRAME(MRFI_P_PAYLOAD(&dFrame), F_TRACTID_OS, tid);

  /* hop count... */
  PUT_INTO_FRAME(MRFI_P_PAYLOAD(&dFrame), F_HOP_COUNT, MAX_HOPS);

  /* set ACK field */
  PUT_INTO_FRAME(MRFI_P_PAYLOAD(&dFrame), F_ACK_RPLY, F_ACK_RPLY_TYPE);
  PUT_INTO_FRAME(MRFI_P_PAYLOAD(&dFrame), F_ACK_REQ, 0);

   /* This is not a forwarded frame */
  PUT_INTO_FRAME(MRFI_P_PAYLOAD(&dFrame), F_FWD_FRAME, 0);

  /* Encryption state */
#if !defined(SMPL_SECURE)
  PUT_INTO_FRAME(MRFI_P_PAYLOAD(&dFrame), F_ENCRYPT_OS, 0);
#else
  PUT_INTO_FRAME(MRFI_P_PAYLOAD(&dFrame), F_ENCRYPT_OS, F_ENCRYPT_OS_MSK);
  nwk_setSecureFrame(&dFrame, 0, 0);
#endif

  MRFI_Transmit(&dFrame, MRFI_TX_TYPE_FORCED);

  return;
}
Beispiel #9
0
void nwk_SendEmptyPollRspFrame(mrfiPacket_t *frame)
{
    mrfiPacket_t dFrame;
    uint8_t port = *(MRFI_P_PAYLOAD(frame) + F_APP_PAYLOAD_OS + M_POLL_PORT_OS);

    /* set the type of device sending the frame in the header. we know it's an AP */
    PUT_INTO_FRAME(MRFI_P_PAYLOAD(&dFrame), F_TX_DEVICE, F_TX_DEVICE_AP);

    /* set the listen type of device sending the frame in the header. we know it's
     * an AP is is probably always on...but use the static variable anyway.
     */
    PUT_INTO_FRAME(MRFI_P_PAYLOAD(&dFrame), F_RX_TYPE, sMyRxType);
    /* destination address from received frame (polling device) */
    memcpy(MRFI_P_DST_ADDR(&dFrame), MRFI_P_SRC_ADDR(frame), NET_ADDR_SIZE);
    /* source address */
    memcpy(MRFI_P_SRC_ADDR(&dFrame), MRFI_P_PAYLOAD(
               frame) + F_APP_PAYLOAD_OS + M_POLL_ADDR_OS, NET_ADDR_SIZE);
    /* port is the port requested */
    PUT_INTO_FRAME(MRFI_P_PAYLOAD(&dFrame), F_PORT_OS, port);
    /* frame length... */
    MRFI_SET_PAYLOAD_LEN(&dFrame, F_APP_PAYLOAD_OS);
    /* transaction ID... */
    PUT_INTO_FRAME(MRFI_P_PAYLOAD(&dFrame), F_TRACTID_OS, sTRACTID);
    sTRACTID++;
    /* hop count... */
    PUT_INTO_FRAME(MRFI_P_PAYLOAD(&dFrame), F_HOP_COUNT, MAX_HOPS_FROM_AP);

    /* Ack fields */
    PUT_INTO_FRAME(MRFI_P_PAYLOAD(&dFrame), F_ACK_RPLY, 0);
    PUT_INTO_FRAME(MRFI_P_PAYLOAD(&dFrame), F_ACK_REQ, 0);

    /* This is logically a forwarded frame */
    PUT_INTO_FRAME(MRFI_P_PAYLOAD(&dFrame), F_FWD_FRAME, F_FRAME_FWD_TYPE);

    /* Encryption state */
#        if !defined(SMPL_SECURE)
    PUT_INTO_FRAME(MRFI_P_PAYLOAD(&dFrame), F_ENCRYPT_OS, 0);
#        else
    PUT_INTO_FRAME(MRFI_P_PAYLOAD(&dFrame), F_ENCRYPT_OS, F_ENCRYPT_OS_MSK);
    nwk_setSecureFrame(&dFrame, 0, 0);
#        endif

    MRFI_Transmit(&dFrame, MRFI_TX_TYPE_FORCED);

    return;
}
/******************************************************************************
 * @fn          nwk_rawSend
 *
 * @brief       Builds an outut frame based on information provided by the
 *              caller. This function allows a raw transmission to the target
 *              if the network address is known. this function is used a lot
 *              to support NWK applications.
 *
 * input parameters
 * @param   info    - pointer to strcuture containing info on how to build
 *                    the outgoing frame.
 * output parameters
 *
 * @return         SMPL_SUCCESS
 *                 SMPL_NOMEM       - no room in output frame queue
 *                 SMPL_TX_CCA_FAIL - CCA failure
 */
smplStatus_t nwk_rawSend(ioctlRawSend_t *info)
{
  frameInfo_t *pOutFrame;
  uint8_t      hops;

  /* If we know frame is going to or from the AP then we can reduce the hop
   * count.
   */
  switch (info->port)
  {
    case SMPL_PORT_JOIN:
    case SMPL_PORT_FREQ:
    case SMPL_PORT_MGMT:
      hops = MAX_HOPS_FROM_AP;
      break;

    default:
      hops = MAX_HOPS;
      break;
  }

  if ((pOutFrame = nwk_buildFrame(info->port, info->msg, info->len, hops)))
  {
#ifdef NWK_PLL
    // get access to the packet data
    void* pkt = MRFI_P_PAYLOAD(&pOutFrame->mrfiPkt)+F_APP_PAYLOAD_OS;
    // get a data logging command
    const uint8_t cmd = ( pll_cmd_LocateReference | pll_cmd_LocateResponse
                          | pll_cmd_PumpRequest | pll_cmd_PumpResponse );
    if( info->port == SMPL_PORT_PLL // if sending to a pll port
           // and its not a data logging packet
           && ( ((pll_Packet_t*)pkt)->Cmd & cmd ) != cmd )
    {
      // update the transmit time stamp address to point
      // into where the message was copied to
      MRFI_SetTxTimeStampAddr( &(((pll_Packet_t*)pkt)->Time) );
    }
#endif
    memcpy(MRFI_P_DST_ADDR(&pOutFrame->mrfiPkt), info->addr, NET_ADDR_SIZE);
#ifdef SMPL_SECURE
    nwk_setSecureFrame(&pOutFrame->mrfiPkt, info->len, 0);
#endif  /* SMPL_SECURE */
    return nwk_sendFrame(pOutFrame, MRFI_TX_TYPE_CCA);
  }
  return SMPL_NOMEM;
}
Beispiel #11
0
/******************************************************************************
 * @fn          nwk_processMgmt
 *
 * @brief       Process Management frame. Just save the frame for the Management
 *              app it it is a reply. If it isn't a reply, send the reply in this
 *              thread.
 *
 * input parameters
 * @param   frame   - pointer to frame to be processed
 *
 * output parameters
 *
 * @return   Keep frame for application, release frame, or replay frame.
 */
fhStatus_t nwk_processMgmt(mrfiPacket_t *frame)
{
  fhStatus_t   rc;
  uint8_t      replyType;

  /* If we sent this then this is the reply. Validate the
   * packet for reception by client app. If we didn't send
   * it then we are the target. send the reply.
   */
  if (SMPL_MY_REPLY == (replyType=nwk_isValidReply(frame, sTid, MB_APP_INFO_OS, MB_TID_OS)))
  {
    /* It's a match and it's a reply. Validate the received packet by
     * returning a 1 so it can be received by the client app.
     */
    MRFI_PostKillSem();
    rc = FHS_KEEP;
  }
#if !defined( END_DEVICE )
  else if (SMPL_A_REPLY == replyType)
  {
    /* no match. if i'm not an ED this is a reply that should be passed on. */
    rc = FHS_REPLAY;
  }
#endif  /* !END_DEVICE */
  else
  {
    /* no, we didn't send it. send reply if it's intended for us */
    if (!memcmp(MRFI_P_DST_ADDR(frame), nwk_getMyAddress(), NET_ADDR_SIZE))
    {
      smpl_send_mgmt_reply(frame);

      /* we're done with the frame. */
      rc = FHS_RELEASE;
    }
    else
    {
      rc = FHS_REPLAY;
    }
  }

  (void) replyType;  /* keep compiler happy */

  return rc;
}
Beispiel #12
0
/*******************************************************************************
 * @fn          nwk_isValidReply
 *
 * @brief       Examine a frame to see if it is a valid reply when compared with
 *              expected parameters.
 *
 * input parameters
 * @param   frame      - pointer to frmae being examined
 * @param   tid        - expected transaction ID in application payload
 * @param   infoOffset - offset to payload information containing reply hint
 * @param   tidOffset  - offset to transaction ID in payload
 *
 * output parameters
 *
 * @return   reply category:
 *               SMPL_NOT_REPLY: not a reply
 *               SMPL_MY_REPLY : a reply that matches input parameters
 *               SMPL_A_REPLY  : a reply but does not match input parameters
 */
uint8_t nwk_isValidReply(mrfiPacket_t *frame, uint8_t tid, uint8_t infoOffset, uint8_t tidOffset)
{
  uint8_t rc = SMPL_NOT_REPLY;

  if ((*(MRFI_P_PAYLOAD(frame)+F_APP_PAYLOAD_OS+infoOffset) & NWK_APP_REPLY_BIT))
  {
    if ((*(MRFI_P_PAYLOAD(frame)+F_APP_PAYLOAD_OS+tidOffset) == tid) &&
        !memcmp(MRFI_P_DST_ADDR(frame), nwk_getMyAddress(), NET_ADDR_SIZE))
    {
      rc = SMPL_MY_REPLY;
    }
    else
    {
      rc = SMPL_A_REPLY;
    }
  }

  return rc;
}
static void smpl_send_unlink_reply(mrfiPacket_t *frame)
{
    connInfo_t  *pCInfo;
    frameInfo_t *pOutFrame;
    uint8_t msg[UNLINK_REPLY_FRAME_SIZE];
    smplStatus_t rc = SMPL_NO_PEER_UNLINK;

    /* match the remote port and source address with a connection table entry */
    if (pCInfo =
            nwk_findPeer((addr_t *)MRFI_P_SRC_ADDR(frame),
                         *(MRFI_P_PAYLOAD(frame) + F_APP_PAYLOAD_OS + UL_RMT_PORT_OS)))
    {
        /* Note we unconditionally free the connection resources */
        nwk_freeConnection(pCInfo);
        rc = SMPL_SUCCESS;
    }

    /* set reply bit */
    msg[LB_REQ_OS] = LINK_REQ_UNLINK | NWK_APP_REPLY_BIT;

    /* sender's TID */
    msg[LB_TID_OS] = *(MRFI_P_PAYLOAD(frame) + F_APP_PAYLOAD_OS + LB_TID_OS);

    /* result of freeing local connection */
    msg[ULR_RESULT_OS] = rc;

    if (pOutFrame = nwk_buildFrame(SMPL_PORT_LINK, msg, sizeof(msg), MAX_HOPS))
    {
        /* destination address is the source adddress of the received frame. */
        memcpy(MRFI_P_DST_ADDR(&pOutFrame->mrfiPkt), MRFI_P_SRC_ADDR(frame), NET_ADDR_SIZE);
#    if defined(SMPL_SECURE)
        nwk_setSecureFrame(&pOutFrame->mrfiPkt, sizeof(msg), 0);
#    endif /* SMPL_SECURE */
        nwk_sendFrame(pOutFrame, MRFI_TX_TYPE_FORCED);
    }
}
Beispiel #14
0
/**************************************************************************************************
 * @fn          MRFI_SyncPinRxIsr
 *
 * @brief       This interrupt is called when the SYNC signal transition from high to low. 
 *              The sync signal is routed to the sync pin which is a GPIO pin.  This high-to-low
 *              transition signifies a receive has completed.  The SYNC signal also goes from
 *              high to low when a transmit completes.   This is protected against within the
 *              transmit function by disabling sync pin interrupts until transmit completes.
 *
 * @param       none
 *
 * @return      none
 **************************************************************************************************
 */
static void MRFI_SyncPinRxIsr(void)
{
  uint8_t frameLen;
  uint8_t rxBytes;

  /* ------------------------------------------------------------------
   *    Abort if asleep
   *   -----------------
   */
 
  /*
   *  If radio is asleep, abort immediately.  Nothing further is required.
   *  If radio is awake, set "receive active" flag and continue processing the receive.
   */
  {
    bspIState_t s;
    
    /* critical section necessary for watertight testing and setting of state variables */
    BSP_ENTER_CRITICAL_SECTION(s);

    /* if radio is asleep, just abort from here */
    if (mrfiRadioIsSleeping)
    {
      BSP_EXIT_CRITICAL_SECTION(s);
      return;
    }
    
    /* radio is not asleep, set flag that indicates receive is active */
    mrfiRxActive = 1;
    BSP_EXIT_CRITICAL_SECTION(s);
  }

  
  /* ------------------------------------------------------------------
   *    Get RXBYTES
   *   -------------
   */

  /*
   *  Read the RXBYTES register from the radio.
   *  Bit description of RXBYTES register:
   *    bit 7     - RXFIFO_OVERFLOW, set if receive overflow occurred
   *    bits 6:0  - NUM_BYTES, number of bytes in receive FIFO
   *
   *  Due a chip bug, the RXBYTES register must read the same value twice
   *  in a row to guarantee an accurate value.
   */
  {
    uint8_t rxBytesVerify;
    
    rxBytesVerify = mrfiSpiReadReg(MRFI_CC2500_SPI_REG_RXBYTES);

    do 
    {
      rxBytes = rxBytesVerify;
      rxBytesVerify = mrfiSpiReadReg(MRFI_CC2500_SPI_REG_RXBYTES);
    }
    while (rxBytes != rxBytesVerify);
  }

  
  /* ------------------------------------------------------------------
   *    FIFO empty?
   *   -------------
   */

  /*
   *  See if the receive FIFIO is empty before attempting to read from it.
   *  It is possible nothing the FIFO is empty even though the interrupt fired.
   *  This can happen if address check is enabled and a non-matching packet is
   *  received.  In that case, the radio automatically removes the packet from
   *  the FIFO.
   */
  if (rxBytes == 0)
  {
    /* receive FIFO is empty - do nothing, skip to end */
  }
  else
  {
    /* receive FIFO is not empty, continue processing */

    /* ------------------------------------------------------------------
     *    Process frame length
     *   ----------------------
     */
    
    /* read the first byte from FIFO - the packet length */
    mrfiSpiReadRxFifo(&frameLen, MRFI_LENGTH_FIELD_SIZE);

    /*
     *  Make sure that the frame length just read corresponds to number of bytes in the buffer.
     *  If these do not match up something is wrong.
     *
     *  This can happen for several reasons:
     *   1) Incoming packet has an incorrect format or is corrupted.
     *   2) The receive FIFO overflowed.  Overflow is indicated by the high
     *      bit of rxBytes.  This guarantees the value of rxBytes value will not
     *      match the number of bytes in the FIFO for overflow condition.
     *   3) Interrupts were blocked for an abnormally long time which
     *      allowed a following packet to at least start filling the
     *      receive FIFO.  In this case, all received and partially received
     *      packets will be lost - the packet in the FIFO and the packet coming in.
     *      This is the price the user pays if they implement a giant
     *      critical section.
     *   4) A failed transmit forced radio to IDLE state to flush the transmit FIFO.
     *      This could cause an active receive to be cut short.
     */
    if (rxBytes != (frameLen + MRFI_LENGTH_FIELD_SIZE + MRFI_RX_METRICS_SIZE))
    {
      bspIState_t s;

      /* mismatch between bytes-in-FIFO and frame length */

      /*
       *  Flush receive FIFO to reset receive.  Must go to IDLE state to do this.
       *  The critical section guarantees a transmit does not occur while cleaning up.
       */
      BSP_ENTER_CRITICAL_SECTION(s);
      mrfiSpiCmdStrobe(MRFI_CC2500_SPI_STROBE_SIDLE);
      mrfiSpiCmdStrobe(MRFI_CC2500_SPI_STROBE_SFRX);
      mrfiSpiCmdStrobe(MRFI_CC2500_SPI_STROBE_SRX);
      BSP_EXIT_CRITICAL_SECTION(s);
      
      /* flush complete, skip to end */
    }
    else
    {
      /* bytes-in-FIFO and frame length match up - continue processing */
      
      /* ------------------------------------------------------------------
       *    Get packet
       *   ------------
       */

      /* set length field */
      mrfiIncomingPacket.frame[MRFI_LENGTH_FIELD_OFS] = frameLen;
  
      /* get packet from FIFO */
      mrfiSpiReadRxFifo(&(mrfiIncomingPacket.frame[MRFI_FRAME_BODY_OFS]), frameLen);
  
      /* get receive metrics from FIFO */
      mrfiSpiReadRxFifo(&(mrfiIncomingPacket.rxMetrics[0]), MRFI_RX_METRICS_SIZE);


      /* ------------------------------------------------------------------
       *    CRC check
       *   ------------
       */

      /*
       *  Note!  Automatic CRC check is not, and must not, be enabled.  This feature
       *  flushes the *entire* receive FIFO when CRC fails.  If this feature is
       *  enabled it is possible to be reading from the FIFO and have a second
       *  receive occur that fails CRC and automatically flushes the receive FIFO.
       *  This could cause reads from an empty receive FIFO which puts the radio
       *  into an undefined state.
       */
      
      /* determine if CRC failed */
      if (!(mrfiIncomingPacket.rxMetrics[MRFI_RX_METRICS_CRC_LQI_OFS] & MRFI_RX_METRICS_CRC_OK_MASK))
      {
        /* CRC failed - do nothing, skip to end */
      }
      else
      {
        /* CRC passed - continue processing */

      /* ------------------------------------------------------------------
       *    Filtering 
       *   -----------
       */

        /* see if filtering is enabled and, if so, determine if address is a match */
        if (mrfiRxFilterEnabled && memcmp(MRFI_P_DST_ADDR(&mrfiIncomingPacket), &mrfiRxFilterAddr[0], MRFI_ADDR_SIZE))
        {
          /* packet filtered out - do nothing, skip to end */
        }
        else
        {
          /* packet not filtered out - receive successful */
          
          /* ------------------------------------------------------------------
           *    Receive succeeded
           *   -------------------
           */

          /* call external, higher level "receive complete" processing routine */
          MRFI_RxCompleteISR();
        }
      }
    }
  }

  /* ------------------------------------------------------------------
   *    End of function
   *   -------------------
   */
  
  /* clear "receive active" flag and exit */
  mrfiRxActive = 0;
}
static uint8_t smpl_send_link_reply(mrfiPacket_t *frame)
{
#if NUM_CONNECTIONS > 0
    frameInfo_t *pOutFrame;
    connInfo_t  *pCInfo;
    uint8_t remotePort;
    uint8_t msg[LINK_REPLY_FRAME_SIZE];

    /* Is this a legacy frame? If so continue. Otherwise check version.*/
    if ((MRFI_GET_PAYLOAD_LEN(frame) - F_APP_PAYLOAD_OS) > LINK_LEGACY_MSG_LENGTH)
    {
        /* see if protocol version is correct... */
        if (*(MRFI_P_PAYLOAD(frame) + F_APP_PAYLOAD_OS + L_PROTOCOL_VERSION_OS) !=
            nwk_getProtocolVersion())
        {
            /* Accommodation of protocol version differences can be noted or accomplished here.
             * This field was also checked in the join transaction but it is checked again here
             * because that check may not have occurred if thre is no AP in this topology.
             * Otherwise, no match and the board goes back
             */
            return SENT_NO_REPLY;
        }
    }

    /* see if token is correct */
    {
        uint32_t lt;

        nwk_getNumObjectFromMsg(MRFI_P_PAYLOAD(
                                    frame) + F_APP_PAYLOAD_OS + L_LINK_TOKEN_OS, &lt, sizeof(lt));
        if (lt != sLinkToken)
        {
            return SENT_NO_REPLY;
        }
    }

    /* if we get here the token matched. */

    /* is this a duplicate request? */
    remotePort = *(MRFI_P_PAYLOAD(frame) + F_APP_PAYLOAD_OS + L_RMT_PORT_OS);
    if (pCInfo = nwk_isLinkDuplicate(MRFI_P_SRC_ADDR(frame), remotePort))
    {
        /* resend reply */
        msg[LB_REQ_OS] = LINK_REQ_LINK | NWK_APP_REPLY_BIT;

        /* sender's TID */
        msg[LB_TID_OS] = *(MRFI_P_PAYLOAD(frame) + F_APP_PAYLOAD_OS + LB_TID_OS);

        /* Send reply with the local port number so the remote device knows where to
         * send packets.
         */
        msg[LR_RMT_PORT_OS] = pCInfo->portRx;

        /* put my Rx type in there. used to know how to set hops when sending back. */
        msg[LR_MY_RXTYPE_OS] = nwk_getMyRxType();
#    if defined(SMPL_SECURE)
        /* Set the Tx counter value for peer's Rx counter object */
        nwk_putNumObjectIntoMsg((void *)&pCInfo->connTxCTR, (void *)&msg[LR_CTR_OS], 4);
        /* We also need to save the newly generated Rx counter value. */
        nwk_getNumObjectFromMsg((void *)(MRFI_P_PAYLOAD(frame) + F_APP_PAYLOAD_OS + L_CTR_OS),
                                (void *)&pCInfo->connRxCTR, 4);
#    endif
        if (pOutFrame =
                nwk_buildFrame(SMPL_PORT_LINK, msg, sizeof(msg), MAX_HOPS -
                               (GET_FROM_FRAME(MRFI_P_PAYLOAD(frame), F_HOP_COUNT))))
        {
            /* destination address is the source adddress of the received frame. */
            memcpy(MRFI_P_DST_ADDR(&pOutFrame->mrfiPkt), MRFI_P_SRC_ADDR(frame), NET_ADDR_SIZE);
#    if defined(SMPL_SECURE)
            nwk_setSecureFrame(&pOutFrame->mrfiPkt, sizeof(msg), 0);
#    endif  /* SMPL_SECURE */
            nwk_sendFrame(pOutFrame, MRFI_TX_TYPE_FORCED);
        }
        return SENT_REPLY;
    }

    if (!sListenActive)
    {
        /* We've checked for duplicate and resent reply. In that case we weren't listening
         * so just go back`.
         */
        return SENT_NO_REPLY;
    }

    /* room to link? */
#    if defined(AP_IS_DATA_HUB)
    pCInfo = nwk_findAlreadyJoined(frame);

    if (!pCInfo)
#    endif
    {
        pCInfo = nwk_getNextConnection();
    }

    if (pCInfo)
    {
        /* yes there's room and it's not a dup. address. */
        memcpy(&pCInfo->peerAddr, MRFI_P_SRC_ADDR(frame), NET_ADDR_SIZE);

        if (!nwk_allocateLocalRxPort(LINK_REPLY, pCInfo))
        {
            nwk_freeConnection(pCInfo);
            /* we're done with the packet */
            return SENT_REPLY;
        }

        /* The local Rx port is the one returned in the connection structure. The
         * caller is waiting on this to be set. The code here is running in an ISR
         * thread so the caller will see this change after RETI.
         */
        if (NUM_CONNECTIONS == sNumLinkers)
        {
            /* Something is wrong -- no room to stack Link request */
            nwk_freeConnection(pCInfo);
            /* we're done with the packet */
            return SENT_REPLY;
        }
        sServiceLinkID[sNumLinkers++] = pCInfo->thisLinkID;

        /* save the remote Tx port */
        pCInfo->portTx = remotePort;

        /* connection is valid... */
        pCInfo->connState = CONNSTATE_CONNECTED;

        /* Set hop count. If it's a polling device set the count to the
         * distance to the AP. otherwise, set it to the max less the remaining
         * which will be the path taken for this frame. It will be no worse
         * then tha max and probably will be better.
         */
        if (F_RX_TYPE_POLLS == *(MRFI_P_PAYLOAD(frame) + F_APP_PAYLOAD_OS + L_MY_RXTYPE_OS))
        {
            /* It polls. so. we'll be sending to the AP which will store the
             * frame. The AP is only MAX_HOPS_FROM_AP hops away from us.
             */
            pCInfo->hops2target = MAX_HOPS_FROM_AP;
        }
        else
        {
            /* Can't really use this trick because the device could move. If the
             * devices are all static this may work unless the initial reception
             * was marginal.
             */
#    if defined(DEVICE_DOES_NOT_MOVE)
            pCInfo->hops2target = MAX_HOPS - GET_FROM_FRAME(MRFI_P_PAYLOAD(frame), F_HOP_COUNT);
#    else
            pCInfo->hops2target = MAX_HOPS;
#    endif
        }

        /* Send reply with the local port number so the remote device knows where to
         * send packets.
         */
        msg[LR_RMT_PORT_OS]  = pCInfo->portRx;

        /* put my Rx type in there. used to know how to set hops when sending back. */
        msg[LR_MY_RXTYPE_OS] = nwk_getMyRxType();

        msg[LB_REQ_OS] = LINK_REQ_LINK | NWK_APP_REPLY_BIT;

        /* sender's TID */
        msg[LB_TID_OS] = *(MRFI_P_PAYLOAD(frame) + F_APP_PAYLOAD_OS + LB_TID_OS);
#    if defined(SMPL_SECURE)
        nwk_getNumObjectFromMsg((void *)(MRFI_P_PAYLOAD(frame) + F_APP_PAYLOAD_OS + L_CTR_OS),
                                (void *)&pCInfo->connRxCTR, 4);
        pCInfo->connTxCTR = MRFI_RandomByte()                   | \
            ((uint32_t)(MRFI_RandomByte()) << 8)  | \
            ((uint32_t)(MRFI_RandomByte()) << 16) | \
            ((uint32_t)(MRFI_RandomByte()) << 24);

        nwk_putNumObjectIntoMsg((void *)&pCInfo->connTxCTR, (void *)&msg[LR_CTR_OS], 4);
#    endif
        if (pOutFrame =
                nwk_buildFrame(SMPL_PORT_LINK, msg, sizeof(msg), MAX_HOPS -
                               (GET_FROM_FRAME(MRFI_P_PAYLOAD(frame), F_HOP_COUNT))))
        {
            /* destination address is the source adddress of the received frame. */
            memcpy(MRFI_P_DST_ADDR(&pOutFrame->mrfiPkt), MRFI_P_SRC_ADDR(frame), NET_ADDR_SIZE);
#    if defined(SMPL_SECURE)
            nwk_setSecureFrame(&pOutFrame->mrfiPkt, sizeof(msg), 0);
#    endif
            if (SMPL_SUCCESS != nwk_sendFrame(pOutFrame, MRFI_TX_TYPE_FORCED))
            {
                /* better release the connection structure */
                nwk_freeConnection(pCInfo);
            }
        }
        else
        {
            /* better release the connection structure */
            nwk_freeConnection(pCInfo);
        }
    }
    /* we're done with the packet */
    return SENT_REPLY;
#else
    return SENT_NO_REPLY;
#endif  /* NUM_CONNECTIONS */
}
/******************************************************************************
 * @fn          dispatchFrame
 *
 * @brief       Received frame looks OK so far. Dispatch to either NWK app by
 *              invoking the handler or the user's app by simply leaving the
 *              frame in the queue and letting the app poll the port.
 *
 * input parameters
 * @param   fiPtr    - frameInfo_t pointer to received frame
 *
 * output parameters
 *
 * @return   void
 */
static void dispatchFrame(frameInfo_t *fiPtr)
{
  uint8_t     port       = GET_FROM_FRAME(MRFI_P_PAYLOAD(&fiPtr->mrfiPkt), F_PORT_OS);
  uint8_t     nwkAppSize = sizeof(func)/sizeof(func[0]);
  fhStatus_t  rc;
  linkID_t    lid;
#if defined(ACCESS_POINT)
  uint8_t loc;
#endif
#if !defined(END_DEVICE)
  uint8_t isForMe;
#endif

  /* be sure it's not an echo... */
  if (!memcmp(MRFI_P_SRC_ADDR(&fiPtr->mrfiPkt), sMyAddr, NET_ADDR_SIZE))
  {
    fiPtr->fi_usage = FI_AVAILABLE;
    return;
  }

  /* Make sure encyrption bit conforms to our security support context. */
#if defined(SMPL_SECURE)
  if (!(GET_FROM_FRAME(MRFI_P_PAYLOAD(&fiPtr->mrfiPkt), F_ENCRYPT_OS)))
  {
    /* Encyrption bit is not on when when it should be */
    fiPtr->fi_usage = FI_AVAILABLE;
    return;
  }
#else
  if (GET_FROM_FRAME(MRFI_P_PAYLOAD(&fiPtr->mrfiPkt), F_ENCRYPT_OS))
  {
    /* Encyrption bit is on when when it should not be */
    fiPtr->fi_usage = FI_AVAILABLE;
    return;
  }
#endif  /* SMPL_SECURE */

  /* If it's a network application port dispatch to service routine. Dispose
   * of frame depending on return code.
   */
  if (port && (port <= nwkAppSize))
  {
#if defined(SMPL_SECURE)
    /* Non-connection-based frame. We can decode here if it was encrypted */
    if (!nwk_getSecureFrame(&fiPtr->mrfiPkt, MRFI_GET_PAYLOAD_LEN(&fiPtr->mrfiPkt) - F_SEC_CTR_OS, 0))
    {
      fiPtr->fi_usage = FI_AVAILABLE;
      return;
    }
#endif
    rc = func[port-1](&fiPtr->mrfiPkt);
    if (FHS_KEEP == rc)
    {
      fiPtr->fi_usage = FI_INUSE_UNTIL_DEL;
    }
#if !defined(END_DEVICE)
    else if (FHS_REPLAY == rc)
    {
      /* an AP or an RE could be relaying a NWK application frame... */
      nwk_replayFrame(fiPtr);
    }
#endif
    else  /* rc == FHS_RELEASE (default...) */
    {
      fiPtr->fi_usage = FI_AVAILABLE;
    }
    return;
  }
  /* sanity check */
  else if ((port != SMPL_PORT_USER_BCAST) && ((port < PORT_BASE_NUMBER) || (port > SMPL_PORT_STATIC_MAX)))
  {
    /* bogus port. drop frame */
    fiPtr->fi_usage = FI_AVAILABLE;
    return;
  }

  /* At this point we know the target is a user app. If this is an end device
   * and we got this far save the frame and we're done. If we're an AP there
   * are 3 cases: it's for us, it's for s store-and-forward client, or we need
   * to replay the frame. If we're and RE and the frame didn't come from an RE
   * and it's not for us, replay the frame.
   */

#if defined(END_DEVICE)
  /* If we're s polling end device we only accept application frames from
   * the AP. This prevents duplicate reception if we happen to be on when
   * a linked peer sends.
   */
#if defined(RX_POLLS)
  if (F_TX_DEVICE_ED != GET_FROM_FRAME(MRFI_P_PAYLOAD(&fiPtr->mrfiPkt), F_TX_DEVICE))
  {
    if (nwk_isConnectionValid(&fiPtr->mrfiPkt, &lid))
    {
      fiPtr->fi_usage = FI_INUSE_UNTIL_DEL;
    }
    else
    {
      fiPtr->fi_usage = FI_AVAILABLE;
    }
  }
  else
  {
    fiPtr->fi_usage = FI_AVAILABLE;
  }
#else
  /* it's destined for a user app. */
  if (nwk_isConnectionValid(&fiPtr->mrfiPkt, &lid))
  {
    fiPtr->fi_usage = FI_INUSE_UNTIL_DEL;
    if (spCallback && spCallback(lid))
    {
      fiPtr->fi_usage = FI_AVAILABLE;
      return;
    }
  }
  else
  {
    fiPtr->fi_usage = FI_AVAILABLE;
  }
#endif  /* RX_POLLS */

#else   /* END_DEVICE */

  /* We have an issue if the frame is broadcast to the UUD port. The AP (or RE) must
   * handle this frame as if it were the target in case there is an application
   * running that is listening on that port. But if it's a broadcast it must also be
   * replayed. It isn't enough just to test for the UUD port because it could be a
   * directed frame to another device. We must check explicitly for broadcast
   * destination address.
   */
  isForMe = !memcmp(sMyAddr, MRFI_P_DST_ADDR(&fiPtr->mrfiPkt), NET_ADDR_SIZE);
  if (isForMe || ((port == SMPL_PORT_USER_BCAST) && !memcmp(nwk_getBCastAddress(), MRFI_P_DST_ADDR(&fiPtr->mrfiPkt), NET_ADDR_SIZE)))
  {
    /* The folllowing test will succeed for the UUD port regardless of the
     * source address.
     */
    if (nwk_isConnectionValid(&fiPtr->mrfiPkt, &lid))
    {
      /* If this is for the UUD port and we are here then the device is either
       * an AP or an RE. In either case it must replay the UUD port frame if the
       * frame is not "for me". But it also must handle it since it could have a
       * UUD-listening application. Do the reply first and let the subsequent code
       * correctly set the frame usage state. Note that the routine return can be
       * from this code block. If not it will drop through to the bottom without
       * doing a replay.
       */
      /* Do I need to replay it? */
      if (!isForMe)
      {
        /* must be a broadcast for the UUD port */
        nwk_replayFrame(fiPtr);
      }
      /* OK. Now I handle it... */
      fiPtr->fi_usage = FI_INUSE_UNTIL_DEL;
      if (spCallback && spCallback(lid))
      {
        fiPtr->fi_usage = FI_AVAILABLE;
        return;
      }
    }
    else
    {
      fiPtr->fi_usage = FI_AVAILABLE;
    }
  }
#if defined( ACCESS_POINT )
  /* Check to see if we need to save this for a S and F client. Otherwise,
   * if it's not for us, get rid of it.
   */
  else if (nwk_isSandFClient(MRFI_P_DST_ADDR(&fiPtr->mrfiPkt), &loc))
  {
    /* Don't bother if it is a duplicate frame or if it's a forwarded frame
     * echoed back from an RE.
     */
    if (!isDupSandFFrame(&fiPtr->mrfiPkt) &&
        !(GET_FROM_FRAME(MRFI_P_PAYLOAD(&fiPtr->mrfiPkt), F_FWD_FRAME))
       )
    {
#if defined(APP_AUTO_ACK)
      /* Make sure ack request bit is off. Sender will have gone away. */
      PUT_INTO_FRAME(MRFI_P_PAYLOAD(&fiPtr->mrfiPkt), F_ACK_REQ, 0);
#endif
      fiPtr->fi_usage = FI_INUSE_UNTIL_FWD;
    }
    else
    {
      fiPtr->fi_usage = FI_AVAILABLE;
    }
  }
  else if (GET_FROM_FRAME(MRFI_P_PAYLOAD(&fiPtr->mrfiPkt), F_TX_DEVICE) == F_TX_DEVICE_AP)
  {
    /* I'm an AP and this frame came from an AP. Don't replay. */
    fiPtr->fi_usage = FI_AVAILABLE;
  }
#elif defined( RANGE_EXTENDER )
  else if (GET_FROM_FRAME(MRFI_P_PAYLOAD(&fiPtr->mrfiPkt), F_TX_DEVICE) == F_TX_DEVICE_RE)
  {
    /* I'm an RE and this frame came from an RE. Don't replay. */
    fiPtr->fi_usage = FI_AVAILABLE;//////ojooooo descomentar!!!
	//nwk_replayFrame(fiPtr);//ojoooooooooo borrar!!!
  }
#endif
  else
  {
    /* It's not for me and I'm either an AP or I'm an RE and the frame
     * didn't come from an RE. Replay the frame.
     */
    nwk_replayFrame(fiPtr);
  }
#endif  /* !END_DEVICE */
  return;
}
Beispiel #17
0
smplStatus_t nwk_ping(linkID_t lid)
{
    connInfo_t  *pCInfo   = nwk_getConnInfo(lid);
    smplStatus_t rc       = SMPL_BAD_PARAM;
    uint8_t done     = 0;
    uint8_t repeatIt = 2;
    uint8_t msg[MAX_PING_APP_FRAME];
    uint8_t radioState = MRFI_GetRadioState();

    union
    {
        ioctlRawSend_t send;
        ioctlRawReceive_t recv;
    } ioctl_info;

    if (!pCInfo || (SMPL_LINKID_USER_UUD == lid))
    {
        /* either link ID bogus or tried to ping the unconnected user datagram link ID. */
        return rc;
    }

    do
    {
#if defined(FREQUENCY_AGILITY) && !defined(ACCESS_POINT)
        uint8_t i, numChan;
        freqEntry_t channels[NWK_FREQ_TBL_SIZE];

        if (repeatIt == 2)
        {
            /* If FA enabled, first time through set up so that the 'for'
             * loop checks the current channel. This saves time (no scan)
             * and is very likely to succeed. Populate the proper strucure.
             */
            SMPL_Ioctl(IOCTL_OBJ_FREQ, IOCTL_ACT_GET, channels);
            numChan = 1;
        }
        else
        {
            /* If we get here we must scan for the channel we're now on */
            if (!(numChan = nwk_scanForChannels(channels)))
            {
                return SMPL_NO_CHANNEL;
            }
        }
        /* Either we scan next time through or we're done */
        repeatIt--;

        /* this loop Pings on each channel (probably only 1) looking
         * for peer.
         */
        for (i = 0; i < numChan && !done; ++i)
        {
            nwk_setChannel(&channels[i]);
#else
        {
            repeatIt = 0;
#endif      /* defined(FREQUENCY_AGILITY) && !defined(ACCESS_POINT) */

            ioctl_info.send.addr = (addr_t *)pCInfo->peerAddr;
            ioctl_info.send.msg  = msg;
            ioctl_info.send.len  = sizeof(msg);
            ioctl_info.send.port = SMPL_PORT_PING;

            /* fill in msg */
            msg[PB_REQ_OS] = PING_REQ_PING;
            msg[PB_TID_OS] = sTid;

            SMPL_Ioctl(IOCTL_OBJ_RAW_IO, IOCTL_ACT_WRITE, &ioctl_info.send);

            ioctl_info.recv.port = SMPL_PORT_PING;
            ioctl_info.recv.msg  = msg;
            ioctl_info.recv.addr = 0;

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

            if (SMPL_SUCCESS == SMPL_Ioctl(IOCTL_OBJ_RAW_IO, IOCTL_ACT_READ, &ioctl_info.recv))
            {
                repeatIt = 0;
                done     = 1;
                sTid++; /* guard against duplicates */
            }
        }
    } while (repeatIt);

    return done ? SMPL_SUCCESS : SMPL_TIMEOUT;

}

/******************************************************************************
 * @fn          smpl_send_ping_reply
 *
 * @brief       Send a reply to a ping request.
 *
 * input parameters
 * @param   frame     - pointer to frame containing request
 *
 * output parameters
 *
 * @return   void
 */

static void smpl_send_ping_reply(mrfiPacket_t *frame)
{
    frameInfo_t *pOutFrame;

    /* Build the reply frame. The application payload is the one included in the
     * received frame payload.
     */
    if (pOutFrame =
            nwk_buildFrame(SMPL_PORT_PING, MRFI_P_PAYLOAD(frame) + F_APP_PAYLOAD_OS,
                           MRFI_GET_PAYLOAD_LEN(frame) - F_APP_PAYLOAD_OS, MAX_HOPS))
    {
        /* destination address is the source adddress of the received frame. */
        memcpy(MRFI_P_DST_ADDR(&pOutFrame->mrfiPkt), MRFI_P_SRC_ADDR(frame), NET_ADDR_SIZE);

        /* turn on the reply bit in the application payload */
        *(MRFI_P_PAYLOAD(&pOutFrame->mrfiPkt) + F_APP_PAYLOAD_OS + PB_REQ_OS) |= NWK_APP_REPLY_BIT;
#ifdef SMPL_SECURE
        nwk_setSecureFrame(&pOutFrame->mrfiPkt, MRFI_GET_PAYLOAD_LEN(frame) - F_APP_PAYLOAD_OS, 0);
#endif  /* SMPL_SECURE */
        nwk_sendFrame(pOutFrame, MRFI_TX_TYPE_FORCED);
    }
}
Beispiel #18
0
/******************************************************************************
 * @fn          SMPL_SendOpt
 *
 * @brief       Send a message to a peer application.
 *
 * input parameters
 * @param   lid     - Link ID (port) from application
 * @param   msg     - pointer to message from app to be sent
 * @param   len     - length of enclosed message
 * @param   options - Transmit options (bit map)
 *
 * output parameters
 *
 * @return   Status of operation. On a filaure the frame buffer is discarded
 *           and the Send call must be redone by the app.
 *             SMPL_SUCCESS
 *             SMPL_BAD_PARAM    No valid Connection Table entry for Link ID
 *                               Data in Connection Table entry bad
 *                               No message or message too long
 *             SMPL_NOMEM        No room in output frame queue
 *             SMPL_TX_CCA_FAIL  CCA failure.
 *             SMPL_NO_ACK       If application auto acknowledgement enabled
 *                               and no acknowledgement is received
 */
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;
  uint8_t       ackreq     = 0;
#if defined(ACCESS_POINT)
  uint8_t  loc;
#endif
  radioState = MRFI_GetRadioState();
  /* 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 */
}
Beispiel #19
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, *pAddr2, *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;
}
Beispiel #20
0
/******************************************************************************
 * @fn          smpl_send_join_reply
 *
 * @brief       Send the Join reply. Include the Link token. If the device is
 *              a polling sleeper put it into the list of store-and-forward
 *              clients.
 *
 * input parameters
 * @param   frame     - join frame for which a reply is needed...maybe
 *
 * output parameters
 *
 * @return   void
 */
static void smpl_send_join_reply(mrfiPacket_t *frame)
{
  frameInfo_t *pOutFrame;
  uint8_t      msg[JOIN_REPLY_FRAME_SIZE];

  /* Is this a legacy frame? If so continue. Otherwise check verion.*/
  if ((MRFI_GET_PAYLOAD_LEN(frame) - F_APP_PAYLOAD_OS) > JOIN_LEGACY_MSG_LENGTH)
  {
    /* see if protocol version is correct... */
    if (*(MRFI_P_PAYLOAD(frame)+F_APP_PAYLOAD_OS+J_PROTOCOL_VERSION_OS) != nwk_getProtocolVersion())
    {
      /* Accommodation of protocol version differences can be noted or accomplished here.
       * Otherwise, no match and the board goes back
       */
      return;
    }
  }


  /* see if join token is correct */
  {
    uint32_t jt;

    nwk_getNumObjectFromMsg(MRFI_P_PAYLOAD(frame)+F_APP_PAYLOAD_OS+J_JOIN_TOKEN_OS, &jt, sizeof(jt));
    if (jt != sJoinToken)
    {
      return;
    }
  }

  /* send reply with tid, the link token, and the encryption context */
  {
    uint32_t linkToken;

    nwk_getLinkToken(&linkToken);
    nwk_putNumObjectIntoMsg((void *)&linkToken, msg+JR_LINK_TOKEN_OS, sizeof(linkToken));
  }
  msg[JR_CRYPTKEY_SIZE_OS] = SEC_CRYPT_KEY_SIZE;
  msg[JB_REQ_OS]           = JOIN_REQ_JOIN | NWK_APP_REPLY_BIT;
  /* sender's tid... */
  msg[JB_TID_OS]           = *(MRFI_P_PAYLOAD(frame)+F_APP_PAYLOAD_OS+JB_TID_OS);

  if (pOutFrame = nwk_buildFrame(SMPL_PORT_JOIN, msg, sizeof(msg), MAX_HOPS_FROM_AP))
  {
    /* destination address is the source adddress of the received frame. */
    memcpy(MRFI_P_DST_ADDR(&pOutFrame->mrfiPkt), MRFI_P_SRC_ADDR(frame), NET_ADDR_SIZE);

#ifdef AP_IS_DATA_HUB
    /* if source device supports ED objects save source address to detect duplicate joins */
    if (*(MRFI_P_PAYLOAD(frame)+F_APP_PAYLOAD_OS+J_NUMCONN_OS))
    {
      if (nwk_saveJoinedDevice(frame) && spCallback)
      {
        spCallback(0);
      }
    }
#endif
  }
  else
  {
    /* oops -- no room left for Tx frame. Don't send reply. */
    return;
  }

  /* If this device polls we need to provide store-and-forward support */
  if (GET_FROM_FRAME(MRFI_P_PAYLOAD(frame),F_RX_TYPE) == F_RX_TYPE_POLLS)
  {
    uint8_t loc;

    /* Check duplicate status */
    if (!nwk_isSandFClient(MRFI_P_SRC_ADDR(frame), &loc))
    {
      uint8_t        *pNumc   = &spSandFContext->curNumSFClients;
      sfClientInfo_t *pClient = &spSandFContext->sfClients[*pNumc];

      /* It's not a duplicate. Save it if there's room */
      if (*pNumc < NUM_STORE_AND_FWD_CLIENTS)
      {
        memcpy(pClient->clientAddr.addr, MRFI_P_SRC_ADDR(frame), NET_ADDR_SIZE);
        *pNumc = *pNumc + 1;
      }
      else
      {
        /* No room left. Just return and don't send reply. */
        return;
      }
    }
    else
    {
      /* We get here if it's a duplicate. We drop through and send reply.
       * Reset the S&F marker in the Management application -- we should
       * assume that the Client reset so the TID will be random. If this is
       * simply a duplicate frame it causes no harm.
       */
      nwk_resetSFMarker(loc);
    }
  }

#ifdef SMPL_SECURE
    nwk_setSecureFrame(&pOutFrame->mrfiPkt, sizeof(msg), 0);
#endif  /* SMPL_SECURE */

  /* It's not S&F or it is but we're OK to send reply. */
  nwk_sendFrame(pOutFrame, MRFI_TX_TYPE_FORCED);

  return;
}