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