xref: /aosp_15_r20/external/openthread/src/lib/spinel/radio_spinel.cpp (revision cfb92d1480a9e65faed56933e9c12405f45898b4)
1*cfb92d14SAndroid Build Coastguard Worker /*
2*cfb92d14SAndroid Build Coastguard Worker  *  Copyright (c) 2020, 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 /**
30*cfb92d14SAndroid Build Coastguard Worker  * @file
31*cfb92d14SAndroid Build Coastguard Worker  *   This file implements the spinel based radio transceiver.
32*cfb92d14SAndroid Build Coastguard Worker  */
33*cfb92d14SAndroid Build Coastguard Worker 
34*cfb92d14SAndroid Build Coastguard Worker #include "radio_spinel.hpp"
35*cfb92d14SAndroid Build Coastguard Worker 
36*cfb92d14SAndroid Build Coastguard Worker #include <assert.h>
37*cfb92d14SAndroid Build Coastguard Worker #include <errno.h>
38*cfb92d14SAndroid Build Coastguard Worker #include <stdarg.h>
39*cfb92d14SAndroid Build Coastguard Worker #include <stdlib.h>
40*cfb92d14SAndroid Build Coastguard Worker 
41*cfb92d14SAndroid Build Coastguard Worker #include <openthread/link.h>
42*cfb92d14SAndroid Build Coastguard Worker #include <openthread/logging.h>
43*cfb92d14SAndroid Build Coastguard Worker #include <openthread/platform/diag.h>
44*cfb92d14SAndroid Build Coastguard Worker #include <openthread/platform/time.h>
45*cfb92d14SAndroid Build Coastguard Worker 
46*cfb92d14SAndroid Build Coastguard Worker #include "lib/platform/exit_code.h"
47*cfb92d14SAndroid Build Coastguard Worker #include "lib/spinel/logger.hpp"
48*cfb92d14SAndroid Build Coastguard Worker #include "lib/spinel/spinel_decoder.hpp"
49*cfb92d14SAndroid Build Coastguard Worker #include "lib/spinel/spinel_driver.hpp"
50*cfb92d14SAndroid Build Coastguard Worker #include "lib/spinel/spinel_helper.hpp"
51*cfb92d14SAndroid Build Coastguard Worker #include "lib/utils/utils.hpp"
52*cfb92d14SAndroid Build Coastguard Worker 
53*cfb92d14SAndroid Build Coastguard Worker namespace ot {
54*cfb92d14SAndroid Build Coastguard Worker namespace Spinel {
55*cfb92d14SAndroid Build Coastguard Worker 
56*cfb92d14SAndroid Build Coastguard Worker otExtAddress RadioSpinel::sIeeeEui64;
57*cfb92d14SAndroid Build Coastguard Worker 
58*cfb92d14SAndroid Build Coastguard Worker bool RadioSpinel::sSupportsLogStream =
59*cfb92d14SAndroid Build Coastguard Worker     false; ///< RCP supports `LOG_STREAM` property with OpenThread log meta-data format.
60*cfb92d14SAndroid Build Coastguard Worker 
61*cfb92d14SAndroid Build Coastguard Worker bool RadioSpinel::sSupportsResetToBootloader = false; ///< RCP supports resetting into bootloader mode.
62*cfb92d14SAndroid Build Coastguard Worker 
63*cfb92d14SAndroid Build Coastguard Worker bool RadioSpinel::sSupportsLogCrashDump = false; ///< RCP supports logging a crash dump.
64*cfb92d14SAndroid Build Coastguard Worker 
65*cfb92d14SAndroid Build Coastguard Worker otRadioCaps RadioSpinel::sRadioCaps = OT_RADIO_CAPS_NONE;
66*cfb92d14SAndroid Build Coastguard Worker 
RadioSpinel(void)67*cfb92d14SAndroid Build Coastguard Worker RadioSpinel::RadioSpinel(void)
68*cfb92d14SAndroid Build Coastguard Worker     : Logger("RadioSpinel")
69*cfb92d14SAndroid Build Coastguard Worker     , mInstance(nullptr)
70*cfb92d14SAndroid Build Coastguard Worker     , mCmdTidsInUse(0)
71*cfb92d14SAndroid Build Coastguard Worker     , mCmdNextTid(1)
72*cfb92d14SAndroid Build Coastguard Worker     , mTxRadioTid(0)
73*cfb92d14SAndroid Build Coastguard Worker     , mWaitingTid(0)
74*cfb92d14SAndroid Build Coastguard Worker     , mWaitingKey(SPINEL_PROP_LAST_STATUS)
75*cfb92d14SAndroid Build Coastguard Worker     , mPropertyFormat(nullptr)
76*cfb92d14SAndroid Build Coastguard Worker     , mExpectedCommand(0)
77*cfb92d14SAndroid Build Coastguard Worker     , mError(OT_ERROR_NONE)
78*cfb92d14SAndroid Build Coastguard Worker     , mTransmitFrame(nullptr)
79*cfb92d14SAndroid Build Coastguard Worker     , mShortAddress(0)
80*cfb92d14SAndroid Build Coastguard Worker     , mPanId(0xffff)
81*cfb92d14SAndroid Build Coastguard Worker     , mChannel(0)
82*cfb92d14SAndroid Build Coastguard Worker     , mRxSensitivity(0)
83*cfb92d14SAndroid Build Coastguard Worker     , mBusLatency(0)
84*cfb92d14SAndroid Build Coastguard Worker     , mState(kStateDisabled)
85*cfb92d14SAndroid Build Coastguard Worker     , mIsPromiscuous(false)
86*cfb92d14SAndroid Build Coastguard Worker     , mRxOnWhenIdle(true)
87*cfb92d14SAndroid Build Coastguard Worker     , mIsTimeSynced(false)
88*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0
89*cfb92d14SAndroid Build Coastguard Worker     , mRcpFailureCount(0)
90*cfb92d14SAndroid Build Coastguard Worker     , mRcpFailure(kRcpFailureNone)
91*cfb92d14SAndroid Build Coastguard Worker     , mSrcMatchShortEntryCount(0)
92*cfb92d14SAndroid Build Coastguard Worker     , mSrcMatchExtEntryCount(0)
93*cfb92d14SAndroid Build Coastguard Worker     , mSrcMatchEnabled(false)
94*cfb92d14SAndroid Build Coastguard Worker     , mMacKeySet(false)
95*cfb92d14SAndroid Build Coastguard Worker     , mCcaEnergyDetectThresholdSet(false)
96*cfb92d14SAndroid Build Coastguard Worker     , mTransmitPowerSet(false)
97*cfb92d14SAndroid Build Coastguard Worker     , mCoexEnabledSet(false)
98*cfb92d14SAndroid Build Coastguard Worker     , mFemLnaGainSet(false)
99*cfb92d14SAndroid Build Coastguard Worker     , mEnergyScanning(false)
100*cfb92d14SAndroid Build Coastguard Worker     , mMacFrameCounterSet(false)
101*cfb92d14SAndroid Build Coastguard Worker     , mSrcMatchSet(false)
102*cfb92d14SAndroid Build Coastguard Worker #endif
103*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_CONFIG_DIAG_ENABLE
104*cfb92d14SAndroid Build Coastguard Worker     , mDiagMode(false)
105*cfb92d14SAndroid Build Coastguard Worker     , mOutputCallback(nullptr)
106*cfb92d14SAndroid Build Coastguard Worker     , mOutputContext(nullptr)
107*cfb92d14SAndroid Build Coastguard Worker #endif
108*cfb92d14SAndroid Build Coastguard Worker     , mTxRadioEndUs(UINT64_MAX)
109*cfb92d14SAndroid Build Coastguard Worker     , mRadioTimeRecalcStart(UINT64_MAX)
110*cfb92d14SAndroid Build Coastguard Worker     , mRadioTimeOffset(UINT64_MAX)
111*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_SPINEL_CONFIG_VENDOR_HOOK_ENABLE
112*cfb92d14SAndroid Build Coastguard Worker     , mVendorRestorePropertiesCallback(nullptr)
113*cfb92d14SAndroid Build Coastguard Worker     , mVendorRestorePropertiesContext(nullptr)
114*cfb92d14SAndroid Build Coastguard Worker #endif
115*cfb92d14SAndroid Build Coastguard Worker     , mTimeSyncEnabled(false)
116*cfb92d14SAndroid Build Coastguard Worker     , mTimeSyncOn(false)
117*cfb92d14SAndroid Build Coastguard Worker     , mSpinelDriver(nullptr)
118*cfb92d14SAndroid Build Coastguard Worker {
119*cfb92d14SAndroid Build Coastguard Worker     memset(&mRadioSpinelMetrics, 0, sizeof(mRadioSpinelMetrics));
120*cfb92d14SAndroid Build Coastguard Worker     memset(&mCallbacks, 0, sizeof(mCallbacks));
121*cfb92d14SAndroid Build Coastguard Worker }
122*cfb92d14SAndroid Build Coastguard Worker 
Init(bool aSkipRcpCompatibilityCheck,bool aSoftwareReset,SpinelDriver * aSpinelDriver,otRadioCaps aRequiredRadioCaps,bool aEnableRcpTimeSync)123*cfb92d14SAndroid Build Coastguard Worker void RadioSpinel::Init(bool          aSkipRcpCompatibilityCheck,
124*cfb92d14SAndroid Build Coastguard Worker                        bool          aSoftwareReset,
125*cfb92d14SAndroid Build Coastguard Worker                        SpinelDriver *aSpinelDriver,
126*cfb92d14SAndroid Build Coastguard Worker                        otRadioCaps   aRequiredRadioCaps,
127*cfb92d14SAndroid Build Coastguard Worker                        bool          aEnableRcpTimeSync)
128*cfb92d14SAndroid Build Coastguard Worker {
129*cfb92d14SAndroid Build Coastguard Worker     otError error = OT_ERROR_NONE;
130*cfb92d14SAndroid Build Coastguard Worker     bool    supportsRcpApiVersion;
131*cfb92d14SAndroid Build Coastguard Worker     bool    supportsRcpMinHostApiVersion;
132*cfb92d14SAndroid Build Coastguard Worker 
133*cfb92d14SAndroid Build Coastguard Worker     OT_UNUSED_VARIABLE(aSoftwareReset);
134*cfb92d14SAndroid Build Coastguard Worker 
135*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0
136*cfb92d14SAndroid Build Coastguard Worker     mResetRadioOnStartup = aSoftwareReset;
137*cfb92d14SAndroid Build Coastguard Worker #endif
138*cfb92d14SAndroid Build Coastguard Worker 
139*cfb92d14SAndroid Build Coastguard Worker     mTimeSyncEnabled = aEnableRcpTimeSync;
140*cfb92d14SAndroid Build Coastguard Worker 
141*cfb92d14SAndroid Build Coastguard Worker     mSpinelDriver = aSpinelDriver;
142*cfb92d14SAndroid Build Coastguard Worker     mSpinelDriver->SetFrameHandler(&HandleReceivedFrame, &HandleSavedFrame, this);
143*cfb92d14SAndroid Build Coastguard Worker 
144*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT && OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
145*cfb92d14SAndroid Build Coastguard Worker     memset(&mTxIeInfo, 0, sizeof(otRadioIeInfo));
146*cfb92d14SAndroid Build Coastguard Worker     mTxRadioFrame.mInfo.mTxInfo.mIeInfo = &mTxIeInfo;
147*cfb92d14SAndroid Build Coastguard Worker #endif
148*cfb92d14SAndroid Build Coastguard Worker 
149*cfb92d14SAndroid Build Coastguard Worker     EXPECT_NO_ERROR(error = Get(SPINEL_PROP_HWADDR, SPINEL_DATATYPE_EUI64_S, sIeeeEui64.m8));
150*cfb92d14SAndroid Build Coastguard Worker     InitializeCaps(supportsRcpApiVersion, supportsRcpMinHostApiVersion);
151*cfb92d14SAndroid Build Coastguard Worker 
152*cfb92d14SAndroid Build Coastguard Worker     if (sSupportsLogCrashDump)
153*cfb92d14SAndroid Build Coastguard Worker     {
154*cfb92d14SAndroid Build Coastguard Worker         LogDebg("RCP supports crash dump logging. Requesting crash dump.");
155*cfb92d14SAndroid Build Coastguard Worker         EXPECT_NO_ERROR(error = Set(SPINEL_PROP_RCP_LOG_CRASH_DUMP, nullptr));
156*cfb92d14SAndroid Build Coastguard Worker     }
157*cfb92d14SAndroid Build Coastguard Worker 
158*cfb92d14SAndroid Build Coastguard Worker     if (!aSkipRcpCompatibilityCheck)
159*cfb92d14SAndroid Build Coastguard Worker     {
160*cfb92d14SAndroid Build Coastguard Worker         SuccessOrDie(CheckRcpApiVersion(supportsRcpApiVersion, supportsRcpMinHostApiVersion));
161*cfb92d14SAndroid Build Coastguard Worker         SuccessOrDie(CheckRadioCapabilities(aRequiredRadioCaps));
162*cfb92d14SAndroid Build Coastguard Worker     }
163*cfb92d14SAndroid Build Coastguard Worker 
164*cfb92d14SAndroid Build Coastguard Worker     mRxRadioFrame.mPsdu  = mRxPsdu;
165*cfb92d14SAndroid Build Coastguard Worker     mTxRadioFrame.mPsdu  = mTxPsdu;
166*cfb92d14SAndroid Build Coastguard Worker     mAckRadioFrame.mPsdu = mAckPsdu;
167*cfb92d14SAndroid Build Coastguard Worker 
168*cfb92d14SAndroid Build Coastguard Worker exit:
169*cfb92d14SAndroid Build Coastguard Worker     SuccessOrDie(error);
170*cfb92d14SAndroid Build Coastguard Worker }
171*cfb92d14SAndroid Build Coastguard Worker 
SetCallbacks(const struct RadioSpinelCallbacks & aCallbacks)172*cfb92d14SAndroid Build Coastguard Worker void RadioSpinel::SetCallbacks(const struct RadioSpinelCallbacks &aCallbacks)
173*cfb92d14SAndroid Build Coastguard Worker {
174*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_CONFIG_DIAG_ENABLE
175*cfb92d14SAndroid Build Coastguard Worker     assert(aCallbacks.mDiagReceiveDone != nullptr);
176*cfb92d14SAndroid Build Coastguard Worker     assert(aCallbacks.mDiagTransmitDone != nullptr);
177*cfb92d14SAndroid Build Coastguard Worker #endif
178*cfb92d14SAndroid Build Coastguard Worker     assert(aCallbacks.mEnergyScanDone != nullptr);
179*cfb92d14SAndroid Build Coastguard Worker     assert(aCallbacks.mReceiveDone != nullptr);
180*cfb92d14SAndroid Build Coastguard Worker     assert(aCallbacks.mTransmitDone != nullptr);
181*cfb92d14SAndroid Build Coastguard Worker     assert(aCallbacks.mTxStarted != nullptr);
182*cfb92d14SAndroid Build Coastguard Worker 
183*cfb92d14SAndroid Build Coastguard Worker     mCallbacks = aCallbacks;
184*cfb92d14SAndroid Build Coastguard Worker }
185*cfb92d14SAndroid Build Coastguard Worker 
CheckSpinelVersion(void)186*cfb92d14SAndroid Build Coastguard Worker otError RadioSpinel::CheckSpinelVersion(void)
187*cfb92d14SAndroid Build Coastguard Worker {
188*cfb92d14SAndroid Build Coastguard Worker     otError      error = OT_ERROR_NONE;
189*cfb92d14SAndroid Build Coastguard Worker     unsigned int versionMajor;
190*cfb92d14SAndroid Build Coastguard Worker     unsigned int versionMinor;
191*cfb92d14SAndroid Build Coastguard Worker 
192*cfb92d14SAndroid Build Coastguard Worker     EXPECT_NO_ERROR(error =
193*cfb92d14SAndroid Build Coastguard Worker                         Get(SPINEL_PROP_PROTOCOL_VERSION, (SPINEL_DATATYPE_UINT_PACKED_S SPINEL_DATATYPE_UINT_PACKED_S),
194*cfb92d14SAndroid Build Coastguard Worker                             &versionMajor, &versionMinor));
195*cfb92d14SAndroid Build Coastguard Worker 
196*cfb92d14SAndroid Build Coastguard Worker     if ((versionMajor != SPINEL_PROTOCOL_VERSION_THREAD_MAJOR) ||
197*cfb92d14SAndroid Build Coastguard Worker         (versionMinor != SPINEL_PROTOCOL_VERSION_THREAD_MINOR))
198*cfb92d14SAndroid Build Coastguard Worker     {
199*cfb92d14SAndroid Build Coastguard Worker         LogCrit("Spinel version mismatch - Posix:%d.%d, RCP:%d.%d", SPINEL_PROTOCOL_VERSION_THREAD_MAJOR,
200*cfb92d14SAndroid Build Coastguard Worker                 SPINEL_PROTOCOL_VERSION_THREAD_MINOR, versionMajor, versionMinor);
201*cfb92d14SAndroid Build Coastguard Worker         DieNow(OT_EXIT_RADIO_SPINEL_INCOMPATIBLE);
202*cfb92d14SAndroid Build Coastguard Worker     }
203*cfb92d14SAndroid Build Coastguard Worker 
204*cfb92d14SAndroid Build Coastguard Worker exit:
205*cfb92d14SAndroid Build Coastguard Worker     return error;
206*cfb92d14SAndroid Build Coastguard Worker }
207*cfb92d14SAndroid Build Coastguard Worker 
InitializeCaps(bool & aSupportsRcpApiVersion,bool & aSupportsRcpMinHostApiVersion)208*cfb92d14SAndroid Build Coastguard Worker void RadioSpinel::InitializeCaps(bool &aSupportsRcpApiVersion, bool &aSupportsRcpMinHostApiVersion)
209*cfb92d14SAndroid Build Coastguard Worker {
210*cfb92d14SAndroid Build Coastguard Worker     if (!GetSpinelDriver().CoprocessorHasCap(SPINEL_CAP_CONFIG_RADIO))
211*cfb92d14SAndroid Build Coastguard Worker     {
212*cfb92d14SAndroid Build Coastguard Worker         LogCrit("The co-processor isn't a RCP!");
213*cfb92d14SAndroid Build Coastguard Worker         DieNow(OT_EXIT_RADIO_SPINEL_INCOMPATIBLE);
214*cfb92d14SAndroid Build Coastguard Worker     }
215*cfb92d14SAndroid Build Coastguard Worker 
216*cfb92d14SAndroid Build Coastguard Worker     if (!GetSpinelDriver().CoprocessorHasCap(SPINEL_CAP_MAC_RAW))
217*cfb92d14SAndroid Build Coastguard Worker     {
218*cfb92d14SAndroid Build Coastguard Worker         LogCrit("RCP capability list does not include support for radio/raw mode");
219*cfb92d14SAndroid Build Coastguard Worker         DieNow(OT_EXIT_RADIO_SPINEL_INCOMPATIBLE);
220*cfb92d14SAndroid Build Coastguard Worker     }
221*cfb92d14SAndroid Build Coastguard Worker 
222*cfb92d14SAndroid Build Coastguard Worker     sSupportsLogStream            = GetSpinelDriver().CoprocessorHasCap(SPINEL_CAP_OPENTHREAD_LOG_METADATA);
223*cfb92d14SAndroid Build Coastguard Worker     aSupportsRcpApiVersion        = GetSpinelDriver().CoprocessorHasCap(SPINEL_CAP_RCP_API_VERSION);
224*cfb92d14SAndroid Build Coastguard Worker     sSupportsResetToBootloader    = GetSpinelDriver().CoprocessorHasCap(SPINEL_CAP_RCP_RESET_TO_BOOTLOADER);
225*cfb92d14SAndroid Build Coastguard Worker     aSupportsRcpMinHostApiVersion = GetSpinelDriver().CoprocessorHasCap(SPINEL_CAP_RCP_MIN_HOST_API_VERSION);
226*cfb92d14SAndroid Build Coastguard Worker     sSupportsLogCrashDump         = GetSpinelDriver().CoprocessorHasCap(SPINEL_CAP_RCP_LOG_CRASH_DUMP);
227*cfb92d14SAndroid Build Coastguard Worker }
228*cfb92d14SAndroid Build Coastguard Worker 
CheckRadioCapabilities(otRadioCaps aRequiredRadioCaps)229*cfb92d14SAndroid Build Coastguard Worker otError RadioSpinel::CheckRadioCapabilities(otRadioCaps aRequiredRadioCaps)
230*cfb92d14SAndroid Build Coastguard Worker {
231*cfb92d14SAndroid Build Coastguard Worker     static const char *const kAllRadioCapsStr[] = {"ack-timeout",     "energy-scan",   "tx-retries", "CSMA-backoff",
232*cfb92d14SAndroid Build Coastguard Worker                                                    "sleep-to-tx",     "tx-security",   "tx-timing",  "rx-timing",
233*cfb92d14SAndroid Build Coastguard Worker                                                    "rx-on-when-idle", "tx-frame-power"};
234*cfb92d14SAndroid Build Coastguard Worker 
235*cfb92d14SAndroid Build Coastguard Worker     otError      error = OT_ERROR_NONE;
236*cfb92d14SAndroid Build Coastguard Worker     unsigned int radioCaps;
237*cfb92d14SAndroid Build Coastguard Worker 
238*cfb92d14SAndroid Build Coastguard Worker     EXPECT_NO_ERROR(error = Get(SPINEL_PROP_RADIO_CAPS, SPINEL_DATATYPE_UINT_PACKED_S, &radioCaps));
239*cfb92d14SAndroid Build Coastguard Worker     sRadioCaps = static_cast<otRadioCaps>(radioCaps);
240*cfb92d14SAndroid Build Coastguard Worker 
241*cfb92d14SAndroid Build Coastguard Worker     if ((sRadioCaps & aRequiredRadioCaps) != aRequiredRadioCaps)
242*cfb92d14SAndroid Build Coastguard Worker     {
243*cfb92d14SAndroid Build Coastguard Worker         otRadioCaps missingCaps = (sRadioCaps & aRequiredRadioCaps) ^ aRequiredRadioCaps;
244*cfb92d14SAndroid Build Coastguard Worker         LogCrit("RCP is missing required capabilities: ");
245*cfb92d14SAndroid Build Coastguard Worker 
246*cfb92d14SAndroid Build Coastguard Worker         for (unsigned long i = 0; i < sizeof(kAllRadioCapsStr) / sizeof(kAllRadioCapsStr[0]); i++)
247*cfb92d14SAndroid Build Coastguard Worker         {
248*cfb92d14SAndroid Build Coastguard Worker             if (missingCaps & (1 << i))
249*cfb92d14SAndroid Build Coastguard Worker             {
250*cfb92d14SAndroid Build Coastguard Worker                 LogCrit("    %s", kAllRadioCapsStr[i]);
251*cfb92d14SAndroid Build Coastguard Worker             }
252*cfb92d14SAndroid Build Coastguard Worker         }
253*cfb92d14SAndroid Build Coastguard Worker 
254*cfb92d14SAndroid Build Coastguard Worker         DieNow(OT_EXIT_RADIO_SPINEL_INCOMPATIBLE);
255*cfb92d14SAndroid Build Coastguard Worker     }
256*cfb92d14SAndroid Build Coastguard Worker 
257*cfb92d14SAndroid Build Coastguard Worker exit:
258*cfb92d14SAndroid Build Coastguard Worker     return error;
259*cfb92d14SAndroid Build Coastguard Worker }
260*cfb92d14SAndroid Build Coastguard Worker 
CheckRcpApiVersion(bool aSupportsRcpApiVersion,bool aSupportsRcpMinHostApiVersion)261*cfb92d14SAndroid Build Coastguard Worker otError RadioSpinel::CheckRcpApiVersion(bool aSupportsRcpApiVersion, bool aSupportsRcpMinHostApiVersion)
262*cfb92d14SAndroid Build Coastguard Worker {
263*cfb92d14SAndroid Build Coastguard Worker     otError error = OT_ERROR_NONE;
264*cfb92d14SAndroid Build Coastguard Worker 
265*cfb92d14SAndroid Build Coastguard Worker     static_assert(SPINEL_MIN_HOST_SUPPORTED_RCP_API_VERSION <= SPINEL_RCP_API_VERSION,
266*cfb92d14SAndroid Build Coastguard Worker                   "MIN_HOST_SUPPORTED_RCP_API_VERSION must be smaller than or equal to RCP_API_VERSION");
267*cfb92d14SAndroid Build Coastguard Worker 
268*cfb92d14SAndroid Build Coastguard Worker     if (aSupportsRcpApiVersion)
269*cfb92d14SAndroid Build Coastguard Worker     {
270*cfb92d14SAndroid Build Coastguard Worker         // Make sure RCP is not too old and its version is within the
271*cfb92d14SAndroid Build Coastguard Worker         // range host supports.
272*cfb92d14SAndroid Build Coastguard Worker 
273*cfb92d14SAndroid Build Coastguard Worker         unsigned int rcpApiVersion;
274*cfb92d14SAndroid Build Coastguard Worker 
275*cfb92d14SAndroid Build Coastguard Worker         EXPECT_NO_ERROR(error = Get(SPINEL_PROP_RCP_API_VERSION, SPINEL_DATATYPE_UINT_PACKED_S, &rcpApiVersion));
276*cfb92d14SAndroid Build Coastguard Worker 
277*cfb92d14SAndroid Build Coastguard Worker         if (rcpApiVersion < SPINEL_MIN_HOST_SUPPORTED_RCP_API_VERSION)
278*cfb92d14SAndroid Build Coastguard Worker         {
279*cfb92d14SAndroid Build Coastguard Worker             LogCrit("RCP and host are using incompatible API versions");
280*cfb92d14SAndroid Build Coastguard Worker             LogCrit("RCP API Version %u is older than min required by host %u", rcpApiVersion,
281*cfb92d14SAndroid Build Coastguard Worker                     SPINEL_MIN_HOST_SUPPORTED_RCP_API_VERSION);
282*cfb92d14SAndroid Build Coastguard Worker             DieNow(OT_EXIT_RADIO_SPINEL_INCOMPATIBLE);
283*cfb92d14SAndroid Build Coastguard Worker         }
284*cfb92d14SAndroid Build Coastguard Worker     }
285*cfb92d14SAndroid Build Coastguard Worker 
286*cfb92d14SAndroid Build Coastguard Worker     if (aSupportsRcpMinHostApiVersion)
287*cfb92d14SAndroid Build Coastguard Worker     {
288*cfb92d14SAndroid Build Coastguard Worker         // Check with RCP about min host API version it can work with,
289*cfb92d14SAndroid Build Coastguard Worker         // and make sure on host side our version is within the supported
290*cfb92d14SAndroid Build Coastguard Worker         // range.
291*cfb92d14SAndroid Build Coastguard Worker 
292*cfb92d14SAndroid Build Coastguard Worker         unsigned int minHostRcpApiVersion;
293*cfb92d14SAndroid Build Coastguard Worker 
294*cfb92d14SAndroid Build Coastguard Worker         EXPECT_NO_ERROR(
295*cfb92d14SAndroid Build Coastguard Worker             error = Get(SPINEL_PROP_RCP_MIN_HOST_API_VERSION, SPINEL_DATATYPE_UINT_PACKED_S, &minHostRcpApiVersion));
296*cfb92d14SAndroid Build Coastguard Worker 
297*cfb92d14SAndroid Build Coastguard Worker         if (SPINEL_RCP_API_VERSION < minHostRcpApiVersion)
298*cfb92d14SAndroid Build Coastguard Worker         {
299*cfb92d14SAndroid Build Coastguard Worker             LogCrit("RCP and host are using incompatible API versions");
300*cfb92d14SAndroid Build Coastguard Worker             LogCrit("RCP requires min host API version %u but host is older and at version %u", minHostRcpApiVersion,
301*cfb92d14SAndroid Build Coastguard Worker                     SPINEL_RCP_API_VERSION);
302*cfb92d14SAndroid Build Coastguard Worker             DieNow(OT_EXIT_RADIO_SPINEL_INCOMPATIBLE);
303*cfb92d14SAndroid Build Coastguard Worker         }
304*cfb92d14SAndroid Build Coastguard Worker     }
305*cfb92d14SAndroid Build Coastguard Worker 
306*cfb92d14SAndroid Build Coastguard Worker exit:
307*cfb92d14SAndroid Build Coastguard Worker     return error;
308*cfb92d14SAndroid Build Coastguard Worker }
309*cfb92d14SAndroid Build Coastguard Worker 
Deinit(void)310*cfb92d14SAndroid Build Coastguard Worker void RadioSpinel::Deinit(void)
311*cfb92d14SAndroid Build Coastguard Worker {
312*cfb92d14SAndroid Build Coastguard Worker     // This allows implementing pseudo reset.
313*cfb92d14SAndroid Build Coastguard Worker     new (this) RadioSpinel();
314*cfb92d14SAndroid Build Coastguard Worker }
315*cfb92d14SAndroid Build Coastguard Worker 
HandleNotification(const uint8_t * aFrame,uint16_t aLength,bool & aShouldSaveFrame)316*cfb92d14SAndroid Build Coastguard Worker void RadioSpinel::HandleNotification(const uint8_t *aFrame, uint16_t aLength, bool &aShouldSaveFrame)
317*cfb92d14SAndroid Build Coastguard Worker {
318*cfb92d14SAndroid Build Coastguard Worker     spinel_prop_key_t key;
319*cfb92d14SAndroid Build Coastguard Worker     spinel_size_t     len = 0;
320*cfb92d14SAndroid Build Coastguard Worker     spinel_ssize_t    unpacked;
321*cfb92d14SAndroid Build Coastguard Worker     uint8_t          *data = nullptr;
322*cfb92d14SAndroid Build Coastguard Worker     uint32_t          cmd;
323*cfb92d14SAndroid Build Coastguard Worker     uint8_t           header;
324*cfb92d14SAndroid Build Coastguard Worker     otError           error = OT_ERROR_NONE;
325*cfb92d14SAndroid Build Coastguard Worker 
326*cfb92d14SAndroid Build Coastguard Worker     aShouldSaveFrame = false;
327*cfb92d14SAndroid Build Coastguard Worker 
328*cfb92d14SAndroid Build Coastguard Worker     unpacked = spinel_datatype_unpack(aFrame, aLength, "CiiD", &header, &cmd, &key, &data, &len);
329*cfb92d14SAndroid Build Coastguard Worker 
330*cfb92d14SAndroid Build Coastguard Worker     EXPECT(unpacked > 0, error = OT_ERROR_PARSE);
331*cfb92d14SAndroid Build Coastguard Worker     EXPECT(SPINEL_HEADER_GET_TID(header) == 0, error = OT_ERROR_PARSE);
332*cfb92d14SAndroid Build Coastguard Worker 
333*cfb92d14SAndroid Build Coastguard Worker     switch (cmd)
334*cfb92d14SAndroid Build Coastguard Worker     {
335*cfb92d14SAndroid Build Coastguard Worker     case SPINEL_CMD_PROP_VALUE_IS:
336*cfb92d14SAndroid Build Coastguard Worker         // Some spinel properties cannot be handled during `WaitResponse()`, we must cache these events.
337*cfb92d14SAndroid Build Coastguard Worker         // `mWaitingTid` is released immediately after received the response. And `mWaitingKey` is be set
338*cfb92d14SAndroid Build Coastguard Worker         // to `SPINEL_PROP_LAST_STATUS` at the end of `WaitResponse()`.
339*cfb92d14SAndroid Build Coastguard Worker 
340*cfb92d14SAndroid Build Coastguard Worker         if (!IsSafeToHandleNow(key))
341*cfb92d14SAndroid Build Coastguard Worker         {
342*cfb92d14SAndroid Build Coastguard Worker             EXIT_NOW(aShouldSaveFrame = true);
343*cfb92d14SAndroid Build Coastguard Worker         }
344*cfb92d14SAndroid Build Coastguard Worker 
345*cfb92d14SAndroid Build Coastguard Worker         HandleValueIs(key, data, static_cast<uint16_t>(len));
346*cfb92d14SAndroid Build Coastguard Worker         break;
347*cfb92d14SAndroid Build Coastguard Worker 
348*cfb92d14SAndroid Build Coastguard Worker     case SPINEL_CMD_PROP_VALUE_INSERTED:
349*cfb92d14SAndroid Build Coastguard Worker     case SPINEL_CMD_PROP_VALUE_REMOVED:
350*cfb92d14SAndroid Build Coastguard Worker         LogInfo("Ignored command %lu", ToUlong(cmd));
351*cfb92d14SAndroid Build Coastguard Worker         break;
352*cfb92d14SAndroid Build Coastguard Worker 
353*cfb92d14SAndroid Build Coastguard Worker     default:
354*cfb92d14SAndroid Build Coastguard Worker         EXIT_NOW(error = OT_ERROR_PARSE);
355*cfb92d14SAndroid Build Coastguard Worker     }
356*cfb92d14SAndroid Build Coastguard Worker 
357*cfb92d14SAndroid Build Coastguard Worker exit:
358*cfb92d14SAndroid Build Coastguard Worker 
359*cfb92d14SAndroid Build Coastguard Worker     UpdateParseErrorCount(error);
360*cfb92d14SAndroid Build Coastguard Worker     LogIfFail("Error processing notification", error);
361*cfb92d14SAndroid Build Coastguard Worker }
362*cfb92d14SAndroid Build Coastguard Worker 
HandleNotification(const uint8_t * aFrame,uint16_t aLength)363*cfb92d14SAndroid Build Coastguard Worker void RadioSpinel::HandleNotification(const uint8_t *aFrame, uint16_t aLength)
364*cfb92d14SAndroid Build Coastguard Worker {
365*cfb92d14SAndroid Build Coastguard Worker     spinel_prop_key_t key;
366*cfb92d14SAndroid Build Coastguard Worker     spinel_size_t     len = 0;
367*cfb92d14SAndroid Build Coastguard Worker     spinel_ssize_t    unpacked;
368*cfb92d14SAndroid Build Coastguard Worker     uint8_t          *data = nullptr;
369*cfb92d14SAndroid Build Coastguard Worker     uint32_t          cmd;
370*cfb92d14SAndroid Build Coastguard Worker     uint8_t           header;
371*cfb92d14SAndroid Build Coastguard Worker     otError           error = OT_ERROR_NONE;
372*cfb92d14SAndroid Build Coastguard Worker 
373*cfb92d14SAndroid Build Coastguard Worker     unpacked = spinel_datatype_unpack(aFrame, aLength, "CiiD", &header, &cmd, &key, &data, &len);
374*cfb92d14SAndroid Build Coastguard Worker     EXPECT(unpacked > 0, error = OT_ERROR_PARSE);
375*cfb92d14SAndroid Build Coastguard Worker     EXPECT(SPINEL_HEADER_GET_TID(header) == 0, error = OT_ERROR_PARSE);
376*cfb92d14SAndroid Build Coastguard Worker     EXPECT(cmd == SPINEL_CMD_PROP_VALUE_IS, NO_ACTION);
377*cfb92d14SAndroid Build Coastguard Worker     HandleValueIs(key, data, static_cast<uint16_t>(len));
378*cfb92d14SAndroid Build Coastguard Worker 
379*cfb92d14SAndroid Build Coastguard Worker exit:
380*cfb92d14SAndroid Build Coastguard Worker     UpdateParseErrorCount(error);
381*cfb92d14SAndroid Build Coastguard Worker     LogIfFail("Error processing saved notification", error);
382*cfb92d14SAndroid Build Coastguard Worker }
383*cfb92d14SAndroid Build Coastguard Worker 
HandleResponse(const uint8_t * aBuffer,uint16_t aLength)384*cfb92d14SAndroid Build Coastguard Worker void RadioSpinel::HandleResponse(const uint8_t *aBuffer, uint16_t aLength)
385*cfb92d14SAndroid Build Coastguard Worker {
386*cfb92d14SAndroid Build Coastguard Worker     spinel_prop_key_t key;
387*cfb92d14SAndroid Build Coastguard Worker     uint8_t          *data   = nullptr;
388*cfb92d14SAndroid Build Coastguard Worker     spinel_size_t     len    = 0;
389*cfb92d14SAndroid Build Coastguard Worker     uint8_t           header = 0;
390*cfb92d14SAndroid Build Coastguard Worker     uint32_t          cmd    = 0;
391*cfb92d14SAndroid Build Coastguard Worker     spinel_ssize_t    rval   = 0;
392*cfb92d14SAndroid Build Coastguard Worker     otError           error  = OT_ERROR_NONE;
393*cfb92d14SAndroid Build Coastguard Worker 
394*cfb92d14SAndroid Build Coastguard Worker     rval = spinel_datatype_unpack(aBuffer, aLength, "CiiD", &header, &cmd, &key, &data, &len);
395*cfb92d14SAndroid Build Coastguard Worker     EXPECT(rval > 0 && cmd >= SPINEL_CMD_PROP_VALUE_IS && cmd <= SPINEL_CMD_PROP_VALUE_REMOVED, error = OT_ERROR_PARSE);
396*cfb92d14SAndroid Build Coastguard Worker 
397*cfb92d14SAndroid Build Coastguard Worker     if (mWaitingTid == SPINEL_HEADER_GET_TID(header))
398*cfb92d14SAndroid Build Coastguard Worker     {
399*cfb92d14SAndroid Build Coastguard Worker         HandleWaitingResponse(cmd, key, data, static_cast<uint16_t>(len));
400*cfb92d14SAndroid Build Coastguard Worker         FreeTid(mWaitingTid);
401*cfb92d14SAndroid Build Coastguard Worker         mWaitingTid = 0;
402*cfb92d14SAndroid Build Coastguard Worker     }
403*cfb92d14SAndroid Build Coastguard Worker     else if (mTxRadioTid == SPINEL_HEADER_GET_TID(header))
404*cfb92d14SAndroid Build Coastguard Worker     {
405*cfb92d14SAndroid Build Coastguard Worker         if (mState == kStateTransmitting)
406*cfb92d14SAndroid Build Coastguard Worker         {
407*cfb92d14SAndroid Build Coastguard Worker             HandleTransmitDone(cmd, key, data, static_cast<uint16_t>(len));
408*cfb92d14SAndroid Build Coastguard Worker         }
409*cfb92d14SAndroid Build Coastguard Worker 
410*cfb92d14SAndroid Build Coastguard Worker         FreeTid(mTxRadioTid);
411*cfb92d14SAndroid Build Coastguard Worker         mTxRadioTid = 0;
412*cfb92d14SAndroid Build Coastguard Worker     }
413*cfb92d14SAndroid Build Coastguard Worker     else
414*cfb92d14SAndroid Build Coastguard Worker     {
415*cfb92d14SAndroid Build Coastguard Worker         LogWarn("Unexpected Spinel transaction message: %u", SPINEL_HEADER_GET_TID(header));
416*cfb92d14SAndroid Build Coastguard Worker         error = OT_ERROR_DROP;
417*cfb92d14SAndroid Build Coastguard Worker     }
418*cfb92d14SAndroid Build Coastguard Worker 
419*cfb92d14SAndroid Build Coastguard Worker exit:
420*cfb92d14SAndroid Build Coastguard Worker     UpdateParseErrorCount(error);
421*cfb92d14SAndroid Build Coastguard Worker     LogIfFail("Error processing response", error);
422*cfb92d14SAndroid Build Coastguard Worker }
423*cfb92d14SAndroid Build Coastguard Worker 
HandleWaitingResponse(uint32_t aCommand,spinel_prop_key_t aKey,const uint8_t * aBuffer,uint16_t aLength)424*cfb92d14SAndroid Build Coastguard Worker void RadioSpinel::HandleWaitingResponse(uint32_t          aCommand,
425*cfb92d14SAndroid Build Coastguard Worker                                         spinel_prop_key_t aKey,
426*cfb92d14SAndroid Build Coastguard Worker                                         const uint8_t    *aBuffer,
427*cfb92d14SAndroid Build Coastguard Worker                                         uint16_t          aLength)
428*cfb92d14SAndroid Build Coastguard Worker {
429*cfb92d14SAndroid Build Coastguard Worker     if (aKey == SPINEL_PROP_LAST_STATUS)
430*cfb92d14SAndroid Build Coastguard Worker     {
431*cfb92d14SAndroid Build Coastguard Worker         spinel_status_t status;
432*cfb92d14SAndroid Build Coastguard Worker         spinel_ssize_t  unpacked = spinel_datatype_unpack(aBuffer, aLength, "i", &status);
433*cfb92d14SAndroid Build Coastguard Worker 
434*cfb92d14SAndroid Build Coastguard Worker         EXPECT(unpacked > 0, mError = OT_ERROR_PARSE);
435*cfb92d14SAndroid Build Coastguard Worker         mError = SpinelStatusToOtError(status);
436*cfb92d14SAndroid Build Coastguard Worker     }
437*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_CONFIG_DIAG_ENABLE
438*cfb92d14SAndroid Build Coastguard Worker     else if (aKey == SPINEL_PROP_NEST_STREAM_MFG)
439*cfb92d14SAndroid Build Coastguard Worker     {
440*cfb92d14SAndroid Build Coastguard Worker         spinel_ssize_t unpacked;
441*cfb92d14SAndroid Build Coastguard Worker         const char    *diagOutput;
442*cfb92d14SAndroid Build Coastguard Worker 
443*cfb92d14SAndroid Build Coastguard Worker         mError = OT_ERROR_NONE;
444*cfb92d14SAndroid Build Coastguard Worker         EXPECT(mOutputCallback != nullptr, NO_ACTION);
445*cfb92d14SAndroid Build Coastguard Worker         unpacked = spinel_datatype_unpack(aBuffer, aLength, SPINEL_DATATYPE_UTF8_S, &diagOutput);
446*cfb92d14SAndroid Build Coastguard Worker         EXPECT(unpacked > 0, mError = OT_ERROR_PARSE);
447*cfb92d14SAndroid Build Coastguard Worker         PlatDiagOutput("%s", diagOutput);
448*cfb92d14SAndroid Build Coastguard Worker     }
449*cfb92d14SAndroid Build Coastguard Worker #endif
450*cfb92d14SAndroid Build Coastguard Worker     else if (aKey == mWaitingKey)
451*cfb92d14SAndroid Build Coastguard Worker     {
452*cfb92d14SAndroid Build Coastguard Worker         if (mPropertyFormat)
453*cfb92d14SAndroid Build Coastguard Worker         {
454*cfb92d14SAndroid Build Coastguard Worker             if (static_cast<spinel_datatype_t>(mPropertyFormat[0]) == SPINEL_DATATYPE_VOID_C)
455*cfb92d14SAndroid Build Coastguard Worker             {
456*cfb92d14SAndroid Build Coastguard Worker                 // reserved SPINEL_DATATYPE_VOID_C indicate caller want to parse the spinel response itself
457*cfb92d14SAndroid Build Coastguard Worker                 ResponseHandler handler = va_arg(mPropertyArgs, ResponseHandler);
458*cfb92d14SAndroid Build Coastguard Worker 
459*cfb92d14SAndroid Build Coastguard Worker                 assert(handler != nullptr);
460*cfb92d14SAndroid Build Coastguard Worker                 mError = (this->*handler)(aBuffer, aLength);
461*cfb92d14SAndroid Build Coastguard Worker             }
462*cfb92d14SAndroid Build Coastguard Worker             else
463*cfb92d14SAndroid Build Coastguard Worker             {
464*cfb92d14SAndroid Build Coastguard Worker                 spinel_ssize_t unpacked =
465*cfb92d14SAndroid Build Coastguard Worker                     spinel_datatype_vunpack_in_place(aBuffer, aLength, mPropertyFormat, mPropertyArgs);
466*cfb92d14SAndroid Build Coastguard Worker 
467*cfb92d14SAndroid Build Coastguard Worker                 EXPECT(unpacked > 0, mError = OT_ERROR_PARSE);
468*cfb92d14SAndroid Build Coastguard Worker                 mError = OT_ERROR_NONE;
469*cfb92d14SAndroid Build Coastguard Worker             }
470*cfb92d14SAndroid Build Coastguard Worker         }
471*cfb92d14SAndroid Build Coastguard Worker         else
472*cfb92d14SAndroid Build Coastguard Worker         {
473*cfb92d14SAndroid Build Coastguard Worker             if (aCommand == mExpectedCommand)
474*cfb92d14SAndroid Build Coastguard Worker             {
475*cfb92d14SAndroid Build Coastguard Worker                 mError = OT_ERROR_NONE;
476*cfb92d14SAndroid Build Coastguard Worker             }
477*cfb92d14SAndroid Build Coastguard Worker             else
478*cfb92d14SAndroid Build Coastguard Worker             {
479*cfb92d14SAndroid Build Coastguard Worker                 mError = OT_ERROR_DROP;
480*cfb92d14SAndroid Build Coastguard Worker             }
481*cfb92d14SAndroid Build Coastguard Worker         }
482*cfb92d14SAndroid Build Coastguard Worker     }
483*cfb92d14SAndroid Build Coastguard Worker     else
484*cfb92d14SAndroid Build Coastguard Worker     {
485*cfb92d14SAndroid Build Coastguard Worker         mError = OT_ERROR_DROP;
486*cfb92d14SAndroid Build Coastguard Worker     }
487*cfb92d14SAndroid Build Coastguard Worker 
488*cfb92d14SAndroid Build Coastguard Worker exit:
489*cfb92d14SAndroid Build Coastguard Worker     UpdateParseErrorCount(mError);
490*cfb92d14SAndroid Build Coastguard Worker     LogIfFail("Error processing result", mError);
491*cfb92d14SAndroid Build Coastguard Worker }
492*cfb92d14SAndroid Build Coastguard Worker 
HandleValueIs(spinel_prop_key_t aKey,const uint8_t * aBuffer,uint16_t aLength)493*cfb92d14SAndroid Build Coastguard Worker void RadioSpinel::HandleValueIs(spinel_prop_key_t aKey, const uint8_t *aBuffer, uint16_t aLength)
494*cfb92d14SAndroid Build Coastguard Worker {
495*cfb92d14SAndroid Build Coastguard Worker     otError        error = OT_ERROR_NONE;
496*cfb92d14SAndroid Build Coastguard Worker     spinel_ssize_t unpacked;
497*cfb92d14SAndroid Build Coastguard Worker 
498*cfb92d14SAndroid Build Coastguard Worker     if (aKey == SPINEL_PROP_STREAM_RAW)
499*cfb92d14SAndroid Build Coastguard Worker     {
500*cfb92d14SAndroid Build Coastguard Worker         EXPECT_NO_ERROR(error = ParseRadioFrame(mRxRadioFrame, aBuffer, aLength, unpacked));
501*cfb92d14SAndroid Build Coastguard Worker         RadioReceive();
502*cfb92d14SAndroid Build Coastguard Worker     }
503*cfb92d14SAndroid Build Coastguard Worker     else if (aKey == SPINEL_PROP_LAST_STATUS)
504*cfb92d14SAndroid Build Coastguard Worker     {
505*cfb92d14SAndroid Build Coastguard Worker         spinel_status_t status = SPINEL_STATUS_OK;
506*cfb92d14SAndroid Build Coastguard Worker 
507*cfb92d14SAndroid Build Coastguard Worker         unpacked = spinel_datatype_unpack(aBuffer, aLength, "i", &status);
508*cfb92d14SAndroid Build Coastguard Worker         EXPECT(unpacked > 0, error = OT_ERROR_PARSE);
509*cfb92d14SAndroid Build Coastguard Worker 
510*cfb92d14SAndroid Build Coastguard Worker         if (status >= SPINEL_STATUS_RESET__BEGIN && status <= SPINEL_STATUS_RESET__END)
511*cfb92d14SAndroid Build Coastguard Worker         {
512*cfb92d14SAndroid Build Coastguard Worker             if (IsEnabled())
513*cfb92d14SAndroid Build Coastguard Worker             {
514*cfb92d14SAndroid Build Coastguard Worker                 HandleRcpUnexpectedReset(status);
515*cfb92d14SAndroid Build Coastguard Worker                 EXIT_NOW();
516*cfb92d14SAndroid Build Coastguard Worker             }
517*cfb92d14SAndroid Build Coastguard Worker 
518*cfb92d14SAndroid Build Coastguard Worker             // this clear is necessary in case the RCP has sent messages between disable and reset
519*cfb92d14SAndroid Build Coastguard Worker             mSpinelDriver->ClearRxBuffer();
520*cfb92d14SAndroid Build Coastguard Worker             mSpinelDriver->SetCoprocessorReady();
521*cfb92d14SAndroid Build Coastguard Worker 
522*cfb92d14SAndroid Build Coastguard Worker             LogInfo("RCP reset: %s", spinel_status_to_cstr(status));
523*cfb92d14SAndroid Build Coastguard Worker         }
524*cfb92d14SAndroid Build Coastguard Worker         else if (status == SPINEL_STATUS_SWITCHOVER_DONE || status == SPINEL_STATUS_SWITCHOVER_FAILED)
525*cfb92d14SAndroid Build Coastguard Worker         {
526*cfb92d14SAndroid Build Coastguard Worker             if (mCallbacks.mSwitchoverDone != nullptr)
527*cfb92d14SAndroid Build Coastguard Worker             {
528*cfb92d14SAndroid Build Coastguard Worker                 mCallbacks.mSwitchoverDone(mInstance, status == SPINEL_STATUS_SWITCHOVER_DONE);
529*cfb92d14SAndroid Build Coastguard Worker             }
530*cfb92d14SAndroid Build Coastguard Worker         }
531*cfb92d14SAndroid Build Coastguard Worker         else
532*cfb92d14SAndroid Build Coastguard Worker         {
533*cfb92d14SAndroid Build Coastguard Worker             LogInfo("RCP last status: %s", spinel_status_to_cstr(status));
534*cfb92d14SAndroid Build Coastguard Worker         }
535*cfb92d14SAndroid Build Coastguard Worker     }
536*cfb92d14SAndroid Build Coastguard Worker     else if (aKey == SPINEL_PROP_MAC_ENERGY_SCAN_RESULT)
537*cfb92d14SAndroid Build Coastguard Worker     {
538*cfb92d14SAndroid Build Coastguard Worker         uint8_t scanChannel;
539*cfb92d14SAndroid Build Coastguard Worker         int8_t  maxRssi;
540*cfb92d14SAndroid Build Coastguard Worker 
541*cfb92d14SAndroid Build Coastguard Worker         unpacked = spinel_datatype_unpack(aBuffer, aLength, "Cc", &scanChannel, &maxRssi);
542*cfb92d14SAndroid Build Coastguard Worker 
543*cfb92d14SAndroid Build Coastguard Worker         EXPECT(unpacked > 0, error = OT_ERROR_PARSE);
544*cfb92d14SAndroid Build Coastguard Worker 
545*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0
546*cfb92d14SAndroid Build Coastguard Worker         mEnergyScanning = false;
547*cfb92d14SAndroid Build Coastguard Worker #endif
548*cfb92d14SAndroid Build Coastguard Worker 
549*cfb92d14SAndroid Build Coastguard Worker         mCallbacks.mEnergyScanDone(mInstance, maxRssi);
550*cfb92d14SAndroid Build Coastguard Worker     }
551*cfb92d14SAndroid Build Coastguard Worker     else if (aKey == SPINEL_PROP_STREAM_DEBUG)
552*cfb92d14SAndroid Build Coastguard Worker     {
553*cfb92d14SAndroid Build Coastguard Worker         char         logStream[OPENTHREAD_CONFIG_NCP_SPINEL_LOG_MAX_SIZE + 1];
554*cfb92d14SAndroid Build Coastguard Worker         unsigned int len = sizeof(logStream);
555*cfb92d14SAndroid Build Coastguard Worker 
556*cfb92d14SAndroid Build Coastguard Worker         unpacked = spinel_datatype_unpack_in_place(aBuffer, aLength, SPINEL_DATATYPE_DATA_S, logStream, &len);
557*cfb92d14SAndroid Build Coastguard Worker         assert(len < sizeof(logStream));
558*cfb92d14SAndroid Build Coastguard Worker         EXPECT(unpacked > 0, error = OT_ERROR_PARSE);
559*cfb92d14SAndroid Build Coastguard Worker         logStream[len] = '\0';
560*cfb92d14SAndroid Build Coastguard Worker         LogDebg("RCP => %s", logStream);
561*cfb92d14SAndroid Build Coastguard Worker     }
562*cfb92d14SAndroid Build Coastguard Worker     else if ((aKey == SPINEL_PROP_STREAM_LOG) && sSupportsLogStream)
563*cfb92d14SAndroid Build Coastguard Worker     {
564*cfb92d14SAndroid Build Coastguard Worker         const char *logString;
565*cfb92d14SAndroid Build Coastguard Worker         uint8_t     logLevel;
566*cfb92d14SAndroid Build Coastguard Worker 
567*cfb92d14SAndroid Build Coastguard Worker         unpacked = spinel_datatype_unpack(aBuffer, aLength, SPINEL_DATATYPE_UTF8_S, &logString);
568*cfb92d14SAndroid Build Coastguard Worker         EXPECT(unpacked >= 0, error = OT_ERROR_PARSE);
569*cfb92d14SAndroid Build Coastguard Worker         aBuffer += unpacked;
570*cfb92d14SAndroid Build Coastguard Worker         aLength -= unpacked;
571*cfb92d14SAndroid Build Coastguard Worker 
572*cfb92d14SAndroid Build Coastguard Worker         unpacked = spinel_datatype_unpack(aBuffer, aLength, SPINEL_DATATYPE_UINT8_S, &logLevel);
573*cfb92d14SAndroid Build Coastguard Worker         EXPECT(unpacked > 0, error = OT_ERROR_PARSE);
574*cfb92d14SAndroid Build Coastguard Worker 
575*cfb92d14SAndroid Build Coastguard Worker         switch (logLevel)
576*cfb92d14SAndroid Build Coastguard Worker         {
577*cfb92d14SAndroid Build Coastguard Worker         case SPINEL_NCP_LOG_LEVEL_EMERG:
578*cfb92d14SAndroid Build Coastguard Worker         case SPINEL_NCP_LOG_LEVEL_ALERT:
579*cfb92d14SAndroid Build Coastguard Worker         case SPINEL_NCP_LOG_LEVEL_CRIT:
580*cfb92d14SAndroid Build Coastguard Worker             LogCrit("RCP => %s", logString);
581*cfb92d14SAndroid Build Coastguard Worker             break;
582*cfb92d14SAndroid Build Coastguard Worker 
583*cfb92d14SAndroid Build Coastguard Worker         case SPINEL_NCP_LOG_LEVEL_ERR:
584*cfb92d14SAndroid Build Coastguard Worker         case SPINEL_NCP_LOG_LEVEL_WARN:
585*cfb92d14SAndroid Build Coastguard Worker             LogWarn("RCP => %s", logString);
586*cfb92d14SAndroid Build Coastguard Worker             break;
587*cfb92d14SAndroid Build Coastguard Worker 
588*cfb92d14SAndroid Build Coastguard Worker         case SPINEL_NCP_LOG_LEVEL_NOTICE:
589*cfb92d14SAndroid Build Coastguard Worker             LogNote("RCP => %s", logString);
590*cfb92d14SAndroid Build Coastguard Worker             break;
591*cfb92d14SAndroid Build Coastguard Worker 
592*cfb92d14SAndroid Build Coastguard Worker         case SPINEL_NCP_LOG_LEVEL_INFO:
593*cfb92d14SAndroid Build Coastguard Worker             LogInfo("RCP => %s", logString);
594*cfb92d14SAndroid Build Coastguard Worker             break;
595*cfb92d14SAndroid Build Coastguard Worker 
596*cfb92d14SAndroid Build Coastguard Worker         case SPINEL_NCP_LOG_LEVEL_DEBUG:
597*cfb92d14SAndroid Build Coastguard Worker         default:
598*cfb92d14SAndroid Build Coastguard Worker             LogDebg("RCP => %s", logString);
599*cfb92d14SAndroid Build Coastguard Worker             break;
600*cfb92d14SAndroid Build Coastguard Worker         }
601*cfb92d14SAndroid Build Coastguard Worker     }
602*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_CONFIG_DIAG_ENABLE
603*cfb92d14SAndroid Build Coastguard Worker     else if (aKey == SPINEL_PROP_NEST_STREAM_MFG)
604*cfb92d14SAndroid Build Coastguard Worker     {
605*cfb92d14SAndroid Build Coastguard Worker         const char *diagOutput;
606*cfb92d14SAndroid Build Coastguard Worker 
607*cfb92d14SAndroid Build Coastguard Worker         EXPECT(mOutputCallback != nullptr, NO_ACTION);
608*cfb92d14SAndroid Build Coastguard Worker         unpacked = spinel_datatype_unpack(aBuffer, aLength, SPINEL_DATATYPE_UTF8_S, &diagOutput);
609*cfb92d14SAndroid Build Coastguard Worker         EXPECT(unpacked > 0, error = OT_ERROR_PARSE);
610*cfb92d14SAndroid Build Coastguard Worker         PlatDiagOutput("%s", diagOutput);
611*cfb92d14SAndroid Build Coastguard Worker     }
612*cfb92d14SAndroid Build Coastguard Worker #endif
613*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_SPINEL_CONFIG_VENDOR_HOOK_ENABLE
614*cfb92d14SAndroid Build Coastguard Worker     else if (aKey >= SPINEL_PROP_VENDOR__BEGIN && aKey < SPINEL_PROP_VENDOR__END)
615*cfb92d14SAndroid Build Coastguard Worker     {
616*cfb92d14SAndroid Build Coastguard Worker         error = VendorHandleValueIs(aKey);
617*cfb92d14SAndroid Build Coastguard Worker     }
618*cfb92d14SAndroid Build Coastguard Worker #endif
619*cfb92d14SAndroid Build Coastguard Worker 
620*cfb92d14SAndroid Build Coastguard Worker exit:
621*cfb92d14SAndroid Build Coastguard Worker     UpdateParseErrorCount(error);
622*cfb92d14SAndroid Build Coastguard Worker     LogIfFail("Failed to handle ValueIs", error);
623*cfb92d14SAndroid Build Coastguard Worker }
624*cfb92d14SAndroid Build Coastguard Worker 
625*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_SPINEL_CONFIG_VENDOR_HOOK_ENABLE
SetVendorRestorePropertiesCallback(otRadioSpinelVendorRestorePropertiesCallback aCallback,void * aContext)626*cfb92d14SAndroid Build Coastguard Worker void RadioSpinel::SetVendorRestorePropertiesCallback(otRadioSpinelVendorRestorePropertiesCallback aCallback,
627*cfb92d14SAndroid Build Coastguard Worker                                                      void                                        *aContext)
628*cfb92d14SAndroid Build Coastguard Worker {
629*cfb92d14SAndroid Build Coastguard Worker     mVendorRestorePropertiesCallback = aCallback;
630*cfb92d14SAndroid Build Coastguard Worker     mVendorRestorePropertiesContext  = aContext;
631*cfb92d14SAndroid Build Coastguard Worker }
632*cfb92d14SAndroid Build Coastguard Worker #endif
633*cfb92d14SAndroid Build Coastguard Worker 
GetSpinelDriver(void) const634*cfb92d14SAndroid Build Coastguard Worker SpinelDriver &RadioSpinel::GetSpinelDriver(void) const
635*cfb92d14SAndroid Build Coastguard Worker {
636*cfb92d14SAndroid Build Coastguard Worker     OT_ASSERT(mSpinelDriver != nullptr);
637*cfb92d14SAndroid Build Coastguard Worker     return *mSpinelDriver;
638*cfb92d14SAndroid Build Coastguard Worker }
639*cfb92d14SAndroid Build Coastguard Worker 
SendReset(uint8_t aResetType)640*cfb92d14SAndroid Build Coastguard Worker otError RadioSpinel::SendReset(uint8_t aResetType)
641*cfb92d14SAndroid Build Coastguard Worker {
642*cfb92d14SAndroid Build Coastguard Worker     otError error;
643*cfb92d14SAndroid Build Coastguard Worker 
644*cfb92d14SAndroid Build Coastguard Worker     if ((aResetType == SPINEL_RESET_BOOTLOADER) && !sSupportsResetToBootloader)
645*cfb92d14SAndroid Build Coastguard Worker     {
646*cfb92d14SAndroid Build Coastguard Worker         EXIT_NOW(error = OT_ERROR_NOT_CAPABLE);
647*cfb92d14SAndroid Build Coastguard Worker     }
648*cfb92d14SAndroid Build Coastguard Worker     error = GetSpinelDriver().SendReset(aResetType);
649*cfb92d14SAndroid Build Coastguard Worker 
650*cfb92d14SAndroid Build Coastguard Worker exit:
651*cfb92d14SAndroid Build Coastguard Worker     return error;
652*cfb92d14SAndroid Build Coastguard Worker }
653*cfb92d14SAndroid Build Coastguard Worker 
ParseRadioFrame(otRadioFrame & aFrame,const uint8_t * aBuffer,uint16_t aLength,spinel_ssize_t & aUnpacked)654*cfb92d14SAndroid Build Coastguard Worker otError RadioSpinel::ParseRadioFrame(otRadioFrame   &aFrame,
655*cfb92d14SAndroid Build Coastguard Worker                                      const uint8_t  *aBuffer,
656*cfb92d14SAndroid Build Coastguard Worker                                      uint16_t        aLength,
657*cfb92d14SAndroid Build Coastguard Worker                                      spinel_ssize_t &aUnpacked)
658*cfb92d14SAndroid Build Coastguard Worker {
659*cfb92d14SAndroid Build Coastguard Worker     otError        error        = OT_ERROR_NONE;
660*cfb92d14SAndroid Build Coastguard Worker     uint16_t       flags        = 0;
661*cfb92d14SAndroid Build Coastguard Worker     int8_t         noiseFloor   = -128;
662*cfb92d14SAndroid Build Coastguard Worker     spinel_size_t  size         = OT_RADIO_FRAME_MAX_SIZE;
663*cfb92d14SAndroid Build Coastguard Worker     unsigned int   receiveError = 0;
664*cfb92d14SAndroid Build Coastguard Worker     spinel_ssize_t unpacked;
665*cfb92d14SAndroid Build Coastguard Worker 
666*cfb92d14SAndroid Build Coastguard Worker     EXPECT(aLength > 0, aFrame.mLength = 0);
667*cfb92d14SAndroid Build Coastguard Worker 
668*cfb92d14SAndroid Build Coastguard Worker     unpacked = spinel_datatype_unpack_in_place(aBuffer, aLength,
669*cfb92d14SAndroid Build Coastguard Worker                                                SPINEL_DATATYPE_DATA_WLEN_S                          // Frame
670*cfb92d14SAndroid Build Coastguard Worker                                                    SPINEL_DATATYPE_INT8_S                           // RSSI
671*cfb92d14SAndroid Build Coastguard Worker                                                        SPINEL_DATATYPE_INT8_S                       // Noise Floor
672*cfb92d14SAndroid Build Coastguard Worker                                                            SPINEL_DATATYPE_UINT16_S                 // Flags
673*cfb92d14SAndroid Build Coastguard Worker                                                                SPINEL_DATATYPE_STRUCT_S(            // PHY-data
674*cfb92d14SAndroid Build Coastguard Worker                                                                    SPINEL_DATATYPE_UINT8_S          // 802.15.4 channel
675*cfb92d14SAndroid Build Coastguard Worker                                                                        SPINEL_DATATYPE_UINT8_S      // 802.15.4 LQI
676*cfb92d14SAndroid Build Coastguard Worker                                                                            SPINEL_DATATYPE_UINT64_S // Timestamp (us).
677*cfb92d14SAndroid Build Coastguard Worker                                                                    ) SPINEL_DATATYPE_STRUCT_S(      // Vendor-data
678*cfb92d14SAndroid Build Coastguard Worker                                                                    SPINEL_DATATYPE_UINT_PACKED_S    // Receive error
679*cfb92d14SAndroid Build Coastguard Worker                                                                    ),
680*cfb92d14SAndroid Build Coastguard Worker                                                aFrame.mPsdu, &size, &aFrame.mInfo.mRxInfo.mRssi, &noiseFloor, &flags,
681*cfb92d14SAndroid Build Coastguard Worker                                                &aFrame.mChannel, &aFrame.mInfo.mRxInfo.mLqi,
682*cfb92d14SAndroid Build Coastguard Worker                                                &aFrame.mInfo.mRxInfo.mTimestamp, &receiveError);
683*cfb92d14SAndroid Build Coastguard Worker 
684*cfb92d14SAndroid Build Coastguard Worker     EXPECT(unpacked > 0, error = OT_ERROR_PARSE);
685*cfb92d14SAndroid Build Coastguard Worker     aUnpacked = unpacked;
686*cfb92d14SAndroid Build Coastguard Worker 
687*cfb92d14SAndroid Build Coastguard Worker     aBuffer += unpacked;
688*cfb92d14SAndroid Build Coastguard Worker     aLength -= static_cast<uint16_t>(unpacked);
689*cfb92d14SAndroid Build Coastguard Worker 
690*cfb92d14SAndroid Build Coastguard Worker     if (sRadioCaps & OT_RADIO_CAPS_TRANSMIT_SEC)
691*cfb92d14SAndroid Build Coastguard Worker     {
692*cfb92d14SAndroid Build Coastguard Worker         unpacked =
693*cfb92d14SAndroid Build Coastguard Worker             spinel_datatype_unpack_in_place(aBuffer, aLength,
694*cfb92d14SAndroid Build Coastguard Worker                                             SPINEL_DATATYPE_STRUCT_S(        // MAC-data
695*cfb92d14SAndroid Build Coastguard Worker                                                 SPINEL_DATATYPE_UINT8_S      // Security key index
696*cfb92d14SAndroid Build Coastguard Worker                                                     SPINEL_DATATYPE_UINT32_S // Security frame counter
697*cfb92d14SAndroid Build Coastguard Worker                                                 ),
698*cfb92d14SAndroid Build Coastguard Worker                                             &aFrame.mInfo.mRxInfo.mAckKeyId, &aFrame.mInfo.mRxInfo.mAckFrameCounter);
699*cfb92d14SAndroid Build Coastguard Worker 
700*cfb92d14SAndroid Build Coastguard Worker         EXPECT(unpacked > 0, error = OT_ERROR_PARSE);
701*cfb92d14SAndroid Build Coastguard Worker         aUnpacked += unpacked;
702*cfb92d14SAndroid Build Coastguard Worker 
703*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0
704*cfb92d14SAndroid Build Coastguard Worker         if (flags & SPINEL_MD_FLAG_ACKED_SEC)
705*cfb92d14SAndroid Build Coastguard Worker         {
706*cfb92d14SAndroid Build Coastguard Worker             mMacFrameCounterSet = true;
707*cfb92d14SAndroid Build Coastguard Worker         }
708*cfb92d14SAndroid Build Coastguard Worker #endif
709*cfb92d14SAndroid Build Coastguard Worker     }
710*cfb92d14SAndroid Build Coastguard Worker 
711*cfb92d14SAndroid Build Coastguard Worker     if (receiveError == OT_ERROR_NONE)
712*cfb92d14SAndroid Build Coastguard Worker     {
713*cfb92d14SAndroid Build Coastguard Worker         aFrame.mLength = static_cast<uint8_t>(size);
714*cfb92d14SAndroid Build Coastguard Worker 
715*cfb92d14SAndroid Build Coastguard Worker         aFrame.mInfo.mRxInfo.mAckedWithFramePending = ((flags & SPINEL_MD_FLAG_ACKED_FP) != 0);
716*cfb92d14SAndroid Build Coastguard Worker         aFrame.mInfo.mRxInfo.mAckedWithSecEnhAck    = ((flags & SPINEL_MD_FLAG_ACKED_SEC) != 0);
717*cfb92d14SAndroid Build Coastguard Worker     }
718*cfb92d14SAndroid Build Coastguard Worker     else if (receiveError < OT_NUM_ERRORS)
719*cfb92d14SAndroid Build Coastguard Worker     {
720*cfb92d14SAndroid Build Coastguard Worker         error = static_cast<otError>(receiveError);
721*cfb92d14SAndroid Build Coastguard Worker     }
722*cfb92d14SAndroid Build Coastguard Worker     else
723*cfb92d14SAndroid Build Coastguard Worker     {
724*cfb92d14SAndroid Build Coastguard Worker         error = OT_ERROR_PARSE;
725*cfb92d14SAndroid Build Coastguard Worker     }
726*cfb92d14SAndroid Build Coastguard Worker 
727*cfb92d14SAndroid Build Coastguard Worker exit:
728*cfb92d14SAndroid Build Coastguard Worker     UpdateParseErrorCount(error);
729*cfb92d14SAndroid Build Coastguard Worker     LogIfFail("Handle radio frame failed", error);
730*cfb92d14SAndroid Build Coastguard Worker     return error;
731*cfb92d14SAndroid Build Coastguard Worker }
732*cfb92d14SAndroid Build Coastguard Worker 
RadioReceive(void)733*cfb92d14SAndroid Build Coastguard Worker void RadioSpinel::RadioReceive(void)
734*cfb92d14SAndroid Build Coastguard Worker {
735*cfb92d14SAndroid Build Coastguard Worker     if (!mIsPromiscuous)
736*cfb92d14SAndroid Build Coastguard Worker     {
737*cfb92d14SAndroid Build Coastguard Worker         switch (mState)
738*cfb92d14SAndroid Build Coastguard Worker         {
739*cfb92d14SAndroid Build Coastguard Worker         case kStateDisabled:
740*cfb92d14SAndroid Build Coastguard Worker         case kStateSleep:
741*cfb92d14SAndroid Build Coastguard Worker             EXIT_NOW();
742*cfb92d14SAndroid Build Coastguard Worker 
743*cfb92d14SAndroid Build Coastguard Worker         case kStateReceive:
744*cfb92d14SAndroid Build Coastguard Worker         case kStateTransmitting:
745*cfb92d14SAndroid Build Coastguard Worker         case kStateTransmitDone:
746*cfb92d14SAndroid Build Coastguard Worker             break;
747*cfb92d14SAndroid Build Coastguard Worker         }
748*cfb92d14SAndroid Build Coastguard Worker     }
749*cfb92d14SAndroid Build Coastguard Worker 
750*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_CONFIG_DIAG_ENABLE
751*cfb92d14SAndroid Build Coastguard Worker     if (otPlatDiagModeGet())
752*cfb92d14SAndroid Build Coastguard Worker     {
753*cfb92d14SAndroid Build Coastguard Worker         mCallbacks.mDiagReceiveDone(mInstance, &mRxRadioFrame, OT_ERROR_NONE);
754*cfb92d14SAndroid Build Coastguard Worker     }
755*cfb92d14SAndroid Build Coastguard Worker     else
756*cfb92d14SAndroid Build Coastguard Worker #endif
757*cfb92d14SAndroid Build Coastguard Worker     {
758*cfb92d14SAndroid Build Coastguard Worker         mCallbacks.mReceiveDone(mInstance, &mRxRadioFrame, OT_ERROR_NONE);
759*cfb92d14SAndroid Build Coastguard Worker     }
760*cfb92d14SAndroid Build Coastguard Worker exit:
761*cfb92d14SAndroid Build Coastguard Worker     return;
762*cfb92d14SAndroid Build Coastguard Worker }
763*cfb92d14SAndroid Build Coastguard Worker 
TransmitDone(otRadioFrame * aFrame,otRadioFrame * aAckFrame,otError aError)764*cfb92d14SAndroid Build Coastguard Worker void RadioSpinel::TransmitDone(otRadioFrame *aFrame, otRadioFrame *aAckFrame, otError aError)
765*cfb92d14SAndroid Build Coastguard Worker {
766*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_CONFIG_DIAG_ENABLE
767*cfb92d14SAndroid Build Coastguard Worker     if (otPlatDiagModeGet())
768*cfb92d14SAndroid Build Coastguard Worker     {
769*cfb92d14SAndroid Build Coastguard Worker         mCallbacks.mDiagTransmitDone(mInstance, aFrame, aError);
770*cfb92d14SAndroid Build Coastguard Worker     }
771*cfb92d14SAndroid Build Coastguard Worker     else
772*cfb92d14SAndroid Build Coastguard Worker #endif
773*cfb92d14SAndroid Build Coastguard Worker     {
774*cfb92d14SAndroid Build Coastguard Worker         mCallbacks.mTransmitDone(mInstance, aFrame, aAckFrame, aError);
775*cfb92d14SAndroid Build Coastguard Worker     }
776*cfb92d14SAndroid Build Coastguard Worker }
777*cfb92d14SAndroid Build Coastguard Worker 
ProcessRadioStateMachine(void)778*cfb92d14SAndroid Build Coastguard Worker void RadioSpinel::ProcessRadioStateMachine(void)
779*cfb92d14SAndroid Build Coastguard Worker {
780*cfb92d14SAndroid Build Coastguard Worker     if (mState == kStateTransmitDone)
781*cfb92d14SAndroid Build Coastguard Worker     {
782*cfb92d14SAndroid Build Coastguard Worker         mState        = kStateReceive;
783*cfb92d14SAndroid Build Coastguard Worker         mTxRadioEndUs = UINT64_MAX;
784*cfb92d14SAndroid Build Coastguard Worker 
785*cfb92d14SAndroid Build Coastguard Worker         TransmitDone(mTransmitFrame, (mAckRadioFrame.mLength != 0) ? &mAckRadioFrame : nullptr, mTxError);
786*cfb92d14SAndroid Build Coastguard Worker     }
787*cfb92d14SAndroid Build Coastguard Worker     else if (mState == kStateTransmitting && otPlatTimeGet() >= mTxRadioEndUs)
788*cfb92d14SAndroid Build Coastguard Worker     {
789*cfb92d14SAndroid Build Coastguard Worker         // Frame has been successfully passed to radio, but no `TransmitDone` event received within kTxWaitUs.
790*cfb92d14SAndroid Build Coastguard Worker         LogWarn("radio tx timeout");
791*cfb92d14SAndroid Build Coastguard Worker         HandleRcpTimeout();
792*cfb92d14SAndroid Build Coastguard Worker     }
793*cfb92d14SAndroid Build Coastguard Worker }
794*cfb92d14SAndroid Build Coastguard Worker 
Process(const void * aContext)795*cfb92d14SAndroid Build Coastguard Worker void RadioSpinel::Process(const void *aContext)
796*cfb92d14SAndroid Build Coastguard Worker {
797*cfb92d14SAndroid Build Coastguard Worker     OT_UNUSED_VARIABLE(aContext);
798*cfb92d14SAndroid Build Coastguard Worker 
799*cfb92d14SAndroid Build Coastguard Worker     ProcessRadioStateMachine();
800*cfb92d14SAndroid Build Coastguard Worker     RecoverFromRcpFailure();
801*cfb92d14SAndroid Build Coastguard Worker 
802*cfb92d14SAndroid Build Coastguard Worker     if (mTimeSyncEnabled)
803*cfb92d14SAndroid Build Coastguard Worker     {
804*cfb92d14SAndroid Build Coastguard Worker         CalcRcpTimeOffset();
805*cfb92d14SAndroid Build Coastguard Worker     }
806*cfb92d14SAndroid Build Coastguard Worker }
807*cfb92d14SAndroid Build Coastguard Worker 
SetPromiscuous(bool aEnable)808*cfb92d14SAndroid Build Coastguard Worker otError RadioSpinel::SetPromiscuous(bool aEnable)
809*cfb92d14SAndroid Build Coastguard Worker {
810*cfb92d14SAndroid Build Coastguard Worker     otError error;
811*cfb92d14SAndroid Build Coastguard Worker 
812*cfb92d14SAndroid Build Coastguard Worker     uint8_t mode = (aEnable ? SPINEL_MAC_PROMISCUOUS_MODE_NETWORK : SPINEL_MAC_PROMISCUOUS_MODE_OFF);
813*cfb92d14SAndroid Build Coastguard Worker     EXPECT_NO_ERROR(error = Set(SPINEL_PROP_MAC_PROMISCUOUS_MODE, SPINEL_DATATYPE_UINT8_S, mode));
814*cfb92d14SAndroid Build Coastguard Worker     mIsPromiscuous = aEnable;
815*cfb92d14SAndroid Build Coastguard Worker 
816*cfb92d14SAndroid Build Coastguard Worker exit:
817*cfb92d14SAndroid Build Coastguard Worker     return error;
818*cfb92d14SAndroid Build Coastguard Worker }
819*cfb92d14SAndroid Build Coastguard Worker 
SetRxOnWhenIdle(bool aEnable)820*cfb92d14SAndroid Build Coastguard Worker otError RadioSpinel::SetRxOnWhenIdle(bool aEnable)
821*cfb92d14SAndroid Build Coastguard Worker {
822*cfb92d14SAndroid Build Coastguard Worker     otError error = OT_ERROR_NONE;
823*cfb92d14SAndroid Build Coastguard Worker 
824*cfb92d14SAndroid Build Coastguard Worker     EXPECT(mRxOnWhenIdle != aEnable, NO_ACTION);
825*cfb92d14SAndroid Build Coastguard Worker     EXPECT_NO_ERROR(error = Set(SPINEL_PROP_MAC_RX_ON_WHEN_IDLE_MODE, SPINEL_DATATYPE_BOOL_S, aEnable));
826*cfb92d14SAndroid Build Coastguard Worker     mRxOnWhenIdle = aEnable;
827*cfb92d14SAndroid Build Coastguard Worker 
828*cfb92d14SAndroid Build Coastguard Worker exit:
829*cfb92d14SAndroid Build Coastguard Worker     return error;
830*cfb92d14SAndroid Build Coastguard Worker }
831*cfb92d14SAndroid Build Coastguard Worker 
SetShortAddress(uint16_t aAddress)832*cfb92d14SAndroid Build Coastguard Worker otError RadioSpinel::SetShortAddress(uint16_t aAddress)
833*cfb92d14SAndroid Build Coastguard Worker {
834*cfb92d14SAndroid Build Coastguard Worker     otError error = OT_ERROR_NONE;
835*cfb92d14SAndroid Build Coastguard Worker 
836*cfb92d14SAndroid Build Coastguard Worker     EXPECT(mShortAddress != aAddress, NO_ACTION);
837*cfb92d14SAndroid Build Coastguard Worker     EXPECT_NO_ERROR(error = Set(SPINEL_PROP_MAC_15_4_SADDR, SPINEL_DATATYPE_UINT16_S, aAddress));
838*cfb92d14SAndroid Build Coastguard Worker     mShortAddress = aAddress;
839*cfb92d14SAndroid Build Coastguard Worker 
840*cfb92d14SAndroid Build Coastguard Worker exit:
841*cfb92d14SAndroid Build Coastguard Worker     return error;
842*cfb92d14SAndroid Build Coastguard Worker }
843*cfb92d14SAndroid Build Coastguard Worker 
844*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE
845*cfb92d14SAndroid Build Coastguard Worker 
ReadMacKey(const otMacKeyMaterial & aKeyMaterial,otMacKey & aKey)846*cfb92d14SAndroid Build Coastguard Worker otError RadioSpinel::ReadMacKey(const otMacKeyMaterial &aKeyMaterial, otMacKey &aKey)
847*cfb92d14SAndroid Build Coastguard Worker {
848*cfb92d14SAndroid Build Coastguard Worker     size_t  keySize;
849*cfb92d14SAndroid Build Coastguard Worker     otError error = otPlatCryptoExportKey(aKeyMaterial.mKeyMaterial.mKeyRef, aKey.m8, sizeof(aKey), &keySize);
850*cfb92d14SAndroid Build Coastguard Worker 
851*cfb92d14SAndroid Build Coastguard Worker     EXPECT_NO_ERROR(error);
852*cfb92d14SAndroid Build Coastguard Worker     EXPECT(keySize == sizeof(otMacKey), error = OT_ERROR_FAILED);
853*cfb92d14SAndroid Build Coastguard Worker 
854*cfb92d14SAndroid Build Coastguard Worker exit:
855*cfb92d14SAndroid Build Coastguard Worker     return error;
856*cfb92d14SAndroid Build Coastguard Worker }
857*cfb92d14SAndroid Build Coastguard Worker 
SetMacKey(uint8_t aKeyIdMode,uint8_t aKeyId,const otMacKeyMaterial * aPrevKey,const otMacKeyMaterial * aCurrKey,const otMacKeyMaterial * aNextKey)858*cfb92d14SAndroid Build Coastguard Worker otError RadioSpinel::SetMacKey(uint8_t                 aKeyIdMode,
859*cfb92d14SAndroid Build Coastguard Worker                                uint8_t                 aKeyId,
860*cfb92d14SAndroid Build Coastguard Worker                                const otMacKeyMaterial *aPrevKey,
861*cfb92d14SAndroid Build Coastguard Worker                                const otMacKeyMaterial *aCurrKey,
862*cfb92d14SAndroid Build Coastguard Worker                                const otMacKeyMaterial *aNextKey)
863*cfb92d14SAndroid Build Coastguard Worker {
864*cfb92d14SAndroid Build Coastguard Worker     otError  error;
865*cfb92d14SAndroid Build Coastguard Worker     otMacKey prevKey;
866*cfb92d14SAndroid Build Coastguard Worker     otMacKey currKey;
867*cfb92d14SAndroid Build Coastguard Worker     otMacKey nextKey;
868*cfb92d14SAndroid Build Coastguard Worker 
869*cfb92d14SAndroid Build Coastguard Worker     EXPECT_NO_ERROR(error = ReadMacKey(*aPrevKey, prevKey));
870*cfb92d14SAndroid Build Coastguard Worker     EXPECT_NO_ERROR(error = ReadMacKey(*aCurrKey, currKey));
871*cfb92d14SAndroid Build Coastguard Worker     EXPECT_NO_ERROR(error = ReadMacKey(*aNextKey, nextKey));
872*cfb92d14SAndroid Build Coastguard Worker     error = SetMacKey(aKeyIdMode, aKeyId, prevKey, currKey, nextKey);
873*cfb92d14SAndroid Build Coastguard Worker 
874*cfb92d14SAndroid Build Coastguard Worker exit:
875*cfb92d14SAndroid Build Coastguard Worker     return error;
876*cfb92d14SAndroid Build Coastguard Worker }
877*cfb92d14SAndroid Build Coastguard Worker 
878*cfb92d14SAndroid Build Coastguard Worker #else
879*cfb92d14SAndroid Build Coastguard Worker 
SetMacKey(uint8_t aKeyIdMode,uint8_t aKeyId,const otMacKeyMaterial * aPrevKey,const otMacKeyMaterial * aCurrKey,const otMacKeyMaterial * aNextKey)880*cfb92d14SAndroid Build Coastguard Worker otError RadioSpinel::SetMacKey(uint8_t                 aKeyIdMode,
881*cfb92d14SAndroid Build Coastguard Worker                                uint8_t                 aKeyId,
882*cfb92d14SAndroid Build Coastguard Worker                                const otMacKeyMaterial *aPrevKey,
883*cfb92d14SAndroid Build Coastguard Worker                                const otMacKeyMaterial *aCurrKey,
884*cfb92d14SAndroid Build Coastguard Worker                                const otMacKeyMaterial *aNextKey)
885*cfb92d14SAndroid Build Coastguard Worker {
886*cfb92d14SAndroid Build Coastguard Worker     return SetMacKey(aKeyIdMode, aKeyId, aPrevKey->mKeyMaterial.mKey, aCurrKey->mKeyMaterial.mKey,
887*cfb92d14SAndroid Build Coastguard Worker                      aNextKey->mKeyMaterial.mKey);
888*cfb92d14SAndroid Build Coastguard Worker }
889*cfb92d14SAndroid Build Coastguard Worker 
890*cfb92d14SAndroid Build Coastguard Worker #endif // OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE
891*cfb92d14SAndroid Build Coastguard Worker 
SetMacKey(uint8_t aKeyIdMode,uint8_t aKeyId,const otMacKey & aPrevKey,const otMacKey & aCurrKey,const otMacKey & aNextKey)892*cfb92d14SAndroid Build Coastguard Worker otError RadioSpinel::SetMacKey(uint8_t         aKeyIdMode,
893*cfb92d14SAndroid Build Coastguard Worker                                uint8_t         aKeyId,
894*cfb92d14SAndroid Build Coastguard Worker                                const otMacKey &aPrevKey,
895*cfb92d14SAndroid Build Coastguard Worker                                const otMacKey &aCurrKey,
896*cfb92d14SAndroid Build Coastguard Worker                                const otMacKey &aNextKey)
897*cfb92d14SAndroid Build Coastguard Worker {
898*cfb92d14SAndroid Build Coastguard Worker     otError error;
899*cfb92d14SAndroid Build Coastguard Worker 
900*cfb92d14SAndroid Build Coastguard Worker     EXPECT_NO_ERROR(error = Set(SPINEL_PROP_RCP_MAC_KEY,
901*cfb92d14SAndroid Build Coastguard Worker                                 SPINEL_DATATYPE_UINT8_S SPINEL_DATATYPE_UINT8_S SPINEL_DATATYPE_DATA_WLEN_S
902*cfb92d14SAndroid Build Coastguard Worker                                     SPINEL_DATATYPE_DATA_WLEN_S SPINEL_DATATYPE_DATA_WLEN_S,
903*cfb92d14SAndroid Build Coastguard Worker                                 aKeyIdMode, aKeyId, aPrevKey.m8, sizeof(aPrevKey), aCurrKey.m8, sizeof(aCurrKey),
904*cfb92d14SAndroid Build Coastguard Worker                                 aNextKey.m8, sizeof(aNextKey)));
905*cfb92d14SAndroid Build Coastguard Worker 
906*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0
907*cfb92d14SAndroid Build Coastguard Worker     mKeyIdMode = aKeyIdMode;
908*cfb92d14SAndroid Build Coastguard Worker     mKeyId     = aKeyId;
909*cfb92d14SAndroid Build Coastguard Worker 
910*cfb92d14SAndroid Build Coastguard Worker     mPrevKey = aPrevKey;
911*cfb92d14SAndroid Build Coastguard Worker     mCurrKey = aCurrKey;
912*cfb92d14SAndroid Build Coastguard Worker     mNextKey = aNextKey;
913*cfb92d14SAndroid Build Coastguard Worker 
914*cfb92d14SAndroid Build Coastguard Worker     mMacKeySet = true;
915*cfb92d14SAndroid Build Coastguard Worker #endif
916*cfb92d14SAndroid Build Coastguard Worker 
917*cfb92d14SAndroid Build Coastguard Worker exit:
918*cfb92d14SAndroid Build Coastguard Worker     return error;
919*cfb92d14SAndroid Build Coastguard Worker }
920*cfb92d14SAndroid Build Coastguard Worker 
SetMacFrameCounter(uint32_t aMacFrameCounter,bool aSetIfLarger)921*cfb92d14SAndroid Build Coastguard Worker otError RadioSpinel::SetMacFrameCounter(uint32_t aMacFrameCounter, bool aSetIfLarger)
922*cfb92d14SAndroid Build Coastguard Worker {
923*cfb92d14SAndroid Build Coastguard Worker     otError error;
924*cfb92d14SAndroid Build Coastguard Worker 
925*cfb92d14SAndroid Build Coastguard Worker     EXPECT_NO_ERROR(error = Set(SPINEL_PROP_RCP_MAC_FRAME_COUNTER, SPINEL_DATATYPE_UINT32_S SPINEL_DATATYPE_BOOL_S,
926*cfb92d14SAndroid Build Coastguard Worker                                 aMacFrameCounter, aSetIfLarger));
927*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0
928*cfb92d14SAndroid Build Coastguard Worker     mMacFrameCounterSet = true;
929*cfb92d14SAndroid Build Coastguard Worker #endif
930*cfb92d14SAndroid Build Coastguard Worker 
931*cfb92d14SAndroid Build Coastguard Worker exit:
932*cfb92d14SAndroid Build Coastguard Worker     return error;
933*cfb92d14SAndroid Build Coastguard Worker }
934*cfb92d14SAndroid Build Coastguard Worker 
GetIeeeEui64(uint8_t * aIeeeEui64)935*cfb92d14SAndroid Build Coastguard Worker otError RadioSpinel::GetIeeeEui64(uint8_t *aIeeeEui64)
936*cfb92d14SAndroid Build Coastguard Worker {
937*cfb92d14SAndroid Build Coastguard Worker     memcpy(aIeeeEui64, sIeeeEui64.m8, sizeof(sIeeeEui64.m8));
938*cfb92d14SAndroid Build Coastguard Worker 
939*cfb92d14SAndroid Build Coastguard Worker     return OT_ERROR_NONE;
940*cfb92d14SAndroid Build Coastguard Worker }
941*cfb92d14SAndroid Build Coastguard Worker 
SetExtendedAddress(const otExtAddress & aExtAddress)942*cfb92d14SAndroid Build Coastguard Worker otError RadioSpinel::SetExtendedAddress(const otExtAddress &aExtAddress)
943*cfb92d14SAndroid Build Coastguard Worker {
944*cfb92d14SAndroid Build Coastguard Worker     otError error;
945*cfb92d14SAndroid Build Coastguard Worker 
946*cfb92d14SAndroid Build Coastguard Worker     EXPECT_NO_ERROR(error = Set(SPINEL_PROP_MAC_15_4_LADDR, SPINEL_DATATYPE_EUI64_S, aExtAddress.m8));
947*cfb92d14SAndroid Build Coastguard Worker     mExtendedAddress = aExtAddress;
948*cfb92d14SAndroid Build Coastguard Worker 
949*cfb92d14SAndroid Build Coastguard Worker exit:
950*cfb92d14SAndroid Build Coastguard Worker     return error;
951*cfb92d14SAndroid Build Coastguard Worker }
952*cfb92d14SAndroid Build Coastguard Worker 
SetPanId(uint16_t aPanId)953*cfb92d14SAndroid Build Coastguard Worker otError RadioSpinel::SetPanId(uint16_t aPanId)
954*cfb92d14SAndroid Build Coastguard Worker {
955*cfb92d14SAndroid Build Coastguard Worker     otError error = OT_ERROR_NONE;
956*cfb92d14SAndroid Build Coastguard Worker 
957*cfb92d14SAndroid Build Coastguard Worker     EXPECT(mPanId != aPanId, NO_ACTION);
958*cfb92d14SAndroid Build Coastguard Worker     EXPECT_NO_ERROR(error = Set(SPINEL_PROP_MAC_15_4_PANID, SPINEL_DATATYPE_UINT16_S, aPanId));
959*cfb92d14SAndroid Build Coastguard Worker     mPanId = aPanId;
960*cfb92d14SAndroid Build Coastguard Worker 
961*cfb92d14SAndroid Build Coastguard Worker exit:
962*cfb92d14SAndroid Build Coastguard Worker     return error;
963*cfb92d14SAndroid Build Coastguard Worker }
964*cfb92d14SAndroid Build Coastguard Worker 
EnableSrcMatch(bool aEnable)965*cfb92d14SAndroid Build Coastguard Worker otError RadioSpinel::EnableSrcMatch(bool aEnable)
966*cfb92d14SAndroid Build Coastguard Worker {
967*cfb92d14SAndroid Build Coastguard Worker     otError error;
968*cfb92d14SAndroid Build Coastguard Worker 
969*cfb92d14SAndroid Build Coastguard Worker     EXPECT_NO_ERROR(error = Set(SPINEL_PROP_MAC_SRC_MATCH_ENABLED, SPINEL_DATATYPE_BOOL_S, aEnable));
970*cfb92d14SAndroid Build Coastguard Worker 
971*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0
972*cfb92d14SAndroid Build Coastguard Worker     mSrcMatchSet     = true;
973*cfb92d14SAndroid Build Coastguard Worker     mSrcMatchEnabled = aEnable;
974*cfb92d14SAndroid Build Coastguard Worker #endif
975*cfb92d14SAndroid Build Coastguard Worker 
976*cfb92d14SAndroid Build Coastguard Worker exit:
977*cfb92d14SAndroid Build Coastguard Worker     return error;
978*cfb92d14SAndroid Build Coastguard Worker }
979*cfb92d14SAndroid Build Coastguard Worker 
AddSrcMatchShortEntry(uint16_t aShortAddress)980*cfb92d14SAndroid Build Coastguard Worker otError RadioSpinel::AddSrcMatchShortEntry(uint16_t aShortAddress)
981*cfb92d14SAndroid Build Coastguard Worker {
982*cfb92d14SAndroid Build Coastguard Worker     otError error;
983*cfb92d14SAndroid Build Coastguard Worker 
984*cfb92d14SAndroid Build Coastguard Worker     EXPECT_NO_ERROR(error = Insert(SPINEL_PROP_MAC_SRC_MATCH_SHORT_ADDRESSES, SPINEL_DATATYPE_UINT16_S, aShortAddress));
985*cfb92d14SAndroid Build Coastguard Worker 
986*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0
987*cfb92d14SAndroid Build Coastguard Worker     assert(mSrcMatchShortEntryCount < OPENTHREAD_CONFIG_MLE_MAX_CHILDREN);
988*cfb92d14SAndroid Build Coastguard Worker 
989*cfb92d14SAndroid Build Coastguard Worker     for (int i = 0; i < mSrcMatchShortEntryCount; ++i)
990*cfb92d14SAndroid Build Coastguard Worker     {
991*cfb92d14SAndroid Build Coastguard Worker         if (mSrcMatchShortEntries[i] == aShortAddress)
992*cfb92d14SAndroid Build Coastguard Worker         {
993*cfb92d14SAndroid Build Coastguard Worker             EXIT_NOW();
994*cfb92d14SAndroid Build Coastguard Worker         }
995*cfb92d14SAndroid Build Coastguard Worker     }
996*cfb92d14SAndroid Build Coastguard Worker     mSrcMatchShortEntries[mSrcMatchShortEntryCount] = aShortAddress;
997*cfb92d14SAndroid Build Coastguard Worker     ++mSrcMatchShortEntryCount;
998*cfb92d14SAndroid Build Coastguard Worker #endif
999*cfb92d14SAndroid Build Coastguard Worker 
1000*cfb92d14SAndroid Build Coastguard Worker exit:
1001*cfb92d14SAndroid Build Coastguard Worker     return error;
1002*cfb92d14SAndroid Build Coastguard Worker }
1003*cfb92d14SAndroid Build Coastguard Worker 
AddSrcMatchExtEntry(const otExtAddress & aExtAddress)1004*cfb92d14SAndroid Build Coastguard Worker otError RadioSpinel::AddSrcMatchExtEntry(const otExtAddress &aExtAddress)
1005*cfb92d14SAndroid Build Coastguard Worker {
1006*cfb92d14SAndroid Build Coastguard Worker     otError error;
1007*cfb92d14SAndroid Build Coastguard Worker 
1008*cfb92d14SAndroid Build Coastguard Worker     EXPECT_NO_ERROR(error =
1009*cfb92d14SAndroid Build Coastguard Worker                         Insert(SPINEL_PROP_MAC_SRC_MATCH_EXTENDED_ADDRESSES, SPINEL_DATATYPE_EUI64_S, aExtAddress.m8));
1010*cfb92d14SAndroid Build Coastguard Worker 
1011*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0
1012*cfb92d14SAndroid Build Coastguard Worker     assert(mSrcMatchExtEntryCount < OPENTHREAD_CONFIG_MLE_MAX_CHILDREN);
1013*cfb92d14SAndroid Build Coastguard Worker 
1014*cfb92d14SAndroid Build Coastguard Worker     for (int i = 0; i < mSrcMatchExtEntryCount; ++i)
1015*cfb92d14SAndroid Build Coastguard Worker     {
1016*cfb92d14SAndroid Build Coastguard Worker         if (memcmp(aExtAddress.m8, mSrcMatchExtEntries[i].m8, OT_EXT_ADDRESS_SIZE) == 0)
1017*cfb92d14SAndroid Build Coastguard Worker         {
1018*cfb92d14SAndroid Build Coastguard Worker             EXIT_NOW();
1019*cfb92d14SAndroid Build Coastguard Worker         }
1020*cfb92d14SAndroid Build Coastguard Worker     }
1021*cfb92d14SAndroid Build Coastguard Worker     mSrcMatchExtEntries[mSrcMatchExtEntryCount] = aExtAddress;
1022*cfb92d14SAndroid Build Coastguard Worker     ++mSrcMatchExtEntryCount;
1023*cfb92d14SAndroid Build Coastguard Worker #endif
1024*cfb92d14SAndroid Build Coastguard Worker 
1025*cfb92d14SAndroid Build Coastguard Worker exit:
1026*cfb92d14SAndroid Build Coastguard Worker     return error;
1027*cfb92d14SAndroid Build Coastguard Worker }
1028*cfb92d14SAndroid Build Coastguard Worker 
ClearSrcMatchShortEntry(uint16_t aShortAddress)1029*cfb92d14SAndroid Build Coastguard Worker otError RadioSpinel::ClearSrcMatchShortEntry(uint16_t aShortAddress)
1030*cfb92d14SAndroid Build Coastguard Worker {
1031*cfb92d14SAndroid Build Coastguard Worker     otError error;
1032*cfb92d14SAndroid Build Coastguard Worker 
1033*cfb92d14SAndroid Build Coastguard Worker     EXPECT_NO_ERROR(error = Remove(SPINEL_PROP_MAC_SRC_MATCH_SHORT_ADDRESSES, SPINEL_DATATYPE_UINT16_S, aShortAddress));
1034*cfb92d14SAndroid Build Coastguard Worker 
1035*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0
1036*cfb92d14SAndroid Build Coastguard Worker     for (int i = 0; i < mSrcMatchShortEntryCount; ++i)
1037*cfb92d14SAndroid Build Coastguard Worker     {
1038*cfb92d14SAndroid Build Coastguard Worker         if (mSrcMatchShortEntries[i] == aShortAddress)
1039*cfb92d14SAndroid Build Coastguard Worker         {
1040*cfb92d14SAndroid Build Coastguard Worker             mSrcMatchShortEntries[i] = mSrcMatchShortEntries[mSrcMatchShortEntryCount - 1];
1041*cfb92d14SAndroid Build Coastguard Worker             --mSrcMatchShortEntryCount;
1042*cfb92d14SAndroid Build Coastguard Worker             break;
1043*cfb92d14SAndroid Build Coastguard Worker         }
1044*cfb92d14SAndroid Build Coastguard Worker     }
1045*cfb92d14SAndroid Build Coastguard Worker #endif
1046*cfb92d14SAndroid Build Coastguard Worker 
1047*cfb92d14SAndroid Build Coastguard Worker exit:
1048*cfb92d14SAndroid Build Coastguard Worker     return error;
1049*cfb92d14SAndroid Build Coastguard Worker }
1050*cfb92d14SAndroid Build Coastguard Worker 
ClearSrcMatchExtEntry(const otExtAddress & aExtAddress)1051*cfb92d14SAndroid Build Coastguard Worker otError RadioSpinel::ClearSrcMatchExtEntry(const otExtAddress &aExtAddress)
1052*cfb92d14SAndroid Build Coastguard Worker {
1053*cfb92d14SAndroid Build Coastguard Worker     otError error;
1054*cfb92d14SAndroid Build Coastguard Worker 
1055*cfb92d14SAndroid Build Coastguard Worker     EXPECT_NO_ERROR(error =
1056*cfb92d14SAndroid Build Coastguard Worker                         Remove(SPINEL_PROP_MAC_SRC_MATCH_EXTENDED_ADDRESSES, SPINEL_DATATYPE_EUI64_S, aExtAddress.m8));
1057*cfb92d14SAndroid Build Coastguard Worker 
1058*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0
1059*cfb92d14SAndroid Build Coastguard Worker     for (int i = 0; i < mSrcMatchExtEntryCount; ++i)
1060*cfb92d14SAndroid Build Coastguard Worker     {
1061*cfb92d14SAndroid Build Coastguard Worker         if (memcmp(mSrcMatchExtEntries[i].m8, aExtAddress.m8, OT_EXT_ADDRESS_SIZE) == 0)
1062*cfb92d14SAndroid Build Coastguard Worker         {
1063*cfb92d14SAndroid Build Coastguard Worker             mSrcMatchExtEntries[i] = mSrcMatchExtEntries[mSrcMatchExtEntryCount - 1];
1064*cfb92d14SAndroid Build Coastguard Worker             --mSrcMatchExtEntryCount;
1065*cfb92d14SAndroid Build Coastguard Worker             break;
1066*cfb92d14SAndroid Build Coastguard Worker         }
1067*cfb92d14SAndroid Build Coastguard Worker     }
1068*cfb92d14SAndroid Build Coastguard Worker #endif
1069*cfb92d14SAndroid Build Coastguard Worker 
1070*cfb92d14SAndroid Build Coastguard Worker exit:
1071*cfb92d14SAndroid Build Coastguard Worker     return error;
1072*cfb92d14SAndroid Build Coastguard Worker }
1073*cfb92d14SAndroid Build Coastguard Worker 
ClearSrcMatchShortEntries(void)1074*cfb92d14SAndroid Build Coastguard Worker otError RadioSpinel::ClearSrcMatchShortEntries(void)
1075*cfb92d14SAndroid Build Coastguard Worker {
1076*cfb92d14SAndroid Build Coastguard Worker     otError error;
1077*cfb92d14SAndroid Build Coastguard Worker 
1078*cfb92d14SAndroid Build Coastguard Worker     EXPECT_NO_ERROR(error = Set(SPINEL_PROP_MAC_SRC_MATCH_SHORT_ADDRESSES, nullptr));
1079*cfb92d14SAndroid Build Coastguard Worker 
1080*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0
1081*cfb92d14SAndroid Build Coastguard Worker     mSrcMatchShortEntryCount = 0;
1082*cfb92d14SAndroid Build Coastguard Worker #endif
1083*cfb92d14SAndroid Build Coastguard Worker 
1084*cfb92d14SAndroid Build Coastguard Worker exit:
1085*cfb92d14SAndroid Build Coastguard Worker     return error;
1086*cfb92d14SAndroid Build Coastguard Worker }
1087*cfb92d14SAndroid Build Coastguard Worker 
ClearSrcMatchExtEntries(void)1088*cfb92d14SAndroid Build Coastguard Worker otError RadioSpinel::ClearSrcMatchExtEntries(void)
1089*cfb92d14SAndroid Build Coastguard Worker {
1090*cfb92d14SAndroid Build Coastguard Worker     otError error;
1091*cfb92d14SAndroid Build Coastguard Worker 
1092*cfb92d14SAndroid Build Coastguard Worker     EXPECT_NO_ERROR(error = Set(SPINEL_PROP_MAC_SRC_MATCH_EXTENDED_ADDRESSES, nullptr));
1093*cfb92d14SAndroid Build Coastguard Worker 
1094*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0
1095*cfb92d14SAndroid Build Coastguard Worker     mSrcMatchExtEntryCount = 0;
1096*cfb92d14SAndroid Build Coastguard Worker #endif
1097*cfb92d14SAndroid Build Coastguard Worker 
1098*cfb92d14SAndroid Build Coastguard Worker exit:
1099*cfb92d14SAndroid Build Coastguard Worker     return error;
1100*cfb92d14SAndroid Build Coastguard Worker }
1101*cfb92d14SAndroid Build Coastguard Worker 
GetTransmitPower(int8_t & aPower)1102*cfb92d14SAndroid Build Coastguard Worker otError RadioSpinel::GetTransmitPower(int8_t &aPower)
1103*cfb92d14SAndroid Build Coastguard Worker {
1104*cfb92d14SAndroid Build Coastguard Worker     otError error = Get(SPINEL_PROP_PHY_TX_POWER, SPINEL_DATATYPE_INT8_S, &aPower);
1105*cfb92d14SAndroid Build Coastguard Worker 
1106*cfb92d14SAndroid Build Coastguard Worker     LogIfFail("Get transmit power failed", error);
1107*cfb92d14SAndroid Build Coastguard Worker     return error;
1108*cfb92d14SAndroid Build Coastguard Worker }
1109*cfb92d14SAndroid Build Coastguard Worker 
GetCcaEnergyDetectThreshold(int8_t & aThreshold)1110*cfb92d14SAndroid Build Coastguard Worker otError RadioSpinel::GetCcaEnergyDetectThreshold(int8_t &aThreshold)
1111*cfb92d14SAndroid Build Coastguard Worker {
1112*cfb92d14SAndroid Build Coastguard Worker     otError error = Get(SPINEL_PROP_PHY_CCA_THRESHOLD, SPINEL_DATATYPE_INT8_S, &aThreshold);
1113*cfb92d14SAndroid Build Coastguard Worker 
1114*cfb92d14SAndroid Build Coastguard Worker     LogIfFail("Get CCA ED threshold failed", error);
1115*cfb92d14SAndroid Build Coastguard Worker     return error;
1116*cfb92d14SAndroid Build Coastguard Worker }
1117*cfb92d14SAndroid Build Coastguard Worker 
GetFemLnaGain(int8_t & aGain)1118*cfb92d14SAndroid Build Coastguard Worker otError RadioSpinel::GetFemLnaGain(int8_t &aGain)
1119*cfb92d14SAndroid Build Coastguard Worker {
1120*cfb92d14SAndroid Build Coastguard Worker     otError error = Get(SPINEL_PROP_PHY_FEM_LNA_GAIN, SPINEL_DATATYPE_INT8_S, &aGain);
1121*cfb92d14SAndroid Build Coastguard Worker 
1122*cfb92d14SAndroid Build Coastguard Worker     LogIfFail("Get FEM LNA gain failed", error);
1123*cfb92d14SAndroid Build Coastguard Worker     return error;
1124*cfb92d14SAndroid Build Coastguard Worker }
1125*cfb92d14SAndroid Build Coastguard Worker 
GetRssi(void)1126*cfb92d14SAndroid Build Coastguard Worker int8_t RadioSpinel::GetRssi(void)
1127*cfb92d14SAndroid Build Coastguard Worker {
1128*cfb92d14SAndroid Build Coastguard Worker     int8_t  rssi  = OT_RADIO_RSSI_INVALID;
1129*cfb92d14SAndroid Build Coastguard Worker     otError error = Get(SPINEL_PROP_PHY_RSSI, SPINEL_DATATYPE_INT8_S, &rssi);
1130*cfb92d14SAndroid Build Coastguard Worker 
1131*cfb92d14SAndroid Build Coastguard Worker     LogIfFail("Get RSSI failed", error);
1132*cfb92d14SAndroid Build Coastguard Worker     return rssi;
1133*cfb92d14SAndroid Build Coastguard Worker }
1134*cfb92d14SAndroid Build Coastguard Worker 
1135*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_CONFIG_PLATFORM_RADIO_COEX_ENABLE
SetCoexEnabled(bool aEnabled)1136*cfb92d14SAndroid Build Coastguard Worker otError RadioSpinel::SetCoexEnabled(bool aEnabled)
1137*cfb92d14SAndroid Build Coastguard Worker {
1138*cfb92d14SAndroid Build Coastguard Worker     otError error;
1139*cfb92d14SAndroid Build Coastguard Worker 
1140*cfb92d14SAndroid Build Coastguard Worker     EXPECT_NO_ERROR(error = Set(SPINEL_PROP_RADIO_COEX_ENABLE, SPINEL_DATATYPE_BOOL_S, aEnabled));
1141*cfb92d14SAndroid Build Coastguard Worker 
1142*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0
1143*cfb92d14SAndroid Build Coastguard Worker     mCoexEnabled    = aEnabled;
1144*cfb92d14SAndroid Build Coastguard Worker     mCoexEnabledSet = true;
1145*cfb92d14SAndroid Build Coastguard Worker #endif
1146*cfb92d14SAndroid Build Coastguard Worker 
1147*cfb92d14SAndroid Build Coastguard Worker exit:
1148*cfb92d14SAndroid Build Coastguard Worker     return error;
1149*cfb92d14SAndroid Build Coastguard Worker }
1150*cfb92d14SAndroid Build Coastguard Worker 
IsCoexEnabled(void)1151*cfb92d14SAndroid Build Coastguard Worker bool RadioSpinel::IsCoexEnabled(void)
1152*cfb92d14SAndroid Build Coastguard Worker {
1153*cfb92d14SAndroid Build Coastguard Worker     bool    enabled;
1154*cfb92d14SAndroid Build Coastguard Worker     otError error = Get(SPINEL_PROP_RADIO_COEX_ENABLE, SPINEL_DATATYPE_BOOL_S, &enabled);
1155*cfb92d14SAndroid Build Coastguard Worker 
1156*cfb92d14SAndroid Build Coastguard Worker     LogIfFail("Get Coex State failed", error);
1157*cfb92d14SAndroid Build Coastguard Worker     return enabled;
1158*cfb92d14SAndroid Build Coastguard Worker }
1159*cfb92d14SAndroid Build Coastguard Worker 
GetCoexMetrics(otRadioCoexMetrics & aCoexMetrics)1160*cfb92d14SAndroid Build Coastguard Worker otError RadioSpinel::GetCoexMetrics(otRadioCoexMetrics &aCoexMetrics)
1161*cfb92d14SAndroid Build Coastguard Worker {
1162*cfb92d14SAndroid Build Coastguard Worker     otError error;
1163*cfb92d14SAndroid Build Coastguard Worker 
1164*cfb92d14SAndroid Build Coastguard Worker     error = Get(SPINEL_PROP_RADIO_COEX_METRICS,
1165*cfb92d14SAndroid Build Coastguard Worker                 SPINEL_DATATYPE_STRUCT_S(                                    // Tx Coex Metrics Structure
1166*cfb92d14SAndroid Build Coastguard Worker                     SPINEL_DATATYPE_UINT32_S                                 // NumTxRequest
1167*cfb92d14SAndroid Build Coastguard Worker                         SPINEL_DATATYPE_UINT32_S                             // NumTxGrantImmediate
1168*cfb92d14SAndroid Build Coastguard Worker                             SPINEL_DATATYPE_UINT32_S                         // NumTxGrantWait
1169*cfb92d14SAndroid Build Coastguard Worker                                 SPINEL_DATATYPE_UINT32_S                     // NumTxGrantWaitActivated
1170*cfb92d14SAndroid Build Coastguard Worker                                     SPINEL_DATATYPE_UINT32_S                 // NumTxGrantWaitTimeout
1171*cfb92d14SAndroid Build Coastguard Worker                                         SPINEL_DATATYPE_UINT32_S             // NumTxGrantDeactivatedDuringRequest
1172*cfb92d14SAndroid Build Coastguard Worker                                             SPINEL_DATATYPE_UINT32_S         // NumTxDelayedGrant
1173*cfb92d14SAndroid Build Coastguard Worker                                                 SPINEL_DATATYPE_UINT32_S     // AvgTxRequestToGrantTime
1174*cfb92d14SAndroid Build Coastguard Worker                     ) SPINEL_DATATYPE_STRUCT_S(                              // Rx Coex Metrics Structure
1175*cfb92d14SAndroid Build Coastguard Worker                     SPINEL_DATATYPE_UINT32_S                                 // NumRxRequest
1176*cfb92d14SAndroid Build Coastguard Worker                         SPINEL_DATATYPE_UINT32_S                             // NumRxGrantImmediate
1177*cfb92d14SAndroid Build Coastguard Worker                             SPINEL_DATATYPE_UINT32_S                         // NumRxGrantWait
1178*cfb92d14SAndroid Build Coastguard Worker                                 SPINEL_DATATYPE_UINT32_S                     // NumRxGrantWaitActivated
1179*cfb92d14SAndroid Build Coastguard Worker                                     SPINEL_DATATYPE_UINT32_S                 // NumRxGrantWaitTimeout
1180*cfb92d14SAndroid Build Coastguard Worker                                         SPINEL_DATATYPE_UINT32_S             // NumRxGrantDeactivatedDuringRequest
1181*cfb92d14SAndroid Build Coastguard Worker                                             SPINEL_DATATYPE_UINT32_S         // NumRxDelayedGrant
1182*cfb92d14SAndroid Build Coastguard Worker                                                 SPINEL_DATATYPE_UINT32_S     // AvgRxRequestToGrantTime
1183*cfb92d14SAndroid Build Coastguard Worker                                                     SPINEL_DATATYPE_UINT32_S // NumRxGrantNone
1184*cfb92d14SAndroid Build Coastguard Worker                     ) SPINEL_DATATYPE_BOOL_S                                 // Stopped
1185*cfb92d14SAndroid Build Coastguard Worker                     SPINEL_DATATYPE_UINT32_S,                                // NumGrantGlitch
1186*cfb92d14SAndroid Build Coastguard Worker                 &aCoexMetrics.mNumTxRequest, &aCoexMetrics.mNumTxGrantImmediate, &aCoexMetrics.mNumTxGrantWait,
1187*cfb92d14SAndroid Build Coastguard Worker                 &aCoexMetrics.mNumTxGrantWaitActivated, &aCoexMetrics.mNumTxGrantWaitTimeout,
1188*cfb92d14SAndroid Build Coastguard Worker                 &aCoexMetrics.mNumTxGrantDeactivatedDuringRequest, &aCoexMetrics.mNumTxDelayedGrant,
1189*cfb92d14SAndroid Build Coastguard Worker                 &aCoexMetrics.mAvgTxRequestToGrantTime, &aCoexMetrics.mNumRxRequest, &aCoexMetrics.mNumRxGrantImmediate,
1190*cfb92d14SAndroid Build Coastguard Worker                 &aCoexMetrics.mNumRxGrantWait, &aCoexMetrics.mNumRxGrantWaitActivated,
1191*cfb92d14SAndroid Build Coastguard Worker                 &aCoexMetrics.mNumRxGrantWaitTimeout, &aCoexMetrics.mNumRxGrantDeactivatedDuringRequest,
1192*cfb92d14SAndroid Build Coastguard Worker                 &aCoexMetrics.mNumRxDelayedGrant, &aCoexMetrics.mAvgRxRequestToGrantTime, &aCoexMetrics.mNumRxGrantNone,
1193*cfb92d14SAndroid Build Coastguard Worker                 &aCoexMetrics.mStopped, &aCoexMetrics.mNumGrantGlitch);
1194*cfb92d14SAndroid Build Coastguard Worker 
1195*cfb92d14SAndroid Build Coastguard Worker     LogIfFail("Get Coex Metrics failed", error);
1196*cfb92d14SAndroid Build Coastguard Worker     return error;
1197*cfb92d14SAndroid Build Coastguard Worker }
1198*cfb92d14SAndroid Build Coastguard Worker #endif
1199*cfb92d14SAndroid Build Coastguard Worker 
SetTransmitPower(int8_t aPower)1200*cfb92d14SAndroid Build Coastguard Worker otError RadioSpinel::SetTransmitPower(int8_t aPower)
1201*cfb92d14SAndroid Build Coastguard Worker {
1202*cfb92d14SAndroid Build Coastguard Worker     otError error;
1203*cfb92d14SAndroid Build Coastguard Worker 
1204*cfb92d14SAndroid Build Coastguard Worker     EXPECT_NO_ERROR(error = Set(SPINEL_PROP_PHY_TX_POWER, SPINEL_DATATYPE_INT8_S, aPower));
1205*cfb92d14SAndroid Build Coastguard Worker 
1206*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0
1207*cfb92d14SAndroid Build Coastguard Worker     mTransmitPower    = aPower;
1208*cfb92d14SAndroid Build Coastguard Worker     mTransmitPowerSet = true;
1209*cfb92d14SAndroid Build Coastguard Worker #endif
1210*cfb92d14SAndroid Build Coastguard Worker 
1211*cfb92d14SAndroid Build Coastguard Worker exit:
1212*cfb92d14SAndroid Build Coastguard Worker     LogIfFail("Set transmit power failed", error);
1213*cfb92d14SAndroid Build Coastguard Worker     return error;
1214*cfb92d14SAndroid Build Coastguard Worker }
1215*cfb92d14SAndroid Build Coastguard Worker 
SetCcaEnergyDetectThreshold(int8_t aThreshold)1216*cfb92d14SAndroid Build Coastguard Worker otError RadioSpinel::SetCcaEnergyDetectThreshold(int8_t aThreshold)
1217*cfb92d14SAndroid Build Coastguard Worker {
1218*cfb92d14SAndroid Build Coastguard Worker     otError error;
1219*cfb92d14SAndroid Build Coastguard Worker 
1220*cfb92d14SAndroid Build Coastguard Worker     EXPECT_NO_ERROR(error = Set(SPINEL_PROP_PHY_CCA_THRESHOLD, SPINEL_DATATYPE_INT8_S, aThreshold));
1221*cfb92d14SAndroid Build Coastguard Worker 
1222*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0
1223*cfb92d14SAndroid Build Coastguard Worker     mCcaEnergyDetectThreshold    = aThreshold;
1224*cfb92d14SAndroid Build Coastguard Worker     mCcaEnergyDetectThresholdSet = true;
1225*cfb92d14SAndroid Build Coastguard Worker #endif
1226*cfb92d14SAndroid Build Coastguard Worker 
1227*cfb92d14SAndroid Build Coastguard Worker exit:
1228*cfb92d14SAndroid Build Coastguard Worker     LogIfFail("Set CCA ED threshold failed", error);
1229*cfb92d14SAndroid Build Coastguard Worker     return error;
1230*cfb92d14SAndroid Build Coastguard Worker }
1231*cfb92d14SAndroid Build Coastguard Worker 
SetFemLnaGain(int8_t aGain)1232*cfb92d14SAndroid Build Coastguard Worker otError RadioSpinel::SetFemLnaGain(int8_t aGain)
1233*cfb92d14SAndroid Build Coastguard Worker {
1234*cfb92d14SAndroid Build Coastguard Worker     otError error;
1235*cfb92d14SAndroid Build Coastguard Worker 
1236*cfb92d14SAndroid Build Coastguard Worker     EXPECT_NO_ERROR(error = Set(SPINEL_PROP_PHY_FEM_LNA_GAIN, SPINEL_DATATYPE_INT8_S, aGain));
1237*cfb92d14SAndroid Build Coastguard Worker 
1238*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0
1239*cfb92d14SAndroid Build Coastguard Worker     mFemLnaGain    = aGain;
1240*cfb92d14SAndroid Build Coastguard Worker     mFemLnaGainSet = true;
1241*cfb92d14SAndroid Build Coastguard Worker #endif
1242*cfb92d14SAndroid Build Coastguard Worker 
1243*cfb92d14SAndroid Build Coastguard Worker exit:
1244*cfb92d14SAndroid Build Coastguard Worker     LogIfFail("Set FEM LNA gain failed", error);
1245*cfb92d14SAndroid Build Coastguard Worker     return error;
1246*cfb92d14SAndroid Build Coastguard Worker }
1247*cfb92d14SAndroid Build Coastguard Worker 
EnergyScan(uint8_t aScanChannel,uint16_t aScanDuration)1248*cfb92d14SAndroid Build Coastguard Worker otError RadioSpinel::EnergyScan(uint8_t aScanChannel, uint16_t aScanDuration)
1249*cfb92d14SAndroid Build Coastguard Worker {
1250*cfb92d14SAndroid Build Coastguard Worker     otError error;
1251*cfb92d14SAndroid Build Coastguard Worker 
1252*cfb92d14SAndroid Build Coastguard Worker     EXPECT(sRadioCaps & OT_RADIO_CAPS_ENERGY_SCAN, error = OT_ERROR_NOT_CAPABLE);
1253*cfb92d14SAndroid Build Coastguard Worker 
1254*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0
1255*cfb92d14SAndroid Build Coastguard Worker     mScanChannel    = aScanChannel;
1256*cfb92d14SAndroid Build Coastguard Worker     mScanDuration   = aScanDuration;
1257*cfb92d14SAndroid Build Coastguard Worker     mEnergyScanning = true;
1258*cfb92d14SAndroid Build Coastguard Worker #endif
1259*cfb92d14SAndroid Build Coastguard Worker 
1260*cfb92d14SAndroid Build Coastguard Worker     EXPECT_NO_ERROR(error = Set(SPINEL_PROP_MAC_SCAN_MASK, SPINEL_DATATYPE_DATA_S, &aScanChannel, sizeof(uint8_t)));
1261*cfb92d14SAndroid Build Coastguard Worker     EXPECT_NO_ERROR(error = Set(SPINEL_PROP_MAC_SCAN_PERIOD, SPINEL_DATATYPE_UINT16_S, aScanDuration));
1262*cfb92d14SAndroid Build Coastguard Worker     EXPECT_NO_ERROR(error = Set(SPINEL_PROP_MAC_SCAN_STATE, SPINEL_DATATYPE_UINT8_S, SPINEL_SCAN_STATE_ENERGY));
1263*cfb92d14SAndroid Build Coastguard Worker 
1264*cfb92d14SAndroid Build Coastguard Worker     mChannel = aScanChannel;
1265*cfb92d14SAndroid Build Coastguard Worker 
1266*cfb92d14SAndroid Build Coastguard Worker exit:
1267*cfb92d14SAndroid Build Coastguard Worker     return error;
1268*cfb92d14SAndroid Build Coastguard Worker }
1269*cfb92d14SAndroid Build Coastguard Worker 
Get(spinel_prop_key_t aKey,const char * aFormat,...)1270*cfb92d14SAndroid Build Coastguard Worker otError RadioSpinel::Get(spinel_prop_key_t aKey, const char *aFormat, ...)
1271*cfb92d14SAndroid Build Coastguard Worker {
1272*cfb92d14SAndroid Build Coastguard Worker     otError error;
1273*cfb92d14SAndroid Build Coastguard Worker 
1274*cfb92d14SAndroid Build Coastguard Worker     assert(mWaitingTid == 0);
1275*cfb92d14SAndroid Build Coastguard Worker 
1276*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0
1277*cfb92d14SAndroid Build Coastguard Worker     do
1278*cfb92d14SAndroid Build Coastguard Worker     {
1279*cfb92d14SAndroid Build Coastguard Worker         RecoverFromRcpFailure();
1280*cfb92d14SAndroid Build Coastguard Worker #endif
1281*cfb92d14SAndroid Build Coastguard Worker         va_start(mPropertyArgs, aFormat);
1282*cfb92d14SAndroid Build Coastguard Worker         error = RequestWithPropertyFormatV(aFormat, SPINEL_CMD_PROP_VALUE_GET, aKey, nullptr, mPropertyArgs);
1283*cfb92d14SAndroid Build Coastguard Worker         va_end(mPropertyArgs);
1284*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0
1285*cfb92d14SAndroid Build Coastguard Worker     } while (mRcpFailure != kRcpFailureNone);
1286*cfb92d14SAndroid Build Coastguard Worker #endif
1287*cfb92d14SAndroid Build Coastguard Worker 
1288*cfb92d14SAndroid Build Coastguard Worker     return error;
1289*cfb92d14SAndroid Build Coastguard Worker }
1290*cfb92d14SAndroid Build Coastguard Worker 
1291*cfb92d14SAndroid Build Coastguard Worker // This is not a normal use case for VALUE_GET command and should be only used to get RCP timestamp with dummy payload
GetWithParam(spinel_prop_key_t aKey,const uint8_t * aParam,spinel_size_t aParamSize,const char * aFormat,...)1292*cfb92d14SAndroid Build Coastguard Worker otError RadioSpinel::GetWithParam(spinel_prop_key_t aKey,
1293*cfb92d14SAndroid Build Coastguard Worker                                   const uint8_t    *aParam,
1294*cfb92d14SAndroid Build Coastguard Worker                                   spinel_size_t     aParamSize,
1295*cfb92d14SAndroid Build Coastguard Worker                                   const char       *aFormat,
1296*cfb92d14SAndroid Build Coastguard Worker                                   ...)
1297*cfb92d14SAndroid Build Coastguard Worker {
1298*cfb92d14SAndroid Build Coastguard Worker     otError error;
1299*cfb92d14SAndroid Build Coastguard Worker 
1300*cfb92d14SAndroid Build Coastguard Worker     assert(mWaitingTid == 0);
1301*cfb92d14SAndroid Build Coastguard Worker 
1302*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0
1303*cfb92d14SAndroid Build Coastguard Worker     do
1304*cfb92d14SAndroid Build Coastguard Worker     {
1305*cfb92d14SAndroid Build Coastguard Worker         RecoverFromRcpFailure();
1306*cfb92d14SAndroid Build Coastguard Worker #endif
1307*cfb92d14SAndroid Build Coastguard Worker         va_start(mPropertyArgs, aFormat);
1308*cfb92d14SAndroid Build Coastguard Worker         error = RequestWithPropertyFormat(aFormat, SPINEL_CMD_PROP_VALUE_GET, aKey, SPINEL_DATATYPE_DATA_S, aParam,
1309*cfb92d14SAndroid Build Coastguard Worker                                           aParamSize);
1310*cfb92d14SAndroid Build Coastguard Worker         va_end(mPropertyArgs);
1311*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0
1312*cfb92d14SAndroid Build Coastguard Worker     } while (mRcpFailure != kRcpFailureNone);
1313*cfb92d14SAndroid Build Coastguard Worker #endif
1314*cfb92d14SAndroid Build Coastguard Worker 
1315*cfb92d14SAndroid Build Coastguard Worker     return error;
1316*cfb92d14SAndroid Build Coastguard Worker }
1317*cfb92d14SAndroid Build Coastguard Worker 
Set(spinel_prop_key_t aKey,const char * aFormat,...)1318*cfb92d14SAndroid Build Coastguard Worker otError RadioSpinel::Set(spinel_prop_key_t aKey, const char *aFormat, ...)
1319*cfb92d14SAndroid Build Coastguard Worker {
1320*cfb92d14SAndroid Build Coastguard Worker     otError error;
1321*cfb92d14SAndroid Build Coastguard Worker 
1322*cfb92d14SAndroid Build Coastguard Worker     assert(mWaitingTid == 0);
1323*cfb92d14SAndroid Build Coastguard Worker 
1324*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0
1325*cfb92d14SAndroid Build Coastguard Worker     do
1326*cfb92d14SAndroid Build Coastguard Worker     {
1327*cfb92d14SAndroid Build Coastguard Worker         RecoverFromRcpFailure();
1328*cfb92d14SAndroid Build Coastguard Worker #endif
1329*cfb92d14SAndroid Build Coastguard Worker         va_start(mPropertyArgs, aFormat);
1330*cfb92d14SAndroid Build Coastguard Worker         error = RequestWithExpectedCommandV(SPINEL_CMD_PROP_VALUE_IS, SPINEL_CMD_PROP_VALUE_SET, aKey, aFormat,
1331*cfb92d14SAndroid Build Coastguard Worker                                             mPropertyArgs);
1332*cfb92d14SAndroid Build Coastguard Worker         va_end(mPropertyArgs);
1333*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0
1334*cfb92d14SAndroid Build Coastguard Worker     } while (mRcpFailure != kRcpFailureNone);
1335*cfb92d14SAndroid Build Coastguard Worker #endif
1336*cfb92d14SAndroid Build Coastguard Worker 
1337*cfb92d14SAndroid Build Coastguard Worker     return error;
1338*cfb92d14SAndroid Build Coastguard Worker }
1339*cfb92d14SAndroid Build Coastguard Worker 
Insert(spinel_prop_key_t aKey,const char * aFormat,...)1340*cfb92d14SAndroid Build Coastguard Worker otError RadioSpinel::Insert(spinel_prop_key_t aKey, const char *aFormat, ...)
1341*cfb92d14SAndroid Build Coastguard Worker {
1342*cfb92d14SAndroid Build Coastguard Worker     otError error;
1343*cfb92d14SAndroid Build Coastguard Worker 
1344*cfb92d14SAndroid Build Coastguard Worker     assert(mWaitingTid == 0);
1345*cfb92d14SAndroid Build Coastguard Worker 
1346*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0
1347*cfb92d14SAndroid Build Coastguard Worker     do
1348*cfb92d14SAndroid Build Coastguard Worker     {
1349*cfb92d14SAndroid Build Coastguard Worker         RecoverFromRcpFailure();
1350*cfb92d14SAndroid Build Coastguard Worker #endif
1351*cfb92d14SAndroid Build Coastguard Worker         va_start(mPropertyArgs, aFormat);
1352*cfb92d14SAndroid Build Coastguard Worker         error = RequestWithExpectedCommandV(SPINEL_CMD_PROP_VALUE_INSERTED, SPINEL_CMD_PROP_VALUE_INSERT, aKey, aFormat,
1353*cfb92d14SAndroid Build Coastguard Worker                                             mPropertyArgs);
1354*cfb92d14SAndroid Build Coastguard Worker         va_end(mPropertyArgs);
1355*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0
1356*cfb92d14SAndroid Build Coastguard Worker     } while (mRcpFailure != kRcpFailureNone);
1357*cfb92d14SAndroid Build Coastguard Worker #endif
1358*cfb92d14SAndroid Build Coastguard Worker 
1359*cfb92d14SAndroid Build Coastguard Worker     return error;
1360*cfb92d14SAndroid Build Coastguard Worker }
1361*cfb92d14SAndroid Build Coastguard Worker 
Remove(spinel_prop_key_t aKey,const char * aFormat,...)1362*cfb92d14SAndroid Build Coastguard Worker otError RadioSpinel::Remove(spinel_prop_key_t aKey, const char *aFormat, ...)
1363*cfb92d14SAndroid Build Coastguard Worker {
1364*cfb92d14SAndroid Build Coastguard Worker     otError error;
1365*cfb92d14SAndroid Build Coastguard Worker 
1366*cfb92d14SAndroid Build Coastguard Worker     assert(mWaitingTid == 0);
1367*cfb92d14SAndroid Build Coastguard Worker 
1368*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0
1369*cfb92d14SAndroid Build Coastguard Worker     do
1370*cfb92d14SAndroid Build Coastguard Worker     {
1371*cfb92d14SAndroid Build Coastguard Worker         RecoverFromRcpFailure();
1372*cfb92d14SAndroid Build Coastguard Worker #endif
1373*cfb92d14SAndroid Build Coastguard Worker         va_start(mPropertyArgs, aFormat);
1374*cfb92d14SAndroid Build Coastguard Worker         error = RequestWithExpectedCommandV(SPINEL_CMD_PROP_VALUE_REMOVED, SPINEL_CMD_PROP_VALUE_REMOVE, aKey, aFormat,
1375*cfb92d14SAndroid Build Coastguard Worker                                             mPropertyArgs);
1376*cfb92d14SAndroid Build Coastguard Worker         va_end(mPropertyArgs);
1377*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0
1378*cfb92d14SAndroid Build Coastguard Worker     } while (mRcpFailure != kRcpFailureNone);
1379*cfb92d14SAndroid Build Coastguard Worker #endif
1380*cfb92d14SAndroid Build Coastguard Worker 
1381*cfb92d14SAndroid Build Coastguard Worker     return error;
1382*cfb92d14SAndroid Build Coastguard Worker }
1383*cfb92d14SAndroid Build Coastguard Worker 
WaitResponse(bool aHandleRcpTimeout)1384*cfb92d14SAndroid Build Coastguard Worker otError RadioSpinel::WaitResponse(bool aHandleRcpTimeout)
1385*cfb92d14SAndroid Build Coastguard Worker {
1386*cfb92d14SAndroid Build Coastguard Worker     uint64_t end = otPlatTimeGet() + kMaxWaitTime * kUsPerMs;
1387*cfb92d14SAndroid Build Coastguard Worker 
1388*cfb92d14SAndroid Build Coastguard Worker     LogDebg("Wait response: tid=%u key=%lu", mWaitingTid, ToUlong(mWaitingKey));
1389*cfb92d14SAndroid Build Coastguard Worker 
1390*cfb92d14SAndroid Build Coastguard Worker     do
1391*cfb92d14SAndroid Build Coastguard Worker     {
1392*cfb92d14SAndroid Build Coastguard Worker         uint64_t now;
1393*cfb92d14SAndroid Build Coastguard Worker 
1394*cfb92d14SAndroid Build Coastguard Worker         now = otPlatTimeGet();
1395*cfb92d14SAndroid Build Coastguard Worker         if ((end <= now) || (GetSpinelDriver().GetSpinelInterface()->WaitForFrame(end - now) != OT_ERROR_NONE))
1396*cfb92d14SAndroid Build Coastguard Worker         {
1397*cfb92d14SAndroid Build Coastguard Worker             LogWarn("Wait for response timeout");
1398*cfb92d14SAndroid Build Coastguard Worker             if (aHandleRcpTimeout)
1399*cfb92d14SAndroid Build Coastguard Worker             {
1400*cfb92d14SAndroid Build Coastguard Worker                 HandleRcpTimeout();
1401*cfb92d14SAndroid Build Coastguard Worker             }
1402*cfb92d14SAndroid Build Coastguard Worker             EXIT_NOW(mError = OT_ERROR_RESPONSE_TIMEOUT);
1403*cfb92d14SAndroid Build Coastguard Worker         }
1404*cfb92d14SAndroid Build Coastguard Worker     } while (mWaitingTid);
1405*cfb92d14SAndroid Build Coastguard Worker 
1406*cfb92d14SAndroid Build Coastguard Worker     LogIfFail("Error waiting response", mError);
1407*cfb92d14SAndroid Build Coastguard Worker     // This indicates end of waiting response.
1408*cfb92d14SAndroid Build Coastguard Worker     mWaitingKey = SPINEL_PROP_LAST_STATUS;
1409*cfb92d14SAndroid Build Coastguard Worker 
1410*cfb92d14SAndroid Build Coastguard Worker exit:
1411*cfb92d14SAndroid Build Coastguard Worker     return mError;
1412*cfb92d14SAndroid Build Coastguard Worker }
1413*cfb92d14SAndroid Build Coastguard Worker 
GetNextTid(void)1414*cfb92d14SAndroid Build Coastguard Worker spinel_tid_t RadioSpinel::GetNextTid(void)
1415*cfb92d14SAndroid Build Coastguard Worker {
1416*cfb92d14SAndroid Build Coastguard Worker     spinel_tid_t tid = mCmdNextTid;
1417*cfb92d14SAndroid Build Coastguard Worker 
1418*cfb92d14SAndroid Build Coastguard Worker     while (((1 << tid) & mCmdTidsInUse) != 0)
1419*cfb92d14SAndroid Build Coastguard Worker     {
1420*cfb92d14SAndroid Build Coastguard Worker         tid = SPINEL_GET_NEXT_TID(tid);
1421*cfb92d14SAndroid Build Coastguard Worker 
1422*cfb92d14SAndroid Build Coastguard Worker         if (tid == mCmdNextTid)
1423*cfb92d14SAndroid Build Coastguard Worker         {
1424*cfb92d14SAndroid Build Coastguard Worker             // We looped back to `mCmdNextTid` indicating that all
1425*cfb92d14SAndroid Build Coastguard Worker             // TIDs are in-use.
1426*cfb92d14SAndroid Build Coastguard Worker 
1427*cfb92d14SAndroid Build Coastguard Worker             EXIT_NOW(tid = 0);
1428*cfb92d14SAndroid Build Coastguard Worker         }
1429*cfb92d14SAndroid Build Coastguard Worker     }
1430*cfb92d14SAndroid Build Coastguard Worker 
1431*cfb92d14SAndroid Build Coastguard Worker     mCmdTidsInUse |= (1 << tid);
1432*cfb92d14SAndroid Build Coastguard Worker     mCmdNextTid = SPINEL_GET_NEXT_TID(tid);
1433*cfb92d14SAndroid Build Coastguard Worker 
1434*cfb92d14SAndroid Build Coastguard Worker exit:
1435*cfb92d14SAndroid Build Coastguard Worker     return tid;
1436*cfb92d14SAndroid Build Coastguard Worker }
1437*cfb92d14SAndroid Build Coastguard Worker 
RequestV(uint32_t command,spinel_prop_key_t aKey,const char * aFormat,va_list aArgs)1438*cfb92d14SAndroid Build Coastguard Worker otError RadioSpinel::RequestV(uint32_t command, spinel_prop_key_t aKey, const char *aFormat, va_list aArgs)
1439*cfb92d14SAndroid Build Coastguard Worker {
1440*cfb92d14SAndroid Build Coastguard Worker     otError      error = OT_ERROR_NONE;
1441*cfb92d14SAndroid Build Coastguard Worker     spinel_tid_t tid   = GetNextTid();
1442*cfb92d14SAndroid Build Coastguard Worker 
1443*cfb92d14SAndroid Build Coastguard Worker     EXPECT(tid > 0, error = OT_ERROR_BUSY);
1444*cfb92d14SAndroid Build Coastguard Worker 
1445*cfb92d14SAndroid Build Coastguard Worker     error = GetSpinelDriver().SendCommand(command, aKey, tid, aFormat, aArgs);
1446*cfb92d14SAndroid Build Coastguard Worker     EXPECT_NO_ERROR(error);
1447*cfb92d14SAndroid Build Coastguard Worker 
1448*cfb92d14SAndroid Build Coastguard Worker     if (aKey == SPINEL_PROP_STREAM_RAW)
1449*cfb92d14SAndroid Build Coastguard Worker     {
1450*cfb92d14SAndroid Build Coastguard Worker         // not allowed to send another frame before the last frame is done.
1451*cfb92d14SAndroid Build Coastguard Worker         assert(mTxRadioTid == 0);
1452*cfb92d14SAndroid Build Coastguard Worker         EXPECT(mTxRadioTid == 0, error = OT_ERROR_BUSY);
1453*cfb92d14SAndroid Build Coastguard Worker         mTxRadioTid = tid;
1454*cfb92d14SAndroid Build Coastguard Worker     }
1455*cfb92d14SAndroid Build Coastguard Worker     else
1456*cfb92d14SAndroid Build Coastguard Worker     {
1457*cfb92d14SAndroid Build Coastguard Worker         mWaitingKey = aKey;
1458*cfb92d14SAndroid Build Coastguard Worker         mWaitingTid = tid;
1459*cfb92d14SAndroid Build Coastguard Worker         error       = WaitResponse();
1460*cfb92d14SAndroid Build Coastguard Worker     }
1461*cfb92d14SAndroid Build Coastguard Worker 
1462*cfb92d14SAndroid Build Coastguard Worker exit:
1463*cfb92d14SAndroid Build Coastguard Worker     return error;
1464*cfb92d14SAndroid Build Coastguard Worker }
1465*cfb92d14SAndroid Build Coastguard Worker 
Request(uint32_t aCommand,spinel_prop_key_t aKey,const char * aFormat,...)1466*cfb92d14SAndroid Build Coastguard Worker otError RadioSpinel::Request(uint32_t aCommand, spinel_prop_key_t aKey, const char *aFormat, ...)
1467*cfb92d14SAndroid Build Coastguard Worker {
1468*cfb92d14SAndroid Build Coastguard Worker     va_list args;
1469*cfb92d14SAndroid Build Coastguard Worker     va_start(args, aFormat);
1470*cfb92d14SAndroid Build Coastguard Worker     otError status = RequestV(aCommand, aKey, aFormat, args);
1471*cfb92d14SAndroid Build Coastguard Worker     va_end(args);
1472*cfb92d14SAndroid Build Coastguard Worker     return status;
1473*cfb92d14SAndroid Build Coastguard Worker }
1474*cfb92d14SAndroid Build Coastguard Worker 
RequestWithPropertyFormat(const char * aPropertyFormat,uint32_t aCommand,spinel_prop_key_t aKey,const char * aFormat,...)1475*cfb92d14SAndroid Build Coastguard Worker otError RadioSpinel::RequestWithPropertyFormat(const char       *aPropertyFormat,
1476*cfb92d14SAndroid Build Coastguard Worker                                                uint32_t          aCommand,
1477*cfb92d14SAndroid Build Coastguard Worker                                                spinel_prop_key_t aKey,
1478*cfb92d14SAndroid Build Coastguard Worker                                                const char       *aFormat,
1479*cfb92d14SAndroid Build Coastguard Worker                                                ...)
1480*cfb92d14SAndroid Build Coastguard Worker {
1481*cfb92d14SAndroid Build Coastguard Worker     otError error;
1482*cfb92d14SAndroid Build Coastguard Worker     va_list args;
1483*cfb92d14SAndroid Build Coastguard Worker 
1484*cfb92d14SAndroid Build Coastguard Worker     va_start(args, aFormat);
1485*cfb92d14SAndroid Build Coastguard Worker     error = RequestWithPropertyFormatV(aPropertyFormat, aCommand, aKey, aFormat, args);
1486*cfb92d14SAndroid Build Coastguard Worker     va_end(args);
1487*cfb92d14SAndroid Build Coastguard Worker 
1488*cfb92d14SAndroid Build Coastguard Worker     return error;
1489*cfb92d14SAndroid Build Coastguard Worker }
1490*cfb92d14SAndroid Build Coastguard Worker 
RequestWithPropertyFormatV(const char * aPropertyFormat,uint32_t aCommand,spinel_prop_key_t aKey,const char * aFormat,va_list aArgs)1491*cfb92d14SAndroid Build Coastguard Worker otError RadioSpinel::RequestWithPropertyFormatV(const char       *aPropertyFormat,
1492*cfb92d14SAndroid Build Coastguard Worker                                                 uint32_t          aCommand,
1493*cfb92d14SAndroid Build Coastguard Worker                                                 spinel_prop_key_t aKey,
1494*cfb92d14SAndroid Build Coastguard Worker                                                 const char       *aFormat,
1495*cfb92d14SAndroid Build Coastguard Worker                                                 va_list           aArgs)
1496*cfb92d14SAndroid Build Coastguard Worker {
1497*cfb92d14SAndroid Build Coastguard Worker     otError error;
1498*cfb92d14SAndroid Build Coastguard Worker 
1499*cfb92d14SAndroid Build Coastguard Worker     mPropertyFormat = aPropertyFormat;
1500*cfb92d14SAndroid Build Coastguard Worker     error           = RequestV(aCommand, aKey, aFormat, aArgs);
1501*cfb92d14SAndroid Build Coastguard Worker     mPropertyFormat = nullptr;
1502*cfb92d14SAndroid Build Coastguard Worker 
1503*cfb92d14SAndroid Build Coastguard Worker     return error;
1504*cfb92d14SAndroid Build Coastguard Worker }
1505*cfb92d14SAndroid Build Coastguard Worker 
RequestWithExpectedCommandV(uint32_t aExpectedCommand,uint32_t aCommand,spinel_prop_key_t aKey,const char * aFormat,va_list aArgs)1506*cfb92d14SAndroid Build Coastguard Worker otError RadioSpinel::RequestWithExpectedCommandV(uint32_t          aExpectedCommand,
1507*cfb92d14SAndroid Build Coastguard Worker                                                  uint32_t          aCommand,
1508*cfb92d14SAndroid Build Coastguard Worker                                                  spinel_prop_key_t aKey,
1509*cfb92d14SAndroid Build Coastguard Worker                                                  const char       *aFormat,
1510*cfb92d14SAndroid Build Coastguard Worker                                                  va_list           aArgs)
1511*cfb92d14SAndroid Build Coastguard Worker {
1512*cfb92d14SAndroid Build Coastguard Worker     otError error;
1513*cfb92d14SAndroid Build Coastguard Worker 
1514*cfb92d14SAndroid Build Coastguard Worker     mExpectedCommand = aExpectedCommand;
1515*cfb92d14SAndroid Build Coastguard Worker     error            = RequestV(aCommand, aKey, aFormat, aArgs);
1516*cfb92d14SAndroid Build Coastguard Worker     mExpectedCommand = SPINEL_CMD_NOOP;
1517*cfb92d14SAndroid Build Coastguard Worker 
1518*cfb92d14SAndroid Build Coastguard Worker     return error;
1519*cfb92d14SAndroid Build Coastguard Worker }
1520*cfb92d14SAndroid Build Coastguard Worker 
HandleTransmitDone(uint32_t aCommand,spinel_prop_key_t aKey,const uint8_t * aBuffer,uint16_t aLength)1521*cfb92d14SAndroid Build Coastguard Worker void RadioSpinel::HandleTransmitDone(uint32_t          aCommand,
1522*cfb92d14SAndroid Build Coastguard Worker                                      spinel_prop_key_t aKey,
1523*cfb92d14SAndroid Build Coastguard Worker                                      const uint8_t    *aBuffer,
1524*cfb92d14SAndroid Build Coastguard Worker                                      uint16_t          aLength)
1525*cfb92d14SAndroid Build Coastguard Worker {
1526*cfb92d14SAndroid Build Coastguard Worker     otError         error         = OT_ERROR_NONE;
1527*cfb92d14SAndroid Build Coastguard Worker     spinel_status_t status        = SPINEL_STATUS_OK;
1528*cfb92d14SAndroid Build Coastguard Worker     bool            framePending  = false;
1529*cfb92d14SAndroid Build Coastguard Worker     bool            headerUpdated = false;
1530*cfb92d14SAndroid Build Coastguard Worker     spinel_ssize_t  unpacked;
1531*cfb92d14SAndroid Build Coastguard Worker 
1532*cfb92d14SAndroid Build Coastguard Worker     EXPECT(aCommand == SPINEL_CMD_PROP_VALUE_IS && aKey == SPINEL_PROP_LAST_STATUS, error = OT_ERROR_FAILED);
1533*cfb92d14SAndroid Build Coastguard Worker 
1534*cfb92d14SAndroid Build Coastguard Worker     unpacked = spinel_datatype_unpack(aBuffer, aLength, SPINEL_DATATYPE_UINT_PACKED_S, &status);
1535*cfb92d14SAndroid Build Coastguard Worker     EXPECT(unpacked > 0, error = OT_ERROR_PARSE);
1536*cfb92d14SAndroid Build Coastguard Worker 
1537*cfb92d14SAndroid Build Coastguard Worker     aBuffer += unpacked;
1538*cfb92d14SAndroid Build Coastguard Worker     aLength -= static_cast<uint16_t>(unpacked);
1539*cfb92d14SAndroid Build Coastguard Worker 
1540*cfb92d14SAndroid Build Coastguard Worker     unpacked = spinel_datatype_unpack(aBuffer, aLength, SPINEL_DATATYPE_BOOL_S, &framePending);
1541*cfb92d14SAndroid Build Coastguard Worker     EXPECT(unpacked > 0, error = OT_ERROR_PARSE);
1542*cfb92d14SAndroid Build Coastguard Worker 
1543*cfb92d14SAndroid Build Coastguard Worker     aBuffer += unpacked;
1544*cfb92d14SAndroid Build Coastguard Worker     aLength -= static_cast<uint16_t>(unpacked);
1545*cfb92d14SAndroid Build Coastguard Worker 
1546*cfb92d14SAndroid Build Coastguard Worker     unpacked = spinel_datatype_unpack(aBuffer, aLength, SPINEL_DATATYPE_BOOL_S, &headerUpdated);
1547*cfb92d14SAndroid Build Coastguard Worker     EXPECT(unpacked > 0, error = OT_ERROR_PARSE);
1548*cfb92d14SAndroid Build Coastguard Worker 
1549*cfb92d14SAndroid Build Coastguard Worker     aBuffer += unpacked;
1550*cfb92d14SAndroid Build Coastguard Worker     aLength -= static_cast<uint16_t>(unpacked);
1551*cfb92d14SAndroid Build Coastguard Worker 
1552*cfb92d14SAndroid Build Coastguard Worker     if (status == SPINEL_STATUS_OK)
1553*cfb92d14SAndroid Build Coastguard Worker     {
1554*cfb92d14SAndroid Build Coastguard Worker         EXPECT_NO_ERROR(error = ParseRadioFrame(mAckRadioFrame, aBuffer, aLength, unpacked));
1555*cfb92d14SAndroid Build Coastguard Worker         aBuffer += unpacked;
1556*cfb92d14SAndroid Build Coastguard Worker         aLength -= static_cast<uint16_t>(unpacked);
1557*cfb92d14SAndroid Build Coastguard Worker     }
1558*cfb92d14SAndroid Build Coastguard Worker     else
1559*cfb92d14SAndroid Build Coastguard Worker     {
1560*cfb92d14SAndroid Build Coastguard Worker         error = SpinelStatusToOtError(status);
1561*cfb92d14SAndroid Build Coastguard Worker     }
1562*cfb92d14SAndroid Build Coastguard Worker 
1563*cfb92d14SAndroid Build Coastguard Worker     static_cast<Mac::TxFrame *>(mTransmitFrame)->SetIsHeaderUpdated(headerUpdated);
1564*cfb92d14SAndroid Build Coastguard Worker 
1565*cfb92d14SAndroid Build Coastguard Worker     if ((sRadioCaps & OT_RADIO_CAPS_TRANSMIT_SEC) && headerUpdated &&
1566*cfb92d14SAndroid Build Coastguard Worker         static_cast<Mac::TxFrame *>(mTransmitFrame)->GetSecurityEnabled())
1567*cfb92d14SAndroid Build Coastguard Worker     {
1568*cfb92d14SAndroid Build Coastguard Worker         uint8_t  keyId;
1569*cfb92d14SAndroid Build Coastguard Worker         uint32_t frameCounter;
1570*cfb92d14SAndroid Build Coastguard Worker 
1571*cfb92d14SAndroid Build Coastguard Worker         // Replace transmit frame security key index and frame counter with the one filled by RCP
1572*cfb92d14SAndroid Build Coastguard Worker         unpacked = spinel_datatype_unpack(aBuffer, aLength, SPINEL_DATATYPE_UINT8_S SPINEL_DATATYPE_UINT32_S, &keyId,
1573*cfb92d14SAndroid Build Coastguard Worker                                           &frameCounter);
1574*cfb92d14SAndroid Build Coastguard Worker         EXPECT(unpacked > 0, error = OT_ERROR_PARSE);
1575*cfb92d14SAndroid Build Coastguard Worker         static_cast<Mac::TxFrame *>(mTransmitFrame)->SetKeyId(keyId);
1576*cfb92d14SAndroid Build Coastguard Worker         static_cast<Mac::TxFrame *>(mTransmitFrame)->SetFrameCounter(frameCounter);
1577*cfb92d14SAndroid Build Coastguard Worker 
1578*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0
1579*cfb92d14SAndroid Build Coastguard Worker         mMacFrameCounterSet = true;
1580*cfb92d14SAndroid Build Coastguard Worker #endif
1581*cfb92d14SAndroid Build Coastguard Worker     }
1582*cfb92d14SAndroid Build Coastguard Worker 
1583*cfb92d14SAndroid Build Coastguard Worker exit:
1584*cfb92d14SAndroid Build Coastguard Worker     // A parse error indicates an RCP misbehavior, so recover the RCP immediately.
1585*cfb92d14SAndroid Build Coastguard Worker     mState = kStateTransmitDone;
1586*cfb92d14SAndroid Build Coastguard Worker     if (error != OT_ERROR_PARSE)
1587*cfb92d14SAndroid Build Coastguard Worker     {
1588*cfb92d14SAndroid Build Coastguard Worker         mTxError = error;
1589*cfb92d14SAndroid Build Coastguard Worker     }
1590*cfb92d14SAndroid Build Coastguard Worker     else
1591*cfb92d14SAndroid Build Coastguard Worker     {
1592*cfb92d14SAndroid Build Coastguard Worker         mTxError = kErrorAbort;
1593*cfb92d14SAndroid Build Coastguard Worker         HandleRcpTimeout();
1594*cfb92d14SAndroid Build Coastguard Worker         RecoverFromRcpFailure();
1595*cfb92d14SAndroid Build Coastguard Worker     }
1596*cfb92d14SAndroid Build Coastguard Worker     UpdateParseErrorCount(error);
1597*cfb92d14SAndroid Build Coastguard Worker     LogIfFail("Handle transmit done failed", error);
1598*cfb92d14SAndroid Build Coastguard Worker }
1599*cfb92d14SAndroid Build Coastguard Worker 
Transmit(otRadioFrame & aFrame)1600*cfb92d14SAndroid Build Coastguard Worker otError RadioSpinel::Transmit(otRadioFrame &aFrame)
1601*cfb92d14SAndroid Build Coastguard Worker {
1602*cfb92d14SAndroid Build Coastguard Worker     otError error = OT_ERROR_INVALID_STATE;
1603*cfb92d14SAndroid Build Coastguard Worker 
1604*cfb92d14SAndroid Build Coastguard Worker     EXPECT(mState == kStateReceive || (mState == kStateSleep && (sRadioCaps & OT_RADIO_CAPS_SLEEP_TO_TX)), NO_ACTION);
1605*cfb92d14SAndroid Build Coastguard Worker 
1606*cfb92d14SAndroid Build Coastguard Worker     mTransmitFrame = &aFrame;
1607*cfb92d14SAndroid Build Coastguard Worker 
1608*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT && OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
1609*cfb92d14SAndroid Build Coastguard Worker     if (mTransmitFrame->mInfo.mTxInfo.mIeInfo->mTimeIeOffset != 0)
1610*cfb92d14SAndroid Build Coastguard Worker     {
1611*cfb92d14SAndroid Build Coastguard Worker         uint64_t netRadioTime = otPlatRadioGetNow(mInstance);
1612*cfb92d14SAndroid Build Coastguard Worker         uint64_t netSyncTime;
1613*cfb92d14SAndroid Build Coastguard Worker         uint8_t *timeIe = mTransmitFrame->mPsdu + mTransmitFrame->mInfo.mTxInfo.mIeInfo->mTimeIeOffset;
1614*cfb92d14SAndroid Build Coastguard Worker 
1615*cfb92d14SAndroid Build Coastguard Worker         if (netRadioTime == UINT64_MAX)
1616*cfb92d14SAndroid Build Coastguard Worker         {
1617*cfb92d14SAndroid Build Coastguard Worker             // If we can't get the radio time, get the platform time
1618*cfb92d14SAndroid Build Coastguard Worker             netSyncTime = static_cast<uint64_t>(static_cast<int64_t>(otPlatTimeGet()) +
1619*cfb92d14SAndroid Build Coastguard Worker                                                 mTransmitFrame->mInfo.mTxInfo.mIeInfo->mNetworkTimeOffset);
1620*cfb92d14SAndroid Build Coastguard Worker         }
1621*cfb92d14SAndroid Build Coastguard Worker         else
1622*cfb92d14SAndroid Build Coastguard Worker         {
1623*cfb92d14SAndroid Build Coastguard Worker             uint32_t transmitDelay = 0;
1624*cfb92d14SAndroid Build Coastguard Worker 
1625*cfb92d14SAndroid Build Coastguard Worker             // If supported, add a delay and transmit the network time at a precise moment
1626*cfb92d14SAndroid Build Coastguard Worker #if !OPENTHREAD_MTD && OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
1627*cfb92d14SAndroid Build Coastguard Worker             transmitDelay                                  = kTxWaitUs / 10;
1628*cfb92d14SAndroid Build Coastguard Worker             mTransmitFrame->mInfo.mTxInfo.mTxDelayBaseTime = static_cast<uint32_t>(netRadioTime);
1629*cfb92d14SAndroid Build Coastguard Worker             mTransmitFrame->mInfo.mTxInfo.mTxDelay         = transmitDelay;
1630*cfb92d14SAndroid Build Coastguard Worker #endif
1631*cfb92d14SAndroid Build Coastguard Worker             netSyncTime = static_cast<uint64_t>(static_cast<int64_t>(netRadioTime) + transmitDelay +
1632*cfb92d14SAndroid Build Coastguard Worker                                                 mTransmitFrame->mInfo.mTxInfo.mIeInfo->mNetworkTimeOffset);
1633*cfb92d14SAndroid Build Coastguard Worker         }
1634*cfb92d14SAndroid Build Coastguard Worker 
1635*cfb92d14SAndroid Build Coastguard Worker         *(timeIe++) = mTransmitFrame->mInfo.mTxInfo.mIeInfo->mTimeSyncSeq;
1636*cfb92d14SAndroid Build Coastguard Worker 
1637*cfb92d14SAndroid Build Coastguard Worker         for (uint8_t i = 0; i < sizeof(uint64_t); i++)
1638*cfb92d14SAndroid Build Coastguard Worker         {
1639*cfb92d14SAndroid Build Coastguard Worker             *(timeIe++) = static_cast<uint8_t>(netSyncTime & 0xff);
1640*cfb92d14SAndroid Build Coastguard Worker             netSyncTime = netSyncTime >> 8;
1641*cfb92d14SAndroid Build Coastguard Worker         }
1642*cfb92d14SAndroid Build Coastguard Worker     }
1643*cfb92d14SAndroid Build Coastguard Worker #endif // OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT && OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
1644*cfb92d14SAndroid Build Coastguard Worker 
1645*cfb92d14SAndroid Build Coastguard Worker     // `otPlatRadioTxStarted()` is triggered immediately for now, which may be earlier than real started time.
1646*cfb92d14SAndroid Build Coastguard Worker     mCallbacks.mTxStarted(mInstance, mTransmitFrame);
1647*cfb92d14SAndroid Build Coastguard Worker 
1648*cfb92d14SAndroid Build Coastguard Worker     error = Request(SPINEL_CMD_PROP_VALUE_SET, SPINEL_PROP_STREAM_RAW,
1649*cfb92d14SAndroid Build Coastguard Worker                     SPINEL_DATATYPE_DATA_WLEN_S                                      // Frame data
1650*cfb92d14SAndroid Build Coastguard Worker                         SPINEL_DATATYPE_UINT8_S                                      // Channel
1651*cfb92d14SAndroid Build Coastguard Worker                             SPINEL_DATATYPE_UINT8_S                                  // MaxCsmaBackoffs
1652*cfb92d14SAndroid Build Coastguard Worker                                 SPINEL_DATATYPE_UINT8_S                              // MaxFrameRetries
1653*cfb92d14SAndroid Build Coastguard Worker                                     SPINEL_DATATYPE_BOOL_S                           // CsmaCaEnabled
1654*cfb92d14SAndroid Build Coastguard Worker                                         SPINEL_DATATYPE_BOOL_S                       // IsHeaderUpdated
1655*cfb92d14SAndroid Build Coastguard Worker                                             SPINEL_DATATYPE_BOOL_S                   // IsARetx
1656*cfb92d14SAndroid Build Coastguard Worker                                                 SPINEL_DATATYPE_BOOL_S               // IsSecurityProcessed
1657*cfb92d14SAndroid Build Coastguard Worker                                                     SPINEL_DATATYPE_UINT32_S         // TxDelay
1658*cfb92d14SAndroid Build Coastguard Worker                                                         SPINEL_DATATYPE_UINT32_S     // TxDelayBaseTime
1659*cfb92d14SAndroid Build Coastguard Worker                                                             SPINEL_DATATYPE_UINT8_S, // RxChannelAfterTxDone
1660*cfb92d14SAndroid Build Coastguard Worker                     mTransmitFrame->mPsdu, mTransmitFrame->mLength, mTransmitFrame->mChannel,
1661*cfb92d14SAndroid Build Coastguard Worker                     mTransmitFrame->mInfo.mTxInfo.mMaxCsmaBackoffs, mTransmitFrame->mInfo.mTxInfo.mMaxFrameRetries,
1662*cfb92d14SAndroid Build Coastguard Worker                     mTransmitFrame->mInfo.mTxInfo.mCsmaCaEnabled, mTransmitFrame->mInfo.mTxInfo.mIsHeaderUpdated,
1663*cfb92d14SAndroid Build Coastguard Worker                     mTransmitFrame->mInfo.mTxInfo.mIsARetx, mTransmitFrame->mInfo.mTxInfo.mIsSecurityProcessed,
1664*cfb92d14SAndroid Build Coastguard Worker                     mTransmitFrame->mInfo.mTxInfo.mTxDelay, mTransmitFrame->mInfo.mTxInfo.mTxDelayBaseTime,
1665*cfb92d14SAndroid Build Coastguard Worker                     mTransmitFrame->mInfo.mTxInfo.mRxChannelAfterTxDone);
1666*cfb92d14SAndroid Build Coastguard Worker 
1667*cfb92d14SAndroid Build Coastguard Worker     if (error == OT_ERROR_NONE)
1668*cfb92d14SAndroid Build Coastguard Worker     {
1669*cfb92d14SAndroid Build Coastguard Worker         // Waiting for `TransmitDone` event.
1670*cfb92d14SAndroid Build Coastguard Worker         mState        = kStateTransmitting;
1671*cfb92d14SAndroid Build Coastguard Worker         mTxRadioEndUs = otPlatTimeGet() + kTxWaitUs;
1672*cfb92d14SAndroid Build Coastguard Worker         mChannel      = mTransmitFrame->mChannel;
1673*cfb92d14SAndroid Build Coastguard Worker     }
1674*cfb92d14SAndroid Build Coastguard Worker 
1675*cfb92d14SAndroid Build Coastguard Worker exit:
1676*cfb92d14SAndroid Build Coastguard Worker     return error;
1677*cfb92d14SAndroid Build Coastguard Worker }
1678*cfb92d14SAndroid Build Coastguard Worker 
Receive(uint8_t aChannel)1679*cfb92d14SAndroid Build Coastguard Worker otError RadioSpinel::Receive(uint8_t aChannel)
1680*cfb92d14SAndroid Build Coastguard Worker {
1681*cfb92d14SAndroid Build Coastguard Worker     otError error = OT_ERROR_NONE;
1682*cfb92d14SAndroid Build Coastguard Worker 
1683*cfb92d14SAndroid Build Coastguard Worker     EXPECT(mState != kStateDisabled, error = OT_ERROR_INVALID_STATE);
1684*cfb92d14SAndroid Build Coastguard Worker 
1685*cfb92d14SAndroid Build Coastguard Worker     if (mChannel != aChannel)
1686*cfb92d14SAndroid Build Coastguard Worker     {
1687*cfb92d14SAndroid Build Coastguard Worker         error = Set(SPINEL_PROP_PHY_CHAN, SPINEL_DATATYPE_UINT8_S, aChannel);
1688*cfb92d14SAndroid Build Coastguard Worker         EXPECT_NO_ERROR(error);
1689*cfb92d14SAndroid Build Coastguard Worker         mChannel = aChannel;
1690*cfb92d14SAndroid Build Coastguard Worker     }
1691*cfb92d14SAndroid Build Coastguard Worker 
1692*cfb92d14SAndroid Build Coastguard Worker     if (mState == kStateSleep)
1693*cfb92d14SAndroid Build Coastguard Worker     {
1694*cfb92d14SAndroid Build Coastguard Worker         error = Set(SPINEL_PROP_MAC_RAW_STREAM_ENABLED, SPINEL_DATATYPE_BOOL_S, true);
1695*cfb92d14SAndroid Build Coastguard Worker         EXPECT_NO_ERROR(error);
1696*cfb92d14SAndroid Build Coastguard Worker     }
1697*cfb92d14SAndroid Build Coastguard Worker 
1698*cfb92d14SAndroid Build Coastguard Worker     if (mTxRadioTid != 0)
1699*cfb92d14SAndroid Build Coastguard Worker     {
1700*cfb92d14SAndroid Build Coastguard Worker         FreeTid(mTxRadioTid);
1701*cfb92d14SAndroid Build Coastguard Worker         mTxRadioTid = 0;
1702*cfb92d14SAndroid Build Coastguard Worker     }
1703*cfb92d14SAndroid Build Coastguard Worker 
1704*cfb92d14SAndroid Build Coastguard Worker     mState = kStateReceive;
1705*cfb92d14SAndroid Build Coastguard Worker 
1706*cfb92d14SAndroid Build Coastguard Worker exit:
1707*cfb92d14SAndroid Build Coastguard Worker     return error;
1708*cfb92d14SAndroid Build Coastguard Worker }
1709*cfb92d14SAndroid Build Coastguard Worker 
Sleep(void)1710*cfb92d14SAndroid Build Coastguard Worker otError RadioSpinel::Sleep(void)
1711*cfb92d14SAndroid Build Coastguard Worker {
1712*cfb92d14SAndroid Build Coastguard Worker     otError error = OT_ERROR_NONE;
1713*cfb92d14SAndroid Build Coastguard Worker 
1714*cfb92d14SAndroid Build Coastguard Worker     switch (mState)
1715*cfb92d14SAndroid Build Coastguard Worker     {
1716*cfb92d14SAndroid Build Coastguard Worker     case kStateReceive:
1717*cfb92d14SAndroid Build Coastguard Worker         error = Set(SPINEL_PROP_MAC_RAW_STREAM_ENABLED, SPINEL_DATATYPE_BOOL_S, false);
1718*cfb92d14SAndroid Build Coastguard Worker         EXPECT_NO_ERROR(error);
1719*cfb92d14SAndroid Build Coastguard Worker 
1720*cfb92d14SAndroid Build Coastguard Worker         mState = kStateSleep;
1721*cfb92d14SAndroid Build Coastguard Worker         break;
1722*cfb92d14SAndroid Build Coastguard Worker 
1723*cfb92d14SAndroid Build Coastguard Worker     case kStateSleep:
1724*cfb92d14SAndroid Build Coastguard Worker         break;
1725*cfb92d14SAndroid Build Coastguard Worker 
1726*cfb92d14SAndroid Build Coastguard Worker     default:
1727*cfb92d14SAndroid Build Coastguard Worker         error = OT_ERROR_INVALID_STATE;
1728*cfb92d14SAndroid Build Coastguard Worker         break;
1729*cfb92d14SAndroid Build Coastguard Worker     }
1730*cfb92d14SAndroid Build Coastguard Worker 
1731*cfb92d14SAndroid Build Coastguard Worker exit:
1732*cfb92d14SAndroid Build Coastguard Worker     return error;
1733*cfb92d14SAndroid Build Coastguard Worker }
1734*cfb92d14SAndroid Build Coastguard Worker 
Enable(otInstance * aInstance)1735*cfb92d14SAndroid Build Coastguard Worker otError RadioSpinel::Enable(otInstance *aInstance)
1736*cfb92d14SAndroid Build Coastguard Worker {
1737*cfb92d14SAndroid Build Coastguard Worker     otError error = OT_ERROR_NONE;
1738*cfb92d14SAndroid Build Coastguard Worker 
1739*cfb92d14SAndroid Build Coastguard Worker     EXPECT(!IsEnabled(), NO_ACTION);
1740*cfb92d14SAndroid Build Coastguard Worker 
1741*cfb92d14SAndroid Build Coastguard Worker     mInstance = aInstance;
1742*cfb92d14SAndroid Build Coastguard Worker 
1743*cfb92d14SAndroid Build Coastguard Worker     EXPECT_NO_ERROR(error = Set(SPINEL_PROP_PHY_ENABLED, SPINEL_DATATYPE_BOOL_S, true));
1744*cfb92d14SAndroid Build Coastguard Worker     EXPECT_NO_ERROR(error = Set(SPINEL_PROP_MAC_15_4_PANID, SPINEL_DATATYPE_UINT16_S, mPanId));
1745*cfb92d14SAndroid Build Coastguard Worker     EXPECT_NO_ERROR(error = Set(SPINEL_PROP_MAC_15_4_SADDR, SPINEL_DATATYPE_UINT16_S, mShortAddress));
1746*cfb92d14SAndroid Build Coastguard Worker     EXPECT_NO_ERROR(error = Get(SPINEL_PROP_PHY_RX_SENSITIVITY, SPINEL_DATATYPE_INT8_S, &mRxSensitivity));
1747*cfb92d14SAndroid Build Coastguard Worker 
1748*cfb92d14SAndroid Build Coastguard Worker     mState = kStateSleep;
1749*cfb92d14SAndroid Build Coastguard Worker 
1750*cfb92d14SAndroid Build Coastguard Worker exit:
1751*cfb92d14SAndroid Build Coastguard Worker     if (error != OT_ERROR_NONE)
1752*cfb92d14SAndroid Build Coastguard Worker     {
1753*cfb92d14SAndroid Build Coastguard Worker         LogWarn("RadioSpinel enable: %s", otThreadErrorToString(error));
1754*cfb92d14SAndroid Build Coastguard Worker         error = OT_ERROR_FAILED;
1755*cfb92d14SAndroid Build Coastguard Worker     }
1756*cfb92d14SAndroid Build Coastguard Worker 
1757*cfb92d14SAndroid Build Coastguard Worker     return error;
1758*cfb92d14SAndroid Build Coastguard Worker }
1759*cfb92d14SAndroid Build Coastguard Worker 
Disable(void)1760*cfb92d14SAndroid Build Coastguard Worker otError RadioSpinel::Disable(void)
1761*cfb92d14SAndroid Build Coastguard Worker {
1762*cfb92d14SAndroid Build Coastguard Worker     otError error = OT_ERROR_NONE;
1763*cfb92d14SAndroid Build Coastguard Worker 
1764*cfb92d14SAndroid Build Coastguard Worker     EXPECT(IsEnabled(), NO_ACTION);
1765*cfb92d14SAndroid Build Coastguard Worker     EXPECT(mState == kStateSleep, error = OT_ERROR_INVALID_STATE);
1766*cfb92d14SAndroid Build Coastguard Worker 
1767*cfb92d14SAndroid Build Coastguard Worker     SuccessOrDie(Set(SPINEL_PROP_PHY_ENABLED, SPINEL_DATATYPE_BOOL_S, false));
1768*cfb92d14SAndroid Build Coastguard Worker     mState    = kStateDisabled;
1769*cfb92d14SAndroid Build Coastguard Worker     mInstance = nullptr;
1770*cfb92d14SAndroid Build Coastguard Worker 
1771*cfb92d14SAndroid Build Coastguard Worker exit:
1772*cfb92d14SAndroid Build Coastguard Worker     return error;
1773*cfb92d14SAndroid Build Coastguard Worker }
1774*cfb92d14SAndroid Build Coastguard Worker 
1775*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_CONFIG_DIAG_ENABLE
SetDiagOutputCallback(otPlatDiagOutputCallback aCallback,void * aContext)1776*cfb92d14SAndroid Build Coastguard Worker void RadioSpinel::SetDiagOutputCallback(otPlatDiagOutputCallback aCallback, void *aContext)
1777*cfb92d14SAndroid Build Coastguard Worker {
1778*cfb92d14SAndroid Build Coastguard Worker     mOutputCallback = aCallback;
1779*cfb92d14SAndroid Build Coastguard Worker     mOutputContext  = aContext;
1780*cfb92d14SAndroid Build Coastguard Worker }
1781*cfb92d14SAndroid Build Coastguard Worker 
GetDiagOutputCallback(otPlatDiagOutputCallback & aCallback,void * & aContext)1782*cfb92d14SAndroid Build Coastguard Worker void RadioSpinel::GetDiagOutputCallback(otPlatDiagOutputCallback &aCallback, void *&aContext)
1783*cfb92d14SAndroid Build Coastguard Worker {
1784*cfb92d14SAndroid Build Coastguard Worker     aCallback = mOutputCallback;
1785*cfb92d14SAndroid Build Coastguard Worker     aContext  = mOutputContext;
1786*cfb92d14SAndroid Build Coastguard Worker }
1787*cfb92d14SAndroid Build Coastguard Worker 
RadioSpinelDiagProcess(char * aArgs[],uint8_t aArgsLength)1788*cfb92d14SAndroid Build Coastguard Worker otError RadioSpinel::RadioSpinelDiagProcess(char *aArgs[], uint8_t aArgsLength)
1789*cfb92d14SAndroid Build Coastguard Worker {
1790*cfb92d14SAndroid Build Coastguard Worker     otError error = OT_ERROR_NONE;
1791*cfb92d14SAndroid Build Coastguard Worker 
1792*cfb92d14SAndroid Build Coastguard Worker     VerifyOrExit(aArgsLength > 1, error = OT_ERROR_INVALID_ARGS);
1793*cfb92d14SAndroid Build Coastguard Worker 
1794*cfb92d14SAndroid Build Coastguard Worker     aArgs++;
1795*cfb92d14SAndroid Build Coastguard Worker     aArgsLength--;
1796*cfb92d14SAndroid Build Coastguard Worker 
1797*cfb92d14SAndroid Build Coastguard Worker     if (strcmp(aArgs[0], "buslatency") == 0)
1798*cfb92d14SAndroid Build Coastguard Worker     {
1799*cfb92d14SAndroid Build Coastguard Worker         if (aArgsLength == 1)
1800*cfb92d14SAndroid Build Coastguard Worker         {
1801*cfb92d14SAndroid Build Coastguard Worker             PlatDiagOutput("%lu\n", ToUlong(GetBusLatency()));
1802*cfb92d14SAndroid Build Coastguard Worker         }
1803*cfb92d14SAndroid Build Coastguard Worker         else if (aArgsLength == 2)
1804*cfb92d14SAndroid Build Coastguard Worker         {
1805*cfb92d14SAndroid Build Coastguard Worker             uint32_t busLatency;
1806*cfb92d14SAndroid Build Coastguard Worker             char    *endptr;
1807*cfb92d14SAndroid Build Coastguard Worker 
1808*cfb92d14SAndroid Build Coastguard Worker             busLatency = static_cast<uint32_t>(strtoul(aArgs[1], &endptr, 0));
1809*cfb92d14SAndroid Build Coastguard Worker             VerifyOrExit(*endptr == '\0', error = OT_ERROR_INVALID_ARGS);
1810*cfb92d14SAndroid Build Coastguard Worker 
1811*cfb92d14SAndroid Build Coastguard Worker             SetBusLatency(busLatency);
1812*cfb92d14SAndroid Build Coastguard Worker         }
1813*cfb92d14SAndroid Build Coastguard Worker         else
1814*cfb92d14SAndroid Build Coastguard Worker         {
1815*cfb92d14SAndroid Build Coastguard Worker             error = OT_ERROR_INVALID_ARGS;
1816*cfb92d14SAndroid Build Coastguard Worker         }
1817*cfb92d14SAndroid Build Coastguard Worker     }
1818*cfb92d14SAndroid Build Coastguard Worker 
1819*cfb92d14SAndroid Build Coastguard Worker exit:
1820*cfb92d14SAndroid Build Coastguard Worker     return error;
1821*cfb92d14SAndroid Build Coastguard Worker }
1822*cfb92d14SAndroid Build Coastguard Worker 
PlatDiagProcess(const char * aString)1823*cfb92d14SAndroid Build Coastguard Worker otError RadioSpinel::PlatDiagProcess(const char *aString)
1824*cfb92d14SAndroid Build Coastguard Worker {
1825*cfb92d14SAndroid Build Coastguard Worker     return Set(SPINEL_PROP_NEST_STREAM_MFG, SPINEL_DATATYPE_UTF8_S, aString);
1826*cfb92d14SAndroid Build Coastguard Worker }
1827*cfb92d14SAndroid Build Coastguard Worker 
PlatDiagOutput(const char * aFormat,...)1828*cfb92d14SAndroid Build Coastguard Worker void RadioSpinel::PlatDiagOutput(const char *aFormat, ...)
1829*cfb92d14SAndroid Build Coastguard Worker {
1830*cfb92d14SAndroid Build Coastguard Worker     va_list args;
1831*cfb92d14SAndroid Build Coastguard Worker 
1832*cfb92d14SAndroid Build Coastguard Worker     va_start(args, aFormat);
1833*cfb92d14SAndroid Build Coastguard Worker 
1834*cfb92d14SAndroid Build Coastguard Worker     if (mOutputCallback != nullptr)
1835*cfb92d14SAndroid Build Coastguard Worker     {
1836*cfb92d14SAndroid Build Coastguard Worker         mOutputCallback(aFormat, args, mOutputContext);
1837*cfb92d14SAndroid Build Coastguard Worker     }
1838*cfb92d14SAndroid Build Coastguard Worker 
1839*cfb92d14SAndroid Build Coastguard Worker     va_end(args);
1840*cfb92d14SAndroid Build Coastguard Worker }
1841*cfb92d14SAndroid Build Coastguard Worker 
1842*cfb92d14SAndroid Build Coastguard Worker #endif // OPENTHREAD_CONFIG_DIAG_ENABLE
1843*cfb92d14SAndroid Build Coastguard Worker 
GetRadioChannelMask(bool aPreferred)1844*cfb92d14SAndroid Build Coastguard Worker uint32_t RadioSpinel::GetRadioChannelMask(bool aPreferred)
1845*cfb92d14SAndroid Build Coastguard Worker {
1846*cfb92d14SAndroid Build Coastguard Worker     uint8_t        maskBuffer[kChannelMaskBufferSize];
1847*cfb92d14SAndroid Build Coastguard Worker     otError        error       = OT_ERROR_NONE;
1848*cfb92d14SAndroid Build Coastguard Worker     uint32_t       channelMask = 0;
1849*cfb92d14SAndroid Build Coastguard Worker     const uint8_t *maskData    = maskBuffer;
1850*cfb92d14SAndroid Build Coastguard Worker     spinel_size_t  maskLength  = sizeof(maskBuffer);
1851*cfb92d14SAndroid Build Coastguard Worker 
1852*cfb92d14SAndroid Build Coastguard Worker     SuccessOrDie(Get(aPreferred ? SPINEL_PROP_PHY_CHAN_PREFERRED : SPINEL_PROP_PHY_CHAN_SUPPORTED,
1853*cfb92d14SAndroid Build Coastguard Worker                      SPINEL_DATATYPE_DATA_S, maskBuffer, &maskLength));
1854*cfb92d14SAndroid Build Coastguard Worker 
1855*cfb92d14SAndroid Build Coastguard Worker     while (maskLength > 0)
1856*cfb92d14SAndroid Build Coastguard Worker     {
1857*cfb92d14SAndroid Build Coastguard Worker         uint8_t        channel;
1858*cfb92d14SAndroid Build Coastguard Worker         spinel_ssize_t unpacked;
1859*cfb92d14SAndroid Build Coastguard Worker 
1860*cfb92d14SAndroid Build Coastguard Worker         unpacked = spinel_datatype_unpack(maskData, maskLength, SPINEL_DATATYPE_UINT8_S, &channel);
1861*cfb92d14SAndroid Build Coastguard Worker         EXPECT(unpacked > 0, error = OT_ERROR_FAILED);
1862*cfb92d14SAndroid Build Coastguard Worker         EXPECT(channel < kChannelMaskBufferSize, error = OT_ERROR_PARSE);
1863*cfb92d14SAndroid Build Coastguard Worker         channelMask |= (1UL << channel);
1864*cfb92d14SAndroid Build Coastguard Worker 
1865*cfb92d14SAndroid Build Coastguard Worker         maskData += unpacked;
1866*cfb92d14SAndroid Build Coastguard Worker         maskLength -= static_cast<spinel_size_t>(unpacked);
1867*cfb92d14SAndroid Build Coastguard Worker     }
1868*cfb92d14SAndroid Build Coastguard Worker 
1869*cfb92d14SAndroid Build Coastguard Worker     channelMask &= mMaxPowerTable.GetSupportedChannelMask();
1870*cfb92d14SAndroid Build Coastguard Worker 
1871*cfb92d14SAndroid Build Coastguard Worker exit:
1872*cfb92d14SAndroid Build Coastguard Worker     UpdateParseErrorCount(error);
1873*cfb92d14SAndroid Build Coastguard Worker     LogIfFail("Get radio channel mask failed", error);
1874*cfb92d14SAndroid Build Coastguard Worker     return channelMask;
1875*cfb92d14SAndroid Build Coastguard Worker }
1876*cfb92d14SAndroid Build Coastguard Worker 
GetState(void) const1877*cfb92d14SAndroid Build Coastguard Worker otRadioState RadioSpinel::GetState(void) const
1878*cfb92d14SAndroid Build Coastguard Worker {
1879*cfb92d14SAndroid Build Coastguard Worker     static const otRadioState sOtRadioStateMap[] = {
1880*cfb92d14SAndroid Build Coastguard Worker         OT_RADIO_STATE_DISABLED, OT_RADIO_STATE_SLEEP,    OT_RADIO_STATE_RECEIVE,
1881*cfb92d14SAndroid Build Coastguard Worker         OT_RADIO_STATE_TRANSMIT, OT_RADIO_STATE_TRANSMIT,
1882*cfb92d14SAndroid Build Coastguard Worker     };
1883*cfb92d14SAndroid Build Coastguard Worker 
1884*cfb92d14SAndroid Build Coastguard Worker     return sOtRadioStateMap[mState];
1885*cfb92d14SAndroid Build Coastguard Worker }
1886*cfb92d14SAndroid Build Coastguard Worker 
CalcRcpTimeOffset(void)1887*cfb92d14SAndroid Build Coastguard Worker void RadioSpinel::CalcRcpTimeOffset(void)
1888*cfb92d14SAndroid Build Coastguard Worker {
1889*cfb92d14SAndroid Build Coastguard Worker     otError        error = OT_ERROR_NONE;
1890*cfb92d14SAndroid Build Coastguard Worker     uint64_t       localTxTimestamp;
1891*cfb92d14SAndroid Build Coastguard Worker     uint64_t       localRxTimestamp;
1892*cfb92d14SAndroid Build Coastguard Worker     uint64_t       remoteTimestamp = 0;
1893*cfb92d14SAndroid Build Coastguard Worker     uint8_t        buffer[sizeof(remoteTimestamp)];
1894*cfb92d14SAndroid Build Coastguard Worker     spinel_ssize_t packed;
1895*cfb92d14SAndroid Build Coastguard Worker 
1896*cfb92d14SAndroid Build Coastguard Worker     /*
1897*cfb92d14SAndroid Build Coastguard Worker      * Use a modified Network Time Protocol(NTP) to calculate the time offset
1898*cfb92d14SAndroid Build Coastguard Worker      * Assume the time offset is D so that local can calculate remote time with,
1899*cfb92d14SAndroid Build Coastguard Worker      *         T' = T + D
1900*cfb92d14SAndroid Build Coastguard Worker      * Where T is the local time and T' is the remote time.
1901*cfb92d14SAndroid Build Coastguard Worker      * The time offset is calculated using timestamp measured at local and remote.
1902*cfb92d14SAndroid Build Coastguard Worker      *
1903*cfb92d14SAndroid Build Coastguard Worker      *              T0  P    P T2
1904*cfb92d14SAndroid Build Coastguard Worker      *  local time --+----+----+--->
1905*cfb92d14SAndroid Build Coastguard Worker      *                \   |   ^
1906*cfb92d14SAndroid Build Coastguard Worker      *              get\  |  /is
1907*cfb92d14SAndroid Build Coastguard Worker      *                  v | /
1908*cfb92d14SAndroid Build Coastguard Worker      * remote time -------+--------->
1909*cfb92d14SAndroid Build Coastguard Worker      *                    T1'
1910*cfb92d14SAndroid Build Coastguard Worker      *
1911*cfb92d14SAndroid Build Coastguard Worker      * Based on the assumptions,
1912*cfb92d14SAndroid Build Coastguard Worker      * 1. If the propagation time(P) from local to remote and from remote to local are same.
1913*cfb92d14SAndroid Build Coastguard Worker      * 2. Both the host and RCP can accurately measure the time they send or receive a message.
1914*cfb92d14SAndroid Build Coastguard Worker      * The degree to which these assumptions hold true determines the accuracy of the offset.
1915*cfb92d14SAndroid Build Coastguard Worker      * Then,
1916*cfb92d14SAndroid Build Coastguard Worker      *         T1' = T0 + P + D and T1' = T2 - P + D
1917*cfb92d14SAndroid Build Coastguard Worker      * Time offset can be calculated with,
1918*cfb92d14SAndroid Build Coastguard Worker      *         D = T1' - ((T0 + T2)/ 2)
1919*cfb92d14SAndroid Build Coastguard Worker      */
1920*cfb92d14SAndroid Build Coastguard Worker 
1921*cfb92d14SAndroid Build Coastguard Worker     EXPECT(mTimeSyncOn, NO_ACTION);
1922*cfb92d14SAndroid Build Coastguard Worker     EXPECT(!mIsTimeSynced || (otPlatTimeGet() >= GetNextRadioTimeRecalcStart()), NO_ACTION);
1923*cfb92d14SAndroid Build Coastguard Worker 
1924*cfb92d14SAndroid Build Coastguard Worker     LogDebg("Trying to get RCP time offset");
1925*cfb92d14SAndroid Build Coastguard Worker 
1926*cfb92d14SAndroid Build Coastguard Worker     packed = spinel_datatype_pack(buffer, sizeof(buffer), SPINEL_DATATYPE_UINT64_S, remoteTimestamp);
1927*cfb92d14SAndroid Build Coastguard Worker     EXPECT(packed > 0 && static_cast<size_t>(packed) <= sizeof(buffer), error = OT_ERROR_NO_BUFS);
1928*cfb92d14SAndroid Build Coastguard Worker 
1929*cfb92d14SAndroid Build Coastguard Worker     localTxTimestamp = otPlatTimeGet();
1930*cfb92d14SAndroid Build Coastguard Worker 
1931*cfb92d14SAndroid Build Coastguard Worker     // Dummy timestamp payload to make request length same as response
1932*cfb92d14SAndroid Build Coastguard Worker     error = GetWithParam(SPINEL_PROP_RCP_TIMESTAMP, buffer, static_cast<spinel_size_t>(packed),
1933*cfb92d14SAndroid Build Coastguard Worker                          SPINEL_DATATYPE_UINT64_S, &remoteTimestamp);
1934*cfb92d14SAndroid Build Coastguard Worker 
1935*cfb92d14SAndroid Build Coastguard Worker     localRxTimestamp = otPlatTimeGet();
1936*cfb92d14SAndroid Build Coastguard Worker 
1937*cfb92d14SAndroid Build Coastguard Worker     EXPECT(error == OT_ERROR_NONE, mRadioTimeRecalcStart = localRxTimestamp);
1938*cfb92d14SAndroid Build Coastguard Worker 
1939*cfb92d14SAndroid Build Coastguard Worker     mRadioTimeOffset      = (remoteTimestamp - ((localRxTimestamp / 2) + (localTxTimestamp / 2)));
1940*cfb92d14SAndroid Build Coastguard Worker     mIsTimeSynced         = true;
1941*cfb92d14SAndroid Build Coastguard Worker     mRadioTimeRecalcStart = localRxTimestamp + OPENTHREAD_SPINEL_CONFIG_RCP_TIME_SYNC_INTERVAL;
1942*cfb92d14SAndroid Build Coastguard Worker 
1943*cfb92d14SAndroid Build Coastguard Worker exit:
1944*cfb92d14SAndroid Build Coastguard Worker     LogIfFail("Error calculating RCP time offset: %s", error);
1945*cfb92d14SAndroid Build Coastguard Worker }
1946*cfb92d14SAndroid Build Coastguard Worker 
GetNow(void)1947*cfb92d14SAndroid Build Coastguard Worker uint64_t RadioSpinel::GetNow(void) { return (mIsTimeSynced) ? (otPlatTimeGet() + mRadioTimeOffset) : UINT64_MAX; }
1948*cfb92d14SAndroid Build Coastguard Worker 
GetBusSpeed(void) const1949*cfb92d14SAndroid Build Coastguard Worker uint32_t RadioSpinel::GetBusSpeed(void) const { return GetSpinelDriver().GetSpinelInterface()->GetBusSpeed(); }
1950*cfb92d14SAndroid Build Coastguard Worker 
GetBusLatency(void) const1951*cfb92d14SAndroid Build Coastguard Worker uint32_t RadioSpinel::GetBusLatency(void) const { return mBusLatency; }
1952*cfb92d14SAndroid Build Coastguard Worker 
SetBusLatency(uint32_t aBusLatency)1953*cfb92d14SAndroid Build Coastguard Worker void RadioSpinel::SetBusLatency(uint32_t aBusLatency)
1954*cfb92d14SAndroid Build Coastguard Worker {
1955*cfb92d14SAndroid Build Coastguard Worker     mBusLatency = aBusLatency;
1956*cfb92d14SAndroid Build Coastguard Worker 
1957*cfb92d14SAndroid Build Coastguard Worker     if (IsEnabled() && mCallbacks.mBusLatencyChanged != nullptr)
1958*cfb92d14SAndroid Build Coastguard Worker     {
1959*cfb92d14SAndroid Build Coastguard Worker         mCallbacks.mBusLatencyChanged(mInstance);
1960*cfb92d14SAndroid Build Coastguard Worker     }
1961*cfb92d14SAndroid Build Coastguard Worker }
1962*cfb92d14SAndroid Build Coastguard Worker 
HandleRcpUnexpectedReset(spinel_status_t aStatus)1963*cfb92d14SAndroid Build Coastguard Worker void RadioSpinel::HandleRcpUnexpectedReset(spinel_status_t aStatus)
1964*cfb92d14SAndroid Build Coastguard Worker {
1965*cfb92d14SAndroid Build Coastguard Worker     OT_UNUSED_VARIABLE(aStatus);
1966*cfb92d14SAndroid Build Coastguard Worker 
1967*cfb92d14SAndroid Build Coastguard Worker     mRadioSpinelMetrics.mRcpUnexpectedResetCount++;
1968*cfb92d14SAndroid Build Coastguard Worker     LogCrit("Unexpected RCP reset: %s", spinel_status_to_cstr(aStatus));
1969*cfb92d14SAndroid Build Coastguard Worker 
1970*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0
1971*cfb92d14SAndroid Build Coastguard Worker     mRcpFailure = kRcpFailureUnexpectedReset;
1972*cfb92d14SAndroid Build Coastguard Worker #elif OPENTHREAD_SPINEL_CONFIG_ABORT_ON_UNEXPECTED_RCP_RESET_ENABLE
1973*cfb92d14SAndroid Build Coastguard Worker     abort();
1974*cfb92d14SAndroid Build Coastguard Worker #else
1975*cfb92d14SAndroid Build Coastguard Worker     DieNow(OT_EXIT_RADIO_SPINEL_RESET);
1976*cfb92d14SAndroid Build Coastguard Worker #endif
1977*cfb92d14SAndroid Build Coastguard Worker }
1978*cfb92d14SAndroid Build Coastguard Worker 
HandleRcpTimeout(void)1979*cfb92d14SAndroid Build Coastguard Worker void RadioSpinel::HandleRcpTimeout(void)
1980*cfb92d14SAndroid Build Coastguard Worker {
1981*cfb92d14SAndroid Build Coastguard Worker     mRadioSpinelMetrics.mRcpTimeoutCount++;
1982*cfb92d14SAndroid Build Coastguard Worker 
1983*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0
1984*cfb92d14SAndroid Build Coastguard Worker     mRcpFailure = kRcpFailureTimeout;
1985*cfb92d14SAndroid Build Coastguard Worker #else
1986*cfb92d14SAndroid Build Coastguard Worker     LogCrit("Failed to communicate with RCP - no response from RCP during initialization");
1987*cfb92d14SAndroid Build Coastguard Worker     LogCrit("This is not a bug and typically due a config error (wrong URL parameters) or bad RCP image:");
1988*cfb92d14SAndroid Build Coastguard Worker     LogCrit("- Make sure RCP is running the correct firmware");
1989*cfb92d14SAndroid Build Coastguard Worker     LogCrit("- Double check the config parameters passed as `RadioURL` input");
1990*cfb92d14SAndroid Build Coastguard Worker 
1991*cfb92d14SAndroid Build Coastguard Worker     DieNow(OT_EXIT_RADIO_SPINEL_NO_RESPONSE);
1992*cfb92d14SAndroid Build Coastguard Worker #endif
1993*cfb92d14SAndroid Build Coastguard Worker }
1994*cfb92d14SAndroid Build Coastguard Worker 
RecoverFromRcpFailure(void)1995*cfb92d14SAndroid Build Coastguard Worker void RadioSpinel::RecoverFromRcpFailure(void)
1996*cfb92d14SAndroid Build Coastguard Worker {
1997*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0
1998*cfb92d14SAndroid Build Coastguard Worker     constexpr int16_t kMaxFailureCount = OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT;
1999*cfb92d14SAndroid Build Coastguard Worker     State             recoveringState  = mState;
2000*cfb92d14SAndroid Build Coastguard Worker     bool              skipReset        = false;
2001*cfb92d14SAndroid Build Coastguard Worker 
2002*cfb92d14SAndroid Build Coastguard Worker     if (mRcpFailure == kRcpFailureNone)
2003*cfb92d14SAndroid Build Coastguard Worker     {
2004*cfb92d14SAndroid Build Coastguard Worker         EXIT_NOW();
2005*cfb92d14SAndroid Build Coastguard Worker     }
2006*cfb92d14SAndroid Build Coastguard Worker 
2007*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE
2008*cfb92d14SAndroid Build Coastguard Worker     skipReset = (mRcpFailure == kRcpFailureUnexpectedReset);
2009*cfb92d14SAndroid Build Coastguard Worker #endif
2010*cfb92d14SAndroid Build Coastguard Worker 
2011*cfb92d14SAndroid Build Coastguard Worker     mRcpFailure = kRcpFailureNone;
2012*cfb92d14SAndroid Build Coastguard Worker 
2013*cfb92d14SAndroid Build Coastguard Worker     LogWarn("RCP failure detected");
2014*cfb92d14SAndroid Build Coastguard Worker 
2015*cfb92d14SAndroid Build Coastguard Worker     ++mRadioSpinelMetrics.mRcpRestorationCount;
2016*cfb92d14SAndroid Build Coastguard Worker     ++mRcpFailureCount;
2017*cfb92d14SAndroid Build Coastguard Worker     if (mRcpFailureCount > kMaxFailureCount)
2018*cfb92d14SAndroid Build Coastguard Worker     {
2019*cfb92d14SAndroid Build Coastguard Worker         LogCrit("Too many rcp failures, exiting");
2020*cfb92d14SAndroid Build Coastguard Worker         DieNow(OT_EXIT_FAILURE);
2021*cfb92d14SAndroid Build Coastguard Worker     }
2022*cfb92d14SAndroid Build Coastguard Worker 
2023*cfb92d14SAndroid Build Coastguard Worker     LogWarn("Trying to recover (%d/%d)", mRcpFailureCount, kMaxFailureCount);
2024*cfb92d14SAndroid Build Coastguard Worker 
2025*cfb92d14SAndroid Build Coastguard Worker     mState = kStateDisabled;
2026*cfb92d14SAndroid Build Coastguard Worker 
2027*cfb92d14SAndroid Build Coastguard Worker     GetSpinelDriver().ClearRxBuffer();
2028*cfb92d14SAndroid Build Coastguard Worker     if (skipReset)
2029*cfb92d14SAndroid Build Coastguard Worker     {
2030*cfb92d14SAndroid Build Coastguard Worker         GetSpinelDriver().SetCoprocessorReady();
2031*cfb92d14SAndroid Build Coastguard Worker     }
2032*cfb92d14SAndroid Build Coastguard Worker     else
2033*cfb92d14SAndroid Build Coastguard Worker     {
2034*cfb92d14SAndroid Build Coastguard Worker         GetSpinelDriver().ResetCoprocessor(mResetRadioOnStartup);
2035*cfb92d14SAndroid Build Coastguard Worker     }
2036*cfb92d14SAndroid Build Coastguard Worker 
2037*cfb92d14SAndroid Build Coastguard Worker     mCmdTidsInUse = 0;
2038*cfb92d14SAndroid Build Coastguard Worker     mCmdNextTid   = 1;
2039*cfb92d14SAndroid Build Coastguard Worker     mTxRadioTid   = 0;
2040*cfb92d14SAndroid Build Coastguard Worker     mWaitingTid   = 0;
2041*cfb92d14SAndroid Build Coastguard Worker     mError        = OT_ERROR_NONE;
2042*cfb92d14SAndroid Build Coastguard Worker     mIsTimeSynced = false;
2043*cfb92d14SAndroid Build Coastguard Worker 
2044*cfb92d14SAndroid Build Coastguard Worker     SuccessOrDie(Set(SPINEL_PROP_PHY_ENABLED, SPINEL_DATATYPE_BOOL_S, true));
2045*cfb92d14SAndroid Build Coastguard Worker     mState = kStateSleep;
2046*cfb92d14SAndroid Build Coastguard Worker 
2047*cfb92d14SAndroid Build Coastguard Worker     RestoreProperties();
2048*cfb92d14SAndroid Build Coastguard Worker 
2049*cfb92d14SAndroid Build Coastguard Worker     switch (recoveringState)
2050*cfb92d14SAndroid Build Coastguard Worker     {
2051*cfb92d14SAndroid Build Coastguard Worker     case kStateDisabled:
2052*cfb92d14SAndroid Build Coastguard Worker         mState = kStateDisabled;
2053*cfb92d14SAndroid Build Coastguard Worker         break;
2054*cfb92d14SAndroid Build Coastguard Worker     case kStateSleep:
2055*cfb92d14SAndroid Build Coastguard Worker         break;
2056*cfb92d14SAndroid Build Coastguard Worker     case kStateReceive:
2057*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE
2058*cfb92d14SAndroid Build Coastguard Worker         // In case multiple PANs are running, don't force RCP to receive state.
2059*cfb92d14SAndroid Build Coastguard Worker         IGNORE_RETURN(Set(SPINEL_PROP_MAC_RAW_STREAM_ENABLED, SPINEL_DATATYPE_BOOL_S, true));
2060*cfb92d14SAndroid Build Coastguard Worker #else
2061*cfb92d14SAndroid Build Coastguard Worker         SuccessOrDie(Set(SPINEL_PROP_MAC_RAW_STREAM_ENABLED, SPINEL_DATATYPE_BOOL_S, true));
2062*cfb92d14SAndroid Build Coastguard Worker #endif
2063*cfb92d14SAndroid Build Coastguard Worker         mState = kStateReceive;
2064*cfb92d14SAndroid Build Coastguard Worker         break;
2065*cfb92d14SAndroid Build Coastguard Worker     case kStateTransmitting:
2066*cfb92d14SAndroid Build Coastguard Worker     case kStateTransmitDone:
2067*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE
2068*cfb92d14SAndroid Build Coastguard Worker         // In case multiple PANs are running, don't force RCP to receive state.
2069*cfb92d14SAndroid Build Coastguard Worker         IGNORE_RETURN(Set(SPINEL_PROP_MAC_RAW_STREAM_ENABLED, SPINEL_DATATYPE_BOOL_S, true));
2070*cfb92d14SAndroid Build Coastguard Worker #else
2071*cfb92d14SAndroid Build Coastguard Worker         SuccessOrDie(Set(SPINEL_PROP_MAC_RAW_STREAM_ENABLED, SPINEL_DATATYPE_BOOL_S, true));
2072*cfb92d14SAndroid Build Coastguard Worker #endif
2073*cfb92d14SAndroid Build Coastguard Worker         mTxError = OT_ERROR_ABORT;
2074*cfb92d14SAndroid Build Coastguard Worker         mState   = kStateTransmitDone;
2075*cfb92d14SAndroid Build Coastguard Worker         break;
2076*cfb92d14SAndroid Build Coastguard Worker     }
2077*cfb92d14SAndroid Build Coastguard Worker 
2078*cfb92d14SAndroid Build Coastguard Worker     if (mEnergyScanning)
2079*cfb92d14SAndroid Build Coastguard Worker     {
2080*cfb92d14SAndroid Build Coastguard Worker         SuccessOrDie(EnergyScan(mScanChannel, mScanDuration));
2081*cfb92d14SAndroid Build Coastguard Worker     }
2082*cfb92d14SAndroid Build Coastguard Worker 
2083*cfb92d14SAndroid Build Coastguard Worker     --mRcpFailureCount;
2084*cfb92d14SAndroid Build Coastguard Worker 
2085*cfb92d14SAndroid Build Coastguard Worker     if (sSupportsLogCrashDump)
2086*cfb92d14SAndroid Build Coastguard Worker     {
2087*cfb92d14SAndroid Build Coastguard Worker         LogDebg("RCP supports crash dump logging. Requesting crash dump.");
2088*cfb92d14SAndroid Build Coastguard Worker         SuccessOrDie(Set(SPINEL_PROP_RCP_LOG_CRASH_DUMP, nullptr));
2089*cfb92d14SAndroid Build Coastguard Worker     }
2090*cfb92d14SAndroid Build Coastguard Worker 
2091*cfb92d14SAndroid Build Coastguard Worker     LogNote("RCP recovery is done");
2092*cfb92d14SAndroid Build Coastguard Worker 
2093*cfb92d14SAndroid Build Coastguard Worker exit:
2094*cfb92d14SAndroid Build Coastguard Worker     return;
2095*cfb92d14SAndroid Build Coastguard Worker #endif // OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0
2096*cfb92d14SAndroid Build Coastguard Worker }
2097*cfb92d14SAndroid Build Coastguard Worker 
HandleReceivedFrame(const uint8_t * aFrame,uint16_t aLength,uint8_t aHeader,bool & aSave,void * aContext)2098*cfb92d14SAndroid Build Coastguard Worker void RadioSpinel::HandleReceivedFrame(const uint8_t *aFrame,
2099*cfb92d14SAndroid Build Coastguard Worker                                       uint16_t       aLength,
2100*cfb92d14SAndroid Build Coastguard Worker                                       uint8_t        aHeader,
2101*cfb92d14SAndroid Build Coastguard Worker                                       bool          &aSave,
2102*cfb92d14SAndroid Build Coastguard Worker                                       void          *aContext)
2103*cfb92d14SAndroid Build Coastguard Worker {
2104*cfb92d14SAndroid Build Coastguard Worker     static_cast<RadioSpinel *>(aContext)->HandleReceivedFrame(aFrame, aLength, aHeader, aSave);
2105*cfb92d14SAndroid Build Coastguard Worker }
2106*cfb92d14SAndroid Build Coastguard Worker 
HandleReceivedFrame(const uint8_t * aFrame,uint16_t aLength,uint8_t aHeader,bool & aShouldSaveFrame)2107*cfb92d14SAndroid Build Coastguard Worker void RadioSpinel::HandleReceivedFrame(const uint8_t *aFrame, uint16_t aLength, uint8_t aHeader, bool &aShouldSaveFrame)
2108*cfb92d14SAndroid Build Coastguard Worker {
2109*cfb92d14SAndroid Build Coastguard Worker     if (SPINEL_HEADER_GET_TID(aHeader) == 0)
2110*cfb92d14SAndroid Build Coastguard Worker     {
2111*cfb92d14SAndroid Build Coastguard Worker         HandleNotification(aFrame, aLength, aShouldSaveFrame);
2112*cfb92d14SAndroid Build Coastguard Worker     }
2113*cfb92d14SAndroid Build Coastguard Worker     else
2114*cfb92d14SAndroid Build Coastguard Worker     {
2115*cfb92d14SAndroid Build Coastguard Worker         HandleResponse(aFrame, aLength);
2116*cfb92d14SAndroid Build Coastguard Worker         aShouldSaveFrame = false;
2117*cfb92d14SAndroid Build Coastguard Worker     }
2118*cfb92d14SAndroid Build Coastguard Worker }
2119*cfb92d14SAndroid Build Coastguard Worker 
HandleSavedFrame(const uint8_t * aFrame,uint16_t aLength,void * aContext)2120*cfb92d14SAndroid Build Coastguard Worker void RadioSpinel::HandleSavedFrame(const uint8_t *aFrame, uint16_t aLength, void *aContext)
2121*cfb92d14SAndroid Build Coastguard Worker {
2122*cfb92d14SAndroid Build Coastguard Worker     static_cast<RadioSpinel *>(aContext)->HandleSavedFrame(aFrame, aLength);
2123*cfb92d14SAndroid Build Coastguard Worker }
2124*cfb92d14SAndroid Build Coastguard Worker 
HandleSavedFrame(const uint8_t * aFrame,uint16_t aLength)2125*cfb92d14SAndroid Build Coastguard Worker void RadioSpinel::HandleSavedFrame(const uint8_t *aFrame, uint16_t aLength) { HandleNotification(aFrame, aLength); }
2126*cfb92d14SAndroid Build Coastguard Worker 
2127*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0
RestoreProperties(void)2128*cfb92d14SAndroid Build Coastguard Worker void RadioSpinel::RestoreProperties(void)
2129*cfb92d14SAndroid Build Coastguard Worker {
2130*cfb92d14SAndroid Build Coastguard Worker     SuccessOrDie(Set(SPINEL_PROP_MAC_15_4_PANID, SPINEL_DATATYPE_UINT16_S, mPanId));
2131*cfb92d14SAndroid Build Coastguard Worker     SuccessOrDie(Set(SPINEL_PROP_MAC_15_4_SADDR, SPINEL_DATATYPE_UINT16_S, mShortAddress));
2132*cfb92d14SAndroid Build Coastguard Worker     SuccessOrDie(Set(SPINEL_PROP_MAC_15_4_LADDR, SPINEL_DATATYPE_EUI64_S, mExtendedAddress.m8));
2133*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE
2134*cfb92d14SAndroid Build Coastguard Worker     // In case multiple PANs are running, don't force RCP to change channel.
2135*cfb92d14SAndroid Build Coastguard Worker     IGNORE_RETURN(Set(SPINEL_PROP_PHY_CHAN, SPINEL_DATATYPE_UINT8_S, mChannel));
2136*cfb92d14SAndroid Build Coastguard Worker #else
2137*cfb92d14SAndroid Build Coastguard Worker     SuccessOrDie(Set(SPINEL_PROP_PHY_CHAN, SPINEL_DATATYPE_UINT8_S, mChannel));
2138*cfb92d14SAndroid Build Coastguard Worker #endif
2139*cfb92d14SAndroid Build Coastguard Worker 
2140*cfb92d14SAndroid Build Coastguard Worker     if (mMacKeySet)
2141*cfb92d14SAndroid Build Coastguard Worker     {
2142*cfb92d14SAndroid Build Coastguard Worker         SuccessOrDie(Set(SPINEL_PROP_RCP_MAC_KEY,
2143*cfb92d14SAndroid Build Coastguard Worker                          SPINEL_DATATYPE_UINT8_S SPINEL_DATATYPE_UINT8_S SPINEL_DATATYPE_DATA_WLEN_S
2144*cfb92d14SAndroid Build Coastguard Worker                              SPINEL_DATATYPE_DATA_WLEN_S SPINEL_DATATYPE_DATA_WLEN_S,
2145*cfb92d14SAndroid Build Coastguard Worker                          mKeyIdMode, mKeyId, mPrevKey.m8, sizeof(otMacKey), mCurrKey.m8, sizeof(otMacKey), mNextKey.m8,
2146*cfb92d14SAndroid Build Coastguard Worker                          sizeof(otMacKey)));
2147*cfb92d14SAndroid Build Coastguard Worker     }
2148*cfb92d14SAndroid Build Coastguard Worker 
2149*cfb92d14SAndroid Build Coastguard Worker     if (mMacFrameCounterSet)
2150*cfb92d14SAndroid Build Coastguard Worker     {
2151*cfb92d14SAndroid Build Coastguard Worker         // There is a chance that radio/RCP has used some counters after otLinkGetFrameCounter() (for enh ack) and they
2152*cfb92d14SAndroid Build Coastguard Worker         // are in queue to be sent to host (not yet processed by host RadioSpinel). Here we add some guard jump
2153*cfb92d14SAndroid Build Coastguard Worker         // when we restore the frame counter.
2154*cfb92d14SAndroid Build Coastguard Worker         // Consider the worst case: the radio/RCP continuously receives the shortest data frame and replies with the
2155*cfb92d14SAndroid Build Coastguard Worker         // shortest enhanced ACK. The radio/RCP consumes at most 992 frame counters during the timeout time.
2156*cfb92d14SAndroid Build Coastguard Worker         // The frame counter guard is set to 1000 which should ensure that the restored frame counter is unused.
2157*cfb92d14SAndroid Build Coastguard Worker         //
2158*cfb92d14SAndroid Build Coastguard Worker         // DataFrame: 6(PhyHeader) + 2(Fcf) + 1(Seq) + 6(AddrInfo) + 6(SecHeader) + 1(Payload) + 4(Mic) + 2(Fcs) = 28
2159*cfb92d14SAndroid Build Coastguard Worker         // AckFrame : 6(PhyHeader) + 2(Fcf) + 1(Seq) + 6(AddrInfo) + 6(SecHeader) + 2(Ie) + 4(Mic) + 2(Fcs) = 29
2160*cfb92d14SAndroid Build Coastguard Worker         // CounterGuard: 2000ms(Timeout) / [(28bytes(Data) + 29bytes(Ack)) * 32us/byte + 192us(Ifs)] = 992
2161*cfb92d14SAndroid Build Coastguard Worker         static constexpr uint16_t kFrameCounterGuard = 1000;
2162*cfb92d14SAndroid Build Coastguard Worker 
2163*cfb92d14SAndroid Build Coastguard Worker         SuccessOrDie(Set(SPINEL_PROP_RCP_MAC_FRAME_COUNTER, SPINEL_DATATYPE_UINT32_S,
2164*cfb92d14SAndroid Build Coastguard Worker                          otLinkGetFrameCounter(mInstance) + kFrameCounterGuard));
2165*cfb92d14SAndroid Build Coastguard Worker     }
2166*cfb92d14SAndroid Build Coastguard Worker 
2167*cfb92d14SAndroid Build Coastguard Worker     for (int i = 0; i < mSrcMatchShortEntryCount; ++i)
2168*cfb92d14SAndroid Build Coastguard Worker     {
2169*cfb92d14SAndroid Build Coastguard Worker         SuccessOrDie(
2170*cfb92d14SAndroid Build Coastguard Worker             Insert(SPINEL_PROP_MAC_SRC_MATCH_SHORT_ADDRESSES, SPINEL_DATATYPE_UINT16_S, mSrcMatchShortEntries[i]));
2171*cfb92d14SAndroid Build Coastguard Worker     }
2172*cfb92d14SAndroid Build Coastguard Worker 
2173*cfb92d14SAndroid Build Coastguard Worker     for (int i = 0; i < mSrcMatchExtEntryCount; ++i)
2174*cfb92d14SAndroid Build Coastguard Worker     {
2175*cfb92d14SAndroid Build Coastguard Worker         SuccessOrDie(
2176*cfb92d14SAndroid Build Coastguard Worker             Insert(SPINEL_PROP_MAC_SRC_MATCH_EXTENDED_ADDRESSES, SPINEL_DATATYPE_EUI64_S, mSrcMatchExtEntries[i].m8));
2177*cfb92d14SAndroid Build Coastguard Worker     }
2178*cfb92d14SAndroid Build Coastguard Worker 
2179*cfb92d14SAndroid Build Coastguard Worker     if (mSrcMatchSet)
2180*cfb92d14SAndroid Build Coastguard Worker     {
2181*cfb92d14SAndroid Build Coastguard Worker         SuccessOrDie(Set(SPINEL_PROP_MAC_SRC_MATCH_ENABLED, SPINEL_DATATYPE_BOOL_S, mSrcMatchEnabled));
2182*cfb92d14SAndroid Build Coastguard Worker     }
2183*cfb92d14SAndroid Build Coastguard Worker 
2184*cfb92d14SAndroid Build Coastguard Worker     if (mCcaEnergyDetectThresholdSet)
2185*cfb92d14SAndroid Build Coastguard Worker     {
2186*cfb92d14SAndroid Build Coastguard Worker         SuccessOrDie(Set(SPINEL_PROP_PHY_CCA_THRESHOLD, SPINEL_DATATYPE_INT8_S, mCcaEnergyDetectThreshold));
2187*cfb92d14SAndroid Build Coastguard Worker     }
2188*cfb92d14SAndroid Build Coastguard Worker 
2189*cfb92d14SAndroid Build Coastguard Worker     if (mTransmitPowerSet)
2190*cfb92d14SAndroid Build Coastguard Worker     {
2191*cfb92d14SAndroid Build Coastguard Worker         SuccessOrDie(Set(SPINEL_PROP_PHY_TX_POWER, SPINEL_DATATYPE_INT8_S, mTransmitPower));
2192*cfb92d14SAndroid Build Coastguard Worker     }
2193*cfb92d14SAndroid Build Coastguard Worker 
2194*cfb92d14SAndroid Build Coastguard Worker     if (mCoexEnabledSet)
2195*cfb92d14SAndroid Build Coastguard Worker     {
2196*cfb92d14SAndroid Build Coastguard Worker         SuccessOrDie(Set(SPINEL_PROP_RADIO_COEX_ENABLE, SPINEL_DATATYPE_BOOL_S, mCoexEnabled));
2197*cfb92d14SAndroid Build Coastguard Worker     }
2198*cfb92d14SAndroid Build Coastguard Worker 
2199*cfb92d14SAndroid Build Coastguard Worker     if (mFemLnaGainSet)
2200*cfb92d14SAndroid Build Coastguard Worker     {
2201*cfb92d14SAndroid Build Coastguard Worker         SuccessOrDie(Set(SPINEL_PROP_PHY_FEM_LNA_GAIN, SPINEL_DATATYPE_INT8_S, mFemLnaGain));
2202*cfb92d14SAndroid Build Coastguard Worker     }
2203*cfb92d14SAndroid Build Coastguard Worker 
2204*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_POSIX_CONFIG_MAX_POWER_TABLE_ENABLE
2205*cfb92d14SAndroid Build Coastguard Worker     for (uint8_t channel = Radio::kChannelMin; channel <= Radio::kChannelMax; channel++)
2206*cfb92d14SAndroid Build Coastguard Worker     {
2207*cfb92d14SAndroid Build Coastguard Worker         int8_t power = mMaxPowerTable.GetTransmitPower(channel);
2208*cfb92d14SAndroid Build Coastguard Worker 
2209*cfb92d14SAndroid Build Coastguard Worker         if (power != OT_RADIO_POWER_INVALID)
2210*cfb92d14SAndroid Build Coastguard Worker         {
2211*cfb92d14SAndroid Build Coastguard Worker             // Some old RCPs doesn't support max transmit power
2212*cfb92d14SAndroid Build Coastguard Worker             otError error = SetChannelMaxTransmitPower(channel, power);
2213*cfb92d14SAndroid Build Coastguard Worker 
2214*cfb92d14SAndroid Build Coastguard Worker             if (error != OT_ERROR_NONE && error != OT_ERROR_NOT_FOUND)
2215*cfb92d14SAndroid Build Coastguard Worker             {
2216*cfb92d14SAndroid Build Coastguard Worker                 DieNow(OT_EXIT_FAILURE);
2217*cfb92d14SAndroid Build Coastguard Worker             }
2218*cfb92d14SAndroid Build Coastguard Worker         }
2219*cfb92d14SAndroid Build Coastguard Worker     }
2220*cfb92d14SAndroid Build Coastguard Worker #endif // OPENTHREAD_POSIX_CONFIG_MAX_POWER_TABLE_ENABLE
2221*cfb92d14SAndroid Build Coastguard Worker 
2222*cfb92d14SAndroid Build Coastguard Worker     if ((sRadioCaps & OT_RADIO_CAPS_RX_ON_WHEN_IDLE) != 0)
2223*cfb92d14SAndroid Build Coastguard Worker     {
2224*cfb92d14SAndroid Build Coastguard Worker         SuccessOrDie(Set(SPINEL_PROP_MAC_RX_ON_WHEN_IDLE_MODE, SPINEL_DATATYPE_BOOL_S, mRxOnWhenIdle));
2225*cfb92d14SAndroid Build Coastguard Worker     }
2226*cfb92d14SAndroid Build Coastguard Worker 
2227*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_SPINEL_CONFIG_VENDOR_HOOK_ENABLE
2228*cfb92d14SAndroid Build Coastguard Worker     if (mVendorRestorePropertiesCallback)
2229*cfb92d14SAndroid Build Coastguard Worker     {
2230*cfb92d14SAndroid Build Coastguard Worker         mVendorRestorePropertiesCallback(mVendorRestorePropertiesContext);
2231*cfb92d14SAndroid Build Coastguard Worker     }
2232*cfb92d14SAndroid Build Coastguard Worker #endif
2233*cfb92d14SAndroid Build Coastguard Worker 
2234*cfb92d14SAndroid Build Coastguard Worker     if (mTimeSyncEnabled)
2235*cfb92d14SAndroid Build Coastguard Worker     {
2236*cfb92d14SAndroid Build Coastguard Worker         CalcRcpTimeOffset();
2237*cfb92d14SAndroid Build Coastguard Worker     }
2238*cfb92d14SAndroid Build Coastguard Worker }
2239*cfb92d14SAndroid Build Coastguard Worker #endif // OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0
2240*cfb92d14SAndroid Build Coastguard Worker 
GetMultipanActiveInterface(spinel_iid_t * aIid)2241*cfb92d14SAndroid Build Coastguard Worker otError RadioSpinel::GetMultipanActiveInterface(spinel_iid_t *aIid)
2242*cfb92d14SAndroid Build Coastguard Worker {
2243*cfb92d14SAndroid Build Coastguard Worker     otError error = Get(SPINEL_PROP_MULTIPAN_ACTIVE_INTERFACE, SPINEL_DATATYPE_UINT8_S, aIid);
2244*cfb92d14SAndroid Build Coastguard Worker     LogIfFail("Get GetMultipanActiveInterface failed", error);
2245*cfb92d14SAndroid Build Coastguard Worker     return error;
2246*cfb92d14SAndroid Build Coastguard Worker }
2247*cfb92d14SAndroid Build Coastguard Worker 
SetMultipanActiveInterface(spinel_iid_t aIid,bool aCompletePending)2248*cfb92d14SAndroid Build Coastguard Worker otError RadioSpinel::SetMultipanActiveInterface(spinel_iid_t aIid, bool aCompletePending)
2249*cfb92d14SAndroid Build Coastguard Worker {
2250*cfb92d14SAndroid Build Coastguard Worker     otError error;
2251*cfb92d14SAndroid Build Coastguard Worker     uint8_t value;
2252*cfb92d14SAndroid Build Coastguard Worker 
2253*cfb92d14SAndroid Build Coastguard Worker     EXPECT(aIid == (aIid & SPINEL_MULTIPAN_INTERFACE_ID_MASK), error = OT_ERROR_INVALID_ARGS);
2254*cfb92d14SAndroid Build Coastguard Worker 
2255*cfb92d14SAndroid Build Coastguard Worker     value = static_cast<uint8_t>(aIid);
2256*cfb92d14SAndroid Build Coastguard Worker     if (aCompletePending)
2257*cfb92d14SAndroid Build Coastguard Worker     {
2258*cfb92d14SAndroid Build Coastguard Worker         value |= (1 << SPINEL_MULTIPAN_INTERFACE_SOFT_SWITCH_SHIFT);
2259*cfb92d14SAndroid Build Coastguard Worker     }
2260*cfb92d14SAndroid Build Coastguard Worker 
2261*cfb92d14SAndroid Build Coastguard Worker     error = Set(SPINEL_PROP_MULTIPAN_ACTIVE_INTERFACE, SPINEL_DATATYPE_UINT8_S, value);
2262*cfb92d14SAndroid Build Coastguard Worker 
2263*cfb92d14SAndroid Build Coastguard Worker exit:
2264*cfb92d14SAndroid Build Coastguard Worker     return error;
2265*cfb92d14SAndroid Build Coastguard Worker }
2266*cfb92d14SAndroid Build Coastguard Worker 
SetChannelMaxTransmitPower(uint8_t aChannel,int8_t aMaxPower)2267*cfb92d14SAndroid Build Coastguard Worker otError RadioSpinel::SetChannelMaxTransmitPower(uint8_t aChannel, int8_t aMaxPower)
2268*cfb92d14SAndroid Build Coastguard Worker {
2269*cfb92d14SAndroid Build Coastguard Worker     otError error = OT_ERROR_NONE;
2270*cfb92d14SAndroid Build Coastguard Worker     EXPECT(aChannel >= Radio::kChannelMin && aChannel <= Radio::kChannelMax, error = OT_ERROR_INVALID_ARGS);
2271*cfb92d14SAndroid Build Coastguard Worker     mMaxPowerTable.SetTransmitPower(aChannel, aMaxPower);
2272*cfb92d14SAndroid Build Coastguard Worker     error = Set(SPINEL_PROP_PHY_CHAN_MAX_POWER, SPINEL_DATATYPE_UINT8_S SPINEL_DATATYPE_INT8_S, aChannel, aMaxPower);
2273*cfb92d14SAndroid Build Coastguard Worker 
2274*cfb92d14SAndroid Build Coastguard Worker exit:
2275*cfb92d14SAndroid Build Coastguard Worker     return error;
2276*cfb92d14SAndroid Build Coastguard Worker }
2277*cfb92d14SAndroid Build Coastguard Worker 
SetRadioRegion(uint16_t aRegionCode)2278*cfb92d14SAndroid Build Coastguard Worker otError RadioSpinel::SetRadioRegion(uint16_t aRegionCode)
2279*cfb92d14SAndroid Build Coastguard Worker {
2280*cfb92d14SAndroid Build Coastguard Worker     otError error;
2281*cfb92d14SAndroid Build Coastguard Worker 
2282*cfb92d14SAndroid Build Coastguard Worker     error = Set(SPINEL_PROP_PHY_REGION_CODE, SPINEL_DATATYPE_UINT16_S, aRegionCode);
2283*cfb92d14SAndroid Build Coastguard Worker 
2284*cfb92d14SAndroid Build Coastguard Worker     if (error == OT_ERROR_NONE)
2285*cfb92d14SAndroid Build Coastguard Worker     {
2286*cfb92d14SAndroid Build Coastguard Worker         LogNote("Set region code \"%c%c\" successfully", static_cast<char>(aRegionCode >> 8),
2287*cfb92d14SAndroid Build Coastguard Worker                 static_cast<char>(aRegionCode));
2288*cfb92d14SAndroid Build Coastguard Worker     }
2289*cfb92d14SAndroid Build Coastguard Worker     else
2290*cfb92d14SAndroid Build Coastguard Worker     {
2291*cfb92d14SAndroid Build Coastguard Worker         LogWarn("Failed to set region code \"%c%c\": %s", static_cast<char>(aRegionCode >> 8),
2292*cfb92d14SAndroid Build Coastguard Worker                 static_cast<char>(aRegionCode), otThreadErrorToString(error));
2293*cfb92d14SAndroid Build Coastguard Worker     }
2294*cfb92d14SAndroid Build Coastguard Worker 
2295*cfb92d14SAndroid Build Coastguard Worker     return error;
2296*cfb92d14SAndroid Build Coastguard Worker }
2297*cfb92d14SAndroid Build Coastguard Worker 
GetRadioRegion(uint16_t * aRegionCode)2298*cfb92d14SAndroid Build Coastguard Worker otError RadioSpinel::GetRadioRegion(uint16_t *aRegionCode)
2299*cfb92d14SAndroid Build Coastguard Worker {
2300*cfb92d14SAndroid Build Coastguard Worker     otError error = OT_ERROR_NONE;
2301*cfb92d14SAndroid Build Coastguard Worker 
2302*cfb92d14SAndroid Build Coastguard Worker     EXPECT(aRegionCode != nullptr, error = OT_ERROR_INVALID_ARGS);
2303*cfb92d14SAndroid Build Coastguard Worker     error = Get(SPINEL_PROP_PHY_REGION_CODE, SPINEL_DATATYPE_UINT16_S, aRegionCode);
2304*cfb92d14SAndroid Build Coastguard Worker 
2305*cfb92d14SAndroid Build Coastguard Worker exit:
2306*cfb92d14SAndroid Build Coastguard Worker     return error;
2307*cfb92d14SAndroid Build Coastguard Worker }
2308*cfb92d14SAndroid Build Coastguard Worker 
2309*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
ConfigureEnhAckProbing(otLinkMetrics aLinkMetrics,const otShortAddress & aShortAddress,const otExtAddress & aExtAddress)2310*cfb92d14SAndroid Build Coastguard Worker otError RadioSpinel::ConfigureEnhAckProbing(otLinkMetrics         aLinkMetrics,
2311*cfb92d14SAndroid Build Coastguard Worker                                             const otShortAddress &aShortAddress,
2312*cfb92d14SAndroid Build Coastguard Worker                                             const otExtAddress   &aExtAddress)
2313*cfb92d14SAndroid Build Coastguard Worker {
2314*cfb92d14SAndroid Build Coastguard Worker     otError error = OT_ERROR_NONE;
2315*cfb92d14SAndroid Build Coastguard Worker     uint8_t flags = 0;
2316*cfb92d14SAndroid Build Coastguard Worker 
2317*cfb92d14SAndroid Build Coastguard Worker     if (aLinkMetrics.mPduCount)
2318*cfb92d14SAndroid Build Coastguard Worker     {
2319*cfb92d14SAndroid Build Coastguard Worker         flags |= SPINEL_THREAD_LINK_METRIC_PDU_COUNT;
2320*cfb92d14SAndroid Build Coastguard Worker     }
2321*cfb92d14SAndroid Build Coastguard Worker 
2322*cfb92d14SAndroid Build Coastguard Worker     if (aLinkMetrics.mLqi)
2323*cfb92d14SAndroid Build Coastguard Worker     {
2324*cfb92d14SAndroid Build Coastguard Worker         flags |= SPINEL_THREAD_LINK_METRIC_LQI;
2325*cfb92d14SAndroid Build Coastguard Worker     }
2326*cfb92d14SAndroid Build Coastguard Worker 
2327*cfb92d14SAndroid Build Coastguard Worker     if (aLinkMetrics.mLinkMargin)
2328*cfb92d14SAndroid Build Coastguard Worker     {
2329*cfb92d14SAndroid Build Coastguard Worker         flags |= SPINEL_THREAD_LINK_METRIC_LINK_MARGIN;
2330*cfb92d14SAndroid Build Coastguard Worker     }
2331*cfb92d14SAndroid Build Coastguard Worker 
2332*cfb92d14SAndroid Build Coastguard Worker     if (aLinkMetrics.mRssi)
2333*cfb92d14SAndroid Build Coastguard Worker     {
2334*cfb92d14SAndroid Build Coastguard Worker         flags |= SPINEL_THREAD_LINK_METRIC_RSSI;
2335*cfb92d14SAndroid Build Coastguard Worker     }
2336*cfb92d14SAndroid Build Coastguard Worker 
2337*cfb92d14SAndroid Build Coastguard Worker     error =
2338*cfb92d14SAndroid Build Coastguard Worker         Set(SPINEL_PROP_RCP_ENH_ACK_PROBING, SPINEL_DATATYPE_UINT16_S SPINEL_DATATYPE_EUI64_S SPINEL_DATATYPE_UINT8_S,
2339*cfb92d14SAndroid Build Coastguard Worker             aShortAddress, aExtAddress.m8, flags);
2340*cfb92d14SAndroid Build Coastguard Worker 
2341*cfb92d14SAndroid Build Coastguard Worker     return error;
2342*cfb92d14SAndroid Build Coastguard Worker }
2343*cfb92d14SAndroid Build Coastguard Worker #endif
2344*cfb92d14SAndroid Build Coastguard Worker 
2345*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE || OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
GetCslAccuracy(void)2346*cfb92d14SAndroid Build Coastguard Worker uint8_t RadioSpinel::GetCslAccuracy(void)
2347*cfb92d14SAndroid Build Coastguard Worker {
2348*cfb92d14SAndroid Build Coastguard Worker     uint8_t accuracy = UINT8_MAX;
2349*cfb92d14SAndroid Build Coastguard Worker     otError error    = Get(SPINEL_PROP_RCP_CSL_ACCURACY, SPINEL_DATATYPE_UINT8_S, &accuracy);
2350*cfb92d14SAndroid Build Coastguard Worker 
2351*cfb92d14SAndroid Build Coastguard Worker     LogIfFail("Get CSL Accuracy failed", error);
2352*cfb92d14SAndroid Build Coastguard Worker     return accuracy;
2353*cfb92d14SAndroid Build Coastguard Worker }
2354*cfb92d14SAndroid Build Coastguard Worker #endif
2355*cfb92d14SAndroid Build Coastguard Worker 
2356*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
GetCslUncertainty(void)2357*cfb92d14SAndroid Build Coastguard Worker uint8_t RadioSpinel::GetCslUncertainty(void)
2358*cfb92d14SAndroid Build Coastguard Worker {
2359*cfb92d14SAndroid Build Coastguard Worker     uint8_t uncertainty = UINT8_MAX;
2360*cfb92d14SAndroid Build Coastguard Worker     otError error       = Get(SPINEL_PROP_RCP_CSL_UNCERTAINTY, SPINEL_DATATYPE_UINT8_S, &uncertainty);
2361*cfb92d14SAndroid Build Coastguard Worker 
2362*cfb92d14SAndroid Build Coastguard Worker     LogIfFail("Get CSL Uncertainty failed", error);
2363*cfb92d14SAndroid Build Coastguard Worker     return uncertainty;
2364*cfb92d14SAndroid Build Coastguard Worker }
2365*cfb92d14SAndroid Build Coastguard Worker #endif
2366*cfb92d14SAndroid Build Coastguard Worker 
2367*cfb92d14SAndroid Build Coastguard Worker #if OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE
AddCalibratedPower(uint8_t aChannel,int16_t aActualPower,const uint8_t * aRawPowerSetting,uint16_t aRawPowerSettingLength)2368*cfb92d14SAndroid Build Coastguard Worker otError RadioSpinel::AddCalibratedPower(uint8_t        aChannel,
2369*cfb92d14SAndroid Build Coastguard Worker                                         int16_t        aActualPower,
2370*cfb92d14SAndroid Build Coastguard Worker                                         const uint8_t *aRawPowerSetting,
2371*cfb92d14SAndroid Build Coastguard Worker                                         uint16_t       aRawPowerSettingLength)
2372*cfb92d14SAndroid Build Coastguard Worker {
2373*cfb92d14SAndroid Build Coastguard Worker     otError error;
2374*cfb92d14SAndroid Build Coastguard Worker 
2375*cfb92d14SAndroid Build Coastguard Worker     assert(aRawPowerSetting != nullptr);
2376*cfb92d14SAndroid Build Coastguard Worker     EXPECT_NO_ERROR(error = Insert(SPINEL_PROP_PHY_CALIBRATED_POWER,
2377*cfb92d14SAndroid Build Coastguard Worker                                    SPINEL_DATATYPE_UINT8_S SPINEL_DATATYPE_INT16_S SPINEL_DATATYPE_DATA_WLEN_S,
2378*cfb92d14SAndroid Build Coastguard Worker                                    aChannel, aActualPower, aRawPowerSetting, aRawPowerSettingLength));
2379*cfb92d14SAndroid Build Coastguard Worker 
2380*cfb92d14SAndroid Build Coastguard Worker exit:
2381*cfb92d14SAndroid Build Coastguard Worker     return error;
2382*cfb92d14SAndroid Build Coastguard Worker }
2383*cfb92d14SAndroid Build Coastguard Worker 
ClearCalibratedPowers(void)2384*cfb92d14SAndroid Build Coastguard Worker otError RadioSpinel::ClearCalibratedPowers(void) { return Set(SPINEL_PROP_PHY_CALIBRATED_POWER, nullptr); }
2385*cfb92d14SAndroid Build Coastguard Worker 
SetChannelTargetPower(uint8_t aChannel,int16_t aTargetPower)2386*cfb92d14SAndroid Build Coastguard Worker otError RadioSpinel::SetChannelTargetPower(uint8_t aChannel, int16_t aTargetPower)
2387*cfb92d14SAndroid Build Coastguard Worker {
2388*cfb92d14SAndroid Build Coastguard Worker     otError error = OT_ERROR_NONE;
2389*cfb92d14SAndroid Build Coastguard Worker     EXPECT(aChannel >= Radio::kChannelMin && aChannel <= Radio::kChannelMax, error = OT_ERROR_INVALID_ARGS);
2390*cfb92d14SAndroid Build Coastguard Worker     error =
2391*cfb92d14SAndroid Build Coastguard Worker         Set(SPINEL_PROP_PHY_CHAN_TARGET_POWER, SPINEL_DATATYPE_UINT8_S SPINEL_DATATYPE_INT16_S, aChannel, aTargetPower);
2392*cfb92d14SAndroid Build Coastguard Worker 
2393*cfb92d14SAndroid Build Coastguard Worker exit:
2394*cfb92d14SAndroid Build Coastguard Worker     return error;
2395*cfb92d14SAndroid Build Coastguard Worker }
2396*cfb92d14SAndroid Build Coastguard Worker #endif // OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE
2397*cfb92d14SAndroid Build Coastguard Worker 
2398*cfb92d14SAndroid Build Coastguard Worker } // namespace Spinel
2399*cfb92d14SAndroid Build Coastguard Worker } // namespace ot
2400