ncp-uart: Fix for platforms which call otPlatUartSendDone() reentrantly (#306)

This change makes the `NcpUart` class behave more robustly against
various sorts of `otPlatUart` API implementations; specifically those
that might call `otPlatUartSendDone()` directly from
`otPlatUartSend()`.

Without this change, all NCP frames after the first few at startup
will be squelched.
This commit is contained in:
Robert Quattlebaum
2016-07-29 17:55:31 -07:00
committed by Jonathan Hui
parent 9a1a6206d0
commit 5f9f9e2ce2
3 changed files with 44 additions and 17 deletions
+29 -15
View File
@@ -298,6 +298,7 @@ static spinel_status_t ResetReasonToSpinelStatus(otPlatResetReason reason)
// ----------------------------------------------------------------------------
NcpBase::NcpBase():
mSendDoneTask(&SendDoneTask, this),
mUpdateChangedPropsTask(&UpdateChangedProps, this)
{
mSupportedChannelMask = kPhySupportedChannelMask;
@@ -569,27 +570,40 @@ void NcpBase::HandleReceive(const uint8_t *buf, uint16_t bufLength)
}
}
void NcpBase::HandleSendDone()
void NcpBase::SendDoneTask(void *context)
{
if (mSendQueue.GetHead() != NULL)
{
Message &message(*mSendQueue.GetHead());
mSendQueue.Dequeue(message);
HandleDatagramFromStack(message);
}
NcpBase *obj = reinterpret_cast<NcpBase *>(context);
obj->SendDoneTask();
}
if (mQueuedGetHeader != 0)
{
HandleCommandPropertyGet(mQueuedGetHeader, mQueuedGetKey);
mQueuedGetHeader = 0;
}
void NcpBase::SendDoneTask(void)
{
if (!mSending) {
if (mSendQueue.GetHead() != NULL)
{
Message &message(*mSendQueue.GetHead());
mSendQueue.Dequeue(message);
HandleDatagramFromStack(message);
}
if (!mSending)
{
UpdateChangedProps();
if (mQueuedGetHeader != 0)
{
HandleCommandPropertyGet(mQueuedGetHeader, mQueuedGetKey);
mQueuedGetHeader = 0;
}
if (!mSending)
{
UpdateChangedProps();
}
}
}
void NcpBase::HandleSendDone(void)
{
mSendDoneTask.Post();
}
// ----------------------------------------------------------------------------
// MARK: Inbound Command Handlers
+8
View File
@@ -94,6 +94,12 @@ private:
void UpdateChangedProps(void);
/**
* Trampoline for SendDoneTask().
*/
static void SendDoneTask(void *context);
void SendDoneTask(void);
static void HandleNetifStateChanged(uint32_t flags, void *context);
@@ -309,6 +315,8 @@ private:
spinel_prop_key_t mQueuedGetKey;
Tasklet mSendDoneTask;
Tasklet mUpdateChangedPropsTask;
MessageQueue mSendQueue;
+7 -2
View File
@@ -145,12 +145,17 @@ NcpUart::OutboundFrameSend(void)
if (errorCode == kThreadError_None)
{
// We go ahead and set this to `true` here in case
// `otPlatUartSend()` ends up directly calling
// `otPlatUartSendDone()`.
mSending = true;
errorCode = otPlatUartSend(mSendFrame.GetBuffer(), mSendFrame.GetLength());
}
if (errorCode == kThreadError_None)
if (errorCode != kThreadError_None)
{
mSending = true;
mSending = false;
}
return errorCode;