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/diag.h>
38 #include <openthread/platform/radio.h>
39 
40 #include "openthread-spinel-config.h"
41 #include "core/radio/max_power_table.hpp"
42 #include "lib/spinel/logger.hpp"
43 #include "lib/spinel/radio_spinel_metrics.h"
44 #include "lib/spinel/spinel.h"
45 #include "lib/spinel/spinel_driver.hpp"
46 #include "lib/spinel/spinel_interface.hpp"
47 #include "ncp/ncp_config.h"
48 
49 namespace ot {
50 namespace Spinel {
51 
52 struct RadioSpinelCallbacks
53 {
54     /**
55      * This callback notifies user of `RadioSpinel` of a received frame.
56      *
57      * @param[in]  aInstance  The OpenThread instance structure.
58      * @param[in]  aFrame     A pointer to the received frame or nullptr if the receive operation failed.
59      * @param[in]  aError     kErrorNone when successfully received a frame,
60      *                        kErrorAbort when reception was aborted and a frame was not received,
61      *                        kErrorNoBufs when a frame could not be received due to lack of rx buffer space.
62      */
63     void (*mReceiveDone)(otInstance *aInstance, otRadioFrame *aFrame, Error aError);
64 
65     /**
66      * The callback notifies user of `RadioSpinel` that the transmit operation has completed, providing, if
67      * applicable, the received ACK frame.
68      *
69      * @param[in]  aInstance  The OpenThread instance structure.
70      * @param[in]  aFrame     The transmitted frame.
71      * @param[in]  aAckFrame  A pointer to the ACK frame, nullptr if no ACK was received.
72      * @param[in]  aError     kErrorNone when the frame was transmitted,
73      *                        kErrorNoAck when the frame was transmitted but no ACK was received,
74      *                        kErrorChannelAccessFailure tx failed due to activity on the channel,
75      *                        kErrorAbort when transmission was aborted for other reasons.
76      */
77     void (*mTransmitDone)(otInstance *aInstance, otRadioFrame *aFrame, otRadioFrame *aAckFrame, Error aError);
78 
79     /**
80      * This callback notifies user of `RadioSpinel` that energy scan is complete.
81      *
82      * @param[in]  aInstance  The OpenThread instance structure.
83      * @param[in]  aMaxRssi   Maximum RSSI seen on the channel, or `SubMac::kInvalidRssiValue` if failed.
84      */
85     void (*mEnergyScanDone)(otInstance *aInstance, int8_t aMaxRssi);
86 
87     /**
88      * This callback notifies user of `RadioSpinel` that the bus latency has been changed.
89      *
90      * @param[in]  aInstance  The OpenThread instance structure.
91      */
92     void (*mBusLatencyChanged)(otInstance *aInstance);
93 
94     /**
95      * This callback notifies user of `RadioSpinel` that the transmission has started.
96      *
97      * @param[in]  aInstance  A pointer to the OpenThread instance structure.
98      * @param[in]  aFrame     A pointer to the frame that is being transmitted.
99      */
100     void (*mTxStarted)(otInstance *aInstance, otRadioFrame *aFrame);
101 
102     /**
103      * This callback notifies user of `RadioSpinel` that the radio interface switchover has completed.
104      *
105      * @param[in]  aInstance  A pointer to the OpenThread instance structure.
106      * @param[in]  aSuccess   A value indicating if the switchover was successful or not.
107      */
108     void (*mSwitchoverDone)(otInstance *aInstance, bool aSuccess);
109 
110 #if OPENTHREAD_CONFIG_DIAG_ENABLE
111     /**
112      * This callback notifies diagnostics module using `RadioSpinel` of a received frame.
113      *
114      * This callback is used when diagnostics is enabled.
115      *
116      * @param[in]  aInstance  The OpenThread instance structure.
117      * @param[in]  aFrame     A pointer to the received frame or NULL if the receive operation failed.
118      * @param[in]  aError     OT_ERROR_NONE when successfully received a frame,
119      *                        OT_ERROR_ABORT when reception was aborted and a frame was not received,
120      *                        OT_ERROR_NO_BUFS when a frame could not be received due to lack of rx buffer space.
121      */
122     void (*mDiagReceiveDone)(otInstance *aInstance, otRadioFrame *aFrame, Error aError);
123 
124     /**
125      * This callback notifies diagnostics module using `RadioSpinel` that the transmission has completed.
126      *
127      * This callback is used when diagnostics is enabled.
128      *
129      * @param[in]  aInstance  The OpenThread instance structure.
130      * @param[in]  aFrame     A pointer to the frame that was transmitted.
131      * @param[in]  aError     OT_ERROR_NONE when the frame was transmitted,
132      *                        OT_ERROR_CHANNEL_ACCESS_FAILURE tx could not take place due to activity on the
133      * channel, OT_ERROR_ABORT when transmission was aborted for other reasons.
134      */
135     void (*mDiagTransmitDone)(otInstance *aInstance, otRadioFrame *aFrame, Error aError);
136 #endif // OPENTHREAD_CONFIG_DIAG_ENABLE
137 };
138 
139 /**
140  * The class for providing a OpenThread radio interface by talking with a radio-only
141  * co-processor(RCP).
142  */
143 class RadioSpinel : private Logger
144 {
145 public:
146     /**
147      * Initializes the spinel based OpenThread transceiver.
148      */
149     RadioSpinel(void);
150 
151     /**
152      * Deinitializes the spinel based OpenThread transceiver.
153      */
~RadioSpinel(void)154     ~RadioSpinel(void) { Deinit(); }
155 
156     /**
157      * Initialize this radio transceiver.
158      *
159      * @param[in]  aSkipRcpVersionCheck        TRUE to skip RCP version check, FALSE to perform the check.
160      * @param[in]  aSoftwareReset              When doing RCP recovery, TRUE to try software reset first, FALSE to
161      *                                         directly do a hardware reset.
162      * @param[in]  aSpinelDriver               A pointer to the spinel driver instance that this object depends on.
163      * @param[in]  aRequiredRadioCaps          The required radio capabilities. RadioSpinel will check if RCP has
164      *                                         the required capabilities during initialization.
165      * @param[in]  aEnableRcpTimeSync          TRUE to enable RCP time sync, FALSE to not enable.
166      */
167     void Init(bool          aSkipRcpVersionCheck,
168               bool          aSoftwareReset,
169               SpinelDriver *aSpinelDriver,
170               otRadioCaps   aRequiredRadioCaps,
171               bool          aEnableRcpTimeSync);
172 
173     /**
174      * This method sets the notification callbacks.
175      *
176      * @param[in]  aCallbacks  A pointer to structure with notification callbacks.
177      */
178     void SetCallbacks(const struct RadioSpinelCallbacks &aCallbacks);
179 
180     /**
181      * Deinitialize this radio transceiver.
182      */
183     void Deinit(void);
184 
185     /**
186      * Gets the status of promiscuous mode.
187      *
188      * @retval true   Promiscuous mode is enabled.
189      * @retval false  Promiscuous mode is disabled.
190      */
IsPromiscuous(void) const191     bool IsPromiscuous(void) const { return mIsPromiscuous; }
192 
193     /**
194      * Sets the status of promiscuous mode.
195      *
196      * @param[in]   aEnable     Whether to enable or disable promiscuous mode.
197      *
198      * @retval  OT_ERROR_NONE               Succeeded.
199      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
200      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
201      */
202     otError SetPromiscuous(bool aEnable);
203 
204     /**
205      * Sets the status of RxOnWhenIdle mode.
206      *
207      * @param[in]   aEnable     Whether to enable or disable RxOnWhenIdle mode.
208      *
209      * @retval  OT_ERROR_NONE               Succeeded.
210      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
211      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
212      */
213     otError SetRxOnWhenIdle(bool aEnable);
214 
215     /**
216      * Sets the Short Address for address filtering.
217      *
218      * @param[in] aShortAddress  The IEEE 802.15.4 Short Address.
219      *
220      * @retval  OT_ERROR_NONE               Succeeded.
221      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
222      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
223      */
224     otError SetShortAddress(uint16_t aAddress);
225 
226     /**
227      * Sets the alternate short address.
228      *
229      * @param[in] aShortAddress   The alternate short address.
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     otError SetAlternateShortAddress(uint16_t aAddress);
236 
237     /**
238      * Gets the factory-assigned IEEE EUI-64 for this transceiver.
239      *
240      * @param[in]  aInstance   The OpenThread instance structure.
241      * @param[out] aIeeeEui64  A pointer to the factory-assigned IEEE EUI-64.
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     otError GetIeeeEui64(uint8_t *aIeeeEui64);
248 
249     /**
250      * Sets the Extended Address for address filtering.
251      *
252      * @param[in] aExtAddress  A pointer to the IEEE 802.15.4 Extended Address stored in little-endian byte order.
253      *
254      * @retval  OT_ERROR_NONE               Succeeded.
255      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
256      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
257      */
258     otError SetExtendedAddress(const otExtAddress &aExtAddress);
259 
260     /**
261      * Sets the PAN ID for address filtering.
262      *
263      * @param[in]   aPanId  The IEEE 802.15.4 PAN ID.
264      *
265      * @retval  OT_ERROR_NONE               Succeeded.
266      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
267      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
268      */
269     otError SetPanId(uint16_t aPanId);
270 
271     /**
272      * Gets the radio's transmit power in dBm.
273      *
274      * @param[out]  aPower    The transmit power in dBm.
275      *
276      * @retval  OT_ERROR_NONE               Succeeded.
277      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
278      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
279      */
280     otError GetTransmitPower(int8_t &aPower);
281 
282     /**
283      * Sets the radio's transmit power in dBm.
284      *
285      * @param[in]   aPower     The transmit power in dBm.
286      *
287      * @retval  OT_ERROR_NONE               Succeeded.
288      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
289      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
290      */
291     otError SetTransmitPower(int8_t aPower);
292 
293     /**
294      * Gets the radio's CCA ED threshold in dBm.
295      *
296      * @param[out]  aThreshold    The CCA ED threshold 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     otError GetCcaEnergyDetectThreshold(int8_t &aThreshold);
303 
304     /**
305      * Sets the radio's CCA ED threshold in dBm.
306      *
307      * @param[in]   aThreshold     The CCA ED threshold in dBm.
308      *
309      * @retval  OT_ERROR_NONE               Succeeded.
310      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
311      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
312      */
313     otError SetCcaEnergyDetectThreshold(int8_t aThreshold);
314 
315     /**
316      * Gets the FEM's Rx LNA gain in dBm.
317      *
318      * @param[out]  aGain    The FEM's Rx LNA gain in dBm.
319      *
320      * @retval  OT_ERROR_NONE               Succeeded.
321      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
322      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
323      */
324     otError GetFemLnaGain(int8_t &aGain);
325 
326     /**
327      * Sets the FEM's Rx LNA gain in dBm.
328      *
329      * @param[in]   aGain     The FEM's Rx LNA gain in dBm.
330      *
331      * @retval  OT_ERROR_NONE               Succeeded.
332      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
333      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
334      */
335     otError SetFemLnaGain(int8_t aGain);
336 
337     /**
338      * Returns the radio capabilities.
339      *
340      * @returns The radio capability bit vector.
341      */
GetRadioCaps(void) const342     otRadioCaps GetRadioCaps(void) const { return sRadioCaps; }
343 
344     /**
345      * Gets the most recent RSSI measurement.
346      *
347      * @returns The RSSI in dBm when it is valid.  127 when RSSI is invalid.
348      */
349     int8_t GetRssi(void);
350 
351     /**
352      * Returns the radio receive sensitivity value.
353      *
354      * @returns The radio receive sensitivity value in dBm.
355      *
356      * @retval  OT_ERROR_NONE               Succeeded.
357      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
358      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
359      */
GetReceiveSensitivity(void) const360     int8_t GetReceiveSensitivity(void) const { return mRxSensitivity; }
361 
362     /**
363      * Gets current state of the radio.
364      *
365      * @return  Current state of the radio.
366      */
367     otRadioState GetState(void) const;
368 
369     /**
370      * Gets the current receiving channel.
371      *
372      * @returns Current receiving channel.
373      */
GetChannel(void) const374     uint8_t GetChannel(void) const { return mChannel; }
375 
376 #if OPENTHREAD_CONFIG_PLATFORM_RADIO_COEX_ENABLE
377     /**
378      * Enable the radio coex.
379      *
380      * @param[in] aInstance  The OpenThread instance structure.
381      * @param[in] aEnabled   TRUE to enable the radio coex, FALSE otherwise.
382      *
383      * @retval OT_ERROR_NONE     Successfully enabled.
384      * @retval OT_ERROR_FAILED   The radio coex could not be enabled.
385      */
386     otError SetCoexEnabled(bool aEnabled);
387 
388     /**
389      * Check whether radio coex is enabled or not.
390      *
391      * @param[in] aInstance  The OpenThread instance structure.
392      *
393      * @returns TRUE if the radio coex is enabled, FALSE otherwise.
394      */
395     bool IsCoexEnabled(void);
396 
397     /**
398      * Retrieves the radio coexistence metrics.
399      *
400      * @param[out] aCoexMetrics  A reference to the coexistence metrics structure.
401      *
402      * @retval OT_ERROR_NONE          Successfully retrieved the coex metrics.
403      * @retval OT_ERROR_INVALID_ARGS  @p aCoexMetrics was nullptr.
404      */
405     otError GetCoexMetrics(otRadioCoexMetrics &aCoexMetrics);
406 #endif // OPENTHREAD_CONFIG_PLATFORM_RADIO_COEX_ENABLE
407 
408     /**
409      * Get currently active interface.
410      *
411      * @param[out] aIid IID of the interface that owns the radio.
412      *
413      * @retval  OT_ERROR_NONE               Successfully got the property.
414      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
415      * @retval  OT_ERROR_NOT_IMPLEMENTED    Failed due to lack of the support in radio
416      * @retval  OT_ERROR_INVALID_COMMAND    Platform supports all interfaces simultaneously.
417      *                                      (i.e. no active/inactive interface concept in the platform level)
418      */
419     otError GetMultipanActiveInterface(spinel_iid_t *aIid);
420 
421     /**
422      * Sets specified radio interface active
423      *
424      * This function allows selecting currently active radio interface on platforms that do not support parallel
425      * communication on multiple interfaces. I.e. if more than one interface is in receive state calling
426      * SetMultipanActiveInterface guarantees that specified interface will not be losing frames. This function
427      * returns if the request was received properly. After interface switching is complete SwitchoverDone callback is
428      * Invoked. Switching interfaces may take longer if aCompletePending is set true.
429      *
430      * @param[in] aIid              IID of the interface to set active.
431      * @param[in] aCompletePending  Set true if pending radio operation should complete first(Soft switch) or false if
432      * ongoing operations should be interrupted (Force switch).
433      *
434      * @retval  OT_ERROR_NONE               Successfully requested interface switch.
435      * @retval  OT_ERROR_BUSY               Failed due to another operation on going.
436      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
437      * @retval  OT_ERROR_NOT_IMPLEMENTED    Failed due to lack of support in radio for the given interface id or
438      * @retval  OT_ERROR_INVALID_COMMAND    Platform supports all interfaces simultaneously
439      *                                      (i.e. no active/inactive interface concept in the platform level)
440      * @retval  OT_ERROR_ALREADY            Given interface is already active.
441      */
442     otError SetMultipanActiveInterface(spinel_iid_t aIid, bool aCompletePending);
443 
444     /**
445      * Returns a reference to the transmit buffer.
446      *
447      * The caller forms the IEEE 802.15.4 frame in this buffer then calls otPlatRadioTransmit() to request transmission.
448      *
449      * @returns A reference to the transmit buffer.
450      */
GetTransmitFrame(void)451     otRadioFrame &GetTransmitFrame(void) { return mTxRadioFrame; }
452 
453     /**
454      * Enables or disables source address match feature.
455      *
456      * @param[in]  aEnable     Enable/disable source address match feature.
457      *
458      * @retval  OT_ERROR_NONE               Succeeded.
459      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
460      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
461      */
462     otError EnableSrcMatch(bool aEnable);
463 
464     /**
465      * Adds a short address to the source address match table.
466      *
467      * @param[in]  aInstance      The OpenThread instance structure.
468      * @param[in]  aShortAddress  The short address to be added.
469      *
470      * @retval  OT_ERROR_NONE               Successfully added short address to the source match table.
471      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
472      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
473      * @retval  OT_ERROR_NO_BUFS            No available entry in the source match table.
474      */
475     otError AddSrcMatchShortEntry(uint16_t aShortAddress);
476 
477     /**
478      * Removes a short address from the source address match table.
479      *
480      * @param[in]  aInstance      The OpenThread instance structure.
481      * @param[in]  aShortAddress  The short address to be removed.
482      *
483      * @retval  OT_ERROR_NONE               Successfully removed short address from the source match table.
484      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
485      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
486      * @retval  OT_ERROR_NO_ADDRESS         The short address is not in source address match table.
487      */
488     otError ClearSrcMatchShortEntry(uint16_t aShortAddress);
489 
490     /**
491      * Clear all short addresses from the source address match table.
492      *
493      * @param[in]  aInstance   The OpenThread instance structure.
494      *
495      * @retval  OT_ERROR_NONE               Succeeded.
496      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
497      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
498      */
499     otError ClearSrcMatchShortEntries(void);
500 
501     /**
502      * Add an extended address to the source address match table.
503      *
504      * @param[in]  aInstance    The OpenThread instance structure.
505      * @param[in]  aExtAddress  The extended address to be added stored in little-endian byte order.
506      *
507      * @retval  OT_ERROR_NONE               Successfully added extended address to the source match table.
508      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
509      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
510      * @retval  OT_ERROR_NO_BUFS            No available entry in the source match table.
511      */
512     otError AddSrcMatchExtEntry(const otExtAddress &aExtAddress);
513 
514     /**
515      * Remove an extended address from the source address match table.
516      *
517      * @param[in]  aInstance    The OpenThread instance structure.
518      * @param[in]  aExtAddress  The extended address to be removed stored in little-endian byte order.
519      *
520      * @retval  OT_ERROR_NONE               Successfully removed the extended address from the source match table.
521      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
522      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
523      * @retval  OT_ERROR_NO_ADDRESS         The extended address is not in source address match table.
524      */
525     otError ClearSrcMatchExtEntry(const otExtAddress &aExtAddress);
526 
527     /**
528      * Clear all the extended/long addresses from source address match table.
529      *
530      * @param[in]  aInstance   The OpenThread instance structure.
531      *
532      * @retval  OT_ERROR_NONE               Succeeded.
533      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
534      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
535      */
536     otError ClearSrcMatchExtEntries(void);
537 
538     /**
539      * Begins the energy scan sequence on the radio.
540      *
541      * @param[in]  aScanChannel     The channel to perform the energy scan on.
542      * @param[in]  aScanDuration    The duration, in milliseconds, for the channel to be scanned.
543      *
544      * @retval  OT_ERROR_NONE               Succeeded.
545      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
546      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
547      */
548     otError EnergyScan(uint8_t aScanChannel, uint16_t aScanDuration);
549 
550     /**
551      * Switches the radio state from Receive to Transmit.
552      *
553      * @param[in] aFrame     A reference to the transmitted frame.
554      *
555      * @retval  OT_ERROR_NONE               Successfully transitioned to Transmit.
556      * @retval  OT_ERROR_BUSY               Failed due to another transmission is on going.
557      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
558      * @retval  OT_ERROR_INVALID_STATE      The radio was not in the Receive state.
559      */
560     otError Transmit(otRadioFrame &aFrame);
561 
562     /**
563      * Switches the radio state from Sleep to Receive.
564      *
565      * @param[in]  aChannel   The channel to use for receiving.
566      *
567      * @retval OT_ERROR_NONE          Successfully transitioned to Receive.
568      * @retval OT_ERROR_INVALID_STATE The radio was disabled or transmitting.
569      */
570     otError Receive(uint8_t aChannel);
571 
572     /**
573      * Schedule a radio reception window at a specific time and duration.
574      *
575      * @param[in]  aWhen      The receive window start time in the local
576      *                        radio clock, see `otPlatRadioGetNow`. The radio
577      *                        receiver SHALL be on and ready to receive the first
578      *                        symbol of a frame's SHR at the window start time.
579      * @param[in]  aDuration  The receive window duration, in microseconds, as
580      *                        measured by the local radio clock.
581      * @param[in]  aChannel   The channel to use for receiving.
582      *
583      * @retval OT_ERROR_NONE          Successfully scheduled the reception.
584      * @retval OT_ERROR_INVALID_STATE The radio was disabled.
585      */
586     otError ReceiveAt(uint64_t aWhen, uint32_t aDuration, uint8_t aChannel);
587 
588     /**
589      * Switches the radio state from Receive to Sleep.
590      *
591      * @retval OT_ERROR_NONE          Successfully transitioned to Sleep.
592      * @retval OT_ERROR_BUSY          The radio was transmitting
593      * @retval OT_ERROR_INVALID_STATE The radio was disabled
594      */
595     otError Sleep(void);
596 
597     /**
598      * Enable the radio.
599      *
600      * @param[in]   aInstance   A pointer to the OpenThread instance.
601      *
602      * @retval OT_ERROR_NONE     Successfully enabled.
603      * @retval OT_ERROR_FAILED   The radio could not be enabled.
604      */
605     otError Enable(otInstance *aInstance);
606 
607     /**
608      * Disable the radio.
609      *
610      * @retval  OT_ERROR_NONE               Successfully transitioned to Disabled.
611      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
612      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
613      */
614     otError Disable(void);
615 
616     /**
617      * Checks whether radio is enabled or not.
618      *
619      * @returns TRUE if the radio is enabled, FALSE otherwise.
620      */
IsEnabled(void) const621     bool IsEnabled(void) const { return mState != kStateDisabled; }
622 
623     /**
624      * Indicates whether there is a pending transmission.
625      *
626      * @retval TRUE  There is a pending transmission.
627      * @retval FALSE There is no pending transmission.
628      */
IsTransmitting(void) const629     bool IsTransmitting(void) const { return mState == kStateTransmitting; }
630 
631     /**
632      * Indicates whether a transmit has just finished.
633      *
634      * @retval TRUE  The transmission is done.
635      * @retval FALSE The transmission is not done.
636      */
IsTransmitDone(void) const637     bool IsTransmitDone(void) const { return mState == kStateTransmitDone; }
638 
639     /**
640      * Returns the timeout timepoint for the pending transmission.
641      *
642      * @returns The timeout timepoint for the pending transmission.
643      */
GetTxRadioEndUs(void) const644     uint64_t GetTxRadioEndUs(void) const { return mTxRadioEndUs; }
645 
646     /**
647      * Processes any pending the I/O data.
648      *
649      * @param[in]  aContext   The process context.
650      */
651     void Process(const void *aContext);
652 
653 #if OPENTHREAD_CONFIG_DIAG_ENABLE
654     /**
655      * Enables/disables the factory diagnostics mode.
656      *
657      * @param[in]  aMode  TRUE to enable diagnostics mode, FALSE otherwise.
658      */
SetDiagEnabled(bool aMode)659     void SetDiagEnabled(bool aMode) { mDiagMode = aMode; }
660 
661     /**
662      * Indicates whether or not factory diagnostics mode is enabled.
663      *
664      * @returns TRUE if factory diagnostics mode is enabled, FALSE otherwise.
665      */
IsDiagEnabled(void) const666     bool IsDiagEnabled(void) const { return mDiagMode; }
667 
668     /**
669      * Processes RadioSpinel - specific diagnostics commands.
670      *
671      * @param[in]   aArgsLength     The number of arguments in @p aArgs.
672      * @param[in]   aArgs           The arguments of diagnostics command line.
673      *
674      * @retval  OT_ERROR_NONE               Succeeded.
675      * @retval  OT_ERROR_INVALID_ARGS       Failed due to invalid arguments provided.
676      */
677     otError RadioSpinelDiagProcess(char *aArgs[], uint8_t aArgsLength);
678 
679     /**
680      * Processes platform diagnostics commands.
681      *
682      * @param[in]   aString         A null-terminated input string.
683      *
684      * @retval  OT_ERROR_NONE               Succeeded.
685      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
686      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
687      */
688     otError PlatDiagProcess(const char *aString);
689 
690     /**
691      * Sets the diag output callback.
692      *
693      * @param[in]  aCallback   A pointer to a function that is called on outputting diag messages.
694      * @param[in]  aContext    A pointer to the user context.
695      */
696     void SetDiagOutputCallback(otPlatDiagOutputCallback aCallback, void *aContext);
697 
698     /**
699      * Gets the diag output callback.
700      *
701      * @param[out]  aCallback   A reference to a function that is called on outputting diag messages.
702      * @param[out]  aContext    A reference to the user context.
703      */
704     void GetDiagOutputCallback(otPlatDiagOutputCallback &aCallback, void *&aContext);
705 #endif
706 
707     /**
708      * Returns the radio channel mask.
709      *
710      * @param[in]   aPreferred  TRUE to get preferred channel mask, FALSE to get supported channel mask.
711      *
712      * @returns The radio channel mask according to @aPreferred:
713      *   The radio supported channel mask that the device is allowed to be on.
714      *   The radio preferred channel mask that the device prefers to form on.
715      */
716     uint32_t GetRadioChannelMask(bool aPreferred);
717 
718     /**
719      * Sets MAC key and key index to RCP.
720      *
721      * @param[in] aKeyIdMode  The key ID mode.
722      * @param[in] aKeyId      The key index.
723      * @param[in] aPrevKey    Pointer to previous MAC key.
724      * @param[in] aCurrKey    Pointer to current MAC key.
725      * @param[in] aNextKey    Pointer to next MAC key.
726      *
727      * @retval  OT_ERROR_NONE               Succeeded.
728      * @retval  OT_ERROR_INVALID_ARGS       One of the keys passed is invalid..
729      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
730      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
731      */
732     otError SetMacKey(uint8_t                 aKeyIdMode,
733                       uint8_t                 aKeyId,
734                       const otMacKeyMaterial *aPrevKey,
735                       const otMacKeyMaterial *aCurrKey,
736                       const otMacKeyMaterial *aNextKey);
737 
738     /**
739      * Sets the current MAC Frame Counter value.
740      *
741      * @param[in] aMacFrameCounter  The MAC Frame Counter value.
742      * @param[in] aSetIfLarger      If `true`, set only if the new value is larger than the current value.
743      *                              If `false`, set the new value independent of the current value.
744      */
745     otError SetMacFrameCounter(uint32_t aMacFrameCounter, bool aSetIfLarger);
746 
747     /**
748      * Sets the radio region code.
749      *
750      * @param[in]   aRegionCode  The radio region code.
751      *
752      * @retval  OT_ERROR_NONE             Successfully set region code.
753      * @retval  OT_ERROR_FAILED           Other platform specific errors.
754      */
755     otError SetRadioRegion(uint16_t aRegionCode);
756 
757     /**
758      * Gets the radio region code.
759      *
760      * @param[out]   aRegionCode  The radio region code.
761      *
762      * @retval  OT_ERROR_INVALID_ARGS     @p aRegionCode is nullptr.
763      * @retval  OT_ERROR_NONE             Successfully got region code.
764      * @retval  OT_ERROR_FAILED           Other platform specific errors.
765      */
766     otError GetRadioRegion(uint16_t *aRegionCode);
767 
768 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
769     /**
770      * Enable/disable or update Enhanced-ACK Based Probing in radio for a specific Initiator.
771      *
772      * After Enhanced-ACK Based Probing is configured by a specific Probing Initiator, the Enhanced-ACK sent to that
773      * node should include Vendor-Specific IE containing Link Metrics data. This method informs the radio to start/stop
774      * to collect Link Metrics data and include Vendor-Specific IE that containing the data in Enhanced-ACK sent to that
775      * Probing Initiator.
776      *
777      * @param[in]  aLinkMetrics   This parameter specifies what metrics to query. Per spec 4.11.3.4.4.6, at most 2
778      *                            metrics can be specified. The probing would be disabled if @p aLinkMetrics is
779      *                            bitwise 0.
780      * @param[in]  aShortAddress  The short address of the Probing Initiator.
781      * @param[in]  aExtAddress    The extended source address of the Probing Initiator. @p aExtAddress MUST NOT be
782      *                            nullptr.
783      *
784      * @retval  OT_ERROR_NONE            Successfully configured the Enhanced-ACK Based Probing.
785      * @retval  OT_ERROR_INVALID_ARGS    @p aExtAddress is nullptr.
786      * @retval  OT_ERROR_NOT_FOUND       The Initiator indicated by @p aShortAddress is not found when trying to clear.
787      * @retval  OT_ERROR_NO_BUFS         No more Initiator can be supported.
788      */
789     otError ConfigureEnhAckProbing(otLinkMetrics         aLinkMetrics,
790                                    const otShortAddress &aShortAddress,
791                                    const otExtAddress   &aExtAddress);
792 #endif
793 
794 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE || OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
795     /**
796      * Get the current accuracy, in units of ± ppm, of the clock used for scheduling CSL operations.
797      *
798      * @note Platforms may optimize this value based on operational conditions (i.e.: temperature).
799      *
800      * @retval   The current CSL rx/tx scheduling drift, in units of ± ppm.
801      */
802     uint8_t GetCslAccuracy(void);
803 #endif
804 
805 #if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
806     /**
807      * Get the current uncertainty, in units of 10 us, of the clock used for scheduling CSL operations.
808      *
809      * @retval  The current CSL Clock Uncertainty in units of 10 us.
810      */
811     uint8_t GetCslUncertainty(void);
812 #endif
813 
814     /**
815      * Checks whether there is pending frame in the buffer.
816      *
817      * @returns Whether there is pending frame in the buffer.
818      */
HasPendingFrame(void) const819     bool HasPendingFrame(void) const { return mSpinelDriver->HasPendingFrame(); }
820 
821     /**
822      * Returns the next timepoint to recalculate RCP time offset.
823      *
824      * @returns The timepoint to start the recalculation of RCP time offset.
825      */
GetNextRadioTimeRecalcStart(void) const826     uint64_t GetNextRadioTimeRecalcStart(void) const { return mRadioTimeRecalcStart; }
827 
828     /**
829      * Gets the current estimated time on RCP.
830      *
831      * @returns The current estimated RCP time in microseconds.
832      */
833     uint64_t GetNow(void);
834 
835     /**
836      * Returns the bus speed between the host and the radio.
837      *
838      * @returns   bus speed in bits/second.
839      */
840     uint32_t GetBusSpeed(void) const;
841 
842     /**
843      * Returns the bus latency between the host and the radio.
844      *
845      * @returns   Bus latency in microseconds.
846      */
847     uint32_t GetBusLatency(void) const;
848 
849     /**
850      * Sets the bus latency between the host and the radio.
851      *
852      * @param[in]   aBusLatency  Bus latency in microseconds.
853      */
854     void SetBusLatency(uint32_t aBusLatency);
855 
856     /**
857      * Returns the co-processor sw version string.
858      *
859      * @returns A pointer to the co-processor version string.
860      */
GetVersion(void) const861     const char *GetVersion(void) const { return mSpinelDriver->GetVersion(); }
862 
863     /**
864      * Sets the max transmit power.
865      *
866      * @param[in] aChannel    The radio channel.
867      * @param[in] aMaxPower   The max transmit power in dBm.
868      *
869      * @retval  OT_ERROR_NONE           Successfully set the max transmit power.
870      * @retval  OT_ERROR_INVALID_ARGS   Channel is not in valid range.
871      */
872     otError SetChannelMaxTransmitPower(uint8_t aChannel, int8_t aMaxPower);
873 
874     /**
875      * Tries to retrieve a spinel property from OpenThread transceiver.
876      *
877      * @param[in]   aKey        Spinel property key.
878      * @param[in]   aFormat     Spinel formatter to unpack property value.
879      * @param[out]  ...         Variable arguments list.
880      *
881      * @retval  OT_ERROR_NONE               Successfully got the property.
882      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
883      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
884      */
885     otError Get(spinel_prop_key_t aKey, const char *aFormat, ...);
886 
887     /**
888      * Tries to retrieve a spinel property from OpenThread transceiver with parameter appended.
889      *
890      * @param[in]   aKey        Spinel property key.
891      * @param[in]   aParam      Parameter appended to spinel command.
892      * @param[in]   aParamSize  Size of parameter appended to spinel command
893      * @param[in]   aFormat     Spinel formatter to unpack property value.
894      * @param[out]  ...         Variable arguments list.
895      *
896      * @retval  OT_ERROR_NONE               Successfully got the property.
897      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
898      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
899      */
900     otError GetWithParam(spinel_prop_key_t aKey,
901                          const uint8_t    *aParam,
902                          spinel_size_t     aParamSize,
903                          const char       *aFormat,
904                          ...);
905 
906     /**
907      * Tries to update a spinel property of OpenThread transceiver.
908      *
909      * @param[in]   aKey        Spinel property key.
910      * @param[in]   aFormat     Spinel formatter to pack property value.
911      * @param[in]   ...         Variable arguments list.
912      *
913      * @retval  OT_ERROR_NONE               Successfully set the property.
914      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
915      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
916      */
917     otError Set(spinel_prop_key_t aKey, const char *aFormat, ...);
918 
919     /**
920      * Tries to insert a item into a spinel list property of OpenThread transceiver.
921      *
922      * @param[in]   aKey        Spinel property key.
923      * @param[in]   aFormat     Spinel formatter to pack the item.
924      * @param[in]   ...         Variable arguments list.
925      *
926      * @retval  OT_ERROR_NONE               Successfully insert item into the property.
927      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
928      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
929      */
930     otError Insert(spinel_prop_key_t aKey, const char *aFormat, ...);
931 
932     /**
933      * Tries to remove a item from a spinel list property of OpenThread transceiver.
934      *
935      * @param[in]   aKey        Spinel property key.
936      * @param[in]   aFormat     Spinel formatter to pack the item.
937      * @param[in]   ...         Variable arguments list.
938      *
939      * @retval  OT_ERROR_NONE               Successfully removed item from the property.
940      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
941      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
942      */
943     otError Remove(spinel_prop_key_t aKey, const char *aFormat, ...);
944 
945     /**
946      * Sends a reset command to the RCP.
947      *
948      * @param[in] aResetType The reset type, SPINEL_RESET_PLATFORM, SPINEL_RESET_STACK, or SPINEL_RESET_BOOTLOADER.
949      *
950      * @retval  OT_ERROR_NONE               Successfully sent the reset command.
951      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
952      * @retval  OT_ERROR_NOT_CAPABLE        Requested reset type is not supported by the co-processor.
953      */
954     otError SendReset(uint8_t aResetType);
955 
956     /**
957      * Returns the radio Spinel metrics.
958      *
959      * @returns The radio Spinel metrics.
960      */
GetRadioSpinelMetrics(void) const961     const otRadioSpinelMetrics *GetRadioSpinelMetrics(void) const { return &mRadioSpinelMetrics; }
962 
963 #if OPENTHREAD_CONFIG_PLATFORM_POWER_CALIBRATION_ENABLE
964     /**
965      * Add a calibrated power of the specified channel to the power calibration table.
966      *
967      * @param[in] aChannel                The radio channel.
968      * @param[in] aActualPower            The actual power in 0.01dBm.
969      * @param[in] aRawPowerSetting        A pointer to the raw power setting byte array.
970      * @param[in] aRawPowerSettingLength  The length of the @p aRawPowerSetting.
971      *
972      * @retval  OT_ERROR_NONE              Successfully added the calibrated power to the power calibration table.
973      * @retval  OT_ERROR_NO_BUFS           No available entry in the power calibration table.
974      * @retval  OT_ERROR_INVALID_ARGS      The @p aChannel, @p aActualPower or @p aRawPowerSetting is invalid.
975      * @retval  OT_ERROR_NOT_IMPLEMENTED   This feature is not implemented.
976      * @retval  OT_ERROR_BUSY              Failed due to another operation is on going.
977      * @retval  OT_ERROR_RESPONSE_TIMEOUT  Failed due to no response received from the transceiver.
978      */
979     otError AddCalibratedPower(uint8_t        aChannel,
980                                int16_t        aActualPower,
981                                const uint8_t *aRawPowerSetting,
982                                uint16_t       aRawPowerSettingLength);
983 
984     /**
985      * Clear all calibrated powers from the power calibration table.
986      *
987      * @retval  OT_ERROR_NONE              Successfully cleared all calibrated powers from the power calibration table.
988      * @retval  OT_ERROR_NOT_IMPLEMENTED   This feature is not implemented.
989      * @retval  OT_ERROR_BUSY              Failed due to another operation is on going.
990      * @retval  OT_ERROR_RESPONSE_TIMEOUT  Failed due to no response received from the transceiver.
991      */
992     otError ClearCalibratedPowers(void);
993 
994     /**
995      * Set the target power for the given channel.
996      *
997      * @param[in]  aChannel      The radio channel.
998      * @param[in]  aTargetPower  The target power in 0.01dBm. Passing `INT16_MAX` will disable this channel.
999      *
1000      * @retval  OT_ERROR_NONE              Successfully set the target power.
1001      * @retval  OT_ERROR_INVALID_ARGS      The @p aChannel or @p aTargetPower is invalid..
1002      * @retval  OT_ERROR_NOT_IMPLEMENTED   The feature is not implemented.
1003      * @retval  OT_ERROR_BUSY              Failed due to another operation is on going.
1004      * @retval  OT_ERROR_RESPONSE_TIMEOUT  Failed due to no response received from the transceiver.
1005      */
1006     otError SetChannelTargetPower(uint8_t aChannel, int16_t aTargetPower);
1007 #endif
1008 
1009 #if OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0
1010     /**
1011      * Restore the properties of Radio Co-processor (RCP).
1012      */
1013     void RestoreProperties(void);
1014 #endif
1015 #if OPENTHREAD_SPINEL_CONFIG_VENDOR_HOOK_ENABLE
1016     /**
1017      * Defines a vendor "set property handler" hook to process vendor spinel properties.
1018      *
1019      * The vendor handler should return `OT_ERROR_NOT_FOUND` status if it does not support "set" operation for the
1020      * given property key. Otherwise, the vendor handler should behave like other property set handlers, i.e., it
1021      * should first decode the value from the input spinel frame and then perform the corresponding set operation. The
1022      * handler should not prepare the spinel response and therefore should not write anything to the NCP buffer. The
1023      * `otError` returned from handler (other than `OT_ERROR_NOT_FOUND`) indicates the error in either parsing of the
1024      * input or the error of the set operation. In case of a successful "set", `NcpBase` set command handler will call
1025      * the `VendorGetPropertyHandler()` for the same property key to prepare the response.
1026      *
1027      * @param[in] aPropKey  The spinel property key.
1028      *
1029      * @returns OT_ERROR_NOT_FOUND if it does not support the given property key, otherwise the error in either parsing
1030      *          of the input or the "set" operation.
1031      */
1032     otError VendorHandleValueIs(spinel_prop_key_t aPropKey);
1033 
1034     /**
1035      *  A callback type for restoring vendor properties.
1036      *
1037      * @param[in] aContext  A pointer to the user context.
1038      */
1039     typedef void (*otRadioSpinelVendorRestorePropertiesCallback)(void *aContext);
1040 
1041     /**
1042      * Registers a callback to restore vendor properties.
1043      *
1044      * This function is used to register a callback for vendor properties recovery. When an event which needs to restore
1045      * properties occurs (such as an unexpected RCP reset), the user can restore the vendor properties via the callback.
1046      *
1047      * @param[in] aCallback The callback.
1048      * @param[in] aContext  A pointer to the user context.
1049      */
1050     void SetVendorRestorePropertiesCallback(otRadioSpinelVendorRestorePropertiesCallback aCallback, void *aContext);
1051 #endif // OPENTHREAD_SPINEL_CONFIG_VENDOR_HOOK_ENABLE
1052 
1053 #if OPENTHREAD_SPINEL_CONFIG_COMPATIBILITY_ERROR_CALLBACK_ENABLE
1054     /**
1055      * A callback type for handling compatibility error of radio spinel.
1056      *
1057      * @param[in] aContext  A pointer to the user context.
1058      */
1059     typedef void (*otRadioSpinelCompatibilityErrorCallback)(void *aContext);
1060 
1061     /**
1062      * Registers a callback to handle error of radio spinel.
1063      *
1064      * This function is used to register a callback to handle radio spinel compatibility errors. When a radio spinel
1065      * compatibility error occurs that cannot be resolved by a restart (e.g., RCP version mismatch), the user can
1066      * handle the error through the callback(such as OTA) instead of letting the program crash directly.
1067      *
1068      * @param[in] aCallback The callback.
1069      * @param[in] aContext  A pointer to the user context.
1070      */
1071     void SetCompatibilityErrorCallback(otRadioSpinelCompatibilityErrorCallback aCallback, void *aContext);
1072 #endif
1073 
1074     /**
1075      * Enables or disables the time synchronization between the host and RCP.
1076      *
1077      * @param[in]  aOn  TRUE to turn on the time synchronization, FALSE otherwise.
1078      */
SetTimeSyncState(bool aOn)1079     void SetTimeSyncState(bool aOn) { mTimeSyncOn = aOn; }
1080 
1081 #if OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0
1082     /**
1083      * Enables or disables the RCP restoration feature.
1084      *
1085      * @param[in]  aEnabled  TRUE to enable the RCP restoration feature, FALSE otherwise.
1086      */
SetRcpRestorationEnabled(bool aEnabled)1087     void SetRcpRestorationEnabled(bool aEnabled) { mRcpRestorationEnabled = aEnabled; }
1088 #endif
1089 
1090 private:
1091     enum
1092     {
1093         kMaxWaitTime           = 2000, ///< Max time to wait for response in milliseconds.
1094         kVersionStringSize     = 128,  ///< Max size of version string.
1095         kCapsBufferSize        = 100,  ///< Max buffer size used to store `SPINEL_PROP_CAPS` value.
1096         kChannelMaskBufferSize = 32,   ///< Max buffer size used to store `SPINEL_PROP_PHY_CHAN_SUPPORTED` value.
1097     };
1098 
1099     enum State
1100     {
1101         kStateDisabled,     ///< Radio is disabled.
1102         kStateSleep,        ///< Radio is sleep.
1103         kStateReceive,      ///< Radio is in receive mode.
1104         kStateTransmitting, ///< Frame passed to radio for transmission, waiting for done event from radio.
1105         kStateTransmitDone, ///< Radio indicated frame transmission is done.
1106     };
1107 
1108     static constexpr uint32_t kUsPerMs  = 1000;                 ///< Microseconds per millisecond.
1109     static constexpr uint32_t kMsPerSec = 1000;                 ///< Milliseconds per second.
1110     static constexpr uint32_t kUsPerSec = kUsPerMs * kMsPerSec; ///< Microseconds per second.
1111     static constexpr uint64_t kTxWaitUs =
1112         OPENTHREAD_SPINEL_CONFIG_RCP_TX_WAIT_TIME_SECS *
1113         kUsPerSec; ///< Maximum time of waiting for `TransmitDone` event, in microseconds.
1114 
1115     typedef otError (RadioSpinel::*ResponseHandler)(const uint8_t *aBuffer, uint16_t aLength);
1116 
1117     SpinelDriver &GetSpinelDriver(void) const;
1118 
1119     otError CheckSpinelVersion(void);
1120     otError CheckRadioCapabilities(otRadioCaps aRequiredRadioCaps);
1121     otError CheckRcpApiVersion(bool aSupportsRcpApiVersion, bool aSupportsRcpMinHostApiVersion);
1122     void    InitializeCaps(bool &aSupportsRcpApiVersion, bool &aSupportsRcpMinHostApiVersion);
1123 
1124     /**
1125      * Triggers a state transfer of the state machine.
1126      */
1127     void ProcessRadioStateMachine(void);
1128 
1129     /**
1130      * Processes the frame queue.
1131      */
1132     void ProcessFrameQueue(void);
1133 
1134     spinel_tid_t GetNextTid(void);
FreeTid(spinel_tid_t tid)1135     void         FreeTid(spinel_tid_t tid) { mCmdTidsInUse &= ~(1 << tid); }
1136 
1137     otError RequestV(uint32_t aCommand, spinel_prop_key_t aKey, const char *aFormat, va_list aArgs);
1138     otError Request(uint32_t aCommand, spinel_prop_key_t aKey, const char *aFormat, ...);
1139     otError RequestWithPropertyFormat(const char       *aPropertyFormat,
1140                                       uint32_t          aCommand,
1141                                       spinel_prop_key_t aKey,
1142                                       const char       *aFormat,
1143                                       ...);
1144     otError RequestWithPropertyFormatV(const char       *aPropertyFormat,
1145                                        uint32_t          aCommand,
1146                                        spinel_prop_key_t aKey,
1147                                        const char       *aFormat,
1148                                        va_list           aArgs);
1149     otError RequestWithExpectedCommandV(uint32_t          aExpectedCommand,
1150                                         uint32_t          aCommand,
1151                                         spinel_prop_key_t aKey,
1152                                         const char       *aFormat,
1153                                         va_list           aArgs);
1154     otError WaitResponse(bool aHandleRcpTimeout = true);
1155     otError ParseRadioFrame(otRadioFrame &aFrame, const uint8_t *aBuffer, uint16_t aLength, spinel_ssize_t &aUnpacked);
1156 
1157     /**
1158      * Returns if the property changed event is safe to be handled now.
1159      *
1160      * If a property handler will go up to core stack, it may cause reentrant issue of `Hdlc::Decode()` and
1161      * `WaitResponse()`.
1162      *
1163      * @param[in] aKey The identifier of the property.
1164      *
1165      * @returns Whether this property is safe to be handled now.
1166      */
IsSafeToHandleNow(spinel_prop_key_t aKey) const1167     bool IsSafeToHandleNow(spinel_prop_key_t aKey) const
1168     {
1169         return !(aKey == SPINEL_PROP_STREAM_RAW || aKey == SPINEL_PROP_MAC_ENERGY_SCAN_RESULT);
1170     }
1171 
1172     void HandleNotification(const uint8_t *aFrame, uint16_t aLength, bool &aShouldSaveFrame);
1173     void HandleNotification(const uint8_t *aFrame, uint16_t aLength);
1174     void HandleValueIs(spinel_prop_key_t aKey, const uint8_t *aBuffer, uint16_t aLength);
1175 
1176     void HandleResponse(const uint8_t *aBuffer, uint16_t aLength);
1177     void HandleTransmitDone(uint32_t aCommand, spinel_prop_key_t aKey, const uint8_t *aBuffer, uint16_t aLength);
1178     void HandleWaitingResponse(uint32_t aCommand, spinel_prop_key_t aKey, const uint8_t *aBuffer, uint16_t aLength);
1179 
1180     void RadioReceive(void);
1181 
1182     void TransmitDone(otRadioFrame *aFrame, otRadioFrame *aAckFrame, otError aError);
1183 
1184     void CalcRcpTimeOffset(void);
1185 
1186     void HandleRcpUnexpectedReset(spinel_status_t aStatus);
1187     void HandleRcpTimeout(void);
1188     void RecoverFromRcpFailure(void);
1189 
1190     static void HandleReceivedFrame(const uint8_t *aFrame,
1191                                     uint16_t       aLength,
1192                                     uint8_t        aHeader,
1193                                     bool          &aSave,
1194                                     void          *aContext);
1195     void        HandleReceivedFrame(const uint8_t *aFrame, uint16_t aLength, uint8_t aHeader, bool &aShouldSaveFrame);
1196     static void HandleSavedFrame(const uint8_t *aFrame, uint16_t aLength, void *aContext);
1197     void        HandleSavedFrame(const uint8_t *aFrame, uint16_t aLength);
1198 
UpdateParseErrorCount(otError aError)1199     void UpdateParseErrorCount(otError aError)
1200     {
1201         mRadioSpinelMetrics.mSpinelParseErrorCount += (aError == OT_ERROR_PARSE) ? 1 : 0;
1202     }
1203 
1204     otError SetMacKey(uint8_t         aKeyIdMode,
1205                       uint8_t         aKeyId,
1206                       const otMacKey &aPrevKey,
1207                       const otMacKey &aCurrKey,
1208                       const otMacKey &NextKey);
1209 #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE
1210     static otError ReadMacKey(const otMacKeyMaterial &aKeyMaterial, otMacKey &aKey);
1211 #endif
1212 
1213 #if OPENTHREAD_CONFIG_DIAG_ENABLE
1214     void PlatDiagOutput(const char *aFormat, ...);
1215 #endif
1216 
1217     void HandleCompatibilityError(void);
1218 
1219     otInstance *mInstance;
1220 
1221     RadioSpinelCallbacks mCallbacks; ///< Callbacks for notifications of higher layer.
1222 
1223     uint16_t          mCmdTidsInUse;    ///< Used transaction ids.
1224     spinel_tid_t      mCmdNextTid;      ///< Next available transaction id.
1225     spinel_tid_t      mTxRadioTid;      ///< The transaction id used to send a radio frame.
1226     spinel_tid_t      mWaitingTid;      ///< The transaction id of current transaction.
1227     spinel_prop_key_t mWaitingKey;      ///< The property key of current transaction.
1228     const char       *mPropertyFormat;  ///< The spinel property format of current transaction.
1229     va_list           mPropertyArgs;    ///< The arguments pack or unpack spinel property of current transaction.
1230     uint32_t          mExpectedCommand; ///< Expected response command of current transaction.
1231     otError           mError;           ///< The result of current transaction.
1232     uint8_t           mRxPsdu[OT_RADIO_FRAME_MAX_SIZE];
1233     uint8_t           mTxPsdu[OT_RADIO_FRAME_MAX_SIZE];
1234     uint8_t           mAckPsdu[OT_RADIO_FRAME_MAX_SIZE];
1235     otRadioFrame      mRxRadioFrame;
1236     otRadioFrame      mTxRadioFrame;
1237     otRadioFrame      mAckRadioFrame;
1238     otRadioFrame     *mTransmitFrame; ///< Points to the frame to send
1239 
1240 #if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT && OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
1241     otRadioIeInfo mTxIeInfo;
1242 #endif
1243 
1244     otExtAddress        mExtendedAddress;
1245     uint16_t            mShortAddress;
1246     uint16_t            mPanId;
1247     uint8_t             mChannel;
1248     int8_t              mRxSensitivity;
1249     otError             mTxError;
1250     static otExtAddress sIeeeEui64;
1251     static otRadioCaps  sRadioCaps;
1252     uint32_t            mBusLatency;
1253 
1254     State mState;
1255     bool  mIsPromiscuous : 1; ///< Promiscuous mode.
1256     bool  mRxOnWhenIdle : 1;  ///< RxOnWhenIdle mode.
1257     bool  mIsTimeSynced : 1;  ///< Host has calculated the time difference between host and RCP.
1258 
1259     static bool sSupportsLogStream; ///< RCP supports `LOG_STREAM` property with OpenThread log meta-data format.
1260     static bool sSupportsResetToBootloader; ///< RCP supports resetting into bootloader mode.
1261     static bool sSupportsLogCrashDump;      ///< RCP supports logging a crash dump.
1262 
1263 #if OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0
1264 
1265     enum
1266     {
1267         kRcpFailureNone,
1268         kRcpFailureTimeout,
1269         kRcpFailureUnexpectedReset,
1270     };
1271 
1272     bool    mResetRadioOnStartup : 1; ///< Whether should send reset command when init.
1273     int16_t mRcpFailureCount;         ///< Count of consecutive RCP failures.
1274     uint8_t mRcpFailure : 2;          ///< RCP failure reason, should recover and retry operation.
1275 
1276     // Properties set by core.
1277     uint8_t  mKeyIdMode;
1278     uint8_t  mKeyId;
1279     otMacKey mPrevKey;
1280     otMacKey mCurrKey;
1281     otMacKey mNextKey;
1282     static_assert(OPENTHREAD_SPINEL_CONFIG_MAX_SRC_MATCH_ENTRIES >= OPENTHREAD_CONFIG_MLE_MAX_CHILDREN,
1283                   "SPINEL_CONFIG_MAX_SRC_MATCH_ENTRIES is not large enough to cover MLE_MAX_CHILDREN");
1284     uint16_t     mSrcMatchShortEntries[OPENTHREAD_SPINEL_CONFIG_MAX_SRC_MATCH_ENTRIES];
1285     int16_t      mSrcMatchShortEntryCount;
1286     otExtAddress mSrcMatchExtEntries[OPENTHREAD_SPINEL_CONFIG_MAX_SRC_MATCH_ENTRIES];
1287     int16_t      mSrcMatchExtEntryCount;
1288     uint8_t      mScanChannel;
1289     uint16_t     mScanDuration;
1290     int8_t       mCcaEnergyDetectThreshold;
1291     int8_t       mTransmitPower;
1292     int8_t       mFemLnaGain;
1293     bool         mCoexEnabled : 1;
1294     bool         mSrcMatchEnabled : 1;
1295     bool         mRcpRestorationEnabled : 1;
1296 
1297     bool mMacKeySet : 1;                   ///< Whether MAC key has been set.
1298     bool mCcaEnergyDetectThresholdSet : 1; ///< Whether CCA energy detect threshold has been set.
1299     bool mTransmitPowerSet : 1;            ///< Whether transmit power has been set.
1300     bool mCoexEnabledSet : 1;              ///< Whether coex enabled has been set.
1301     bool mFemLnaGainSet : 1;               ///< Whether FEM LNA gain has been set.
1302     bool mEnergyScanning : 1;              ///< If fails while scanning, restarts scanning.
1303     bool mMacFrameCounterSet : 1;          ///< Whether the MAC frame counter has been set.
1304     bool mSrcMatchSet : 1;                 ///< Whether the source match feature has been set.
1305 
1306 #endif // OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0
1307 
1308 #if OPENTHREAD_CONFIG_DIAG_ENABLE
1309     bool                     mDiagMode;
1310     otPlatDiagOutputCallback mOutputCallback;
1311     void                    *mOutputContext;
1312 #endif
1313 
1314     uint64_t mTxRadioEndUs;
1315     uint64_t mRadioTimeRecalcStart; ///< When to recalculate RCP time offset.
1316     uint64_t mRadioTimeOffset;      ///< Time difference with estimated RCP time minus host time.
1317 
1318     MaxPowerTable mMaxPowerTable;
1319 
1320     otRadioSpinelMetrics mRadioSpinelMetrics;
1321 
1322 #if OPENTHREAD_SPINEL_CONFIG_VENDOR_HOOK_ENABLE
1323     otRadioSpinelVendorRestorePropertiesCallback mVendorRestorePropertiesCallback;
1324     void                                        *mVendorRestorePropertiesContext;
1325 #endif
1326 
1327 #if OPENTHREAD_SPINEL_CONFIG_COMPATIBILITY_ERROR_CALLBACK_ENABLE
1328     otRadioSpinelCompatibilityErrorCallback mCompatibilityErrorCallback;
1329     void                                   *mCompatibilityErrorContext;
1330 #endif
1331 
1332     bool mTimeSyncEnabled : 1;
1333     bool mTimeSyncOn : 1;
1334 
1335     SpinelDriver *mSpinelDriver;
1336 };
1337 
1338 } // namespace Spinel
1339 } // namespace ot
1340 
1341 #endif // RADIO_SPINEL_HPP_
1342