xref: /aosp_15_r20/external/openthread/src/lib/spinel/spinel_driver.cpp (revision cfb92d1480a9e65faed56933e9c12405f45898b4)
1*cfb92d14SAndroid Build Coastguard Worker /*
2*cfb92d14SAndroid Build Coastguard Worker  *  Copyright (c) 2024, 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"
17*cfb92d14SAndroid Build Coastguard Worker  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18*cfb92d14SAndroid Build Coastguard Worker  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19*cfb92d14SAndroid Build Coastguard Worker  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20*cfb92d14SAndroid Build Coastguard Worker  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21*cfb92d14SAndroid Build Coastguard Worker  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22*cfb92d14SAndroid Build Coastguard Worker  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23*cfb92d14SAndroid Build Coastguard Worker  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24*cfb92d14SAndroid Build Coastguard Worker  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25*cfb92d14SAndroid Build Coastguard Worker  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26*cfb92d14SAndroid Build Coastguard Worker  *  POSSIBILITY OF SUCH DAMAGE.
27*cfb92d14SAndroid Build Coastguard Worker  */
28*cfb92d14SAndroid Build Coastguard Worker 
29*cfb92d14SAndroid Build Coastguard Worker #include "spinel_driver.hpp"
30*cfb92d14SAndroid Build Coastguard Worker 
31*cfb92d14SAndroid Build Coastguard Worker #include <assert.h>
32*cfb92d14SAndroid Build Coastguard Worker 
33*cfb92d14SAndroid Build Coastguard Worker #include <openthread/platform/time.h>
34*cfb92d14SAndroid Build Coastguard Worker 
35*cfb92d14SAndroid Build Coastguard Worker #include "lib/platform/exit_code.h"
36*cfb92d14SAndroid Build Coastguard Worker #include "lib/spinel/spinel.h"
37*cfb92d14SAndroid Build Coastguard Worker #include "lib/utils/math.hpp"
38*cfb92d14SAndroid Build Coastguard Worker #include "lib/utils/utils.hpp"
39*cfb92d14SAndroid Build Coastguard Worker 
40*cfb92d14SAndroid Build Coastguard Worker namespace ot {
41*cfb92d14SAndroid Build Coastguard Worker namespace Spinel {
42*cfb92d14SAndroid Build Coastguard Worker 
43*cfb92d14SAndroid Build Coastguard Worker constexpr spinel_tid_t sTid = 1; ///< In Spinel Driver, only use Tid as 1.
44*cfb92d14SAndroid Build Coastguard Worker 
SpinelDriver(void)45*cfb92d14SAndroid Build Coastguard Worker SpinelDriver::SpinelDriver(void)
46*cfb92d14SAndroid Build Coastguard Worker     : Logger("SpinelDriver")
47*cfb92d14SAndroid Build Coastguard Worker     , mSpinelInterface(nullptr)
48*cfb92d14SAndroid Build Coastguard Worker     , mWaitingKey(SPINEL_PROP_LAST_STATUS)
49*cfb92d14SAndroid Build Coastguard Worker     , mIsWaitingForResponse(false)
50*cfb92d14SAndroid Build Coastguard Worker     , mIid(SPINEL_HEADER_INVALID_IID)
51*cfb92d14SAndroid Build Coastguard Worker     , mSpinelVersionMajor(-1)
52*cfb92d14SAndroid Build Coastguard Worker     , mSpinelVersionMinor(-1)
53*cfb92d14SAndroid Build Coastguard Worker     , mIsCoprocessorReady(false)
54*cfb92d14SAndroid Build Coastguard Worker {
55*cfb92d14SAndroid Build Coastguard Worker     memset(mVersion, 0, sizeof(mVersion));
56*cfb92d14SAndroid Build Coastguard Worker 
57*cfb92d14SAndroid Build Coastguard Worker     mReceivedFrameHandler = &HandleInitialFrame;
58*cfb92d14SAndroid Build Coastguard Worker     mFrameHandlerContext  = this;
59*cfb92d14SAndroid Build Coastguard Worker }
60*cfb92d14SAndroid Build Coastguard Worker 
Init(SpinelInterface & aSpinelInterface,bool aSoftwareReset,const spinel_iid_t * aIidList,uint8_t aIidListLength)61*cfb92d14SAndroid Build Coastguard Worker CoprocessorType SpinelDriver::Init(SpinelInterface    &aSpinelInterface,
62*cfb92d14SAndroid Build Coastguard Worker                                    bool                aSoftwareReset,
63*cfb92d14SAndroid Build Coastguard Worker                                    const spinel_iid_t *aIidList,
64*cfb92d14SAndroid Build Coastguard Worker                                    uint8_t             aIidListLength)
65*cfb92d14SAndroid Build Coastguard Worker {
66*cfb92d14SAndroid Build Coastguard Worker     CoprocessorType coprocessorType;
67*cfb92d14SAndroid Build Coastguard Worker 
68*cfb92d14SAndroid Build Coastguard Worker     mSpinelInterface = &aSpinelInterface;
69*cfb92d14SAndroid Build Coastguard Worker     mRxFrameBuffer.Clear();
70*cfb92d14SAndroid Build Coastguard Worker     SuccessOrDie(mSpinelInterface->Init(HandleReceivedFrame, this, mRxFrameBuffer));
71*cfb92d14SAndroid Build Coastguard Worker 
72*cfb92d14SAndroid Build Coastguard Worker     VerifyOrDie(aIidList != nullptr, OT_EXIT_INVALID_ARGUMENTS);
73*cfb92d14SAndroid Build Coastguard Worker     VerifyOrDie(aIidListLength != 0 && aIidListLength <= mIidList.GetMaxSize(), OT_EXIT_INVALID_ARGUMENTS);
74*cfb92d14SAndroid Build Coastguard Worker 
75*cfb92d14SAndroid Build Coastguard Worker     for (uint8_t i = 0; i < aIidListLength; i++)
76*cfb92d14SAndroid Build Coastguard Worker     {
77*cfb92d14SAndroid Build Coastguard Worker         SuccessOrDie(mIidList.PushBack(aIidList[i]));
78*cfb92d14SAndroid Build Coastguard Worker     }
79*cfb92d14SAndroid Build Coastguard Worker     mIid = aIidList[0];
80*cfb92d14SAndroid Build Coastguard Worker 
81*cfb92d14SAndroid Build Coastguard Worker     ResetCoprocessor(aSoftwareReset);
82*cfb92d14SAndroid Build Coastguard Worker     SuccessOrDie(CheckSpinelVersion());
83*cfb92d14SAndroid Build Coastguard Worker     SuccessOrDie(GetCoprocessorVersion());
84*cfb92d14SAndroid Build Coastguard Worker     SuccessOrDie(GetCoprocessorCaps());
85*cfb92d14SAndroid Build Coastguard Worker 
86*cfb92d14SAndroid Build Coastguard Worker     coprocessorType = GetCoprocessorType();
87*cfb92d14SAndroid Build Coastguard Worker     if (coprocessorType == OT_COPROCESSOR_UNKNOWN)
88*cfb92d14SAndroid Build Coastguard Worker     {
89*cfb92d14SAndroid Build Coastguard Worker         LogCrit("The coprocessor mode is unknown!");
90*cfb92d14SAndroid Build Coastguard Worker         DieNow(OT_EXIT_FAILURE);
91*cfb92d14SAndroid Build Coastguard Worker     }
92*cfb92d14SAndroid Build Coastguard Worker 
93*cfb92d14SAndroid Build Coastguard Worker     return coprocessorType;
94*cfb92d14SAndroid Build Coastguard Worker }
95*cfb92d14SAndroid Build Coastguard Worker 
Deinit(void)96*cfb92d14SAndroid Build Coastguard Worker void SpinelDriver::Deinit(void)
97*cfb92d14SAndroid Build Coastguard Worker {
98*cfb92d14SAndroid Build Coastguard Worker     // This allows implementing pseudo reset.
99*cfb92d14SAndroid Build Coastguard Worker     new (this) SpinelDriver();
100*cfb92d14SAndroid Build Coastguard Worker }
101*cfb92d14SAndroid Build Coastguard Worker 
SendReset(uint8_t aResetType)102*cfb92d14SAndroid Build Coastguard Worker otError SpinelDriver::SendReset(uint8_t aResetType)
103*cfb92d14SAndroid Build Coastguard Worker {
104*cfb92d14SAndroid Build Coastguard Worker     otError        error = OT_ERROR_NONE;
105*cfb92d14SAndroid Build Coastguard Worker     uint8_t        buffer[kMaxSpinelFrame];
106*cfb92d14SAndroid Build Coastguard Worker     spinel_ssize_t packed;
107*cfb92d14SAndroid Build Coastguard Worker 
108*cfb92d14SAndroid Build Coastguard Worker     // Pack the header, command and key
109*cfb92d14SAndroid Build Coastguard Worker     packed = spinel_datatype_pack(buffer, sizeof(buffer), SPINEL_DATATYPE_COMMAND_S SPINEL_DATATYPE_UINT8_S,
110*cfb92d14SAndroid Build Coastguard Worker                                   SPINEL_HEADER_FLAG | SPINEL_HEADER_IID(mIid), SPINEL_CMD_RESET, aResetType);
111*cfb92d14SAndroid Build Coastguard Worker 
112*cfb92d14SAndroid Build Coastguard Worker     EXPECT(packed > 0 && static_cast<size_t>(packed) <= sizeof(buffer), error = OT_ERROR_NO_BUFS);
113*cfb92d14SAndroid Build Coastguard Worker 
114*cfb92d14SAndroid Build Coastguard Worker     EXPECT_NO_ERROR(error = mSpinelInterface->SendFrame(buffer, static_cast<uint16_t>(packed)));
115*cfb92d14SAndroid Build Coastguard Worker     LogSpinelFrame(buffer, static_cast<uint16_t>(packed), true /* aTx */);
116*cfb92d14SAndroid Build Coastguard Worker 
117*cfb92d14SAndroid Build Coastguard Worker exit:
118*cfb92d14SAndroid Build Coastguard Worker     return error;
119*cfb92d14SAndroid Build Coastguard Worker }
120*cfb92d14SAndroid Build Coastguard Worker 
ResetCoprocessor(bool aSoftwareReset)121*cfb92d14SAndroid Build Coastguard Worker void SpinelDriver::ResetCoprocessor(bool aSoftwareReset)
122*cfb92d14SAndroid Build Coastguard Worker {
123*cfb92d14SAndroid Build Coastguard Worker     bool hardwareReset;
124*cfb92d14SAndroid Build Coastguard Worker     bool resetDone = false;
125*cfb92d14SAndroid Build Coastguard Worker 
126*cfb92d14SAndroid Build Coastguard Worker     // Avoid resetting the device twice in a row in Multipan RCP architecture
127*cfb92d14SAndroid Build Coastguard Worker     EXPECT(!mIsCoprocessorReady, resetDone = true);
128*cfb92d14SAndroid Build Coastguard Worker 
129*cfb92d14SAndroid Build Coastguard Worker     mWaitingKey = SPINEL_PROP_LAST_STATUS;
130*cfb92d14SAndroid Build Coastguard Worker 
131*cfb92d14SAndroid Build Coastguard Worker     if (aSoftwareReset && (SendReset(SPINEL_RESET_STACK) == OT_ERROR_NONE) && (WaitResponse() == OT_ERROR_NONE))
132*cfb92d14SAndroid Build Coastguard Worker     {
133*cfb92d14SAndroid Build Coastguard Worker         EXPECT(mIsCoprocessorReady, resetDone = false);
134*cfb92d14SAndroid Build Coastguard Worker         LogCrit("Software reset co-processor successfully");
135*cfb92d14SAndroid Build Coastguard Worker         EXIT_NOW(resetDone = true);
136*cfb92d14SAndroid Build Coastguard Worker     }
137*cfb92d14SAndroid Build Coastguard Worker 
138*cfb92d14SAndroid Build Coastguard Worker     hardwareReset = (mSpinelInterface->HardwareReset() == OT_ERROR_NONE);
139*cfb92d14SAndroid Build Coastguard Worker 
140*cfb92d14SAndroid Build Coastguard Worker     if (hardwareReset)
141*cfb92d14SAndroid Build Coastguard Worker     {
142*cfb92d14SAndroid Build Coastguard Worker         EXPECT_NO_ERROR(WaitResponse());
143*cfb92d14SAndroid Build Coastguard Worker     }
144*cfb92d14SAndroid Build Coastguard Worker 
145*cfb92d14SAndroid Build Coastguard Worker     resetDone = true;
146*cfb92d14SAndroid Build Coastguard Worker 
147*cfb92d14SAndroid Build Coastguard Worker     if (hardwareReset)
148*cfb92d14SAndroid Build Coastguard Worker     {
149*cfb92d14SAndroid Build Coastguard Worker         LogInfo("Hardware reset co-processor successfully");
150*cfb92d14SAndroid Build Coastguard Worker     }
151*cfb92d14SAndroid Build Coastguard Worker     else
152*cfb92d14SAndroid Build Coastguard Worker     {
153*cfb92d14SAndroid Build Coastguard Worker         LogInfo("co-processor self reset successfully");
154*cfb92d14SAndroid Build Coastguard Worker     }
155*cfb92d14SAndroid Build Coastguard Worker 
156*cfb92d14SAndroid Build Coastguard Worker exit:
157*cfb92d14SAndroid Build Coastguard Worker     if (!resetDone)
158*cfb92d14SAndroid Build Coastguard Worker     {
159*cfb92d14SAndroid Build Coastguard Worker         LogCrit("Failed to reset co-processor!");
160*cfb92d14SAndroid Build Coastguard Worker         DieNow(OT_EXIT_FAILURE);
161*cfb92d14SAndroid Build Coastguard Worker     }
162*cfb92d14SAndroid Build Coastguard Worker }
163*cfb92d14SAndroid Build Coastguard Worker 
Process(const void * aContext)164*cfb92d14SAndroid Build Coastguard Worker void SpinelDriver::Process(const void *aContext)
165*cfb92d14SAndroid Build Coastguard Worker {
166*cfb92d14SAndroid Build Coastguard Worker     if (mRxFrameBuffer.HasSavedFrame())
167*cfb92d14SAndroid Build Coastguard Worker     {
168*cfb92d14SAndroid Build Coastguard Worker         ProcessFrameQueue();
169*cfb92d14SAndroid Build Coastguard Worker     }
170*cfb92d14SAndroid Build Coastguard Worker 
171*cfb92d14SAndroid Build Coastguard Worker     mSpinelInterface->Process(aContext);
172*cfb92d14SAndroid Build Coastguard Worker 
173*cfb92d14SAndroid Build Coastguard Worker     if (mRxFrameBuffer.HasSavedFrame())
174*cfb92d14SAndroid Build Coastguard Worker     {
175*cfb92d14SAndroid Build Coastguard Worker         ProcessFrameQueue();
176*cfb92d14SAndroid Build Coastguard Worker     }
177*cfb92d14SAndroid Build Coastguard Worker }
178*cfb92d14SAndroid Build Coastguard Worker 
SendCommand(uint32_t aCommand,spinel_prop_key_t aKey,spinel_tid_t aTid)179*cfb92d14SAndroid Build Coastguard Worker otError SpinelDriver::SendCommand(uint32_t aCommand, spinel_prop_key_t aKey, spinel_tid_t aTid)
180*cfb92d14SAndroid Build Coastguard Worker {
181*cfb92d14SAndroid Build Coastguard Worker     otError        error = OT_ERROR_NONE;
182*cfb92d14SAndroid Build Coastguard Worker     uint8_t        buffer[kMaxSpinelFrame];
183*cfb92d14SAndroid Build Coastguard Worker     spinel_ssize_t packed;
184*cfb92d14SAndroid Build Coastguard Worker     uint16_t       offset;
185*cfb92d14SAndroid Build Coastguard Worker 
186*cfb92d14SAndroid Build Coastguard Worker     // Pack the header, command and key
187*cfb92d14SAndroid Build Coastguard Worker     packed = spinel_datatype_pack(buffer, sizeof(buffer), "Cii", SPINEL_HEADER_FLAG | SPINEL_HEADER_IID(mIid) | aTid,
188*cfb92d14SAndroid Build Coastguard Worker                                   aCommand, aKey);
189*cfb92d14SAndroid Build Coastguard Worker 
190*cfb92d14SAndroid Build Coastguard Worker     EXPECT(packed > 0 && static_cast<size_t>(packed) <= sizeof(buffer), error = OT_ERROR_NO_BUFS);
191*cfb92d14SAndroid Build Coastguard Worker 
192*cfb92d14SAndroid Build Coastguard Worker     offset = static_cast<uint16_t>(packed);
193*cfb92d14SAndroid Build Coastguard Worker 
194*cfb92d14SAndroid Build Coastguard Worker     EXPECT_NO_ERROR(error = mSpinelInterface->SendFrame(buffer, offset));
195*cfb92d14SAndroid Build Coastguard Worker     LogSpinelFrame(buffer, offset, true /* aTx */);
196*cfb92d14SAndroid Build Coastguard Worker 
197*cfb92d14SAndroid Build Coastguard Worker exit:
198*cfb92d14SAndroid Build Coastguard Worker     return error;
199*cfb92d14SAndroid Build Coastguard Worker }
200*cfb92d14SAndroid Build Coastguard Worker 
SendCommand(uint32_t aCommand,spinel_prop_key_t aKey,spinel_tid_t aTid,const char * aFormat,va_list aArgs)201*cfb92d14SAndroid Build Coastguard Worker otError SpinelDriver::SendCommand(uint32_t          aCommand,
202*cfb92d14SAndroid Build Coastguard Worker                                   spinel_prop_key_t aKey,
203*cfb92d14SAndroid Build Coastguard Worker                                   spinel_tid_t      aTid,
204*cfb92d14SAndroid Build Coastguard Worker                                   const char       *aFormat,
205*cfb92d14SAndroid Build Coastguard Worker                                   va_list           aArgs)
206*cfb92d14SAndroid Build Coastguard Worker {
207*cfb92d14SAndroid Build Coastguard Worker     otError        error = OT_ERROR_NONE;
208*cfb92d14SAndroid Build Coastguard Worker     uint8_t        buffer[kMaxSpinelFrame];
209*cfb92d14SAndroid Build Coastguard Worker     spinel_ssize_t packed;
210*cfb92d14SAndroid Build Coastguard Worker     uint16_t       offset;
211*cfb92d14SAndroid Build Coastguard Worker 
212*cfb92d14SAndroid Build Coastguard Worker     // Pack the header, command and key
213*cfb92d14SAndroid Build Coastguard Worker     packed = spinel_datatype_pack(buffer, sizeof(buffer), "Cii", SPINEL_HEADER_FLAG | SPINEL_HEADER_IID(mIid) | aTid,
214*cfb92d14SAndroid Build Coastguard Worker                                   aCommand, aKey);
215*cfb92d14SAndroid Build Coastguard Worker 
216*cfb92d14SAndroid Build Coastguard Worker     EXPECT(packed > 0 && static_cast<size_t>(packed) <= sizeof(buffer), error = OT_ERROR_NO_BUFS);
217*cfb92d14SAndroid Build Coastguard Worker 
218*cfb92d14SAndroid Build Coastguard Worker     offset = static_cast<uint16_t>(packed);
219*cfb92d14SAndroid Build Coastguard Worker 
220*cfb92d14SAndroid Build Coastguard Worker     // Pack the data (if any)
221*cfb92d14SAndroid Build Coastguard Worker     if (aFormat)
222*cfb92d14SAndroid Build Coastguard Worker     {
223*cfb92d14SAndroid Build Coastguard Worker         packed = spinel_datatype_vpack(buffer + offset, sizeof(buffer) - offset, aFormat, aArgs);
224*cfb92d14SAndroid Build Coastguard Worker         EXPECT(packed > 0 && static_cast<size_t>(packed + offset) <= sizeof(buffer), error = OT_ERROR_NO_BUFS);
225*cfb92d14SAndroid Build Coastguard Worker 
226*cfb92d14SAndroid Build Coastguard Worker         offset += static_cast<uint16_t>(packed);
227*cfb92d14SAndroid Build Coastguard Worker     }
228*cfb92d14SAndroid Build Coastguard Worker 
229*cfb92d14SAndroid Build Coastguard Worker     EXPECT_NO_ERROR(error = mSpinelInterface->SendFrame(buffer, offset));
230*cfb92d14SAndroid Build Coastguard Worker     LogSpinelFrame(buffer, offset, true /* aTx */);
231*cfb92d14SAndroid Build Coastguard Worker 
232*cfb92d14SAndroid Build Coastguard Worker exit:
233*cfb92d14SAndroid Build Coastguard Worker     return error;
234*cfb92d14SAndroid Build Coastguard Worker }
235*cfb92d14SAndroid Build Coastguard Worker 
SetFrameHandler(ReceivedFrameHandler aReceivedFrameHandler,SavedFrameHandler aSavedFrameHandler,void * aContext)236*cfb92d14SAndroid Build Coastguard Worker void SpinelDriver::SetFrameHandler(ReceivedFrameHandler aReceivedFrameHandler,
237*cfb92d14SAndroid Build Coastguard Worker                                    SavedFrameHandler    aSavedFrameHandler,
238*cfb92d14SAndroid Build Coastguard Worker                                    void                *aContext)
239*cfb92d14SAndroid Build Coastguard Worker {
240*cfb92d14SAndroid Build Coastguard Worker     mReceivedFrameHandler = aReceivedFrameHandler;
241*cfb92d14SAndroid Build Coastguard Worker     mSavedFrameHandler    = aSavedFrameHandler;
242*cfb92d14SAndroid Build Coastguard Worker     mFrameHandlerContext  = aContext;
243*cfb92d14SAndroid Build Coastguard Worker }
244*cfb92d14SAndroid Build Coastguard Worker 
WaitResponse(void)245*cfb92d14SAndroid Build Coastguard Worker otError SpinelDriver::WaitResponse(void)
246*cfb92d14SAndroid Build Coastguard Worker {
247*cfb92d14SAndroid Build Coastguard Worker     otError  error = OT_ERROR_NONE;
248*cfb92d14SAndroid Build Coastguard Worker     uint64_t end   = otPlatTimeGet() + kMaxWaitTime * kUsPerMs;
249*cfb92d14SAndroid Build Coastguard Worker 
250*cfb92d14SAndroid Build Coastguard Worker     LogDebg("Waiting response: key=%lu", Lib::Utils::ToUlong(mWaitingKey));
251*cfb92d14SAndroid Build Coastguard Worker 
252*cfb92d14SAndroid Build Coastguard Worker     do
253*cfb92d14SAndroid Build Coastguard Worker     {
254*cfb92d14SAndroid Build Coastguard Worker         uint64_t now = otPlatTimeGet();
255*cfb92d14SAndroid Build Coastguard Worker 
256*cfb92d14SAndroid Build Coastguard Worker         if ((end <= now) || (mSpinelInterface->WaitForFrame(end - now) != OT_ERROR_NONE))
257*cfb92d14SAndroid Build Coastguard Worker         {
258*cfb92d14SAndroid Build Coastguard Worker             LogWarn("Wait for response timeout");
259*cfb92d14SAndroid Build Coastguard Worker             EXIT_NOW(error = OT_ERROR_RESPONSE_TIMEOUT);
260*cfb92d14SAndroid Build Coastguard Worker         }
261*cfb92d14SAndroid Build Coastguard Worker     } while (mIsWaitingForResponse || !mIsCoprocessorReady);
262*cfb92d14SAndroid Build Coastguard Worker 
263*cfb92d14SAndroid Build Coastguard Worker     mWaitingKey = SPINEL_PROP_LAST_STATUS;
264*cfb92d14SAndroid Build Coastguard Worker 
265*cfb92d14SAndroid Build Coastguard Worker exit:
266*cfb92d14SAndroid Build Coastguard Worker     return error;
267*cfb92d14SAndroid Build Coastguard Worker }
268*cfb92d14SAndroid Build Coastguard Worker 
HandleReceivedFrame(void * aContext)269*cfb92d14SAndroid Build Coastguard Worker void SpinelDriver::HandleReceivedFrame(void *aContext) { static_cast<SpinelDriver *>(aContext)->HandleReceivedFrame(); }
270*cfb92d14SAndroid Build Coastguard Worker 
HandleReceivedFrame(void)271*cfb92d14SAndroid Build Coastguard Worker void SpinelDriver::HandleReceivedFrame(void)
272*cfb92d14SAndroid Build Coastguard Worker {
273*cfb92d14SAndroid Build Coastguard Worker     otError        error = OT_ERROR_NONE;
274*cfb92d14SAndroid Build Coastguard Worker     uint8_t        header;
275*cfb92d14SAndroid Build Coastguard Worker     spinel_ssize_t unpacked;
276*cfb92d14SAndroid Build Coastguard Worker     bool           shouldSave = true;
277*cfb92d14SAndroid Build Coastguard Worker     spinel_iid_t   iid;
278*cfb92d14SAndroid Build Coastguard Worker 
279*cfb92d14SAndroid Build Coastguard Worker     LogSpinelFrame(mRxFrameBuffer.GetFrame(), mRxFrameBuffer.GetLength(), false);
280*cfb92d14SAndroid Build Coastguard Worker     unpacked = spinel_datatype_unpack(mRxFrameBuffer.GetFrame(), mRxFrameBuffer.GetLength(), "C", &header);
281*cfb92d14SAndroid Build Coastguard Worker 
282*cfb92d14SAndroid Build Coastguard Worker     // Accept spinel messages with the correct IID or broadcast IID.
283*cfb92d14SAndroid Build Coastguard Worker     iid = SPINEL_HEADER_GET_IID(header);
284*cfb92d14SAndroid Build Coastguard Worker 
285*cfb92d14SAndroid Build Coastguard Worker     if (!mIidList.Contains(iid))
286*cfb92d14SAndroid Build Coastguard Worker     {
287*cfb92d14SAndroid Build Coastguard Worker         mRxFrameBuffer.DiscardFrame();
288*cfb92d14SAndroid Build Coastguard Worker         EXIT_NOW();
289*cfb92d14SAndroid Build Coastguard Worker     }
290*cfb92d14SAndroid Build Coastguard Worker 
291*cfb92d14SAndroid Build Coastguard Worker     EXPECT(unpacked > 0 && (header & SPINEL_HEADER_FLAG) == SPINEL_HEADER_FLAG, error = OT_ERROR_PARSE);
292*cfb92d14SAndroid Build Coastguard Worker 
293*cfb92d14SAndroid Build Coastguard Worker     assert(mReceivedFrameHandler != nullptr && mFrameHandlerContext != nullptr);
294*cfb92d14SAndroid Build Coastguard Worker     mReceivedFrameHandler(mRxFrameBuffer.GetFrame(), mRxFrameBuffer.GetLength(), header, shouldSave,
295*cfb92d14SAndroid Build Coastguard Worker                           mFrameHandlerContext);
296*cfb92d14SAndroid Build Coastguard Worker 
297*cfb92d14SAndroid Build Coastguard Worker     if (shouldSave)
298*cfb92d14SAndroid Build Coastguard Worker     {
299*cfb92d14SAndroid Build Coastguard Worker         error = mRxFrameBuffer.SaveFrame();
300*cfb92d14SAndroid Build Coastguard Worker     }
301*cfb92d14SAndroid Build Coastguard Worker     else
302*cfb92d14SAndroid Build Coastguard Worker     {
303*cfb92d14SAndroid Build Coastguard Worker         mRxFrameBuffer.DiscardFrame();
304*cfb92d14SAndroid Build Coastguard Worker     }
305*cfb92d14SAndroid Build Coastguard Worker 
306*cfb92d14SAndroid Build Coastguard Worker exit:
307*cfb92d14SAndroid Build Coastguard Worker     if (error != OT_ERROR_NONE)
308*cfb92d14SAndroid Build Coastguard Worker     {
309*cfb92d14SAndroid Build Coastguard Worker         mRxFrameBuffer.DiscardFrame();
310*cfb92d14SAndroid Build Coastguard Worker         LogWarn("Error handling spinel frame: %s", otThreadErrorToString(error));
311*cfb92d14SAndroid Build Coastguard Worker     }
312*cfb92d14SAndroid Build Coastguard Worker }
313*cfb92d14SAndroid Build Coastguard Worker 
HandleInitialFrame(const uint8_t * aFrame,uint16_t aLength,uint8_t aHeader,bool & aSave,void * aContext)314*cfb92d14SAndroid Build Coastguard Worker void SpinelDriver::HandleInitialFrame(const uint8_t *aFrame,
315*cfb92d14SAndroid Build Coastguard Worker                                       uint16_t       aLength,
316*cfb92d14SAndroid Build Coastguard Worker                                       uint8_t        aHeader,
317*cfb92d14SAndroid Build Coastguard Worker                                       bool          &aSave,
318*cfb92d14SAndroid Build Coastguard Worker                                       void          *aContext)
319*cfb92d14SAndroid Build Coastguard Worker {
320*cfb92d14SAndroid Build Coastguard Worker     static_cast<SpinelDriver *>(aContext)->HandleInitialFrame(aFrame, aLength, aHeader, aSave);
321*cfb92d14SAndroid Build Coastguard Worker }
322*cfb92d14SAndroid Build Coastguard Worker 
HandleInitialFrame(const uint8_t * aFrame,uint16_t aLength,uint8_t aHeader,bool & aSave)323*cfb92d14SAndroid Build Coastguard Worker void SpinelDriver::HandleInitialFrame(const uint8_t *aFrame, uint16_t aLength, uint8_t aHeader, bool &aSave)
324*cfb92d14SAndroid Build Coastguard Worker {
325*cfb92d14SAndroid Build Coastguard Worker     spinel_prop_key_t key;
326*cfb92d14SAndroid Build Coastguard Worker     uint8_t          *data   = nullptr;
327*cfb92d14SAndroid Build Coastguard Worker     spinel_size_t     len    = 0;
328*cfb92d14SAndroid Build Coastguard Worker     uint8_t           header = 0;
329*cfb92d14SAndroid Build Coastguard Worker     uint32_t          cmd    = 0;
330*cfb92d14SAndroid Build Coastguard Worker     spinel_ssize_t    rval   = 0;
331*cfb92d14SAndroid Build Coastguard Worker     spinel_ssize_t    unpacked;
332*cfb92d14SAndroid Build Coastguard Worker     otError           error = OT_ERROR_NONE;
333*cfb92d14SAndroid Build Coastguard Worker 
334*cfb92d14SAndroid Build Coastguard Worker     OT_UNUSED_VARIABLE(aHeader);
335*cfb92d14SAndroid Build Coastguard Worker 
336*cfb92d14SAndroid Build Coastguard Worker     rval = spinel_datatype_unpack(aFrame, aLength, "CiiD", &header, &cmd, &key, &data, &len);
337*cfb92d14SAndroid Build Coastguard Worker     EXPECT(rval > 0 && cmd >= SPINEL_CMD_PROP_VALUE_IS && cmd <= SPINEL_CMD_PROP_VALUE_REMOVED, error = OT_ERROR_PARSE);
338*cfb92d14SAndroid Build Coastguard Worker 
339*cfb92d14SAndroid Build Coastguard Worker     EXPECT(cmd == SPINEL_CMD_PROP_VALUE_IS, error = OT_ERROR_DROP);
340*cfb92d14SAndroid Build Coastguard Worker 
341*cfb92d14SAndroid Build Coastguard Worker     if (key == SPINEL_PROP_LAST_STATUS)
342*cfb92d14SAndroid Build Coastguard Worker     {
343*cfb92d14SAndroid Build Coastguard Worker         spinel_status_t status = SPINEL_STATUS_OK;
344*cfb92d14SAndroid Build Coastguard Worker 
345*cfb92d14SAndroid Build Coastguard Worker         unpacked = spinel_datatype_unpack(data, len, "i", &status);
346*cfb92d14SAndroid Build Coastguard Worker         EXPECT(unpacked > 0, error = OT_ERROR_PARSE);
347*cfb92d14SAndroid Build Coastguard Worker 
348*cfb92d14SAndroid Build Coastguard Worker         if (status >= SPINEL_STATUS_RESET__BEGIN && status <= SPINEL_STATUS_RESET__END)
349*cfb92d14SAndroid Build Coastguard Worker         {
350*cfb92d14SAndroid Build Coastguard Worker             // this clear is necessary in case the RCP has sent messages between disable and reset
351*cfb92d14SAndroid Build Coastguard Worker             mRxFrameBuffer.Clear();
352*cfb92d14SAndroid Build Coastguard Worker 
353*cfb92d14SAndroid Build Coastguard Worker             LogInfo("co-processor reset: %s", spinel_status_to_cstr(status));
354*cfb92d14SAndroid Build Coastguard Worker             mIsCoprocessorReady = true;
355*cfb92d14SAndroid Build Coastguard Worker         }
356*cfb92d14SAndroid Build Coastguard Worker         else
357*cfb92d14SAndroid Build Coastguard Worker         {
358*cfb92d14SAndroid Build Coastguard Worker             LogInfo("co-processor last status: %s", spinel_status_to_cstr(status));
359*cfb92d14SAndroid Build Coastguard Worker             EXIT_NOW();
360*cfb92d14SAndroid Build Coastguard Worker         }
361*cfb92d14SAndroid Build Coastguard Worker     }
362*cfb92d14SAndroid Build Coastguard Worker     else
363*cfb92d14SAndroid Build Coastguard Worker     {
364*cfb92d14SAndroid Build Coastguard Worker         // Drop other frames when the key isn't waiting key.
365*cfb92d14SAndroid Build Coastguard Worker         EXPECT(mWaitingKey == key, error = OT_ERROR_DROP);
366*cfb92d14SAndroid Build Coastguard Worker 
367*cfb92d14SAndroid Build Coastguard Worker         if (key == SPINEL_PROP_PROTOCOL_VERSION)
368*cfb92d14SAndroid Build Coastguard Worker         {
369*cfb92d14SAndroid Build Coastguard Worker             unpacked = spinel_datatype_unpack(data, len, (SPINEL_DATATYPE_UINT_PACKED_S SPINEL_DATATYPE_UINT_PACKED_S),
370*cfb92d14SAndroid Build Coastguard Worker                                               &mSpinelVersionMajor, &mSpinelVersionMinor);
371*cfb92d14SAndroid Build Coastguard Worker 
372*cfb92d14SAndroid Build Coastguard Worker             EXPECT(unpacked > 0, error = OT_ERROR_PARSE);
373*cfb92d14SAndroid Build Coastguard Worker         }
374*cfb92d14SAndroid Build Coastguard Worker         else if (key == SPINEL_PROP_NCP_VERSION)
375*cfb92d14SAndroid Build Coastguard Worker         {
376*cfb92d14SAndroid Build Coastguard Worker             unpacked = spinel_datatype_unpack_in_place(data, len, SPINEL_DATATYPE_UTF8_S, mVersion, sizeof(mVersion));
377*cfb92d14SAndroid Build Coastguard Worker 
378*cfb92d14SAndroid Build Coastguard Worker             EXPECT(unpacked > 0, error = OT_ERROR_PARSE);
379*cfb92d14SAndroid Build Coastguard Worker         }
380*cfb92d14SAndroid Build Coastguard Worker         else if (key == SPINEL_PROP_CAPS)
381*cfb92d14SAndroid Build Coastguard Worker         {
382*cfb92d14SAndroid Build Coastguard Worker             uint8_t        capsBuffer[kCapsBufferSize];
383*cfb92d14SAndroid Build Coastguard Worker             spinel_size_t  capsLength = sizeof(capsBuffer);
384*cfb92d14SAndroid Build Coastguard Worker             const uint8_t *capsData   = capsBuffer;
385*cfb92d14SAndroid Build Coastguard Worker 
386*cfb92d14SAndroid Build Coastguard Worker             unpacked = spinel_datatype_unpack_in_place(data, len, SPINEL_DATATYPE_DATA_S, capsBuffer, &capsLength);
387*cfb92d14SAndroid Build Coastguard Worker 
388*cfb92d14SAndroid Build Coastguard Worker             EXPECT(unpacked > 0, error = OT_ERROR_PARSE);
389*cfb92d14SAndroid Build Coastguard Worker 
390*cfb92d14SAndroid Build Coastguard Worker             while (capsLength > 0)
391*cfb92d14SAndroid Build Coastguard Worker             {
392*cfb92d14SAndroid Build Coastguard Worker                 unsigned int capability;
393*cfb92d14SAndroid Build Coastguard Worker 
394*cfb92d14SAndroid Build Coastguard Worker                 unpacked = spinel_datatype_unpack(capsData, capsLength, SPINEL_DATATYPE_UINT_PACKED_S, &capability);
395*cfb92d14SAndroid Build Coastguard Worker                 EXPECT(unpacked > 0, error = OT_ERROR_PARSE);
396*cfb92d14SAndroid Build Coastguard Worker 
397*cfb92d14SAndroid Build Coastguard Worker                 EXPECT_NO_ERROR(error = mCoprocessorCaps.PushBack(capability));
398*cfb92d14SAndroid Build Coastguard Worker 
399*cfb92d14SAndroid Build Coastguard Worker                 capsData += unpacked;
400*cfb92d14SAndroid Build Coastguard Worker                 capsLength -= static_cast<spinel_size_t>(unpacked);
401*cfb92d14SAndroid Build Coastguard Worker             }
402*cfb92d14SAndroid Build Coastguard Worker         }
403*cfb92d14SAndroid Build Coastguard Worker 
404*cfb92d14SAndroid Build Coastguard Worker         mIsWaitingForResponse = false;
405*cfb92d14SAndroid Build Coastguard Worker     }
406*cfb92d14SAndroid Build Coastguard Worker 
407*cfb92d14SAndroid Build Coastguard Worker exit:
408*cfb92d14SAndroid Build Coastguard Worker     aSave = false;
409*cfb92d14SAndroid Build Coastguard Worker     LogIfFail("Error processing frame", error);
410*cfb92d14SAndroid Build Coastguard Worker }
411*cfb92d14SAndroid Build Coastguard Worker 
CheckSpinelVersion(void)412*cfb92d14SAndroid Build Coastguard Worker otError SpinelDriver::CheckSpinelVersion(void)
413*cfb92d14SAndroid Build Coastguard Worker {
414*cfb92d14SAndroid Build Coastguard Worker     otError error = OT_ERROR_NONE;
415*cfb92d14SAndroid Build Coastguard Worker 
416*cfb92d14SAndroid Build Coastguard Worker     EXPECT_NO_ERROR(error = SendCommand(SPINEL_CMD_PROP_VALUE_GET, SPINEL_PROP_PROTOCOL_VERSION, sTid));
417*cfb92d14SAndroid Build Coastguard Worker     mIsWaitingForResponse = true;
418*cfb92d14SAndroid Build Coastguard Worker     mWaitingKey           = SPINEL_PROP_PROTOCOL_VERSION;
419*cfb92d14SAndroid Build Coastguard Worker 
420*cfb92d14SAndroid Build Coastguard Worker     EXPECT_NO_ERROR(error = WaitResponse());
421*cfb92d14SAndroid Build Coastguard Worker 
422*cfb92d14SAndroid Build Coastguard Worker     if ((mSpinelVersionMajor != SPINEL_PROTOCOL_VERSION_THREAD_MAJOR) ||
423*cfb92d14SAndroid Build Coastguard Worker         (mSpinelVersionMinor != SPINEL_PROTOCOL_VERSION_THREAD_MINOR))
424*cfb92d14SAndroid Build Coastguard Worker     {
425*cfb92d14SAndroid Build Coastguard Worker         LogCrit("Spinel version mismatch - Posix:%d.%d, co-processor:%d.%d", SPINEL_PROTOCOL_VERSION_THREAD_MAJOR,
426*cfb92d14SAndroid Build Coastguard Worker                 SPINEL_PROTOCOL_VERSION_THREAD_MINOR, mSpinelVersionMajor, mSpinelVersionMinor);
427*cfb92d14SAndroid Build Coastguard Worker         DieNow(OT_EXIT_RADIO_SPINEL_INCOMPATIBLE);
428*cfb92d14SAndroid Build Coastguard Worker     }
429*cfb92d14SAndroid Build Coastguard Worker 
430*cfb92d14SAndroid Build Coastguard Worker exit:
431*cfb92d14SAndroid Build Coastguard Worker     return error;
432*cfb92d14SAndroid Build Coastguard Worker }
433*cfb92d14SAndroid Build Coastguard Worker 
GetCoprocessorVersion(void)434*cfb92d14SAndroid Build Coastguard Worker otError SpinelDriver::GetCoprocessorVersion(void)
435*cfb92d14SAndroid Build Coastguard Worker {
436*cfb92d14SAndroid Build Coastguard Worker     otError error = OT_ERROR_NONE;
437*cfb92d14SAndroid Build Coastguard Worker 
438*cfb92d14SAndroid Build Coastguard Worker     EXPECT_NO_ERROR(error = SendCommand(SPINEL_CMD_PROP_VALUE_GET, SPINEL_PROP_NCP_VERSION, sTid));
439*cfb92d14SAndroid Build Coastguard Worker     mIsWaitingForResponse = true;
440*cfb92d14SAndroid Build Coastguard Worker     mWaitingKey           = SPINEL_PROP_NCP_VERSION;
441*cfb92d14SAndroid Build Coastguard Worker 
442*cfb92d14SAndroid Build Coastguard Worker     EXPECT_NO_ERROR(error = WaitResponse());
443*cfb92d14SAndroid Build Coastguard Worker exit:
444*cfb92d14SAndroid Build Coastguard Worker     return error;
445*cfb92d14SAndroid Build Coastguard Worker }
446*cfb92d14SAndroid Build Coastguard Worker 
GetCoprocessorCaps(void)447*cfb92d14SAndroid Build Coastguard Worker otError SpinelDriver::GetCoprocessorCaps(void)
448*cfb92d14SAndroid Build Coastguard Worker {
449*cfb92d14SAndroid Build Coastguard Worker     otError error = OT_ERROR_NONE;
450*cfb92d14SAndroid Build Coastguard Worker 
451*cfb92d14SAndroid Build Coastguard Worker     EXPECT_NO_ERROR(error = SendCommand(SPINEL_CMD_PROP_VALUE_GET, SPINEL_PROP_CAPS, sTid));
452*cfb92d14SAndroid Build Coastguard Worker     mIsWaitingForResponse = true;
453*cfb92d14SAndroid Build Coastguard Worker     mWaitingKey           = SPINEL_PROP_CAPS;
454*cfb92d14SAndroid Build Coastguard Worker 
455*cfb92d14SAndroid Build Coastguard Worker     EXPECT_NO_ERROR(error = WaitResponse());
456*cfb92d14SAndroid Build Coastguard Worker exit:
457*cfb92d14SAndroid Build Coastguard Worker     return error;
458*cfb92d14SAndroid Build Coastguard Worker }
459*cfb92d14SAndroid Build Coastguard Worker 
GetCoprocessorType(void)460*cfb92d14SAndroid Build Coastguard Worker CoprocessorType SpinelDriver::GetCoprocessorType(void)
461*cfb92d14SAndroid Build Coastguard Worker {
462*cfb92d14SAndroid Build Coastguard Worker     CoprocessorType type = OT_COPROCESSOR_UNKNOWN;
463*cfb92d14SAndroid Build Coastguard Worker 
464*cfb92d14SAndroid Build Coastguard Worker     if (CoprocessorHasCap(SPINEL_CAP_CONFIG_RADIO))
465*cfb92d14SAndroid Build Coastguard Worker     {
466*cfb92d14SAndroid Build Coastguard Worker         type = OT_COPROCESSOR_RCP;
467*cfb92d14SAndroid Build Coastguard Worker     }
468*cfb92d14SAndroid Build Coastguard Worker     else if (CoprocessorHasCap(SPINEL_CAP_CONFIG_FTD) || CoprocessorHasCap(SPINEL_CAP_CONFIG_MTD))
469*cfb92d14SAndroid Build Coastguard Worker     {
470*cfb92d14SAndroid Build Coastguard Worker         type = OT_COPROCESSOR_NCP;
471*cfb92d14SAndroid Build Coastguard Worker     }
472*cfb92d14SAndroid Build Coastguard Worker 
473*cfb92d14SAndroid Build Coastguard Worker     return type;
474*cfb92d14SAndroid Build Coastguard Worker }
475*cfb92d14SAndroid Build Coastguard Worker 
ProcessFrameQueue(void)476*cfb92d14SAndroid Build Coastguard Worker void SpinelDriver::ProcessFrameQueue(void)
477*cfb92d14SAndroid Build Coastguard Worker {
478*cfb92d14SAndroid Build Coastguard Worker     uint8_t *frame = nullptr;
479*cfb92d14SAndroid Build Coastguard Worker     uint16_t length;
480*cfb92d14SAndroid Build Coastguard Worker 
481*cfb92d14SAndroid Build Coastguard Worker     assert(mSavedFrameHandler != nullptr && mFrameHandlerContext != nullptr);
482*cfb92d14SAndroid Build Coastguard Worker 
483*cfb92d14SAndroid Build Coastguard Worker     while (mRxFrameBuffer.GetNextSavedFrame(frame, length) == OT_ERROR_NONE)
484*cfb92d14SAndroid Build Coastguard Worker     {
485*cfb92d14SAndroid Build Coastguard Worker         mSavedFrameHandler(frame, length, mFrameHandlerContext);
486*cfb92d14SAndroid Build Coastguard Worker     }
487*cfb92d14SAndroid Build Coastguard Worker 
488*cfb92d14SAndroid Build Coastguard Worker     mRxFrameBuffer.ClearSavedFrames();
489*cfb92d14SAndroid Build Coastguard Worker }
490*cfb92d14SAndroid Build Coastguard Worker 
491*cfb92d14SAndroid Build Coastguard Worker } // namespace Spinel
492*cfb92d14SAndroid Build Coastguard Worker } // namespace ot
493