diff --git a/examples/drivers/windows/otApi/otApi.cpp b/examples/drivers/windows/otApi/otApi.cpp index be469e33c..4fa9863db 100644 --- a/examples/drivers/windows/otApi/otApi.cpp +++ b/examples/drivers/windows/otApi/otApi.cpp @@ -1316,6 +1316,18 @@ otIsDiscoverInProgress( return Result != FALSE; } +OTAPI +ThreadError +OTCALL +otSendMacDataRequest( + _In_ otInstance *aInstance + ) +{ + if (aInstance == nullptr) return kThreadError_InvalidArgs; + UNREFERENCED_PARAMETER(aInstance); + return kThreadError_NotImplemented; // TODO +} + OTAPI uint8_t OTCALL diff --git a/include/openthread.h b/include/openthread.h index e771d166b..fb9726a7c 100644 --- a/include/openthread.h +++ b/include/openthread.h @@ -433,6 +433,19 @@ OTAPI ThreadError OTCALL otDiscover(otInstance *aInstance, uint32_t aScanChannel */ OTAPI bool OTCALL otIsDiscoverInProgress(otInstance *aInstance); +/** + * This function enqueues an IEEE 802.15.4 Data Request message for transmission. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * + * @retval kThreadError_None Successfully enqueued an IEEE 802.15.4 Data Request message. + * @retval kThreadError_Already An IEEE 802.15.4 Data Request message is already enqueued. + * @retval kThreadError_InvalidState Device is not in rx-off-when-idle mode. + * @retval kThreadError_NoBufs Insufficient message buffers available. + * + */ +OTAPI ThreadError OTCALL otSendMacDataRequest(otInstance *aInstance); + /** * @} * diff --git a/src/core/openthread.cpp b/src/core/openthread.cpp index a0cd00f5e..dc97c6cbc 100644 --- a/src/core/openthread.cpp +++ b/src/core/openthread.cpp @@ -1376,6 +1376,11 @@ bool otIsDiscoverInProgress(otInstance *aInstance) return aInstance->mThreadNetif.GetMle().IsDiscoverInProgress(); } +ThreadError otSendMacDataRequest(otInstance *aInstance) +{ + return aInstance->mThreadNetif.GetMeshForwarder().SendMacDataRequest(); +} + void otSetReceiveIp6DatagramCallback(otInstance *aInstance, otReceiveIp6DatagramCallback aCallback, void *aCallbackContext) { diff --git a/src/core/thread/mesh_forwarder.cpp b/src/core/thread/mesh_forwarder.cpp index 97647579c..0d33a3ea2 100644 --- a/src/core/thread/mesh_forwarder.cpp +++ b/src/core/thread/mesh_forwarder.cpp @@ -825,15 +825,42 @@ void MeshForwarder::HandlePollTimer(void *aContext) void MeshForwarder::HandlePollTimer() { + ThreadError error; + + error = SendMacDataRequest(); + + if (error == kThreadError_NoBufs) + { + mPollTimer.Start(kDataRequstRetryDelay); + } +} + +ThreadError MeshForwarder::SendMacDataRequest(void) +{ + ThreadError error; Message *message; - if ((message = mNetif.GetIp6().mMessagePool.New(Message::kTypeMacDataPoll, 0)) != NULL) + // only send MAC Data Requests in rx-off-when-idle mode + VerifyOrExit(!mMac.GetRxOnWhenIdle(), error = kThreadError_InvalidState); + + // only enqueue one MAC Data Request at a time + for (message = mSendQueue.GetHead(); message; message = message->GetNext()) { - SendMessage(*message); - otLogInfoMac("Sent poll"); + VerifyOrExit(message->GetType() != Message::kTypeMacDataPoll, error = kThreadError_Already); } + // enqueue a MAC Data Request message + message = mNetif.GetIp6().mMessagePool.New(Message::kTypeMacDataPoll, 0); + VerifyOrExit(message != NULL, error = kThreadError_NoBufs); + + SuccessOrExit(error = SendMessage(*message)); + otLogInfoMac("Sent poll"); + + // restart the polling timer mPollTimer.Start(mPollPeriod); + +exit: + return error; } ThreadError MeshForwarder::GetMacSourceAddress(const Ip6::Address &aIp6Addr, Mac::Address &aMacAddr) @@ -947,10 +974,14 @@ exit: ThreadError MeshForwarder::SendPoll(Message &aMessage, Mac::Frame &aFrame) { + ThreadError error = kThreadError_None; Mac::Address macSource; uint16_t fcf; Neighbor *neighbor; + // only send MAC Data Requests in rx-off-when-idle mode + VerifyOrExit(!mMac.GetRxOnWhenIdle(), error = kThreadError_InvalidState); + macSource.mShortAddress = mMac.GetShortAddress(); if (macSource.mShortAddress != Mac::kShortAddrInvalid) @@ -998,7 +1029,8 @@ ThreadError MeshForwarder::SendPoll(Message &aMessage, Mac::Frame &aFrame) mMessageNextOffset = aMessage.GetLength(); - return kThreadError_None; +exit: + return error; } ThreadError MeshForwarder::SendMesh(Message &aMessage, Mac::Frame &aFrame) diff --git a/src/core/thread/mesh_forwarder.hpp b/src/core/thread/mesh_forwarder.hpp index 73d541c01..06ccc592f 100644 --- a/src/core/thread/mesh_forwarder.hpp +++ b/src/core/thread/mesh_forwarder.hpp @@ -154,6 +154,17 @@ public: */ void SetPollPeriod(uint32_t aPeriod); + /** + * This method enqueues an IEEE 802.15.4 Data Request message. + * + * @retval kThreadError_None Successfully enqueued an IEEE 802.15.4 Data Request message. + * @retval kThreadError_Already An IEEE 802.15.4 Data Request message is already enqueued. + * @retval kThreadError_InvalidState Device is not in rx-off-when-idle mode. + * @retval kThreadError_NoBufs Insufficient message buffers available. + * + */ + ThreadError SendMacDataRequest(void); + /** * This method gets the Data Poll period. * @@ -204,7 +215,8 @@ public: private: enum { - kStateUpdatePeriod = 1000, ///< State update period in milliseconds. + kStateUpdatePeriod = 1000, ///< State update period in milliseconds. + kDataRequstRetryDelay = 1000, ///< Retry delay in milliseconds. }; ThreadError CheckReachability(uint8_t *aFrame, uint8_t aFrameLength,