/****************************************************************************** * @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; }
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 */ }
/****************************************************************************** * @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; }
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 */ }