• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2018, The OpenThread Authors.
3  *  All rights reserved.
4  *
5  *  Redistribution and use in source and binary forms, with or without
6  *  modification, are permitted provided that the following conditions are met:
7  *  1. Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  *  2. Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *  3. Neither the name of the copyright holder nor the
13  *     names of its contributors may be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  *  POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /**
30  * @file
31  *   This file includes definitions for the spinel based radio transceiver.
32  */
33 
34 #ifndef RADIO_SPINEL_HPP_
35 #define RADIO_SPINEL_HPP_
36 
37 #include <openthread/platform/radio.h>
38 
39 #include "openthread-spinel-config.h"
40 #include "radio_spinel_metrics.h"
41 #include "spinel.h"
42 #include "spinel_interface.hpp"
43 #include "core/radio/max_power_table.hpp"
44 #include "ncp/ncp_config.h"
45 
46 namespace ot {
47 namespace Spinel {
48 
49 /**
50  * The class for providing a OpenThread radio interface by talking with a radio-only
51  * co-processor(RCP). The InterfaceType template parameter should provide the following
52  * methods:
53  *
54  * class InterfaceType {
55  *
56  *    // This constructor initializes the object.
57  *
58  *    // @param[in] aCallback         Callback on frame received
59  *    // @param[in] aCallbackContext  Callback context
60  *    // @param[in] aFrameBuffer      A reference to a `RxFrameBuffer` object.
61  *
62  *    InterfaceType(Spinel::SpinelInterface::ReceiveFrameCallback aCallback,
63  *                  void *                                        aCallbackContext,
64  *                  Spinel::SpinelInterface::RxFrameBuffer &      aFrameBuffer);
65  *
66  *
67  *    // This method encodes and sends a spinel frame to Radio Co-processor (RCP) over the socket.
68  *
69  *    // This is blocking call, i.e., if the socket is not writable, this method waits for it to become writable for
70  *    // up to `kMaxWaitTime` interval.
71  *
72  *    // @param[in] aFrame     A pointer to buffer containing the spinel frame to send.
73  *    // @param[in] aLength    The length (number of bytes) in the frame.
74  *
75  *    // @retval OT_ERROR_NONE     Successfully encoded and sent the spinel frame.
76  *    // @retval OT_ERROR_NO_BUFS  Insufficient buffer space available to encode the frame.
77  *    // @retval OT_ERROR_FAILED   Failed to send due to socket not becoming writable within `kMaxWaitTime`.
78  *
79  *    otError SendFrame(const uint8_t *aFrame, uint16_t aLength);
80  *
81  *
82  *    // This method waits for receiving part or all of spinel frame within specified interval.
83  *
84  *    // @param[in]  aTimeout  The timeout value in microseconds.
85  *
86  *    // @retval OT_ERROR_NONE             Part or all of spinel frame is received.
87  *    // @retval OT_ERROR_RESPONSE_TIMEOUT No spinel frame is received within @p aTimeout.
88  *
89  *    otError WaitForFrame(uint64_t& aTimeoutUs);
90  *
91  *
92  *    // This method performs radio driver processing.
93  *
94  *    // @param[in]   aContext        The context containing fd_sets.
95  *    //                              The type is specified by the user in template parameters.
96  *
97  *    void Process(const ProcessContextType &aContext);
98  *
99  *
100  *    // This method deinitializes the interface to the RCP.
101  *
102  *    void Deinit(void);
103  * };
104  */
105 template <typename InterfaceType, typename ProcessContextType> class RadioSpinel
106 {
107 public:
108     /**
109      * This constructor initializes the spinel based OpenThread transceiver.
110      *
111      */
112     RadioSpinel(void);
113 
114     /**
115      * Initialize this radio transceiver.
116      *
117      * @param[in]  aResetRadio                 TRUE to reset on init, FALSE to not reset on init.
118      * @param[in]  aRestoreDatasetFromNcp      TRUE to restore dataset to host from non-volatile memory
119      *                                         (only used when attempts to upgrade from NCP to RCP mode),
120      *                                         FALSE otherwise.
121      * @param[in]  aSkipRcpCompatibilityCheck  TRUE to skip RCP compatibility check, FALSE to perform the check.
122      *
123      */
124     void Init(bool aResetRadio, bool aRestoreDataSetFromNcp, bool aSkipRcpCompatibilityCheck);
125 
126     /**
127      * Deinitialize this radio transceiver.
128      *
129      */
130     void Deinit(void);
131 
132     /**
133      * This method gets the status of promiscuous mode.
134      *
135      * @retval true   Promiscuous mode is enabled.
136      * @retval false  Promiscuous mode is disabled.
137      *
138      */
IsPromiscuous(void) const139     bool IsPromiscuous(void) const { return mIsPromiscuous; }
140 
141     /**
142      * This method sets the status of promiscuous mode.
143      *
144      * @param[in]   aEnable     Whether to enable or disable promiscuous mode.
145      *
146      * @retval  OT_ERROR_NONE               Succeeded.
147      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
148      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
149      *
150      */
151     otError SetPromiscuous(bool aEnable);
152 
153     /**
154      * This method sets the Short Address for address filtering.
155      *
156      * @param[in] aShortAddress  The IEEE 802.15.4 Short Address.
157      *
158      * @retval  OT_ERROR_NONE               Succeeded.
159      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
160      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
161      *
162      */
163     otError SetShortAddress(uint16_t aAddress);
164 
165     /**
166      * This method gets the factory-assigned IEEE EUI-64 for this transceiver.
167      *
168      * @param[in]  aInstance   The OpenThread instance structure.
169      * @param[out] aIeeeEui64  A pointer to the factory-assigned IEEE EUI-64.
170      *
171      * @retval  OT_ERROR_NONE               Succeeded.
172      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
173      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
174      *
175      */
176     otError GetIeeeEui64(uint8_t *aIeeeEui64);
177 
178     /**
179      * This method sets the Extended Address for address filtering.
180      *
181      * @param[in] aExtAddress  A pointer to the IEEE 802.15.4 Extended Address stored in little-endian byte order.
182      *
183      * @retval  OT_ERROR_NONE               Succeeded.
184      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
185      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
186      *
187      */
188     otError SetExtendedAddress(const otExtAddress &aAddress);
189 
190     /**
191      * This method sets the PAN ID for address filtering.
192      *
193      * @param[in]   aPanId  The IEEE 802.15.4 PAN ID.
194      *
195      * @retval  OT_ERROR_NONE               Succeeded.
196      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
197      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
198      *
199      */
200     otError SetPanId(uint16_t aPanId);
201 
202     /**
203      * This method gets the radio's transmit power in dBm.
204      *
205      * @param[out]  aPower    The transmit power in dBm.
206      *
207      * @retval  OT_ERROR_NONE               Succeeded.
208      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
209      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
210      *
211      */
212     otError GetTransmitPower(int8_t &aPower);
213 
214     /**
215      * This method sets the radio's transmit power in dBm.
216      *
217      * @param[in]   aPower     The transmit power in dBm.
218      *
219      * @retval  OT_ERROR_NONE               Succeeded.
220      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
221      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
222      *
223      */
224     otError SetTransmitPower(int8_t aPower);
225 
226     /**
227      * This method gets the radio's CCA ED threshold in dBm.
228      *
229      * @param[out]  aThreshold    The CCA ED threshold in dBm.
230      *
231      * @retval  OT_ERROR_NONE               Succeeded.
232      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
233      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
234      *
235      */
236     otError GetCcaEnergyDetectThreshold(int8_t &aThreshold);
237 
238     /**
239      * This method sets the radio's CCA ED threshold in dBm.
240      *
241      * @param[in]   aThreshold     The CCA ED threshold in dBm.
242      *
243      * @retval  OT_ERROR_NONE               Succeeded.
244      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
245      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
246      *
247      */
248     otError SetCcaEnergyDetectThreshold(int8_t aThreshold);
249 
250     /**
251      * This method gets the FEM's Rx LNA gain in dBm.
252      *
253      * @param[out]  aGain    The FEM's Rx LNA gain in dBm.
254      *
255      * @retval  OT_ERROR_NONE               Succeeded.
256      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
257      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
258      *
259      */
260     otError GetFemLnaGain(int8_t &aGain);
261 
262     /**
263      * This method sets the FEM's Rx LNA gain in dBm.
264      *
265      * @param[in]   aGain     The FEM's Rx LNA gain in dBm.
266      *
267      * @retval  OT_ERROR_NONE               Succeeded.
268      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
269      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
270      *
271      */
272     otError SetFemLnaGain(int8_t aGain);
273 
274     /**
275      * This method returns the radio sw version string.
276      *
277      * @returns A pointer to the radio version string.
278      *
279      */
GetVersion(void) const280     const char *GetVersion(void) const { return mVersion; }
281 
282     /**
283      * This method returns the radio capabilities.
284      *
285      * @returns The radio capability bit vector.
286      *
287      */
GetRadioCaps(void) const288     otRadioCaps GetRadioCaps(void) const { return mRadioCaps; }
289 
290     /**
291      * This method gets the most recent RSSI measurement.
292      *
293      * @returns The RSSI in dBm when it is valid.  127 when RSSI is invalid.
294      */
295     int8_t GetRssi(void);
296 
297     /**
298      * This method returns the radio receive sensitivity value.
299      *
300      * @returns The radio receive sensitivity value in dBm.
301      *
302      * @retval  OT_ERROR_NONE               Succeeded.
303      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
304      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
305      *
306      */
GetReceiveSensitivity(void) const307     int8_t GetReceiveSensitivity(void) const { return mRxSensitivity; }
308 
309     /**
310      * This method gets current state of the radio.
311      *
312      * @return  Current state of the radio.
313      *
314      */
315     otRadioState GetState(void) const;
316 
317     /**
318      * This method gets the current receiving channel.
319      *
320      * @returns Current receiving channel.
321      *
322      */
GetChannel(void) const323     uint8_t GetChannel(void) const { return mChannel; }
324 
325 #if OPENTHREAD_CONFIG_PLATFORM_RADIO_COEX_ENABLE
326     /**
327      * Enable the radio coex.
328      *
329      * @param[in] aInstance  The OpenThread instance structure.
330      * @param[in] aEnabled   TRUE to enable the radio coex, FALSE otherwise.
331      *
332      * @retval OT_ERROR_NONE     Successfully enabled.
333      * @retval OT_ERROR_FAILED   The radio coex could not be enabled.
334      *
335      */
336     otError SetCoexEnabled(bool aEnabled);
337 
338     /**
339      * Check whether radio coex is enabled or not.
340      *
341      * @param[in] aInstance  The OpenThread instance structure.
342      *
343      * @returns TRUE if the radio coex is enabled, FALSE otherwise.
344      *
345      */
346     bool IsCoexEnabled(void);
347 
348     /**
349      * This method retrieves the radio coexistence metrics.
350      *
351      * @param[out] aCoexMetrics  A reference to the coexistence metrics structure.
352      *
353      * @retval OT_ERROR_NONE          Successfully retrieved the coex metrics.
354      * @retval OT_ERROR_INVALID_ARGS  @p aCoexMetrics was nullptr.
355      *
356      */
357     otError GetCoexMetrics(otRadioCoexMetrics &aCoexMetrics);
358 #endif // OPENTHREAD_CONFIG_PLATFORM_RADIO_COEX_ENABLE
359 
360     /**
361      * This method returns a reference to the transmit buffer.
362      *
363      * The caller forms the IEEE 802.15.4 frame in this buffer then calls otPlatRadioTransmit() to request transmission.
364      *
365      * @returns A reference to the transmit buffer.
366      *
367      */
GetTransmitFrame(void)368     otRadioFrame &GetTransmitFrame(void) { return mTxRadioFrame; }
369 
370     /**
371      * This method enables or disables source address match feature.
372      *
373      * @param[in]  aEnable     Enable/disable source address match feature.
374      *
375      * @retval  OT_ERROR_NONE               Succeeded.
376      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
377      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
378      *
379      */
380     otError EnableSrcMatch(bool aEnable);
381 
382     /**
383      * This method adds a short address to the source address match table.
384      *
385      * @param[in]  aInstance      The OpenThread instance structure.
386      * @param[in]  aShortAddress  The short address to be added.
387      *
388      * @retval  OT_ERROR_NONE               Successfully added short address to the source match table.
389      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
390      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
391      * @retval  OT_ERROR_NO_BUFS            No available entry in the source match table.
392      */
393     otError AddSrcMatchShortEntry(uint16_t aShortAddress);
394 
395     /**
396      * This method removes a short address from the source address match table.
397      *
398      * @param[in]  aInstance      The OpenThread instance structure.
399      * @param[in]  aShortAddress  The short address to be removed.
400      *
401      * @retval  OT_ERROR_NONE               Successfully removed short address from the source match table.
402      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
403      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
404      * @retval  OT_ERROR_NO_ADDRESS         The short address is not in source address match table.
405      */
406     otError ClearSrcMatchShortEntry(uint16_t aShortAddress);
407 
408     /**
409      * Clear all short addresses from the source address match table.
410      *
411      * @param[in]  aInstance   The OpenThread instance structure.
412      *
413      * @retval  OT_ERROR_NONE               Succeeded.
414      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
415      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
416      *
417      */
418     otError ClearSrcMatchShortEntries(void);
419 
420     /**
421      * Add an extended address to the source address match table.
422      *
423      * @param[in]  aInstance    The OpenThread instance structure.
424      * @param[in]  aExtAddress  The extended address to be added stored in little-endian byte order.
425      *
426      * @retval  OT_ERROR_NONE               Successfully added extended address to the source match table.
427      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
428      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
429      * @retval  OT_ERROR_NO_BUFS            No available entry in the source match table.
430      */
431     otError AddSrcMatchExtEntry(const otExtAddress &aExtAddress);
432 
433     /**
434      * Remove an extended address from the source address match table.
435      *
436      * @param[in]  aInstance    The OpenThread instance structure.
437      * @param[in]  aExtAddress  The extended address to be removed stored in little-endian byte order.
438      *
439      * @retval  OT_ERROR_NONE               Successfully removed the extended address from the source match table.
440      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
441      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
442      * @retval  OT_ERROR_NO_ADDRESS         The extended address is not in source address match table.
443      */
444     otError ClearSrcMatchExtEntry(const otExtAddress &aExtAddress);
445 
446     /**
447      * Clear all the extended/long addresses from source address match table.
448      *
449      * @param[in]  aInstance   The OpenThread instance structure.
450      *
451      * @retval  OT_ERROR_NONE               Succeeded.
452      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
453      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
454      *
455      */
456     otError ClearSrcMatchExtEntries(void);
457 
458     /**
459      * This method begins the energy scan sequence on the radio.
460      *
461      * @param[in]  aScanChannel     The channel to perform the energy scan on.
462      * @param[in]  aScanDuration    The duration, in milliseconds, for the channel to be scanned.
463      *
464      * @retval  OT_ERROR_NONE               Succeeded.
465      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
466      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
467      *
468      */
469     otError EnergyScan(uint8_t aScanChannel, uint16_t aScanDuration);
470 
471     /**
472      * This method switches the radio state from Receive to Transmit.
473      *
474      * @param[in] aFrame     A reference to the transmitted frame.
475      *
476      * @retval  OT_ERROR_NONE               Successfully transitioned to Transmit.
477      * @retval  OT_ERROR_BUSY               Failed due to another transmission is on going.
478      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
479      * @retval  OT_ERROR_INVALID_STATE      The radio was not in the Receive state.
480      */
481     otError Transmit(otRadioFrame &aFrame);
482 
483     /**
484      * This method switches the radio state from Sleep to Receive.
485      *
486      * @param[in]  aChannel   The channel to use for receiving.
487      *
488      * @retval OT_ERROR_NONE          Successfully transitioned to Receive.
489      * @retval OT_ERROR_INVALID_STATE The radio was disabled or transmitting.
490      *
491      */
492     otError Receive(uint8_t aChannel);
493 
494     /**
495      * This method switches the radio state from Receive to Sleep.
496      *
497      * @retval OT_ERROR_NONE          Successfully transitioned to Sleep.
498      * @retval OT_ERROR_BUSY          The radio was transmitting
499      * @retval OT_ERROR_INVALID_STATE The radio was disabled
500      *
501      */
502     otError Sleep(void);
503 
504     /**
505      * Enable the radio.
506      *
507      * @param[in]   aInstance   A pointer to the OpenThread instance.
508      *
509      * @retval OT_ERROR_NONE     Successfully enabled.
510      * @retval OT_ERROR_FAILED   The radio could not be enabled.
511      *
512      */
513     otError Enable(otInstance *aInstance);
514 
515     /**
516      * Disable the radio.
517      *
518      * @retval  OT_ERROR_NONE               Successfully transitioned to Disabled.
519      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
520      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
521      *
522      */
523     otError Disable(void);
524 
525     /**
526      * This method checks whether radio is enabled or not.
527      *
528      * @returns TRUE if the radio is enabled, FALSE otherwise.
529      *
530      */
IsEnabled(void) const531     bool IsEnabled(void) const { return mState != kStateDisabled; }
532 
533     /**
534      * This method indicates whether there is a pending transmission.
535      *
536      * @retval TRUE  There is a pending transmission.
537      * @retval FALSE There is no pending transmission.
538      *
539      */
IsTransmitting(void) const540     bool IsTransmitting(void) const { return mState == kStateTransmitting; }
541 
542     /**
543      * This method indicates whether a transmit has just finished.
544      *
545      * @retval TRUE  The transmission is done.
546      * @retval FALSE The transmission is not done.
547      *
548      */
IsTransmitDone(void) const549     bool IsTransmitDone(void) const { return mState == kStateTransmitDone; }
550 
551     /**
552      * This method returns the timeout timepoint for the pending transmission.
553      *
554      * @returns The timeout timepoint for the pending transmission.
555      *
556      */
GetTxRadioEndUs(void) const557     uint64_t GetTxRadioEndUs(void) const { return mTxRadioEndUs; }
558 
559     /**
560      * This method processes any pending the I/O data.
561      *
562      * @param[in]  aContext   The process context.
563      *
564      */
565     void Process(const ProcessContextType &aContext);
566 
567     /**
568      * This method returns the underlying spinel interface.
569      *
570      * @returns The underlying spinel interface.
571      *
572      */
GetSpinelInterface(void)573     InterfaceType &GetSpinelInterface(void) { return mSpinelInterface; }
574 
575 #if OPENTHREAD_CONFIG_DIAG_ENABLE
576     /**
577      * This method enables/disables the factory diagnostics mode.
578      *
579      * @param[in]  aMode  TRUE to enable diagnostics mode, FALSE otherwise.
580      *
581      */
SetDiagEnabled(bool aMode)582     void SetDiagEnabled(bool aMode) { mDiagMode = aMode; }
583 
584     /**
585      * This method indicates whether or not factory diagnostics mode is enabled.
586      *
587      * @returns TRUE if factory diagnostics mode is enabled, FALSE otherwise.
588      *
589      */
IsDiagEnabled(void) const590     bool IsDiagEnabled(void) const { return mDiagMode; }
591 
592     /**
593      * This method processes platform diagnostics commands.
594      *
595      * @param[in]   aString         A null-terminated input string.
596      * @param[out]  aOutput         The diagnostics execution result.
597      * @param[in]   aOutputMaxLen   The output buffer size.
598      *
599      * @retval  OT_ERROR_NONE               Succeeded.
600      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
601      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
602      *
603      */
604     otError PlatDiagProcess(const char *aString, char *aOutput, size_t aOutputMaxLen);
605 #endif
606 
607     /**
608      * This method returns the radio channel mask.
609      *
610      * @param[in]   aPreferred  TRUE to get preferred channel mask, FALSE to get supported channel mask.
611      *
612      * @returns The radio channel mask according to @aPreferred:
613      *   The radio supported channel mask that the device is allowed to be on.
614      *   The radio preferred channel mask that the device prefers to form on.
615      *
616      */
617     uint32_t GetRadioChannelMask(bool aPreferred);
618 
619     /**
620      * This method processes a received Spinel frame.
621      *
622      * The newly received frame is available in `RxFrameBuffer` from `SpinelInterface::GetRxFrameBuffer()`.
623      *
624      */
625     void HandleReceivedFrame(void);
626 
627     /**
628      * This method sets MAC key and key index to RCP.
629      *
630      * @param[in] aKeyIdMode  The key ID mode.
631      * @param[in] aKeyId      The key index.
632      * @param[in] aPrevKey    Pointer to previous MAC key.
633      * @param[in] aCurrKey    Pointer to current MAC key.
634      * @param[in] aNextKey    Pointer to next MAC key.
635      *
636      * @retval  OT_ERROR_NONE               Succeeded.
637      * @retval  OT_ERROR_INVALID_ARGS       One of the keys passed is invalid..
638      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
639      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
640      *
641      */
642     otError SetMacKey(uint8_t                 aKeyIdMode,
643                       uint8_t                 aKeyId,
644                       const otMacKeyMaterial *aPrevKey,
645                       const otMacKeyMaterial *aCurrKey,
646                       const otMacKeyMaterial *aNextKey);
647 
648     /**
649      * This method sets the current MAC Frame Counter value.
650      *
651      * @param[in]   aMacFrameCounter  The MAC Frame Counter value.
652      *
653      */
654     otError SetMacFrameCounter(uint32_t aMacFrameCounter);
655 
656     /**
657      * This method sets the radio region code.
658      *
659      * @param[in]   aRegionCode  The radio region code.
660      *
661      * @retval  OT_ERROR_NONE             Successfully set region code.
662      * @retval  OT_ERROR_FAILED           Other platform specific errors.
663      *
664      */
665     otError SetRadioRegion(uint16_t aRegionCode);
666 
667     /**
668      * This method gets the radio region code.
669      *
670      * @param[out]   aRegionCode  The radio region code.
671      *
672      * @retval  OT_ERROR_INVALID_ARGS     @p aRegionCode is nullptr.
673      * @retval  OT_ERROR_NONE             Successfully got region code.
674      * @retval  OT_ERROR_FAILED           Other platform specific errors.
675      *
676      */
677     otError GetRadioRegion(uint16_t *aRegionCode);
678 
679 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
680     /**
681      * Enable/disable or update Enhanced-ACK Based Probing in radio for a specific Initiator.
682      *
683      * After Enhanced-ACK Based Probing is configured by a specific Probing Initiator, the Enhanced-ACK sent to that
684      * node should include Vendor-Specific IE containing Link Metrics data. This method informs the radio to start/stop
685      * to collect Link Metrics data and include Vendor-Specific IE that containing the data in Enhanced-ACK sent to that
686      * Probing Initiator.
687      *
688      * @param[in]  aLinkMetrics   This parameter specifies what metrics to query. Per spec 4.11.3.4.4.6, at most 2
689      *                            metrics can be specified. The probing would be disabled if @p aLinkMetrics is
690      *                            bitwise 0.
691      * @param[in]  aShortAddress  The short address of the Probing Initiator.
692      * @param[in]  aExtAddress    The extended source address of the Probing Initiator. @p aExtAddress MUST NOT be
693      *                            nullptr.
694      *
695      * @retval  OT_ERROR_NONE            Successfully configured the Enhanced-ACK Based Probing.
696      * @retval  OT_ERROR_INVALID_ARGS    @p aExtAddress is nullptr.
697      * @retval  OT_ERROR_NOT_FOUND       The Initiator indicated by @p aShortAddress is not found when trying to clear.
698      * @retval  OT_ERROR_NO_BUFS         No more Initiator can be supported.
699      */
700     otError ConfigureEnhAckProbing(otLinkMetrics        aLinkMetrics,
701                                    const otShortAddress aShortAddress,
702                                    const otExtAddress & aExtAddress);
703 #endif
704 
705 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE || OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
706     /**
707      * Get the current accuracy, in units of ± ppm, of the clock used for scheduling CSL operations.
708      *
709      * @note Platforms may optimize this value based on operational conditions (i.e.: temperature).
710      *
711      * @retval   The current CSL rx/tx scheduling drift, in units of ± ppm.
712      *
713      */
714     uint8_t GetCslAccuracy(void);
715 #endif
716 
717 #if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
718     /**
719      * Get the current uncertainty, in units of 10 us, of the clock used for scheduling CSL operations.
720      *
721      * @retval  The current CSL Clock Uncertainty in units of 10 us.
722      *
723      */
724     uint8_t GetCslUncertainty(void);
725 #endif
726 
727     /**
728      * This method checks whether the spinel interface is radio-only.
729      *
730      * @param[out] aSupportsRcpApiVersion   A reference to a boolean variable to update whether the list of spinel
731      *                                      capabilities include `SPINEL_CAP_RCP_API_VERSION`.
732      *
733      * @retval  TRUE    The radio chip is in radio-only mode.
734      * @retval  FALSE   Otherwise.
735      *
736      */
737     bool IsRcp(bool &aSupportsRcpApiVersion);
738 
739     /**
740      * This method checks whether there is pending frame in the buffer.
741      *
742      * @returns Whether there is pending frame in the buffer.
743      *
744      */
HasPendingFrame(void) const745     bool HasPendingFrame(void) const { return mRxFrameBuffer.HasSavedFrame(); }
746 
747     /**
748      * This method gets dataset from NCP radio and saves it.
749      *
750      * @retval  OT_ERROR_NONE               Successfully restore dataset.
751      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
752      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the radio.
753      * @retval  OT_ERROR_NOT_FOUND          Failed due to spinel property not supported in radio.
754      * @retval  OT_ERROR_FAILED             Failed due to other reasons.
755      */
756     otError RestoreDatasetFromNcp(void);
757 
758     /**
759      * This method returns the next timepoint to recalculate RCP time offset.
760      *
761      * @returns The timepoint to start the recalculation of RCP time offset.
762      *
763      */
GetNextRadioTimeRecalcStart(void) const764     uint64_t GetNextRadioTimeRecalcStart(void) const { return mRadioTimeRecalcStart; }
765 
766     /**
767      * This method gets the current estimated time on RCP.
768      *
769      * @returns The current estimated RCP time in microseconds.
770      *
771      */
772     uint64_t GetNow(void);
773 
774     /**
775      * This method returns the bus speed between the host and the radio.
776      *
777      * @returns   bus speed in bits/second.
778      *
779      */
780     uint32_t GetBusSpeed(void) const;
781 
782     /**
783      * This method sets the max transmit power.
784      *
785      * @param[in] aChannel    The radio channel.
786      * @param[in] aPower      The max transmit power in dBm.
787      *
788      * @retval  OT_ERROR_NONE           Successfully set the max transmit power.
789      * @retval  OT_ERROR_INVALID_ARGS   Channel is not in valid range.
790      *
791      */
792     otError SetChannelMaxTransmitPower(uint8_t aChannel, int8_t aPower);
793 
794     /**
795      * This method tries to retrieve a spinel property from OpenThread transceiver.
796      *
797      * @param[in]   aKey        Spinel property key.
798      * @param[in]   aFormat     Spinel formatter to unpack property value.
799      * @param[out]  ...         Variable arguments list.
800      *
801      * @retval  OT_ERROR_NONE               Successfully got the property.
802      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
803      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
804      *
805      */
806     otError Get(spinel_prop_key_t aKey, const char *aFormat, ...);
807 
808     /**
809      * This method tries to retrieve a spinel property from OpenThread transceiver with parameter appended.
810      *
811      * @param[in]   aKey        Spinel property key.
812      * @param[in]   aParam      Parameter appended to spinel command.
813      * @param[in]   aParamSize  Size of parameter appended to spinel command
814      * @param[in]   aFormat     Spinel formatter to unpack property value.
815      * @param[out]  ...         Variable arguments list.
816      *
817      * @retval  OT_ERROR_NONE               Successfully got the property.
818      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
819      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
820      *
821      */
822     otError GetWithParam(spinel_prop_key_t aKey,
823                          const uint8_t *   aParam,
824                          spinel_size_t     aParamSize,
825                          const char *      aFormat,
826                          ...);
827 
828     /**
829      * This method tries to update a spinel property of OpenThread transceiver.
830      *
831      * @param[in]   aKey        Spinel property key.
832      * @param[in]   aFormat     Spinel formatter to pack property value.
833      * @param[in]   ...         Variable arguments list.
834      *
835      * @retval  OT_ERROR_NONE               Successfully set the property.
836      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
837      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
838      *
839      */
840     otError Set(spinel_prop_key_t aKey, const char *aFormat, ...);
841 
842     /**
843      * This method tries to insert a item into a spinel list property of OpenThread transceiver.
844      *
845      * @param[in]   aKey        Spinel property key.
846      * @param[in]   aFormat     Spinel formatter to pack the item.
847      * @param[in]   ...         Variable arguments list.
848      *
849      * @retval  OT_ERROR_NONE               Successfully insert item into the property.
850      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
851      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
852      *
853      */
854     otError Insert(spinel_prop_key_t aKey, const char *aFormat, ...);
855 
856     /**
857      * This method tries to remove a item from a spinel list property of OpenThread transceiver.
858      *
859      * @param[in]   aKey        Spinel property key.
860      * @param[in]   aFormat     Spinel formatter to pack the item.
861      * @param[in]   ...         Variable arguments list.
862      *
863      * @retval  OT_ERROR_NONE               Successfully removed item from the property.
864      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
865      * @retval  OT_ERROR_RESPONSE_TIMEOUT   Failed due to no response received from the transceiver.
866      *
867      */
868     otError Remove(spinel_prop_key_t aKey, const char *aFormat, ...);
869 
870     /**
871      * This method tries to reset the co-processor.
872      *
873      * @prarm[in] aResetType    The reset type, SPINEL_RESET_PLATFORM or SPINEL_RESET_STACK.
874      *
875      * @retval  OT_ERROR_NONE               Successfully removed item from the property.
876      * @retval  OT_ERROR_BUSY               Failed due to another operation is on going.
877      *
878      */
879     otError SendReset(uint8_t aResetType);
880 
881     /**
882      * This method returns the radio Spinel metrics.
883      *
884      * @returns The radio Spinel metrics.
885      *
886      */
GetRadioSpinelMetrics(void) const887     const otRadioSpinelMetrics *GetRadioSpinelMetrics(void) const { return &mRadioSpinelMetrics; }
888 
889 private:
890     enum
891     {
892         kMaxSpinelFrame        = SPINEL_FRAME_MAX_SIZE,
893         kMaxWaitTime           = 2000, ///< Max time to wait for response in milliseconds.
894         kVersionStringSize     = 128,  ///< Max size of version string.
895         kCapsBufferSize        = 100,  ///< Max buffer size used to store `SPINEL_PROP_CAPS` value.
896         kChannelMaskBufferSize = 32,   ///< Max buffer size used to store `SPINEL_PROP_PHY_CHAN_SUPPORTED` value.
897     };
898 
899     enum State
900     {
901         kStateDisabled,     ///< Radio is disabled.
902         kStateSleep,        ///< Radio is sleep.
903         kStateReceive,      ///< Radio is in receive mode.
904         kStateTransmitting, ///< Frame passed to radio for transmission, waiting for done event from radio.
905         kStateTransmitDone, ///< Radio indicated frame transmission is done.
906     };
907 
908     typedef otError (RadioSpinel::*ResponseHandler)(const uint8_t *aBuffer, uint16_t aLength);
909 
910     static void HandleReceivedFrame(void *aContext);
911 
912     otError CheckSpinelVersion(void);
913     otError CheckRadioCapabilities(void);
914     otError CheckRcpApiVersion(bool aSupportsRcpApiVersion);
915 
916     /**
917      * This method triggers a state transfer of the state machine.
918      *
919      */
920     void ProcessRadioStateMachine(void);
921 
922     /**
923      * This method processes the frame queue.
924      *
925      */
926     void ProcessFrameQueue(void);
927 
928     spinel_tid_t GetNextTid(void);
FreeTid(spinel_tid_t tid)929     void         FreeTid(spinel_tid_t tid) { mCmdTidsInUse &= ~(1 << tid); }
930 
931     otError RequestV(uint32_t aCommand, spinel_prop_key_t aKey, const char *aFormat, va_list aArgs);
932     otError Request(uint32_t aCommand, spinel_prop_key_t aKey, const char *aFormat, ...);
933     otError RequestWithPropertyFormat(const char *      aPropertyFormat,
934                                       uint32_t          aCommand,
935                                       spinel_prop_key_t aKey,
936                                       const char *      aFormat,
937                                       ...);
938     otError RequestWithPropertyFormatV(const char *      aPropertyFormat,
939                                        uint32_t          aCommand,
940                                        spinel_prop_key_t aKey,
941                                        const char *      aFormat,
942                                        va_list           aArgs);
943     otError RequestWithExpectedCommandV(uint32_t          aExpectedCommand,
944                                         uint32_t          aCommand,
945                                         spinel_prop_key_t aKey,
946                                         const char *      aFormat,
947                                         va_list           aArgs);
948     otError WaitResponse(void);
949     otError SendCommand(uint32_t          aCommand,
950                         spinel_prop_key_t aKey,
951                         spinel_tid_t      aTid,
952                         const char *      aFormat,
953                         va_list           aArgs);
954     otError ParseRadioFrame(otRadioFrame &aFrame, const uint8_t *aBuffer, uint16_t aLength, spinel_ssize_t &aUnpacked);
955     otError ThreadDatasetHandler(const uint8_t *aBuffer, uint16_t aLength);
956 
957     /**
958      * This method returns if the property changed event is safe to be handled now.
959      *
960      * If a property handler will go up to core stack, it may cause reentrant issue of `Hdlc::Decode()` and
961      * `WaitResponse()`.
962      *
963      * @param[in] aKey The identifier of the property.
964      *
965      * @returns Whether this property is safe to be handled now.
966      *
967      */
IsSafeToHandleNow(spinel_prop_key_t aKey) const968     bool IsSafeToHandleNow(spinel_prop_key_t aKey) const
969     {
970         return !(aKey == SPINEL_PROP_STREAM_RAW || aKey == SPINEL_PROP_MAC_ENERGY_SCAN_RESULT);
971     }
972 
973     void HandleNotification(SpinelInterface::RxFrameBuffer &aFrameBuffer);
974     void HandleNotification(const uint8_t *aBuffer, uint16_t aLength);
975     void HandleValueIs(spinel_prop_key_t aKey, const uint8_t *aBuffer, uint16_t aLength);
976 
977     void HandleResponse(const uint8_t *aBuffer, uint16_t aLength);
978     void HandleTransmitDone(uint32_t aCommand, spinel_prop_key_t aKey, const uint8_t *aBuffer, uint16_t aLength);
979     void HandleWaitingResponse(uint32_t aCommand, spinel_prop_key_t aKey, const uint8_t *aBuffer, uint16_t aLength);
980 
981     void RadioReceive(void);
982 
983     void TransmitDone(otRadioFrame *aFrame, otRadioFrame *aAckFrame, otError aError);
984 
985     void CalcRcpTimeOffset(void);
986 
987     void HandleRcpUnexpectedReset(spinel_status_t aStatus);
988     void HandleRcpTimeout(void);
989     void RecoverFromRcpFailure(void);
990 
991 #if OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0
992     void RestoreProperties(void);
993 #endif
UpdateParseErrorCount(otError aError)994     void UpdateParseErrorCount(otError aError)
995     {
996         mRadioSpinelMetrics.mSpinelParseErrorCount += (aError == OT_ERROR_PARSE) ? 1 : 0;
997     }
998 
999     otInstance *mInstance;
1000 
1001     SpinelInterface::RxFrameBuffer mRxFrameBuffer;
1002 
1003     InterfaceType mSpinelInterface;
1004 
1005     uint16_t          mCmdTidsInUse;    ///< Used transaction ids.
1006     spinel_tid_t      mCmdNextTid;      ///< Next available transaction id.
1007     spinel_tid_t      mTxRadioTid;      ///< The transaction id used to send a radio frame.
1008     spinel_tid_t      mWaitingTid;      ///< The transaction id of current transaction.
1009     spinel_prop_key_t mWaitingKey;      ///< The property key of current transaction.
1010     const char *      mPropertyFormat;  ///< The spinel property format of current transaction.
1011     va_list           mPropertyArgs;    ///< The arguments pack or unpack spinel property of current transaction.
1012     uint32_t          mExpectedCommand; ///< Expected response command of current transaction.
1013     otError           mError;           ///< The result of current transaction.
1014 
1015     uint8_t       mRxPsdu[OT_RADIO_FRAME_MAX_SIZE];
1016     uint8_t       mTxPsdu[OT_RADIO_FRAME_MAX_SIZE];
1017     uint8_t       mAckPsdu[OT_RADIO_FRAME_MAX_SIZE];
1018     otRadioFrame  mRxRadioFrame;
1019     otRadioFrame  mTxRadioFrame;
1020     otRadioFrame  mAckRadioFrame;
1021     otRadioFrame *mTransmitFrame; ///< Points to the frame to send
1022 
1023     otExtAddress mExtendedAddress;
1024     uint16_t     mShortAddress;
1025     uint16_t     mPanId;
1026     otRadioCaps  mRadioCaps;
1027     uint8_t      mChannel;
1028     int8_t       mRxSensitivity;
1029     otError      mTxError;
1030     char         mVersion[kVersionStringSize];
1031     otExtAddress mIeeeEui64;
1032 
1033     State mState;
1034     bool  mIsPromiscuous : 1;     ///< Promiscuous mode.
1035     bool  mIsReady : 1;           ///< NCP ready.
1036     bool  mSupportsLogStream : 1; ///< RCP supports `LOG_STREAM` property with OpenThread log meta-data format.
1037     bool  mIsTimeSynced : 1;      ///< Host has calculated the time difference between host and RCP.
1038 
1039 #if OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0
1040 
1041     bool    mResetRadioOnStartup : 1; ///< Whether should send reset command when init.
1042     int16_t mRcpFailureCount;         ///< Count of consecutive RCP failures.
1043 
1044     // Properties set by core.
1045     uint8_t      mKeyIdMode;
1046     uint8_t      mKeyId;
1047     otMacKey     mPrevKey;
1048     otMacKey     mCurrKey;
1049     otMacKey     mNextKey;
1050     uint16_t     mSrcMatchShortEntries[OPENTHREAD_CONFIG_MLE_MAX_CHILDREN];
1051     int16_t      mSrcMatchShortEntryCount;
1052     otExtAddress mSrcMatchExtEntries[OPENTHREAD_CONFIG_MLE_MAX_CHILDREN];
1053     int16_t      mSrcMatchExtEntryCount;
1054     uint8_t      mScanChannel;
1055     uint16_t     mScanDuration;
1056     int8_t       mCcaEnergyDetectThreshold;
1057     int8_t       mTransmitPower;
1058     int8_t       mFemLnaGain;
1059     bool         mCoexEnabled : 1;
1060 
1061     bool mMacKeySet : 1;                   ///< Whether MAC key has been set.
1062     bool mCcaEnergyDetectThresholdSet : 1; ///< Whether CCA energy detect threshold has been set.
1063     bool mTransmitPowerSet : 1;            ///< Whether transmit power has been set.
1064     bool mCoexEnabledSet : 1;              ///< Whether coex enabled has been set.
1065     bool mFemLnaGainSet : 1;               ///< Whether FEM LNA gain has been set.
1066     bool mRcpFailed : 1;                   ///< RCP failure happened, should recover and retry operation.
1067     bool mEnergyScanning : 1;              ///< If fails while scanning, restarts scanning.
1068 
1069 #endif // OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0
1070 
1071 #if OPENTHREAD_CONFIG_DIAG_ENABLE
1072     bool   mDiagMode;
1073     char * mDiagOutput;
1074     size_t mDiagOutputMaxLen;
1075 #endif
1076 
1077     uint64_t mTxRadioEndUs;
1078     uint64_t mRadioTimeRecalcStart; ///< When to recalculate RCP time offset.
1079     int64_t  mRadioTimeOffset;      ///< Time difference with estimated RCP time minus host time.
1080 
1081     MaxPowerTable mMaxPowerTable;
1082 
1083     otRadioSpinelMetrics mRadioSpinelMetrics;
1084 };
1085 
1086 } // namespace Spinel
1087 } // namespace ot
1088 
1089 #include "radio_spinel_impl.hpp"
1090 
1091 #endif // RADIO_SPINEL_HPP_
1092