1 /*
2  *  Copyright (c) 2018, The OpenThread Authors.
3  *  All rights reserved.
4  *
5  *  Redistribution and use in source and binary forms, with or without
6  *  modification, are permitted provided that the following conditions are met:
7  *  1. Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  *  2. Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *  3. Neither the name of the copyright holder nor the
13  *     names of its contributors may be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  *  POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /**
30  * @file
31  *   This file includes definitions for the spinel based radio transceiver.
32  */
33 
34 #ifndef RADIO_SPINEL_HPP_
35 #define RADIO_SPINEL_HPP_
36 
37 #include <openthread/platform/radio.h>
38 
39 #include "openthread-spinel-config.h"
40 #include "radio_spinel_metrics.h"
41 #include "spinel.h"
42 #include "spinel_interface.hpp"
43 #include "core/radio/max_power_table.hpp"
44 #include "ncp/ncp_config.h"
45 
46 namespace ot {
47 namespace Spinel {
48 
49 /**
50  * The class for providing a OpenThread radio interface by talking with a radio-only
51  * co-processor(RCP). The InterfaceType template parameter should provide the following
52  * methods:
53  *
54  * class InterfaceType {
55  *
56  *    // This constructor initializes the object.
57  *
58  *    // @param[in] aCallback         Callback on frame received
59  *    // @param[in] aCallbackContext  Callback context
60  *    // @param[in] aFrameBuffer      A reference to a `RxFrameBuffer` object.
61  *
62  *    InterfaceType(Spinel::SpinelInterface::ReceiveFrameCallback aCallback,
63  *                  void *                                        aCallbackContext,
64  *                  Spinel::SpinelInterface::RxFrameBuffer &      aFrameBuffer);
65  *
66  *
67  *    // This method encodes and sends a spinel frame to Radio Co-processor (RCP) over the socket.
68  *
69  *    // This is blocking call, i.e., if the socket is not writable, this method waits for it to become writable for
70  *    // up to `kMaxWaitTime` interval.
71  *
72  *    // @param[in] aFrame     A pointer to buffer containing the spinel frame to send.
73  *    // @param[in] aLength    The length (number of bytes) in the frame.
74  *
75  *    // @retval OT_ERROR_NONE     Successfully encoded and sent the spinel frame.
76  *    // @retval OT_ERROR_NO_BUFS  Insufficient buffer space available to encode the frame.
77  *    // @retval OT_ERROR_FAILED   Failed to send due to socket not becoming writable within `kMaxWaitTime`.
78  *
79  *    otError SendFrame(const uint8_t *aFrame, uint16_t aLength);
80  *
81  *
82  *    // This method waits for receiving part or all of spinel frame within specified interval.
83  *
84  *    // @param[in]  aTimeout  The timeout value in microseconds.
85  *
86  *    // @retval OT_ERROR_NONE             Part or all of spinel frame is received.
87  *    // @retval OT_ERROR_RESPONSE_TIMEOUT No spinel frame is received within @p aTimeout.
88  *
89  *    otError WaitForFrame(uint64_t& aTimeoutUs);
90  *
91  *
92  *    // This method performs radio driver processing.
93  *
94  *    // @param[in]   aContext  The process context.
95  *
96  *    void Process(const void *aContext);
97  *
98  *
99  *    // This method deinitializes the interface to the RCP.
100  *
101  *    void Deinit(void);
102  * };
103  */
104 template <typename InterfaceType> class RadioSpinel
105 {
106 public:
107     /**
108      * Initializes the spinel based OpenThread transceiver.
109      *
110      */
111     RadioSpinel(void);
112 
113     /**
114      * Initialize this radio transceiver.
115      *
116      * @param[in]  aResetRadio                 TRUE to reset on init, FALSE to not reset on init.
117      * @param[in]  aSkipRcpCompatibilityCheck  TRUE to skip RCP compatibility check, FALSE to perform the check.
118      *
119      */
120     void Init(bool aResetRadio, bool aSkipRcpCompatibilityCheck);
121 
122     /**
123      * Deinitialize this radio transceiver.
124      *
125      */
126     void Deinit(void);
127 
128     /**
129      * Gets the status of promiscuous mode.
130      *
131      * @retval true   Promiscuous mode is enabled.
132      * @retval false  Promiscuous mode is disabled.
133      *
134      */
IsPromiscuous(void) const135     bool IsPromiscuous(void) const { return mIsPromiscuous; }
136 
137     /**
138      * Sets the status of promiscuous mode.
139      *
140      * @param[in]   aEnable     Whether to enable or disable promiscuous mode.
141      *
142      * @retval  OT_ERROR_NONE               Succeeded.
143      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
144      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
145      *
146      */
147     otError SetPromiscuous(bool aEnable);
148 
149     /**
150      * Sets the Short Address for address filtering.
151      *
152      * @param[in] aShortAddress  The IEEE 802.15.4 Short Address.
153      *
154      * @retval  OT_ERROR_NONE               Succeeded.
155      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
156      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
157      *
158      */
159     otError SetShortAddress(uint16_t aAddress);
160 
161     /**
162      * Gets the factory-assigned IEEE EUI-64 for this transceiver.
163      *
164      * @param[in]  aInstance   The OpenThread instance structure.
165      * @param[out] aIeeeEui64  A pointer to the factory-assigned IEEE EUI-64.
166      *
167      * @retval  OT_ERROR_NONE               Succeeded.
168      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
169      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
170      *
171      */
172     otError GetIeeeEui64(uint8_t *aIeeeEui64);
173 
174     /**
175      * Sets the Extended Address for address filtering.
176      *
177      * @param[in] aExtAddress  A pointer to the IEEE 802.15.4 Extended Address stored in little-endian byte order.
178      *
179      * @retval  OT_ERROR_NONE               Succeeded.
180      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
181      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
182      *
183      */
184     otError SetExtendedAddress(const otExtAddress &aAddress);
185 
186     /**
187      * Sets the PAN ID for address filtering.
188      *
189      * @param[in]   aPanId  The IEEE 802.15.4 PAN ID.
190      *
191      * @retval  OT_ERROR_NONE               Succeeded.
192      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
193      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
194      *
195      */
196     otError SetPanId(uint16_t aPanId);
197 
198     /**
199      * Gets the radio's transmit power in dBm.
200      *
201      * @param[out]  aPower    The transmit power in dBm.
202      *
203      * @retval  OT_ERROR_NONE               Succeeded.
204      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
205      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
206      *
207      */
208     otError GetTransmitPower(int8_t &aPower);
209 
210     /**
211      * Sets the radio's transmit power in dBm.
212      *
213      * @param[in]   aPower     The transmit power in dBm.
214      *
215      * @retval  OT_ERROR_NONE               Succeeded.
216      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
217      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
218      *
219      */
220     otError SetTransmitPower(int8_t aPower);
221 
222     /**
223      * Gets the radio's CCA ED threshold in dBm.
224      *
225      * @param[out]  aThreshold    The CCA ED threshold in dBm.
226      *
227      * @retval  OT_ERROR_NONE               Succeeded.
228      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
229      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
230      *
231      */
232     otError GetCcaEnergyDetectThreshold(int8_t &aThreshold);
233 
234     /**
235      * Sets the radio's CCA ED threshold in dBm.
236      *
237      * @param[in]   aThreshold     The CCA ED threshold in dBm.
238      *
239      * @retval  OT_ERROR_NONE               Succeeded.
240      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
241      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
242      *
243      */
244     otError SetCcaEnergyDetectThreshold(int8_t aThreshold);
245 
246     /**
247      * Gets the FEM's Rx LNA gain in dBm.
248      *
249      * @param[out]  aGain    The FEM's Rx LNA gain in dBm.
250      *
251      * @retval  OT_ERROR_NONE               Succeeded.
252      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
253      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
254      *
255      */
256     otError GetFemLnaGain(int8_t &aGain);
257 
258     /**
259      * Sets the FEM's Rx LNA gain in dBm.
260      *
261      * @param[in]   aGain     The FEM's Rx LNA gain in dBm.
262      *
263      * @retval  OT_ERROR_NONE               Succeeded.
264      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
265      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
266      *
267      */
268     otError SetFemLnaGain(int8_t aGain);
269 
270     /**
271      * Returns the radio sw version string.
272      *
273      * @returns A pointer to the radio version string.
274      *
275      */
GetVersion(void) const276     const char *GetVersion(void) const { return mVersion; }
277 
278     /**
279      * Returns the radio capabilities.
280      *
281      * @returns The radio capability bit vector.
282      *
283      */
GetRadioCaps(void) const284     otRadioCaps GetRadioCaps(void) const { return mRadioCaps; }
285 
286     /**
287      * Gets the most recent RSSI measurement.
288      *
289      * @returns The RSSI in dBm when it is valid.  127 when RSSI is invalid.
290      */
291     int8_t GetRssi(void);
292 
293     /**
294      * Returns the radio receive sensitivity value.
295      *
296      * @returns The radio receive sensitivity value in dBm.
297      *
298      * @retval  OT_ERROR_NONE               Succeeded.
299      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
300      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
301      *
302      */
GetReceiveSensitivity(void) const303     int8_t GetReceiveSensitivity(void) const { return mRxSensitivity; }
304 
305     /**
306      * Gets current state of the radio.
307      *
308      * @return  Current state of the radio.
309      *
310      */
311     otRadioState GetState(void) const;
312 
313     /**
314      * Gets the current receiving channel.
315      *
316      * @returns Current receiving channel.
317      *
318      */
GetChannel(void) const319     uint8_t GetChannel(void) const { return mChannel; }
320 
321 #if OPENTHREAD_CONFIG_PLATFORM_RADIO_COEX_ENABLE
322     /**
323      * Enable the radio coex.
324      *
325      * @param[in] aInstance  The OpenThread instance structure.
326      * @param[in] aEnabled   TRUE to enable the radio coex, FALSE otherwise.
327      *
328      * @retval OT_ERROR_NONE     Successfully enabled.
329      * @retval OT_ERROR_FAILED   The radio coex could not be enabled.
330      *
331      */
332     otError SetCoexEnabled(bool aEnabled);
333 
334     /**
335      * Check whether radio coex is enabled or not.
336      *
337      * @param[in] aInstance  The OpenThread instance structure.
338      *
339      * @returns TRUE if the radio coex is enabled, FALSE otherwise.
340      *
341      */
342     bool IsCoexEnabled(void);
343 
344     /**
345      * Retrieves the radio coexistence metrics.
346      *
347      * @param[out] aCoexMetrics  A reference to the coexistence metrics structure.
348      *
349      * @retval OT_ERROR_NONE          Successfully retrieved the coex metrics.
350      * @retval OT_ERROR_INVALID_ARGS  @p aCoexMetrics was nullptr.
351      *
352      */
353     otError GetCoexMetrics(otRadioCoexMetrics &aCoexMetrics);
354 #endif // OPENTHREAD_CONFIG_PLATFORM_RADIO_COEX_ENABLE
355 
356     /**
357      * Returns a reference to the transmit buffer.
358      *
359      * The caller forms the IEEE 802.15.4 frame in this buffer then calls otPlatRadioTransmit() to request transmission.
360      *
361      * @returns A reference to the transmit buffer.
362      *
363      */
GetTransmitFrame(void)364     otRadioFrame &GetTransmitFrame(void) { return mTxRadioFrame; }
365 
366     /**
367      * Enables or disables source address match feature.
368      *
369      * @param[in]  aEnable     Enable/disable source address match feature.
370      *
371      * @retval  OT_ERROR_NONE               Succeeded.
372      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
373      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
374      *
375      */
376     otError EnableSrcMatch(bool aEnable);
377 
378     /**
379      * Adds a short address to the source address match table.
380      *
381      * @param[in]  aInstance      The OpenThread instance structure.
382      * @param[in]  aShortAddress  The short address to be added.
383      *
384      * @retval  OT_ERROR_NONE               Successfully added short address to the source match table.
385      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
386      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
387      * @retval  OT_ERROR_NO_BUFS            No available entry in the source match table.
388      */
389     otError AddSrcMatchShortEntry(uint16_t aShortAddress);
390 
391     /**
392      * Removes a short address from the source address match table.
393      *
394      * @param[in]  aInstance      The OpenThread instance structure.
395      * @param[in]  aShortAddress  The short address to be removed.
396      *
397      * @retval  OT_ERROR_NONE               Successfully removed short address from the source match table.
398      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
399      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
400      * @retval  OT_ERROR_NO_ADDRESS         The short address is not in source address match table.
401      */
402     otError ClearSrcMatchShortEntry(uint16_t aShortAddress);
403 
404     /**
405      * Clear all short addresses from the source address match table.
406      *
407      * @param[in]  aInstance   The OpenThread instance structure.
408      *
409      * @retval  OT_ERROR_NONE               Succeeded.
410      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
411      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
412      *
413      */
414     otError ClearSrcMatchShortEntries(void);
415 
416     /**
417      * Add an extended address to the source address match table.
418      *
419      * @param[in]  aInstance    The OpenThread instance structure.
420      * @param[in]  aExtAddress  The extended address to be added stored in little-endian byte order.
421      *
422      * @retval  OT_ERROR_NONE               Successfully added extended address to the source match table.
423      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
424      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
425      * @retval  OT_ERROR_NO_BUFS            No available entry in the source match table.
426      */
427     otError AddSrcMatchExtEntry(const otExtAddress &aExtAddress);
428 
429     /**
430      * Remove an extended address from the source address match table.
431      *
432      * @param[in]  aInstance    The OpenThread instance structure.
433      * @param[in]  aExtAddress  The extended address to be removed stored in little-endian byte order.
434      *
435      * @retval  OT_ERROR_NONE               Successfully removed the extended address from the source match table.
436      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
437      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
438      * @retval  OT_ERROR_NO_ADDRESS         The extended address is not in source address match table.
439      */
440     otError ClearSrcMatchExtEntry(const otExtAddress &aExtAddress);
441 
442     /**
443      * Clear all the extended/long addresses from source address match table.
444      *
445      * @param[in]  aInstance   The OpenThread instance structure.
446      *
447      * @retval  OT_ERROR_NONE               Succeeded.
448      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
449      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
450      *
451      */
452     otError ClearSrcMatchExtEntries(void);
453 
454     /**
455      * Begins the energy scan sequence on the radio.
456      *
457      * @param[in]  aScanChannel     The channel to perform the energy scan on.
458      * @param[in]  aScanDuration    The duration, in milliseconds, for the channel to be scanned.
459      *
460      * @retval  OT_ERROR_NONE               Succeeded.
461      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
462      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
463      *
464      */
465     otError EnergyScan(uint8_t aScanChannel, uint16_t aScanDuration);
466 
467     /**
468      * Switches the radio state from Receive to Transmit.
469      *
470      * @param[in] aFrame     A reference to the transmitted frame.
471      *
472      * @retval  OT_ERROR_NONE               Successfully transitioned to Transmit.
473      * @retval  OT_ERROR_BUSY               Failed due to another transmission is on going.
474      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
475      * @retval  OT_ERROR_INVALID_STATE      The radio was not in the Receive state.
476      */
477     otError Transmit(otRadioFrame &aFrame);
478 
479     /**
480      * Switches the radio state from Sleep to Receive.
481      *
482      * @param[in]  aChannel   The channel to use for receiving.
483      *
484      * @retval OT_ERROR_NONE          Successfully transitioned to Receive.
485      * @retval OT_ERROR_INVALID_STATE The radio was disabled or transmitting.
486      *
487      */
488     otError Receive(uint8_t aChannel);
489 
490     /**
491      * Switches the radio state from Receive to Sleep.
492      *
493      * @retval OT_ERROR_NONE          Successfully transitioned to Sleep.
494      * @retval OT_ERROR_BUSY          The radio was transmitting
495      * @retval OT_ERROR_INVALID_STATE The radio was disabled
496      *
497      */
498     otError Sleep(void);
499 
500     /**
501      * Enable the radio.
502      *
503      * @param[in]   aInstance   A pointer to the OpenThread instance.
504      *
505      * @retval OT_ERROR_NONE     Successfully enabled.
506      * @retval OT_ERROR_FAILED   The radio could not be enabled.
507      *
508      */
509     otError Enable(otInstance *aInstance);
510 
511     /**
512      * Disable the radio.
513      *
514      * @retval  OT_ERROR_NONE               Successfully transitioned to Disabled.
515      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
516      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
517      *
518      */
519     otError Disable(void);
520 
521     /**
522      * Checks whether radio is enabled or not.
523      *
524      * @returns TRUE if the radio is enabled, FALSE otherwise.
525      *
526      */
IsEnabled(void) const527     bool IsEnabled(void) const { return mState != kStateDisabled; }
528 
529     /**
530      * Indicates whether there is a pending transmission.
531      *
532      * @retval TRUE  There is a pending transmission.
533      * @retval FALSE There is no pending transmission.
534      *
535      */
IsTransmitting(void) const536     bool IsTransmitting(void) const { return mState == kStateTransmitting; }
537 
538     /**
539      * Indicates whether a transmit has just finished.
540      *
541      * @retval TRUE  The transmission is done.
542      * @retval FALSE The transmission is not done.
543      *
544      */
IsTransmitDone(void) const545     bool IsTransmitDone(void) const { return mState == kStateTransmitDone; }
546 
547     /**
548      * Returns the timeout timepoint for the pending transmission.
549      *
550      * @returns The timeout timepoint for the pending transmission.
551      *
552      */
GetTxRadioEndUs(void) const553     uint64_t GetTxRadioEndUs(void) const { return mTxRadioEndUs; }
554 
555     /**
556      * Processes any pending the I/O data.
557      *
558      * @param[in]  aContext   The process context.
559      *
560      */
561     void Process(const void *aContext);
562 
563     /**
564      * Returns the underlying spinel interface.
565      *
566      * @returns The underlying spinel interface.
567      *
568      */
GetSpinelInterface(void)569     InterfaceType &GetSpinelInterface(void) { return mSpinelInterface; }
570 
571 #if OPENTHREAD_CONFIG_DIAG_ENABLE
572     /**
573      * Enables/disables the factory diagnostics mode.
574      *
575      * @param[in]  aMode  TRUE to enable diagnostics mode, FALSE otherwise.
576      *
577      */
SetDiagEnabled(bool aMode)578     void SetDiagEnabled(bool aMode) { mDiagMode = aMode; }
579 
580     /**
581      * Indicates whether or not factory diagnostics mode is enabled.
582      *
583      * @returns TRUE if factory diagnostics mode is enabled, FALSE otherwise.
584      *
585      */
IsDiagEnabled(void) const586     bool IsDiagEnabled(void) const { return mDiagMode; }
587 
588     /**
589      * Processes platform diagnostics commands.
590      *
591      * @param[in]   aString         A null-terminated input string.
592      * @param[out]  aOutput         The diagnostics execution result.
593      * @param[in]   aOutputMaxLen   The output buffer size.
594      *
595      * @retval  OT_ERROR_NONE               Succeeded.
596      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
597      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
598      *
599      */
600     otError PlatDiagProcess(const char *aString, char *aOutput, size_t aOutputMaxLen);
601 #endif
602 
603     /**
604      * Returns the radio channel mask.
605      *
606      * @param[in]   aPreferred  TRUE to get preferred channel mask, FALSE to get supported channel mask.
607      *
608      * @returns The radio channel mask according to @aPreferred:
609      *   The radio supported channel mask that the device is allowed to be on.
610      *   The radio preferred channel mask that the device prefers to form on.
611      *
612      */
613     uint32_t GetRadioChannelMask(bool aPreferred);
614 
615     /**
616      * Processes a received Spinel frame.
617      *
618      * The newly received frame is available in `RxFrameBuffer` from `SpinelInterface::GetRxFrameBuffer()`.
619      *
620      */
621     void HandleReceivedFrame(void);
622 
623     /**
624      * Sets MAC key and key index to RCP.
625      *
626      * @param[in] aKeyIdMode  The key ID mode.
627      * @param[in] aKeyId      The key index.
628      * @param[in] aPrevKey    Pointer to previous MAC key.
629      * @param[in] aCurrKey    Pointer to current MAC key.
630      * @param[in] aNextKey    Pointer to next MAC key.
631      *
632      * @retval  OT_ERROR_NONE               Succeeded.
633      * @retval  OT_ERROR_INVALID_ARGS       One of the keys passed is invalid..
634      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
635      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
636      *
637      */
638     otError SetMacKey(uint8_t                 aKeyIdMode,
639                       uint8_t                 aKeyId,
640                       const otMacKeyMaterial *aPrevKey,
641                       const otMacKeyMaterial *aCurrKey,
642                       const otMacKeyMaterial *aNextKey);
643 
644     /**
645      * Sets the current MAC Frame Counter value.
646      *
647      * @param[in] aMacFrameCounter  The MAC Frame Counter value.
648      * @param[in] aSetIfLarger      If `true`, set only if the new value is larger than the current value.
649      *                              If `false`, set the new value independent of the current value.
650      *
651      */
652     otError SetMacFrameCounter(uint32_t aMacFrameCounter, bool aSetIfLarger);
653 
654     /**
655      * Sets the radio region code.
656      *
657      * @param[in]   aRegionCode  The radio region code.
658      *
659      * @retval  OT_ERROR_NONE             Successfully set region code.
660      * @retval  OT_ERROR_FAILED           Other platform specific errors.
661      *
662      */
663     otError SetRadioRegion(uint16_t aRegionCode);
664 
665     /**
666      * Gets the radio region code.
667      *
668      * @param[out]   aRegionCode  The radio region code.
669      *
670      * @retval  OT_ERROR_INVALID_ARGS     @p aRegionCode is nullptr.
671      * @retval  OT_ERROR_NONE             Successfully got region code.
672      * @retval  OT_ERROR_FAILED           Other platform specific errors.
673      *
674      */
675     otError GetRadioRegion(uint16_t *aRegionCode);
676 
677 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
678     /**
679      * Enable/disable or update Enhanced-ACK Based Probing in radio for a specific Initiator.
680      *
681      * After Enhanced-ACK Based Probing is configured by a specific Probing Initiator, the Enhanced-ACK sent to that
682      * node should include Vendor-Specific IE containing Link Metrics data. This method informs the radio to start/stop
683      * to collect Link Metrics data and include Vendor-Specific IE that containing the data in Enhanced-ACK sent to that
684      * Probing Initiator.
685      *
686      * @param[in]  aLinkMetrics   This parameter specifies what metrics to query. Per spec 4.11.3.4.4.6, at most 2
687      *                            metrics can be specified. The probing would be disabled if @p aLinkMetrics is
688      *                            bitwise 0.
689      * @param[in]  aShortAddress  The short address of the Probing Initiator.
690      * @param[in]  aExtAddress    The extended source address of the Probing Initiator. @p aExtAddress MUST NOT be
691      *                            nullptr.
692      *
693      * @retval  OT_ERROR_NONE            Successfully configured the Enhanced-ACK Based Probing.
694      * @retval  OT_ERROR_INVALID_ARGS    @p aExtAddress is nullptr.
695      * @retval  OT_ERROR_NOT_FOUND       The Initiator indicated by @p aShortAddress is not found when trying to clear.
696      * @retval  OT_ERROR_NO_BUFS         No more Initiator can be supported.
697      */
698     otError ConfigureEnhAckProbing(otLinkMetrics        aLinkMetrics,
699                                    const otShortAddress aShortAddress,
700                                    const otExtAddress  &aExtAddress);
701 #endif
702 
703 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE || OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
704     /**
705      * Get the current accuracy, in units of ± ppm, of the clock used for scheduling CSL operations.
706      *
707      * @note Platforms may optimize this value based on operational conditions (i.e.: temperature).
708      *
709      * @retval   The current CSL rx/tx scheduling drift, in units of ± ppm.
710      *
711      */
712     uint8_t GetCslAccuracy(void);
713 #endif
714 
715 #if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
716     /**
717      * Get the current uncertainty, in units of 10 us, of the clock used for scheduling CSL operations.
718      *
719      * @retval  The current CSL Clock Uncertainty in units of 10 us.
720      *
721      */
722     uint8_t GetCslUncertainty(void);
723 #endif
724 
725     /**
726      * Checks whether the spinel interface is radio-only.
727      *
728      * @param[out] aSupportsRcpApiVersion          A reference to a boolean variable to update whether the list of
729      *                                             spinel capabilities includes `SPINEL_CAP_RCP_API_VERSION`.
730      * @param[out] aSupportsRcpMinHostApiVersion   A reference to a boolean variable to update whether the list of
731      *                                             spinel capabilities includes `SPINEL_CAP_RCP_MIN_HOST_API_VERSION`.
732      *
733      * @retval  TRUE    The radio chip is in radio-only mode.
734      * @retval  FALSE   Otherwise.
735      *
736      */
737     bool IsRcp(bool &aSupportsRcpApiVersion, bool &aSupportsRcpMinHostApiVersion);
738 
739     /**
740      * Checks whether there is pending frame in the buffer.
741      *
742      * @returns Whether there is pending frame in the buffer.
743      *
744      */
HasPendingFrame(void) const745     bool HasPendingFrame(void) const { return mRxFrameBuffer.HasSavedFrame(); }
746 
747     /**
748      * Returns the next timepoint to recalculate RCP time offset.
749      *
750      * @returns The timepoint to start the recalculation of RCP time offset.
751      *
752      */
GetNextRadioTimeRecalcStart(void) const753     uint64_t GetNextRadioTimeRecalcStart(void) const { return mRadioTimeRecalcStart; }
754 
755     /**
756      * Gets the current estimated time on RCP.
757      *
758      * @returns The current estimated RCP time in microseconds.
759      *
760      */
761     uint64_t GetNow(void);
762 
763     /**
764      * Returns the bus speed between the host and the radio.
765      *
766      * @returns   bus speed in bits/second.
767      *
768      */
769     uint32_t GetBusSpeed(void) const;
770 
771     /**
772      * Sets the max transmit power.
773      *
774      * @param[in] aChannel    The radio channel.
775      * @param[in] aPower      The max transmit power in dBm.
776      *
777      * @retval  OT_ERROR_NONE           Successfully set the max transmit power.
778      * @retval  OT_ERROR_INVALID_ARGS   Channel is not in valid range.
779      *
780      */
781     otError SetChannelMaxTransmitPower(uint8_t aChannel, int8_t aPower);
782 
783     /**
784      * Tries to retrieve a spinel property from OpenThread transceiver.
785      *
786      * @param[in]   aKey        Spinel property key.
787      * @param[in]   aFormat     Spinel formatter to unpack property value.
788      * @param[out]  ...         Variable arguments list.
789      *
790      * @retval  OT_ERROR_NONE               Successfully got the property.
791      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
792      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
793      *
794      */
795     otError Get(spinel_prop_key_t aKey, const char *aFormat, ...);
796 
797     /**
798      * Tries to retrieve a spinel property from OpenThread transceiver with parameter appended.
799      *
800      * @param[in]   aKey        Spinel property key.
801      * @param[in]   aParam      Parameter appended to spinel command.
802      * @param[in]   aParamSize  Size of parameter appended to spinel command
803      * @param[in]   aFormat     Spinel formatter to unpack property value.
804      * @param[out]  ...         Variable arguments list.
805      *
806      * @retval  OT_ERROR_NONE               Successfully got the property.
807      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
808      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
809      *
810      */
811     otError GetWithParam(spinel_prop_key_t aKey,
812                          const uint8_t    *aParam,
813                          spinel_size_t     aParamSize,
814                          const char       *aFormat,
815                          ...);
816 
817     /**
818      * Tries to update a spinel property of OpenThread transceiver.
819      *
820      * @param[in]   aKey        Spinel property key.
821      * @param[in]   aFormat     Spinel formatter to pack property value.
822      * @param[in]   ...         Variable arguments list.
823      *
824      * @retval  OT_ERROR_NONE               Successfully set the property.
825      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
826      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
827      *
828      */
829     otError Set(spinel_prop_key_t aKey, const char *aFormat, ...);
830 
831     /**
832      * Tries to insert a item into a spinel list property of OpenThread transceiver.
833      *
834      * @param[in]   aKey        Spinel property key.
835      * @param[in]   aFormat     Spinel formatter to pack the item.
836      * @param[in]   ...         Variable arguments list.
837      *
838      * @retval  OT_ERROR_NONE               Successfully insert item into the property.
839      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
840      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
841      *
842      */
843     otError Insert(spinel_prop_key_t aKey, const char *aFormat, ...);
844 
845     /**
846      * Tries to remove a item from a spinel list property of OpenThread transceiver.
847      *
848      * @param[in]   aKey        Spinel property key.
849      * @param[in]   aFormat     Spinel formatter to pack the item.
850      * @param[in]   ...         Variable arguments list.
851      *
852      * @retval  OT_ERROR_NONE               Successfully removed item from the property.
853      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
854      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
855      *
856      */
857     otError Remove(spinel_prop_key_t aKey, const char *aFormat, ...);
858 
859     /**
860      * Tries to reset the co-processor.
861      *
862      * @prarm[in] aResetType    The reset type, SPINEL_RESET_PLATFORM or SPINEL_RESET_STACK.
863      *
864      * @retval  OT_ERROR_NONE               Successfully removed item from the property.
865      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
866      *
867      */
868     otError SendReset(uint8_t aResetType);
869 
870     /**
871      * Returns the radio Spinel metrics.
872      *
873      * @returns The radio Spinel metrics.
874      *
875      */
GetRadioSpinelMetrics(void) const876     const otRadioSpinelMetrics *GetRadioSpinelMetrics(void) const { return &mRadioSpinelMetrics; }
877 
878 #if OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE
879     /**
880      * Add a calibrated power of the specified channel to the power calibration table.
881      *
882      * @param[in] aChannel                The radio channel.
883      * @param[in] aActualPower            The actual power in 0.01dBm.
884      * @param[in] aRawPowerSetting        A pointer to the raw power setting byte array.
885      * @param[in] aRawPowerSettingLength  The length of the @p aRawPowerSetting.
886      *
887      * @retval  OT_ERROR_NONE              Successfully added the calibrated power to the power calibration table.
888      * @retval  OT_ERROR_NO_BUFS           No available entry in the power calibration table.
889      * @retval  OT_ERROR_INVALID_ARGS      The @p aChannel, @p aActualPower or @p aRawPowerSetting is invalid.
890      * @retval  OT_ERROR_NOT_IMPLEMENTED   This feature is not implemented.
891      * @retval  OT_ERROR_BUSY              Failed due to another operation is on going.
892      * @retval  OT_ERROR_RESPONSE_TIMEOUT  Failed due to no response received from the transceiver.
893      *
894      */
895     otError AddCalibratedPower(uint8_t        aChannel,
896                                int16_t        aActualPower,
897                                const uint8_t *aRawPowerSetting,
898                                uint16_t       aRawPowerSettingLength);
899 
900     /**
901      * Clear all calibrated powers from the power calibration table.
902      *
903      * @retval  OT_ERROR_NONE              Successfully cleared all calibrated powers from the power calibration table.
904      * @retval  OT_ERROR_NOT_IMPLEMENTED   This feature is not implemented.
905      * @retval  OT_ERROR_BUSY              Failed due to another operation is on going.
906      * @retval  OT_ERROR_RESPONSE_TIMEOUT  Failed due to no response received from the transceiver.
907      *
908      */
909     otError ClearCalibratedPowers(void);
910 
911     /**
912      * Set the target power for the given channel.
913      *
914      * @param[in]  aChannel      The radio channel.
915      * @param[in]  aTargetPower  The target power in 0.01dBm. Passing `INT16_MAX` will disable this channel.
916      *
917      * @retval  OT_ERROR_NONE              Successfully set the target power.
918      * @retval  OT_ERROR_INVALID_ARGS      The @p aChannel or @p aTargetPower is invalid..
919      * @retval  OT_ERROR_NOT_IMPLEMENTED   The feature is not implemented.
920      * @retval  OT_ERROR_BUSY              Failed due to another operation is on going.
921      * @retval  OT_ERROR_RESPONSE_TIMEOUT  Failed due to no response received from the transceiver.
922      *
923      */
924     otError SetChannelTargetPower(uint8_t aChannel, int16_t aTargetPower);
925 #endif
926 
927 private:
928     enum
929     {
930         kMaxSpinelFrame        = SPINEL_FRAME_MAX_SIZE,
931         kMaxWaitTime           = 2000, ///< Max time to wait for response in milliseconds.
932         kVersionStringSize     = 128,  ///< Max size of version string.
933         kCapsBufferSize        = 100,  ///< Max buffer size used to store `SPINEL_PROP_CAPS` value.
934         kChannelMaskBufferSize = 32,   ///< Max buffer size used to store `SPINEL_PROP_PHY_CHAN_SUPPORTED` value.
935     };
936 
937     enum State
938     {
939         kStateDisabled,     ///< Radio is disabled.
940         kStateSleep,        ///< Radio is sleep.
941         kStateReceive,      ///< Radio is in receive mode.
942         kStateTransmitting, ///< Frame passed to radio for transmission, waiting for done event from radio.
943         kStateTransmitDone, ///< Radio indicated frame transmission is done.
944     };
945 
946     typedef otError (RadioSpinel::*ResponseHandler)(const uint8_t *aBuffer, uint16_t aLength);
947 
948     static void HandleReceivedFrame(void *aContext);
949 
950     void    ResetRcp(bool aResetRadio);
951     otError CheckSpinelVersion(void);
952     otError CheckRadioCapabilities(void);
953     otError CheckRcpApiVersion(bool aSupportsRcpApiVersion, bool aSupportsMinHostRcpApiVersion);
954 
955     /**
956      * Triggers a state transfer of the state machine.
957      *
958      */
959     void ProcessRadioStateMachine(void);
960 
961     /**
962      * Processes the frame queue.
963      *
964      */
965     void ProcessFrameQueue(void);
966 
967     spinel_tid_t GetNextTid(void);
FreeTid(spinel_tid_t tid)968     void         FreeTid(spinel_tid_t tid) { mCmdTidsInUse &= ~(1 << tid); }
969 
970     otError RequestV(uint32_t aCommand, spinel_prop_key_t aKey, const char *aFormat, va_list aArgs);
971     otError Request(uint32_t aCommand, spinel_prop_key_t aKey, const char *aFormat, ...);
972     otError RequestWithPropertyFormat(const char       *aPropertyFormat,
973                                       uint32_t          aCommand,
974                                       spinel_prop_key_t aKey,
975                                       const char       *aFormat,
976                                       ...);
977     otError RequestWithPropertyFormatV(const char       *aPropertyFormat,
978                                        uint32_t          aCommand,
979                                        spinel_prop_key_t aKey,
980                                        const char       *aFormat,
981                                        va_list           aArgs);
982     otError RequestWithExpectedCommandV(uint32_t          aExpectedCommand,
983                                         uint32_t          aCommand,
984                                         spinel_prop_key_t aKey,
985                                         const char       *aFormat,
986                                         va_list           aArgs);
987     otError WaitResponse(bool aHandleRcpTimeout = true);
988     otError SendCommand(uint32_t          aCommand,
989                         spinel_prop_key_t aKey,
990                         spinel_tid_t      aTid,
991                         const char       *aFormat,
992                         va_list           aArgs);
993     otError ParseRadioFrame(otRadioFrame &aFrame, const uint8_t *aBuffer, uint16_t aLength, spinel_ssize_t &aUnpacked);
994 
995     /**
996      * Returns if the property changed event is safe to be handled now.
997      *
998      * If a property handler will go up to core stack, it may cause reentrant issue of `Hdlc::Decode()` and
999      * `WaitResponse()`.
1000      *
1001      * @param[in] aKey The identifier of the property.
1002      *
1003      * @returns Whether this property is safe to be handled now.
1004      *
1005      */
IsSafeToHandleNow(spinel_prop_key_t aKey) const1006     bool IsSafeToHandleNow(spinel_prop_key_t aKey) const
1007     {
1008         return !(aKey == SPINEL_PROP_STREAM_RAW || aKey == SPINEL_PROP_MAC_ENERGY_SCAN_RESULT);
1009     }
1010 
1011     void HandleNotification(SpinelInterface::RxFrameBuffer &aFrameBuffer);
1012     void HandleNotification(const uint8_t *aBuffer, uint16_t aLength);
1013     void HandleValueIs(spinel_prop_key_t aKey, const uint8_t *aBuffer, uint16_t aLength);
1014 
1015     void HandleResponse(const uint8_t *aBuffer, uint16_t aLength);
1016     void HandleTransmitDone(uint32_t aCommand, spinel_prop_key_t aKey, const uint8_t *aBuffer, uint16_t aLength);
1017     void HandleWaitingResponse(uint32_t aCommand, spinel_prop_key_t aKey, const uint8_t *aBuffer, uint16_t aLength);
1018 
1019     void RadioReceive(void);
1020 
1021     void TransmitDone(otRadioFrame *aFrame, otRadioFrame *aAckFrame, otError aError);
1022 
1023     void CalcRcpTimeOffset(void);
1024 
1025     void HandleRcpUnexpectedReset(spinel_status_t aStatus);
1026     void HandleRcpTimeout(void);
1027     void RecoverFromRcpFailure(void);
1028 
1029 #if OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0
1030     void RestoreProperties(void);
1031 #endif
UpdateParseErrorCount(otError aError)1032     void UpdateParseErrorCount(otError aError)
1033     {
1034         mRadioSpinelMetrics.mSpinelParseErrorCount += (aError == OT_ERROR_PARSE) ? 1 : 0;
1035     }
1036 
1037     uint32_t Snprintf(char *aDest, uint32_t aSize, const char *aFormat, ...);
1038     void     LogSpinelFrame(const uint8_t *aFrame, uint16_t aLength, bool aTx);
1039 
1040     otInstance *mInstance;
1041 
1042     SpinelInterface::RxFrameBuffer mRxFrameBuffer;
1043 
1044     InterfaceType mSpinelInterface;
1045 
1046     uint16_t          mCmdTidsInUse;    ///< Used transaction ids.
1047     spinel_tid_t      mCmdNextTid;      ///< Next available transaction id.
1048     spinel_tid_t      mTxRadioTid;      ///< The transaction id used to send a radio frame.
1049     spinel_tid_t      mWaitingTid;      ///< The transaction id of current transaction.
1050     spinel_prop_key_t mWaitingKey;      ///< The property key of current transaction.
1051     const char       *mPropertyFormat;  ///< The spinel property format of current transaction.
1052     va_list           mPropertyArgs;    ///< The arguments pack or unpack spinel property of current transaction.
1053     uint32_t          mExpectedCommand; ///< Expected response command of current transaction.
1054     otError           mError;           ///< The result of current transaction.
1055 
1056     uint8_t       mRxPsdu[OT_RADIO_FRAME_MAX_SIZE];
1057     uint8_t       mTxPsdu[OT_RADIO_FRAME_MAX_SIZE];
1058     uint8_t       mAckPsdu[OT_RADIO_FRAME_MAX_SIZE];
1059     otRadioFrame  mRxRadioFrame;
1060     otRadioFrame  mTxRadioFrame;
1061     otRadioFrame  mAckRadioFrame;
1062     otRadioFrame *mTransmitFrame; ///< Points to the frame to send
1063 
1064     otExtAddress mExtendedAddress;
1065     uint16_t     mShortAddress;
1066     uint16_t     mPanId;
1067     otRadioCaps  mRadioCaps;
1068     uint8_t      mChannel;
1069     int8_t       mRxSensitivity;
1070     otError      mTxError;
1071     char         mVersion[kVersionStringSize];
1072     otExtAddress mIeeeEui64;
1073 
1074     State mState;
1075     bool  mIsPromiscuous : 1;     ///< Promiscuous mode.
1076     bool  mIsReady : 1;           ///< NCP ready.
1077     bool  mSupportsLogStream : 1; ///< RCP supports `LOG_STREAM` property with OpenThread log meta-data format.
1078     bool  mIsTimeSynced : 1;      ///< Host has calculated the time difference between host and RCP.
1079 
1080 #if OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0
1081 
1082     bool    mResetRadioOnStartup : 1; ///< Whether should send reset command when init.
1083     int16_t mRcpFailureCount;         ///< Count of consecutive RCP failures.
1084 
1085     // Properties set by core.
1086     uint8_t      mKeyIdMode;
1087     uint8_t      mKeyId;
1088     otMacKey     mPrevKey;
1089     otMacKey     mCurrKey;
1090     otMacKey     mNextKey;
1091     uint16_t     mSrcMatchShortEntries[OPENTHREAD_CONFIG_MLE_MAX_CHILDREN];
1092     int16_t      mSrcMatchShortEntryCount;
1093     otExtAddress mSrcMatchExtEntries[OPENTHREAD_CONFIG_MLE_MAX_CHILDREN];
1094     int16_t      mSrcMatchExtEntryCount;
1095     uint8_t      mScanChannel;
1096     uint16_t     mScanDuration;
1097     int8_t       mCcaEnergyDetectThreshold;
1098     int8_t       mTransmitPower;
1099     int8_t       mFemLnaGain;
1100     bool         mCoexEnabled : 1;
1101 
1102     bool mMacKeySet : 1;                   ///< Whether MAC key has been set.
1103     bool mCcaEnergyDetectThresholdSet : 1; ///< Whether CCA energy detect threshold has been set.
1104     bool mTransmitPowerSet : 1;            ///< Whether transmit power has been set.
1105     bool mCoexEnabledSet : 1;              ///< Whether coex enabled has been set.
1106     bool mFemLnaGainSet : 1;               ///< Whether FEM LNA gain has been set.
1107     bool mRcpFailed : 1;                   ///< RCP failure happened, should recover and retry operation.
1108     bool mEnergyScanning : 1;              ///< If fails while scanning, restarts scanning.
1109 
1110 #endif // OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0
1111 
1112 #if OPENTHREAD_CONFIG_DIAG_ENABLE
1113     bool   mDiagMode;
1114     char  *mDiagOutput;
1115     size_t mDiagOutputMaxLen;
1116 #endif
1117 
1118     uint64_t mTxRadioEndUs;
1119     uint64_t mRadioTimeRecalcStart; ///< When to recalculate RCP time offset.
1120     uint64_t mRadioTimeOffset;      ///< Time difference with estimated RCP time minus host time.
1121 
1122     MaxPowerTable mMaxPowerTable;
1123 
1124     otRadioSpinelMetrics mRadioSpinelMetrics;
1125 };
1126 
1127 } // namespace Spinel
1128 } // namespace ot
1129 
1130 #include "radio_spinel_impl.hpp"
1131 
1132 #endif // RADIO_SPINEL_HPP_
1133