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