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