void NcpSpi::PrepareNextSpiSendFrame(void) { otError error = OT_ERROR_NONE; uint16_t frameLength; uint16_t readLength; SpiFrame sendFrame(mSendFrame); VerifyOrExit(!mTxFrameBuffer.IsEmpty()); if (ShouldWakeHost()) { otPlatWakeHost(); } SuccessOrExit(error = mTxFrameBuffer.OutFrameBegin()); frameLength = mTxFrameBuffer.OutFrameGetLength(); assert(frameLength <= kSpiBufferSize - kSpiHeaderSize); // The "accept length" in `mSendFrame` is already updated based // on current state of receive. It is changed either from the // `SpiTransactionComplete()` callback or from `HandleRxFrame()`. readLength = mTxFrameBuffer.OutFrameRead(frameLength, sendFrame.GetData()); assert(readLength == frameLength); sendFrame.SetHeaderDataLen(frameLength); mSendFrameLength = frameLength + kSpiHeaderSize; mTxState = kTxStateSending; // Prepare new transaction by using `mSendFrame` as the output // frame while keeping the input frame unchanged. error = otPlatSpiSlavePrepareTransaction(mSendFrame, mSendFrameLength, NULL, 0, /* aRequestTrans */ true); if (error == OT_ERROR_BUSY) { // Being busy is OK. We will get the transaction set up // properly when the current transaction is completed. error = OT_ERROR_NONE; } if (error != OT_ERROR_NONE) { mTxState = kTxStateIdle; mPrepareTxFrameTask.Post(); ExitNow(); } mTxFrameBuffer.OutFrameRemove(); exit: return; }
// This method encodes a frame from the tx frame buffer (mTxFrameBuffer) into the uart buffer and sends it over uart. // If the uart buffer gets full, it sends the current encoded portion. This method remembers current state, so on // sub-sequent calls, it restarts encoding the bytes from where it left of in the frame . void NcpUart::EncodeAndSendToUart(void) { uint16_t len; bool prevHostPowerState; #if OPENTHREAD_ENABLE_NCP_SPINEL_ENCRYPTER NcpFrameBufferEncrypterReader &txFrameBuffer = mTxFrameBufferEncrypterReader; #else NcpFrameBuffer &txFrameBuffer = mTxFrameBuffer; #endif // OPENTHREAD_ENABLE_NCP_SPINEL_ENCRYPTER while (!txFrameBuffer.IsEmpty() || (mState == kFinalizingFrame)) { switch (mState) { case kStartingFrame: if (super_t::ShouldWakeHost()) { otPlatWakeHost(); } VerifyOrExit(super_t::ShouldDeferHostSend() == false); SuccessOrExit(mFrameEncoder.Init(mUartBuffer)); txFrameBuffer.OutFrameBegin(); mState = kEncodingFrame; while (!txFrameBuffer.OutFrameHasEnded()) { mByte = txFrameBuffer.OutFrameReadByte(); case kEncodingFrame: SuccessOrExit(mFrameEncoder.Encode(mByte, mUartBuffer)); } // track the change of mHostPowerStateInProgress by the // call to OutFrameRemove. prevHostPowerState = mHostPowerStateInProgress; txFrameBuffer.OutFrameRemove(); if (prevHostPowerState && !mHostPowerStateInProgress) { // If mHostPowerStateInProgress transitioned from true -> false // in the call to OutFrameRemove, then the frame should be sent // out the UART without attempting to push any new frames into // the mUartBuffer. This is necessary to avoid prematurely calling // otPlatWakeHost. mUartSendImmediate = true; } mState = kFinalizingFrame; // fall through case kFinalizingFrame: SuccessOrExit(mFrameEncoder.Finalize(mUartBuffer)); mState = kStartingFrame; if (mUartSendImmediate) { // clear state and break; mUartSendImmediate = false; break; } } } exit: len = mUartBuffer.GetLength(); if (len > 0) { if (otPlatUartSend(mUartBuffer.GetBuffer(), len) != OT_ERROR_NONE) { assert(false); } } }