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