1*cfb92d14SAndroid Build Coastguard Worker /*
2*cfb92d14SAndroid Build Coastguard Worker * Copyright (c) 2016, The OpenThread Authors.
3*cfb92d14SAndroid Build Coastguard Worker * All rights reserved.
4*cfb92d14SAndroid Build Coastguard Worker *
5*cfb92d14SAndroid Build Coastguard Worker * Redistribution and use in source and binary forms, with or without
6*cfb92d14SAndroid Build Coastguard Worker * modification, are permitted provided that the following conditions are met:
7*cfb92d14SAndroid Build Coastguard Worker * 1. Redistributions of source code must retain the above copyright
8*cfb92d14SAndroid Build Coastguard Worker * notice, this list of conditions and the following disclaimer.
9*cfb92d14SAndroid Build Coastguard Worker * 2. Redistributions in binary form must reproduce the above copyright
10*cfb92d14SAndroid Build Coastguard Worker * notice, this list of conditions and the following disclaimer in the
11*cfb92d14SAndroid Build Coastguard Worker * documentation and/or other materials provided with the distribution.
12*cfb92d14SAndroid Build Coastguard Worker * 3. Neither the name of the copyright holder nor the
13*cfb92d14SAndroid Build Coastguard Worker * names of its contributors may be used to endorse or promote products
14*cfb92d14SAndroid Build Coastguard Worker * derived from this software without specific prior written permission.
15*cfb92d14SAndroid Build Coastguard Worker *
16*cfb92d14SAndroid Build Coastguard Worker * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17*cfb92d14SAndroid Build Coastguard Worker * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18*cfb92d14SAndroid Build Coastguard Worker * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19*cfb92d14SAndroid Build Coastguard Worker * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
20*cfb92d14SAndroid Build Coastguard Worker * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21*cfb92d14SAndroid Build Coastguard Worker * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22*cfb92d14SAndroid Build Coastguard Worker * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23*cfb92d14SAndroid Build Coastguard Worker * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24*cfb92d14SAndroid Build Coastguard Worker * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25*cfb92d14SAndroid Build Coastguard Worker * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*cfb92d14SAndroid Build Coastguard Worker */
27*cfb92d14SAndroid Build Coastguard Worker
28*cfb92d14SAndroid Build Coastguard Worker /**
29*cfb92d14SAndroid Build Coastguard Worker * @file
30*cfb92d14SAndroid Build Coastguard Worker * This file implements a SPI interface to the OpenThread stack.
31*cfb92d14SAndroid Build Coastguard Worker */
32*cfb92d14SAndroid Build Coastguard Worker
33*cfb92d14SAndroid Build Coastguard Worker #include "ncp_spi.hpp"
34*cfb92d14SAndroid Build Coastguard Worker
35*cfb92d14SAndroid Build Coastguard Worker #include <openthread/ncp.h>
36*cfb92d14SAndroid Build Coastguard Worker #include <openthread/platform/misc.h>
37*cfb92d14SAndroid Build Coastguard Worker #include <openthread/platform/spi-slave.h>
38*cfb92d14SAndroid Build Coastguard Worker #include <openthread/platform/toolchain.h>
39*cfb92d14SAndroid Build Coastguard Worker
40*cfb92d14SAndroid Build Coastguard Worker #include "openthread-core-config.h"
41*cfb92d14SAndroid Build Coastguard Worker #include "common/code_utils.hpp"
42*cfb92d14SAndroid Build Coastguard Worker #include "common/debug.hpp"
43*cfb92d14SAndroid Build Coastguard Worker #include "common/new.hpp"
44*cfb92d14SAndroid Build Coastguard Worker #include "instance/instance.hpp"
45*cfb92d14SAndroid Build Coastguard Worker #include "net/ip6.hpp"
46*cfb92d14SAndroid Build Coastguard Worker
47*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_CONFIG_NCP_SPI_ENABLE
48*cfb92d14SAndroid Build Coastguard Worker
49*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_CONFIG_DIAG_ENABLE
50*cfb92d14SAndroid Build Coastguard Worker static_assert(OPENTHREAD_CONFIG_DIAG_OUTPUT_BUFFER_SIZE <=
51*cfb92d14SAndroid Build Coastguard Worker OPENTHREAD_CONFIG_NCP_SPI_BUFFER_SIZE - ot::Ncp::NcpBase::kSpinelCmdHeaderSize -
52*cfb92d14SAndroid Build Coastguard Worker ot::Ncp::NcpBase::kSpinelPropIdSize - ot::Spinel::SpiFrame::kHeaderSize,
53*cfb92d14SAndroid Build Coastguard Worker "diag output should be smaller than NCP SPI tx buffer");
54*cfb92d14SAndroid Build Coastguard Worker static_assert(OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE <= OPENTHREAD_CONFIG_NCP_SPI_BUFFER_SIZE,
55*cfb92d14SAndroid Build Coastguard Worker "diag command line should be smaller than NCP SPI rx buffer");
56*cfb92d14SAndroid Build Coastguard Worker #endif
57*cfb92d14SAndroid Build Coastguard Worker
58*cfb92d14SAndroid Build Coastguard Worker namespace ot {
59*cfb92d14SAndroid Build Coastguard Worker namespace Ncp {
60*cfb92d14SAndroid Build Coastguard Worker
61*cfb92d14SAndroid Build Coastguard Worker using Spinel::SpiFrame;
62*cfb92d14SAndroid Build Coastguard Worker
63*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_ENABLE_NCP_VENDOR_HOOK == 0
64*cfb92d14SAndroid Build Coastguard Worker
65*cfb92d14SAndroid Build Coastguard Worker static OT_DEFINE_ALIGNED_VAR(sNcpRaw, sizeof(NcpSpi), uint64_t);
66*cfb92d14SAndroid Build Coastguard Worker
otNcpSpiInit(otInstance * aInstance)67*cfb92d14SAndroid Build Coastguard Worker extern "C" void otNcpSpiInit(otInstance *aInstance)
68*cfb92d14SAndroid Build Coastguard Worker {
69*cfb92d14SAndroid Build Coastguard Worker NcpSpi *ncpSpi = nullptr;
70*cfb92d14SAndroid Build Coastguard Worker Instance *instance = static_cast<Instance *>(aInstance);
71*cfb92d14SAndroid Build Coastguard Worker
72*cfb92d14SAndroid Build Coastguard Worker ncpSpi = new (&sNcpRaw) NcpSpi(instance);
73*cfb92d14SAndroid Build Coastguard Worker
74*cfb92d14SAndroid Build Coastguard Worker if (ncpSpi == nullptr || ncpSpi != NcpBase::GetNcpInstance())
75*cfb92d14SAndroid Build Coastguard Worker {
76*cfb92d14SAndroid Build Coastguard Worker OT_ASSERT(false);
77*cfb92d14SAndroid Build Coastguard Worker }
78*cfb92d14SAndroid Build Coastguard Worker }
79*cfb92d14SAndroid Build Coastguard Worker
80*cfb92d14SAndroid Build Coastguard Worker #endif // OPENTHREAD_ENABLE_NCP_VENDOR_HOOK == 0
81*cfb92d14SAndroid Build Coastguard Worker
NcpSpi(Instance * aInstance)82*cfb92d14SAndroid Build Coastguard Worker NcpSpi::NcpSpi(Instance *aInstance)
83*cfb92d14SAndroid Build Coastguard Worker : NcpBase(aInstance)
84*cfb92d14SAndroid Build Coastguard Worker , mTxState(kTxStateIdle)
85*cfb92d14SAndroid Build Coastguard Worker , mHandlingRxFrame(false)
86*cfb92d14SAndroid Build Coastguard Worker , mResetFlag(true)
87*cfb92d14SAndroid Build Coastguard Worker , mPrepareTxFrameTask(*aInstance, NcpSpi::PrepareTxFrame)
88*cfb92d14SAndroid Build Coastguard Worker , mSendFrameLength(0)
89*cfb92d14SAndroid Build Coastguard Worker {
90*cfb92d14SAndroid Build Coastguard Worker SpiFrame sendFrame(mSendFrame);
91*cfb92d14SAndroid Build Coastguard Worker SpiFrame emptyFullAccept(mEmptySendFrameFullAccept);
92*cfb92d14SAndroid Build Coastguard Worker SpiFrame emptyZeroAccept(mEmptySendFrameZeroAccept);
93*cfb92d14SAndroid Build Coastguard Worker
94*cfb92d14SAndroid Build Coastguard Worker sendFrame.SetHeaderFlagByte(/* aResetFlag */ true);
95*cfb92d14SAndroid Build Coastguard Worker sendFrame.SetHeaderAcceptLen(0);
96*cfb92d14SAndroid Build Coastguard Worker sendFrame.SetHeaderDataLen(0);
97*cfb92d14SAndroid Build Coastguard Worker
98*cfb92d14SAndroid Build Coastguard Worker emptyFullAccept.SetHeaderFlagByte(/* aResetFlag */ true);
99*cfb92d14SAndroid Build Coastguard Worker emptyFullAccept.SetHeaderAcceptLen(kSpiBufferSize - kSpiHeaderSize);
100*cfb92d14SAndroid Build Coastguard Worker emptyFullAccept.SetHeaderDataLen(0);
101*cfb92d14SAndroid Build Coastguard Worker
102*cfb92d14SAndroid Build Coastguard Worker emptyZeroAccept.SetHeaderFlagByte(/* aResetFlag */ true);
103*cfb92d14SAndroid Build Coastguard Worker emptyZeroAccept.SetHeaderAcceptLen(0);
104*cfb92d14SAndroid Build Coastguard Worker emptyZeroAccept.SetHeaderDataLen(0);
105*cfb92d14SAndroid Build Coastguard Worker
106*cfb92d14SAndroid Build Coastguard Worker mTxFrameBuffer.SetFrameAddedCallback(HandleFrameAddedToTxBuffer, this);
107*cfb92d14SAndroid Build Coastguard Worker
108*cfb92d14SAndroid Build Coastguard Worker IgnoreError(otPlatSpiSlaveEnable(&NcpSpi::SpiTransactionComplete, &NcpSpi::SpiTransactionProcess, this));
109*cfb92d14SAndroid Build Coastguard Worker
110*cfb92d14SAndroid Build Coastguard Worker // We signal an interrupt on this first transaction to
111*cfb92d14SAndroid Build Coastguard Worker // make sure that the host processor knows that our
112*cfb92d14SAndroid Build Coastguard Worker // reset flag was set.
113*cfb92d14SAndroid Build Coastguard Worker
114*cfb92d14SAndroid Build Coastguard Worker IgnoreError(otPlatSpiSlavePrepareTransaction(mEmptySendFrameZeroAccept, kSpiHeaderSize, mEmptyReceiveFrame,
115*cfb92d14SAndroid Build Coastguard Worker kSpiHeaderSize,
116*cfb92d14SAndroid Build Coastguard Worker /* aRequestTransactionFlag */ true));
117*cfb92d14SAndroid Build Coastguard Worker }
118*cfb92d14SAndroid Build Coastguard Worker
SpiTransactionComplete(void * aContext,uint8_t * aOutputBuf,uint16_t aOutputLen,uint8_t * aInputBuf,uint16_t aInputLen,uint16_t aTransLen)119*cfb92d14SAndroid Build Coastguard Worker bool NcpSpi::SpiTransactionComplete(void *aContext,
120*cfb92d14SAndroid Build Coastguard Worker uint8_t *aOutputBuf,
121*cfb92d14SAndroid Build Coastguard Worker uint16_t aOutputLen,
122*cfb92d14SAndroid Build Coastguard Worker uint8_t *aInputBuf,
123*cfb92d14SAndroid Build Coastguard Worker uint16_t aInputLen,
124*cfb92d14SAndroid Build Coastguard Worker uint16_t aTransLen)
125*cfb92d14SAndroid Build Coastguard Worker {
126*cfb92d14SAndroid Build Coastguard Worker NcpSpi *ncp = reinterpret_cast<NcpSpi *>(aContext);
127*cfb92d14SAndroid Build Coastguard Worker
128*cfb92d14SAndroid Build Coastguard Worker return ncp->SpiTransactionComplete(aOutputBuf, aOutputLen, aInputBuf, aInputLen, aTransLen);
129*cfb92d14SAndroid Build Coastguard Worker }
130*cfb92d14SAndroid Build Coastguard Worker
SpiTransactionComplete(uint8_t * aOutputBuf,uint16_t aOutputLen,uint8_t * aInputBuf,uint16_t aInputLen,uint16_t aTransLen)131*cfb92d14SAndroid Build Coastguard Worker bool NcpSpi::SpiTransactionComplete(uint8_t *aOutputBuf,
132*cfb92d14SAndroid Build Coastguard Worker uint16_t aOutputLen,
133*cfb92d14SAndroid Build Coastguard Worker uint8_t *aInputBuf,
134*cfb92d14SAndroid Build Coastguard Worker uint16_t aInputLen,
135*cfb92d14SAndroid Build Coastguard Worker uint16_t aTransLen)
136*cfb92d14SAndroid Build Coastguard Worker {
137*cfb92d14SAndroid Build Coastguard Worker // This can be executed from an interrupt context, therefore we cannot
138*cfb92d14SAndroid Build Coastguard Worker // use any of OpenThread APIs here. If further processing is needed,
139*cfb92d14SAndroid Build Coastguard Worker // returned value `shouldProcess` is set to `true` to indicate to
140*cfb92d14SAndroid Build Coastguard Worker // platform SPI slave driver to invoke `SpiTransactionProcess()` callback
141*cfb92d14SAndroid Build Coastguard Worker // which unlike this callback must be called from the same OS context
142*cfb92d14SAndroid Build Coastguard Worker // that OpenThread APIs/callbacks are executed.
143*cfb92d14SAndroid Build Coastguard Worker
144*cfb92d14SAndroid Build Coastguard Worker uint16_t transDataLen;
145*cfb92d14SAndroid Build Coastguard Worker bool shouldProcess = false;
146*cfb92d14SAndroid Build Coastguard Worker SpiFrame outputFrame(aOutputBuf);
147*cfb92d14SAndroid Build Coastguard Worker SpiFrame inputFrame(aInputBuf);
148*cfb92d14SAndroid Build Coastguard Worker SpiFrame sendFrame(mSendFrame);
149*cfb92d14SAndroid Build Coastguard Worker
150*cfb92d14SAndroid Build Coastguard Worker VerifyOrExit((aTransLen >= kSpiHeaderSize) && (aInputLen >= kSpiHeaderSize) && (aOutputLen >= kSpiHeaderSize));
151*cfb92d14SAndroid Build Coastguard Worker VerifyOrExit(inputFrame.IsValid() && outputFrame.IsValid());
152*cfb92d14SAndroid Build Coastguard Worker
153*cfb92d14SAndroid Build Coastguard Worker transDataLen = aTransLen - kSpiHeaderSize;
154*cfb92d14SAndroid Build Coastguard Worker
155*cfb92d14SAndroid Build Coastguard Worker if (!mHandlingRxFrame)
156*cfb92d14SAndroid Build Coastguard Worker {
157*cfb92d14SAndroid Build Coastguard Worker uint16_t rxDataLen = inputFrame.GetHeaderDataLen();
158*cfb92d14SAndroid Build Coastguard Worker
159*cfb92d14SAndroid Build Coastguard Worker // A new frame is successfully received if input frame
160*cfb92d14SAndroid Build Coastguard Worker // indicates that there is data and the "data len" is not
161*cfb92d14SAndroid Build Coastguard Worker // larger than than the "accept len" we provided in the
162*cfb92d14SAndroid Build Coastguard Worker // exchanged output frame.
163*cfb92d14SAndroid Build Coastguard Worker
164*cfb92d14SAndroid Build Coastguard Worker if ((rxDataLen > 0) && (rxDataLen <= transDataLen) && (rxDataLen <= outputFrame.GetHeaderAcceptLen()))
165*cfb92d14SAndroid Build Coastguard Worker {
166*cfb92d14SAndroid Build Coastguard Worker mHandlingRxFrame = true;
167*cfb92d14SAndroid Build Coastguard Worker shouldProcess = true;
168*cfb92d14SAndroid Build Coastguard Worker }
169*cfb92d14SAndroid Build Coastguard Worker }
170*cfb92d14SAndroid Build Coastguard Worker
171*cfb92d14SAndroid Build Coastguard Worker if (mTxState == kTxStateSending)
172*cfb92d14SAndroid Build Coastguard Worker {
173*cfb92d14SAndroid Build Coastguard Worker uint16_t txDataLen = outputFrame.GetHeaderDataLen();
174*cfb92d14SAndroid Build Coastguard Worker
175*cfb92d14SAndroid Build Coastguard Worker // Frame transmission is successful if master indicates
176*cfb92d14SAndroid Build Coastguard Worker // in the input frame that it could accept the frame
177*cfb92d14SAndroid Build Coastguard Worker // length that was exchanged, i.e., the "data len" in
178*cfb92d14SAndroid Build Coastguard Worker // the output frame is smaller than or equal to "accept
179*cfb92d14SAndroid Build Coastguard Worker // len" in the received input frame from master.
180*cfb92d14SAndroid Build Coastguard Worker
181*cfb92d14SAndroid Build Coastguard Worker if ((txDataLen > 0) && (txDataLen <= transDataLen) && (txDataLen <= inputFrame.GetHeaderAcceptLen()))
182*cfb92d14SAndroid Build Coastguard Worker {
183*cfb92d14SAndroid Build Coastguard Worker mTxState = kTxStateHandlingSendDone;
184*cfb92d14SAndroid Build Coastguard Worker shouldProcess = true;
185*cfb92d14SAndroid Build Coastguard Worker }
186*cfb92d14SAndroid Build Coastguard Worker }
187*cfb92d14SAndroid Build Coastguard Worker
188*cfb92d14SAndroid Build Coastguard Worker exit:
189*cfb92d14SAndroid Build Coastguard Worker // Determine the input and output frames to prepare a new transaction.
190*cfb92d14SAndroid Build Coastguard Worker
191*cfb92d14SAndroid Build Coastguard Worker if (mResetFlag && (aTransLen > 0) && (aOutputLen > 0))
192*cfb92d14SAndroid Build Coastguard Worker {
193*cfb92d14SAndroid Build Coastguard Worker mResetFlag = false;
194*cfb92d14SAndroid Build Coastguard Worker sendFrame.SetHeaderFlagByte(/*aResetFlag */ false);
195*cfb92d14SAndroid Build Coastguard Worker SpiFrame(mEmptySendFrameFullAccept).SetHeaderFlagByte(/*aResetFlag */ false);
196*cfb92d14SAndroid Build Coastguard Worker SpiFrame(mEmptySendFrameZeroAccept).SetHeaderFlagByte(/*aResetFlag */ false);
197*cfb92d14SAndroid Build Coastguard Worker }
198*cfb92d14SAndroid Build Coastguard Worker
199*cfb92d14SAndroid Build Coastguard Worker if (mTxState == kTxStateSending)
200*cfb92d14SAndroid Build Coastguard Worker {
201*cfb92d14SAndroid Build Coastguard Worker aOutputBuf = mSendFrame;
202*cfb92d14SAndroid Build Coastguard Worker aOutputLen = mSendFrameLength;
203*cfb92d14SAndroid Build Coastguard Worker }
204*cfb92d14SAndroid Build Coastguard Worker else
205*cfb92d14SAndroid Build Coastguard Worker {
206*cfb92d14SAndroid Build Coastguard Worker aOutputBuf = mHandlingRxFrame ? mEmptySendFrameZeroAccept : mEmptySendFrameFullAccept;
207*cfb92d14SAndroid Build Coastguard Worker aOutputLen = kSpiHeaderSize;
208*cfb92d14SAndroid Build Coastguard Worker }
209*cfb92d14SAndroid Build Coastguard Worker
210*cfb92d14SAndroid Build Coastguard Worker if (mHandlingRxFrame)
211*cfb92d14SAndroid Build Coastguard Worker {
212*cfb92d14SAndroid Build Coastguard Worker aInputBuf = mEmptyReceiveFrame;
213*cfb92d14SAndroid Build Coastguard Worker aInputLen = kSpiHeaderSize;
214*cfb92d14SAndroid Build Coastguard Worker }
215*cfb92d14SAndroid Build Coastguard Worker else
216*cfb92d14SAndroid Build Coastguard Worker {
217*cfb92d14SAndroid Build Coastguard Worker aInputBuf = mReceiveFrame;
218*cfb92d14SAndroid Build Coastguard Worker aInputLen = kSpiBufferSize;
219*cfb92d14SAndroid Build Coastguard Worker }
220*cfb92d14SAndroid Build Coastguard Worker
221*cfb92d14SAndroid Build Coastguard Worker sendFrame.SetHeaderAcceptLen(aInputLen - kSpiHeaderSize);
222*cfb92d14SAndroid Build Coastguard Worker
223*cfb92d14SAndroid Build Coastguard Worker IgnoreError(
224*cfb92d14SAndroid Build Coastguard Worker otPlatSpiSlavePrepareTransaction(aOutputBuf, aOutputLen, aInputBuf, aInputLen, (mTxState == kTxStateSending)));
225*cfb92d14SAndroid Build Coastguard Worker
226*cfb92d14SAndroid Build Coastguard Worker return shouldProcess;
227*cfb92d14SAndroid Build Coastguard Worker }
228*cfb92d14SAndroid Build Coastguard Worker
SpiTransactionProcess(void * aContext)229*cfb92d14SAndroid Build Coastguard Worker void NcpSpi::SpiTransactionProcess(void *aContext) { reinterpret_cast<NcpSpi *>(aContext)->SpiTransactionProcess(); }
230*cfb92d14SAndroid Build Coastguard Worker
SpiTransactionProcess(void)231*cfb92d14SAndroid Build Coastguard Worker void NcpSpi::SpiTransactionProcess(void)
232*cfb92d14SAndroid Build Coastguard Worker {
233*cfb92d14SAndroid Build Coastguard Worker if (mTxState == kTxStateHandlingSendDone)
234*cfb92d14SAndroid Build Coastguard Worker {
235*cfb92d14SAndroid Build Coastguard Worker mPrepareTxFrameTask.Post();
236*cfb92d14SAndroid Build Coastguard Worker }
237*cfb92d14SAndroid Build Coastguard Worker
238*cfb92d14SAndroid Build Coastguard Worker if (mHandlingRxFrame)
239*cfb92d14SAndroid Build Coastguard Worker {
240*cfb92d14SAndroid Build Coastguard Worker HandleRxFrame();
241*cfb92d14SAndroid Build Coastguard Worker }
242*cfb92d14SAndroid Build Coastguard Worker }
243*cfb92d14SAndroid Build Coastguard Worker
HandleFrameAddedToTxBuffer(void * aContext,Spinel::Buffer::FrameTag aTag,Spinel::Buffer::Priority aPriority,Spinel::Buffer * aBuffer)244*cfb92d14SAndroid Build Coastguard Worker void NcpSpi::HandleFrameAddedToTxBuffer(void *aContext,
245*cfb92d14SAndroid Build Coastguard Worker Spinel::Buffer::FrameTag aTag,
246*cfb92d14SAndroid Build Coastguard Worker Spinel::Buffer::Priority aPriority,
247*cfb92d14SAndroid Build Coastguard Worker Spinel::Buffer *aBuffer)
248*cfb92d14SAndroid Build Coastguard Worker {
249*cfb92d14SAndroid Build Coastguard Worker OT_UNUSED_VARIABLE(aBuffer);
250*cfb92d14SAndroid Build Coastguard Worker OT_UNUSED_VARIABLE(aTag);
251*cfb92d14SAndroid Build Coastguard Worker OT_UNUSED_VARIABLE(aPriority);
252*cfb92d14SAndroid Build Coastguard Worker
253*cfb92d14SAndroid Build Coastguard Worker static_cast<NcpSpi *>(aContext)->mPrepareTxFrameTask.Post();
254*cfb92d14SAndroid Build Coastguard Worker }
255*cfb92d14SAndroid Build Coastguard Worker
PrepareNextSpiSendFrame(void)256*cfb92d14SAndroid Build Coastguard Worker void NcpSpi::PrepareNextSpiSendFrame(void)
257*cfb92d14SAndroid Build Coastguard Worker {
258*cfb92d14SAndroid Build Coastguard Worker otError error = OT_ERROR_NONE;
259*cfb92d14SAndroid Build Coastguard Worker uint16_t frameLength;
260*cfb92d14SAndroid Build Coastguard Worker uint16_t readLength;
261*cfb92d14SAndroid Build Coastguard Worker SpiFrame sendFrame(mSendFrame);
262*cfb92d14SAndroid Build Coastguard Worker
263*cfb92d14SAndroid Build Coastguard Worker VerifyOrExit(!mTxFrameBuffer.IsEmpty());
264*cfb92d14SAndroid Build Coastguard Worker
265*cfb92d14SAndroid Build Coastguard Worker if (ShouldWakeHost())
266*cfb92d14SAndroid Build Coastguard Worker {
267*cfb92d14SAndroid Build Coastguard Worker otPlatWakeHost();
268*cfb92d14SAndroid Build Coastguard Worker }
269*cfb92d14SAndroid Build Coastguard Worker
270*cfb92d14SAndroid Build Coastguard Worker SuccessOrExit(error = mTxFrameBuffer.OutFrameBegin());
271*cfb92d14SAndroid Build Coastguard Worker
272*cfb92d14SAndroid Build Coastguard Worker frameLength = mTxFrameBuffer.OutFrameGetLength();
273*cfb92d14SAndroid Build Coastguard Worker OT_ASSERT(frameLength <= kSpiBufferSize - kSpiHeaderSize);
274*cfb92d14SAndroid Build Coastguard Worker
275*cfb92d14SAndroid Build Coastguard Worker // The "accept length" in `mSendFrame` is already updated based
276*cfb92d14SAndroid Build Coastguard Worker // on current state of receive. It is changed either from the
277*cfb92d14SAndroid Build Coastguard Worker // `SpiTransactionComplete()` callback or from `HandleRxFrame()`.
278*cfb92d14SAndroid Build Coastguard Worker
279*cfb92d14SAndroid Build Coastguard Worker readLength = mTxFrameBuffer.OutFrameRead(frameLength, sendFrame.GetData());
280*cfb92d14SAndroid Build Coastguard Worker OT_ASSERT(readLength == frameLength);
281*cfb92d14SAndroid Build Coastguard Worker
282*cfb92d14SAndroid Build Coastguard Worker // Suppress the warning when assertions are disabled
283*cfb92d14SAndroid Build Coastguard Worker OT_UNUSED_VARIABLE(readLength);
284*cfb92d14SAndroid Build Coastguard Worker
285*cfb92d14SAndroid Build Coastguard Worker sendFrame.SetHeaderDataLen(frameLength);
286*cfb92d14SAndroid Build Coastguard Worker mSendFrameLength = frameLength + kSpiHeaderSize;
287*cfb92d14SAndroid Build Coastguard Worker
288*cfb92d14SAndroid Build Coastguard Worker mTxState = kTxStateSending;
289*cfb92d14SAndroid Build Coastguard Worker
290*cfb92d14SAndroid Build Coastguard Worker // Prepare new transaction by using `mSendFrame` as the output
291*cfb92d14SAndroid Build Coastguard Worker // frame while keeping the input frame unchanged.
292*cfb92d14SAndroid Build Coastguard Worker
293*cfb92d14SAndroid Build Coastguard Worker error = otPlatSpiSlavePrepareTransaction(mSendFrame, mSendFrameLength, nullptr, 0, /* aRequestTrans */ true);
294*cfb92d14SAndroid Build Coastguard Worker
295*cfb92d14SAndroid Build Coastguard Worker if (error == OT_ERROR_BUSY)
296*cfb92d14SAndroid Build Coastguard Worker {
297*cfb92d14SAndroid Build Coastguard Worker // Being busy is OK. We will get the transaction set up
298*cfb92d14SAndroid Build Coastguard Worker // properly when the current transaction is completed.
299*cfb92d14SAndroid Build Coastguard Worker error = OT_ERROR_NONE;
300*cfb92d14SAndroid Build Coastguard Worker }
301*cfb92d14SAndroid Build Coastguard Worker
302*cfb92d14SAndroid Build Coastguard Worker if (error != OT_ERROR_NONE)
303*cfb92d14SAndroid Build Coastguard Worker {
304*cfb92d14SAndroid Build Coastguard Worker mTxState = kTxStateIdle;
305*cfb92d14SAndroid Build Coastguard Worker mPrepareTxFrameTask.Post();
306*cfb92d14SAndroid Build Coastguard Worker ExitNow();
307*cfb92d14SAndroid Build Coastguard Worker }
308*cfb92d14SAndroid Build Coastguard Worker
309*cfb92d14SAndroid Build Coastguard Worker IgnoreError(mTxFrameBuffer.OutFrameRemove());
310*cfb92d14SAndroid Build Coastguard Worker
311*cfb92d14SAndroid Build Coastguard Worker exit:
312*cfb92d14SAndroid Build Coastguard Worker return;
313*cfb92d14SAndroid Build Coastguard Worker }
314*cfb92d14SAndroid Build Coastguard Worker
PrepareTxFrame(Tasklet & aTasklet)315*cfb92d14SAndroid Build Coastguard Worker void NcpSpi::PrepareTxFrame(Tasklet &aTasklet)
316*cfb92d14SAndroid Build Coastguard Worker {
317*cfb92d14SAndroid Build Coastguard Worker OT_UNUSED_VARIABLE(aTasklet);
318*cfb92d14SAndroid Build Coastguard Worker static_cast<NcpSpi *>(GetNcpInstance())->PrepareTxFrame();
319*cfb92d14SAndroid Build Coastguard Worker }
320*cfb92d14SAndroid Build Coastguard Worker
PrepareTxFrame(void)321*cfb92d14SAndroid Build Coastguard Worker void NcpSpi::PrepareTxFrame(void)
322*cfb92d14SAndroid Build Coastguard Worker {
323*cfb92d14SAndroid Build Coastguard Worker switch (mTxState)
324*cfb92d14SAndroid Build Coastguard Worker {
325*cfb92d14SAndroid Build Coastguard Worker case kTxStateHandlingSendDone:
326*cfb92d14SAndroid Build Coastguard Worker mTxState = kTxStateIdle;
327*cfb92d14SAndroid Build Coastguard Worker
328*cfb92d14SAndroid Build Coastguard Worker OT_FALL_THROUGH;
329*cfb92d14SAndroid Build Coastguard Worker // to next case to prepare the next frame (if any).
330*cfb92d14SAndroid Build Coastguard Worker
331*cfb92d14SAndroid Build Coastguard Worker case kTxStateIdle:
332*cfb92d14SAndroid Build Coastguard Worker PrepareNextSpiSendFrame();
333*cfb92d14SAndroid Build Coastguard Worker break;
334*cfb92d14SAndroid Build Coastguard Worker
335*cfb92d14SAndroid Build Coastguard Worker case kTxStateSending:
336*cfb92d14SAndroid Build Coastguard Worker // The next frame in queue (if any) will be prepared when the
337*cfb92d14SAndroid Build Coastguard Worker // current frame is successfully sent and this task is posted
338*cfb92d14SAndroid Build Coastguard Worker // again from the `SpiTransactionComplete()` callback.
339*cfb92d14SAndroid Build Coastguard Worker break;
340*cfb92d14SAndroid Build Coastguard Worker }
341*cfb92d14SAndroid Build Coastguard Worker }
342*cfb92d14SAndroid Build Coastguard Worker
HandleRxFrame(void)343*cfb92d14SAndroid Build Coastguard Worker void NcpSpi::HandleRxFrame(void)
344*cfb92d14SAndroid Build Coastguard Worker {
345*cfb92d14SAndroid Build Coastguard Worker SpiFrame recvFrame(mReceiveFrame);
346*cfb92d14SAndroid Build Coastguard Worker SpiFrame sendFrame(mSendFrame);
347*cfb92d14SAndroid Build Coastguard Worker
348*cfb92d14SAndroid Build Coastguard Worker // Pass the received frame to base class to process.
349*cfb92d14SAndroid Build Coastguard Worker HandleReceive(recvFrame.GetData(), recvFrame.GetHeaderDataLen());
350*cfb92d14SAndroid Build Coastguard Worker
351*cfb92d14SAndroid Build Coastguard Worker // The order of operations below is important. We should clear
352*cfb92d14SAndroid Build Coastguard Worker // the `mHandlingRxFrame` before checking `mTxState` and possibly
353*cfb92d14SAndroid Build Coastguard Worker // preparing the next transaction. Note that the callback
354*cfb92d14SAndroid Build Coastguard Worker // `SpiTransactionComplete()` can be invoked from ISR at any point.
355*cfb92d14SAndroid Build Coastguard Worker //
356*cfb92d14SAndroid Build Coastguard Worker // If we switch the order, we have the following race situation:
357*cfb92d14SAndroid Build Coastguard Worker // We check `mTxState` and it is in `kTxStateSending`, so we skip
358*cfb92d14SAndroid Build Coastguard Worker // preparing the transaction here. But before we set the
359*cfb92d14SAndroid Build Coastguard Worker // `mHandlingRxFrame` to `false`, the `SpiTransactionComplete()`
360*cfb92d14SAndroid Build Coastguard Worker // happens and prepares the next transaction and sets the accept
361*cfb92d14SAndroid Build Coastguard Worker // length to zero on `mSendFrame` (since it assumes we are still
362*cfb92d14SAndroid Build Coastguard Worker // handling the previous received frame).
363*cfb92d14SAndroid Build Coastguard Worker
364*cfb92d14SAndroid Build Coastguard Worker mHandlingRxFrame = false;
365*cfb92d14SAndroid Build Coastguard Worker
366*cfb92d14SAndroid Build Coastguard Worker // If tx state is in `kTxStateSending`, we wait for the callback
367*cfb92d14SAndroid Build Coastguard Worker // `SpiTransactionComplete()` which will then set up everything
368*cfb92d14SAndroid Build Coastguard Worker // and prepare the next transaction.
369*cfb92d14SAndroid Build Coastguard Worker
370*cfb92d14SAndroid Build Coastguard Worker if (mTxState != kTxStateSending)
371*cfb92d14SAndroid Build Coastguard Worker {
372*cfb92d14SAndroid Build Coastguard Worker sendFrame.SetHeaderAcceptLen(kSpiBufferSize - kSpiHeaderSize);
373*cfb92d14SAndroid Build Coastguard Worker
374*cfb92d14SAndroid Build Coastguard Worker IgnoreError(otPlatSpiSlavePrepareTransaction(mEmptySendFrameFullAccept, kSpiHeaderSize, mReceiveFrame,
375*cfb92d14SAndroid Build Coastguard Worker kSpiBufferSize,
376*cfb92d14SAndroid Build Coastguard Worker /* aRequestTrans */ false));
377*cfb92d14SAndroid Build Coastguard Worker
378*cfb92d14SAndroid Build Coastguard Worker // No need to check the error status. Getting `OT_ERROR_BUSY`
379*cfb92d14SAndroid Build Coastguard Worker // is OK as everything will be set up properly from callback when
380*cfb92d14SAndroid Build Coastguard Worker // the current transaction is completed.
381*cfb92d14SAndroid Build Coastguard Worker }
382*cfb92d14SAndroid Build Coastguard Worker }
383*cfb92d14SAndroid Build Coastguard Worker
384*cfb92d14SAndroid Build Coastguard Worker } // namespace Ncp
385*cfb92d14SAndroid Build Coastguard Worker } // namespace ot
386*cfb92d14SAndroid Build Coastguard Worker
387*cfb92d14SAndroid Build Coastguard Worker #endif // OPENTHREAD_CONFIG_NCP_SPI_ENABLE
388