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