virtual net_result nrecv( LinkLayerAddress *addr, uint8_t *payload, size_t &length ) { packet_addr_t dest; packet_error_t pferror = recvFrame( handle, &dest, payload, length ); if( pferror != PACKET_NO_ERROR && pferror != PACKET_RECVTIMEOUT_ERROR ) return net_fatal; if( pferror == PACKET_RECVTIMEOUT_ERROR ) return net_trfail; *addr = LinkLayerAddress( dest.addr ); return net_succeed; }
void NcpSpi::HandleRxFrame(void) { SpiFrame recvFrame(mReceiveFrame); SpiFrame sendFrame(mSendFrame); // Pass the received frame to base class to process. HandleReceive(recvFrame.GetData(), recvFrame.GetHeaderDataLen()); // The order of operations below is important. We should clear // the `mHandlingRxFrame` before checking `mTxState` and possibly // preparing the next transaction. Note that the callback // `SpiTransactionComplete()` can be invoked from ISR at any point. // // If we switch the order, we have the following race situation: // We check `mTxState` and it is in `kTxStateSending`, so we skip // preparing the transaction here. But before we set the // `mHandlingRxFrame` to `false`, the `SpiTransactionComplete()` // happens and prepares the next transaction and sets the accept // length to zero on `mSendFrame` (since it assumes we are still // handling the previous received frame). mHandlingRxFrame = false; // If tx state is in `kTxStateSending`, we wait for the callback // `SpiTransactionComplete()` which will then set up everything // and prepare the next transaction. if (mTxState != kTxStateSending) { sendFrame.SetHeaderAcceptLen(kSpiBufferSize - kSpiHeaderSize); otPlatSpiSlavePrepareTransaction(mEmptySendFrameFullAccept, kSpiHeaderSize, mReceiveFrame, kSpiBufferSize, /* aRequestTrans */ false); // No need to check the error status. Getting `OT_ERROR_BUSY` // is OK as everything will be set up properly from callback when // the current transaction is completed. } }