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