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