void LinkRaw::InvokeTransmitDone(otRadioFrame *aFrame, otRadioFrame *aAckFrame, otError aError) { otLogDebgPlat(&mInstance, "LinkRaw Transmit Done (err=0x%x)", aError); #if OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ACK_TIMEOUT mTimer.Stop(); #endif #if OPENTHREAD_CONFIG_ENABLE_SOFTWARE_RETRANSMIT if (aError == OT_ERROR_CHANNEL_ACCESS_FAILURE) { if (mCsmaAttempts < Mac::kMaxCSMABackoffs) { mCsmaAttempts++; StartCsmaBackoff(); goto exit; } } else { mCsmaAttempts = 0; } if (aError == OT_ERROR_NO_ACK) { if (mTransmitAttempts < aFrame->mMaxTxAttempts) { mTransmitAttempts++; StartCsmaBackoff(); goto exit; } } #endif // Transition back to receive state on previous channel otPlatRadioReceive(&mInstance, mReceiveChannel); if (mTransmitDoneCallback) { if (aError == OT_ERROR_NONE) { otLogInfoPlat(&mInstance, "LinkRaw Invoke Transmit Done"); } else { otLogWarnPlat(&mInstance, "LinkRaw Invoke Transmit Failed (err=0x%x)", aError); } mTransmitDoneCallback(&mInstance, aFrame, aAckFrame, aError); mTransmitDoneCallback = NULL; } #if OPENTHREAD_CONFIG_ENABLE_SOFTWARE_RETRANSMIT exit: return; #endif }
void Mac::SentFrame(bool aAcked) { Address destination; Neighbor *neighbor; Sender *sender; switch (mState) { case kStateActiveScan: mAckTimer.Start(mScanDuration); break; case kStateTransmitBeacon: ScheduleNextTransmission(); break; case kStateTransmitData: if (mSendFrame.GetAckRequest() && !aAcked) { otDumpDebgMac("NO ACK", mSendFrame.GetHeader(), 16); if (mTransmitAttempts < kMaxFrameAttempts) { mTransmitAttempts++; StartCsmaBackoff(); ExitNow(); } mSendFrame.GetDstAddr(destination); if ((neighbor = mMle.GetNeighbor(destination)) != NULL) { neighbor->mState = Neighbor::kStateInvalid; } } mTransmitAttempts = 0; sender = mSendHead; mSendHead = mSendHead->mNext; if (mSendHead == NULL) { mSendTail = NULL; } mDataSequence++; sender->HandleSentFrame(mSendFrame); ScheduleNextTransmission(); break; default: assert(false); break; } exit: {} }
ThreadError Mac::SendFrameRequest(Sender &aSender) { ThreadError error = kThreadError_None; VerifyOrExit(mSendTail != &aSender && aSender.mNext == NULL, error = kThreadError_Busy); if (mSendHead == NULL) { mSendHead = &aSender; mSendTail = &aSender; } else { mSendTail->mNext = &aSender; mSendTail = &aSender; } if (mState == kStateIdle) { mState = kStateTransmitData; StartCsmaBackoff(); } exit: return error; }
ThreadError Mac::ActiveScan(uint16_t aScanChannels, uint16_t aScanDuration, ActiveScanHandler aHandler, void *aContext) { ThreadError error = kThreadError_None; VerifyOrExit(mState != kStateActiveScan && mActiveScanRequest == false, error = kThreadError_Busy); mActiveScanHandler = aHandler; mActiveScanContext = aContext; mScanChannels = (aScanChannels == 0) ? kScanChannelsAll : aScanChannels; mScanDuration = (aScanDuration == 0) ? kScanDurationDefault : aScanDuration; mScanChannel = kPhyMinChannel; while ((mScanChannels & 1) == 0) { mScanChannels >>= 1; mScanChannel++; } if (mState == kStateIdle) { mState = kStateActiveScan; StartCsmaBackoff(); } else { mActiveScanRequest = true; } exit: return error; }
void Mac::TransmitDoneTask(void) { ThreadError error; bool rxPending; error = otPlatRadioHandleTransmitDone(&rxPending); mAckTimer.Stop(); if (error == kThreadError_ChannelAccessFailure && mCsmaAttempts < kMaxCSMABackoffs) { mCsmaAttempts++; StartCsmaBackoff(); ExitNow(); } mCsmaAttempts = 0; switch (mState) { case kStateActiveScan: mAckTimer.Start(mScanDuration); break; case kStateTransmitBeacon: SentFrame(true); break; case kStateTransmitData: if (rxPending) { mReceiveTimer.Start(kDataPollTimeout); } else { mReceiveTimer.Stop(); } SentFrame(error == kThreadError_None); break; default: assert(false); break; } exit: NextOperation(); }
void Mac::ScheduleNextTransmission(void) { if (mActiveScanRequest) { mActiveScanRequest = false; mState = kStateActiveScan; StartCsmaBackoff(); } else if (mTransmitBeacon) { mTransmitBeacon = false; mState = kStateTransmitBeacon; StartCsmaBackoff(); } else if (mSendHead != NULL) { mState = kStateTransmitData; StartCsmaBackoff(); } else { mState = kStateIdle; } }
void Mac::HandleAckTimer(void) { otPlatRadioIdle(); switch (mState) { case kStateActiveScan: do { mScanChannels >>= 1; mScanChannel++; if (mScanChannels == 0 || mScanChannel > kPhyMaxChannel) { mActiveScanHandler(mActiveScanContext, NULL); ScheduleNextTransmission(); ExitNow(); } } while ((mScanChannels & 1) == 0); StartCsmaBackoff(); break; case kStateTransmitData: otLogDebgMac("ack timer fired\n"); SentFrame(false); break; default: assert(false); break; } exit: NextOperation(); }
otError LinkRaw::Transmit(otRadioFrame *aFrame, otLinkRawTransmitDone aCallback) { otError error = OT_ERROR_INVALID_STATE; if (mEnabled) { mTransmitDoneCallback = aCallback; #if OPENTHREAD_CONFIG_ENABLE_SOFTWARE_RETRANSMIT OT_UNUSED_VARIABLE(aFrame); mTransmitAttempts = 0; mCsmaAttempts = 0; // Start the transmission backlog logic StartCsmaBackoff(); error = OT_ERROR_NONE; #else // Let the hardware do the transmission logic error = DoTransmit(aFrame); #endif } return error; }