1 /*
2  *  Copyright (c) 2019, 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 OpenThread radio abstraction.
32  */
33 
34 #ifndef RADIO_HPP_
35 #define RADIO_HPP_
36 
37 #include "openthread-core-config.h"
38 
39 #include <openthread/radio_stats.h>
40 #include <openthread/platform/radio.h>
41 
42 #include <openthread/platform/crypto.h>
43 #include "common/locator.hpp"
44 #include "common/non_copyable.hpp"
45 #include "common/time.hpp"
46 #include "mac/mac_frame.hpp"
47 
48 namespace ot {
49 
50 static constexpr uint32_t kUsPerTenSymbols = OT_US_PER_TEN_SYMBOLS; ///< Time for 10 symbols in units of microseconds
51 static constexpr uint32_t kRadioHeaderShrDuration = 160;            ///< Duration of SHR in us
52 static constexpr uint32_t kRadioHeaderPhrDuration = 32;             ///< Duration of PHR in us
53 
54 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
55 /**
56  * Minimum CSL period supported in units of 10 symbols.
57  *
58  */
59 static constexpr uint64_t kMinCslPeriod  = OPENTHREAD_CONFIG_MAC_CSL_MIN_PERIOD * 1000 / kUsPerTenSymbols;
60 static constexpr uint64_t kMaxCslTimeout = OPENTHREAD_CONFIG_MAC_CSL_MAX_TIMEOUT;
61 #endif
62 
63 /**
64  * @addtogroup core-radio
65  *
66  * @brief
67  *   This module includes definitions for OpenThread radio abstraction.
68  *
69  * @{
70  *
71  */
72 
73 /**
74  * Implements the radio statistics logic.
75  *
76  * The radio statistics are the time when the radio in TX/RX/radio state.
77  * Since this class collects these statistics from pure software level and no platform API is involved, a simplied
78  * model is used to calculate the time of different radio states. The data may not be very accurate, but it's
79  * sufficient to provide a general understanding of the proportion of time a device is in different radio states.
80  *
81  * The simplified model is:
82  * - The RadioStats is only aware of 2 states: RX and sleep.
83  * - Each time `Radio::Receive` or `Radio::Sleep` is called, it will check the current state and add the time since
84  *   last time the methods were called. For example, `Sleep` is first called and `Receive` is called after 1 second,
85  *   then 1 second will be added to SleepTime and the current state switches to `Receive`.
86  * - The time of TX will be calculated from the callback of TransmitDone. If TX returns OT_ERROR_NONE or
87  *   OT_ERROR_NO_ACK, the tx time will be added according to the number of bytes sent. And the SleepTime or RxTime
88  *   will be reduced accordingly.
89  * - When `GetStats` is called, an operation will be executed to calcute the time for the last state. And the result
90  *   will be returned.
91  *
92  */
93 #if OPENTHREAD_CONFIG_RADIO_STATS_ENABLE && (OPENTHREAD_FTD || OPENTHREAD_MTD)
94 
95 #if !OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE
96 #error "OPENTHREAD_CONFIG_RADIO_STATS_ENABLE requires OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE".
97 #endif
98 
99 class RadioStatistics
100 {
101 public:
102     enum Status : uint8_t
103     {
104         kDisabled,
105         kSleep,
106         kReceive,
107     };
108 
109     explicit RadioStatistics(void);
110 
111     void                    RecordStateChange(Status aStatus);
112     void                    HandleReceiveAt(uint32_t aDurationUs);
113     void                    RecordTxDone(otError aError, uint16_t aPsduLength);
114     void                    RecordRxDone(otError aError);
115     const otRadioTimeStats &GetStats(void);
116     void                    ResetTime(void);
117 
118 private:
119     void UpdateTime(void);
120 
121     Status           mStatus;
122     otRadioTimeStats mTimeStats;
123     TimeMicro        mLastUpdateTime;
124 };
125 #endif // OPENTHREAD_CONFIG_RADIO_STATS_ENABLE && (OPENTHREAD_FTD || OPENTHREAD_MTD)
126 
127 /**
128  * Represents an OpenThread radio abstraction.
129  *
130  */
131 class Radio : public InstanceLocator, private NonCopyable
132 {
133     friend class Instance;
134 
135 public:
136     static constexpr uint32_t kSymbolTime      = OT_RADIO_SYMBOL_TIME;
137     static constexpr uint8_t  kSymbolsPerOctet = OT_RADIO_SYMBOLS_PER_OCTET;
138     static constexpr uint32_t kPhyUsPerByte    = kSymbolsPerOctet * kSymbolTime;
139 #if (OPENTHREAD_CONFIG_RADIO_2P4GHZ_OQPSK_SUPPORT && OPENTHREAD_CONFIG_RADIO_915MHZ_OQPSK_SUPPORT)
140     static constexpr uint16_t kNumChannelPages = 2;
141     static constexpr uint32_t kSupportedChannels =
142         OT_RADIO_915MHZ_OQPSK_CHANNEL_MASK | OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MASK;
143     static constexpr uint8_t  kChannelMin            = OT_RADIO_915MHZ_OQPSK_CHANNEL_MIN;
144     static constexpr uint8_t  kChannelMax            = OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MAX;
145     static constexpr uint32_t kSupportedChannelPages = OT_RADIO_CHANNEL_PAGE_0_MASK | OT_RADIO_CHANNEL_PAGE_2_MASK;
146 #elif OPENTHREAD_CONFIG_RADIO_915MHZ_OQPSK_SUPPORT
147     static constexpr uint16_t kNumChannelPages       = 1;
148     static constexpr uint32_t kSupportedChannels     = OT_RADIO_915MHZ_OQPSK_CHANNEL_MASK;
149     static constexpr uint8_t  kChannelMin            = OT_RADIO_915MHZ_OQPSK_CHANNEL_MIN;
150     static constexpr uint8_t  kChannelMax            = OT_RADIO_915MHZ_OQPSK_CHANNEL_MAX;
151     static constexpr uint32_t kSupportedChannelPages = OT_RADIO_CHANNEL_PAGE_2_MASK;
152 #elif OPENTHREAD_CONFIG_RADIO_2P4GHZ_OQPSK_SUPPORT
153     static constexpr uint16_t kNumChannelPages       = 1;
154     static constexpr uint32_t kSupportedChannels     = OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MASK;
155     static constexpr uint8_t  kChannelMin            = OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MIN;
156     static constexpr uint8_t  kChannelMax            = OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MAX;
157     static constexpr uint32_t kSupportedChannelPages = OT_RADIO_CHANNEL_PAGE_0_MASK;
158 #elif OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_SUPPORT
159     static constexpr uint16_t kNumChannelPages       = 1;
160     static constexpr uint32_t kSupportedChannels     = OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_CHANNEL_MASK;
161     static constexpr uint8_t  kChannelMin            = OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_CHANNEL_MIN;
162     static constexpr uint8_t  kChannelMax            = OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_CHANNEL_MAX;
163     static constexpr uint32_t kSupportedChannelPages = (1 << OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_CHANNEL_PAGE);
164 #endif
165 
166     static constexpr int8_t kInvalidRssi = OT_RADIO_RSSI_INVALID; ///< Invalid RSSI value.
167 
168     static constexpr int8_t kDefaultReceiveSensitivity = -110; ///< Default receive sensitivity (in dBm).
169 
170     static_assert((OPENTHREAD_CONFIG_RADIO_2P4GHZ_OQPSK_SUPPORT || OPENTHREAD_CONFIG_RADIO_915MHZ_OQPSK_SUPPORT ||
171                    OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_SUPPORT),
172                   "OPENTHREAD_CONFIG_RADIO_2P4GHZ_OQPSK_SUPPORT "
173                   "or OPENTHREAD_CONFIG_RADIO_915MHZ_OQPSK_SUPPORT "
174                   "or OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_SUPPORT "
175                   "must be set to 1 to specify the radio mode");
176 
177     /**
178      * Defines the callbacks from `Radio`.
179      *
180      */
181     class Callbacks : public InstanceLocator
182     {
183         friend class Radio;
184 
185     public:
186         /**
187          * This callback method handles a "Receive Done" event from radio platform.
188          *
189          * @param[in]  aFrame    A pointer to the received frame or `nullptr` if the receive operation failed.
190          * @param[in]  aError    kErrorNone when successfully received a frame,
191          *                       kErrorAbort when reception was aborted and a frame was not received,
192          *                       kErrorNoBufs when a frame could not be received due to lack of rx buffer space.
193          *
194          */
195         void HandleReceiveDone(Mac::RxFrame *aFrame, Error aError);
196 
197         /**
198          * This callback method handles a "Transmit Started" event from radio platform.
199          *
200          * @param[in]  aFrame     The frame that is being transmitted.
201          *
202          */
203         void HandleTransmitStarted(Mac::TxFrame &aFrame);
204 
205         /**
206          * This callback method handles a "Transmit Done" event from radio platform.
207          *
208          * @param[in]  aFrame     The frame that was transmitted.
209          * @param[in]  aAckFrame  A pointer to the ACK frame, `nullptr` if no ACK was received.
210          * @param[in]  aError     kErrorNone when the frame was transmitted,
211          *                        kErrorNoAck when the frame was transmitted but no ACK was received,
212          *                        kErrorChannelAccessFailure tx could not take place due to activity on the
213          *                        channel, kErrorAbort when transmission was aborted for other reasons.
214          *
215          */
216         void HandleTransmitDone(Mac::TxFrame &aFrame, Mac::RxFrame *aAckFrame, Error aError);
217 
218         /**
219          * This callback method handles "Energy Scan Done" event from radio platform.
220          *
221          * Is used when radio provides OT_RADIO_CAPS_ENERGY_SCAN capability. It is called from
222          * `otPlatRadioEnergyScanDone()`.
223          *
224          * @param[in]  aMaxRssi  The maximum RSSI encountered on the scanned channel.
225          *
226          */
227         void HandleEnergyScanDone(int8_t aMaxRssi);
228 
229 #if OPENTHREAD_CONFIG_DIAG_ENABLE
230         /**
231          * This callback method handles a "Receive Done" event from radio platform when diagnostics mode is enabled.
232          *
233          * @param[in]  aFrame    A pointer to the received frame or `nullptr` if the receive operation failed.
234          * @param[in]  aError    kErrorNone when successfully received a frame,
235          *                       kErrorAbort when reception was aborted and a frame was not received,
236          *                       kErrorNoBufs when a frame could not be received due to lack of rx buffer space.
237          *
238          */
239         void HandleDiagsReceiveDone(Mac::RxFrame *aFrame, Error aError);
240 
241         /**
242          * This callback method handles a "Transmit Done" event from radio platform when diagnostics mode is enabled.
243          *
244          * @param[in]  aFrame     The frame that was transmitted.
245          * @param[in]  aError     kErrorNone when the frame was transmitted,
246          *                        kErrorNoAck when the frame was transmitted but no ACK was received,
247          *                        kErrorChannelAccessFailure tx could not take place due to activity on the
248          *                        channel, kErrorAbort when transmission was aborted for other reasons.
249          *
250          */
251         void HandleDiagsTransmitDone(Mac::TxFrame &aFrame, Error aError);
252 #endif
253 
254     private:
Callbacks(Instance & aInstance)255         explicit Callbacks(Instance &aInstance)
256             : InstanceLocator(aInstance)
257         {
258         }
259     };
260 
261     /**
262      * Initializes the `Radio` object.
263      *
264      * @param[in]  aInstance  A reference to the OpenThread instance.
265      *
266      */
Radio(Instance & aInstance)267     explicit Radio(Instance &aInstance)
268         : InstanceLocator(aInstance)
269         , mCallbacks(aInstance)
270     {
271     }
272 
273     /**
274      * Gets the radio version string.
275      *
276      * @returns A pointer to the OpenThread radio version.
277      *
278      */
279     const char *GetVersionString(void);
280 
281     /**
282      * Gets the factory-assigned IEEE EUI-64 for the device.
283      *
284      * @param[out] aIeeeEui64  A reference to `Mac::ExtAddress` to place the factory-assigned IEEE EUI-64.
285      *
286      */
287     void GetIeeeEui64(Mac::ExtAddress &aIeeeEui64);
288 
289     /**
290      * Gets the radio capabilities.
291      *
292      * @returns The radio capability bit vector (see `OT_RADIO_CAP_*` definitions).
293      *
294      */
295     otRadioCaps GetCaps(void);
296 
297     /**
298      * Gets the radio receive sensitivity value.
299      *
300      * @returns The radio receive sensitivity value in dBm.
301      *
302      */
303     int8_t GetReceiveSensitivity(void) const;
304 
305 #if OPENTHREAD_RADIO
306     /**
307      * Initializes the states of the Thread radio.
308      *
309      */
310     void Init(void);
311 #endif
312 
313     /**
314      * Sets the PAN ID for address filtering.
315      *
316      * @param[in] aPanId     The IEEE 802.15.4 PAN ID.
317      *
318      */
319     void SetPanId(Mac::PanId aPanId);
320 
321     /**
322      * Sets the Extended Address for address filtering.
323      *
324      * @param[in] aExtAddress  The IEEE 802.15.4 Extended Address stored in little-endian byte order.
325      *
326      */
327     void SetExtendedAddress(const Mac::ExtAddress &aExtAddress);
328 
329     /**
330      * Sets the Short Address for address filtering.
331      *
332      * @param[in] aShortAddress  The IEEE 802.15.4 Short Address.
333      *
334      */
335     void SetShortAddress(Mac::ShortAddress aShortAddress);
336 
337     /**
338      * Sets MAC key and key ID.
339      *
340      * @param[in] aKeyIdMode  MAC key ID mode.
341      * @param[in] aKeyId      Current MAC key index.
342      * @param[in] aPrevKey    The previous MAC key.
343      * @param[in] aCurrKey    The current MAC key.
344      * @param[in] aNextKey    The next MAC key.
345      *
346      */
347     void SetMacKey(uint8_t                 aKeyIdMode,
348                    uint8_t                 aKeyId,
349                    const Mac::KeyMaterial &aPrevKey,
350                    const Mac::KeyMaterial &aCurrKey,
351                    const Mac::KeyMaterial &aNextKey);
352 
353     /**
354      * Sets the current MAC Frame Counter value.
355      *
356      * @param[in] aMacFrameCounter  The MAC Frame Counter value.
357      *
358      */
SetMacFrameCounter(uint32_t aMacFrameCounter)359     void SetMacFrameCounter(uint32_t aMacFrameCounter)
360     {
361         otPlatRadioSetMacFrameCounter(GetInstancePtr(), aMacFrameCounter);
362     }
363 
364     /**
365      * Sets the current MAC Frame Counter value only if the new given value is larger than the current
366      * value.
367      *
368      * @param[in] aMacFrameCounter  The MAC Frame Counter value.
369      *
370      */
SetMacFrameCounterIfLarger(uint32_t aMacFrameCounter)371     void SetMacFrameCounterIfLarger(uint32_t aMacFrameCounter)
372     {
373         otPlatRadioSetMacFrameCounterIfLarger(GetInstancePtr(), aMacFrameCounter);
374     }
375 
376     /**
377      * Gets the radio's transmit power in dBm.
378      *
379      * @param[out] aPower    A reference to output the transmit power in dBm.
380      *
381      * @retval kErrorNone             Successfully retrieved the transmit power.
382      * @retval kErrorNotImplemented   Transmit power configuration via dBm is not implemented.
383      *
384      */
385     Error GetTransmitPower(int8_t &aPower);
386 
387     /**
388      * Sets the radio's transmit power in dBm.
389      *
390      * @param[in] aPower     The transmit power in dBm.
391      *
392      * @retval kErrorNone             Successfully set the transmit power.
393      * @retval kErrorNotImplemented   Transmit power configuration via dBm is not implemented.
394      *
395      */
396     Error SetTransmitPower(int8_t aPower);
397 
398     /**
399      * Gets the radio's CCA ED threshold in dBm.
400      *
401      * @param[in] aThreshold    The CCA ED threshold in dBm.
402      *
403      * @retval kErrorNone             A reference to output the CCA ED threshold in dBm.
404      * @retval kErrorNotImplemented   CCA ED threshold configuration via dBm is not implemented.
405      *
406      */
407     Error GetCcaEnergyDetectThreshold(int8_t &aThreshold);
408 
409     /**
410      * Sets the radio's CCA ED threshold in dBm.
411      *
412      * @param[in] aThreshold    The CCA ED threshold in dBm.
413      *
414      * @retval kErrorNone             Successfully set the CCA ED threshold.
415      * @retval kErrorNotImplemented   CCA ED threshold configuration via dBm is not implemented.
416      *
417      */
418     Error SetCcaEnergyDetectThreshold(int8_t aThreshold);
419 
420     /**
421      * Gets the status of promiscuous mode.
422      *
423      * @retval TRUE   Promiscuous mode is enabled.
424      * @retval FALSE  Promiscuous mode is disabled.
425      *
426      */
427     bool GetPromiscuous(void);
428 
429     /**
430      * Enables or disables promiscuous mode.
431      *
432      * @param[in]  aEnable   TRUE to enable or FALSE to disable promiscuous mode.
433      *
434      */
435     void SetPromiscuous(bool aEnable);
436 
437     /**
438      * Returns the current state of the radio.
439      *
440      * Is not required by OpenThread. It may be used for debugging and/or application-specific purposes.
441      *
442      * @note This function may be not implemented. In this case it always returns OT_RADIO_STATE_INVALID state.
443      *
444      * @return  Current state of the radio.
445      *
446      */
447     otRadioState GetState(void);
448 
449     /**
450      * Enables the radio.
451      *
452      * @retval kErrorNone     Successfully enabled.
453      * @retval kErrorFailed   The radio could not be enabled.
454      *
455      */
456     Error Enable(void);
457 
458     /**
459      * Disables the radio.
460      *
461      * @retval kErrorNone           Successfully transitioned to Disabled.
462      * @retval kErrorInvalidState   The radio was not in sleep state.
463      *
464      */
465     Error Disable(void);
466 
467     /**
468      * Indicates whether radio is enabled or not.
469      *
470      * @returns TRUE if the radio is enabled, FALSE otherwise.
471      *
472      */
473     bool IsEnabled(void);
474 
475     /**
476      * Transitions the radio from Receive to Sleep (turn off the radio).
477      *
478      * @retval kErrorNone          Successfully transitioned to Sleep.
479      * @retval kErrorBusy          The radio was transmitting.
480      * @retval kErrorInvalidState  The radio was disabled.
481      *
482      */
483     Error Sleep(void);
484 
485     /**
486      * Transitions the radio from Sleep to Receive (turn on the radio).
487      *
488      * @param[in]  aChannel   The channel to use for receiving.
489      *
490      * @retval kErrorNone          Successfully transitioned to Receive.
491      * @retval kErrorInvalidState  The radio was disabled or transmitting.
492      *
493      */
494     Error Receive(uint8_t aChannel);
495 
496 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
497     /**
498      * Updates the CSL sample time in radio.
499      *
500      * @param[in]  aCslSampleTime  The CSL sample time.
501      *
502      */
503     void UpdateCslSampleTime(uint32_t aCslSampleTime);
504 
505     /**
506      * Schedules a radio reception window at a specific time and duration.
507      *
508      * @param[in]  aChannel   The radio channel on which to receive.
509      * @param[in]  aStart     The receive window start time, in microseconds.
510      * @param[in]  aDuration  The receive window duration, in microseconds.
511      *
512      * @retval kErrorNone    Successfully scheduled receive window.
513      * @retval kErrorFailed  The receive window could not be scheduled.
514      *
515      */
516     Error ReceiveAt(uint8_t aChannel, uint32_t aStart, uint32_t aDuration);
517 
518     /** Enables CSL sampling in radio.
519      *
520      * @param[in]  aCslPeriod    CSL period, 0 for disabling CSL.
521      * @param[in]  aShortAddr    The short source address of CSL receiver's peer.
522      * @param[in]  aExtAddr      The extended source address of CSL receiver's peer.
523      *
524      * @note Platforms should use CSL peer addresses to include CSL IE when generating enhanced acks.
525      *
526      * @retval  kErrorNotImplemented Radio driver doesn't support CSL.
527      * @retval  kErrorFailed         Other platform specific errors.
528      * @retval  kErrorNone           Successfully enabled or disabled CSL.
529      *
530      */
531     Error EnableCsl(uint32_t aCslPeriod, otShortAddress aShortAddr, const otExtAddress *aExtAddr);
532 #endif // OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
533 
534 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE || OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
535     /**
536      * Get the current accuracy, in units of ± ppm, of the clock used for scheduling CSL operations.
537      *
538      * @note Platforms may optimize this value based on operational conditions (i.e.: temperature).
539      *
540      * @returns The current CSL rx/tx scheduling drift, in units of ± ppm.
541      *
542      */
543     uint8_t GetCslAccuracy(void);
544 
545     /**
546      * Get the fixed uncertainty of the Device for scheduling CSL operations in units of 10 microseconds.
547      *
548      * @returns The CSL Uncertainty in units of 10 us.
549      *
550      */
551     uint8_t GetCslUncertainty(void);
552 #endif // OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE || OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
553 
554     /**
555      * Gets the radio transmit frame buffer.
556      *
557      * OpenThread forms the IEEE 802.15.4 frame in this buffer then calls `Transmit()` to request transmission.
558      *
559      * @returns A reference to the transmit frame buffer.
560      *
561      */
562     Mac::TxFrame &GetTransmitBuffer(void);
563 
564     /**
565      * Starts the transmit sequence on the radio.
566      *
567      * The caller must form the IEEE 802.15.4 frame in the buffer provided by `GetTransmitBuffer()` before
568      * requesting transmission.  The channel and transmit power are also included in the frame.
569      *
570      * @param[in] aFrame     A reference to the frame to be transmitted.
571      *
572      * @retval kErrorNone          Successfully transitioned to Transmit.
573      * @retval kErrorInvalidState  The radio was not in the Receive state.
574      *
575      */
576     Error Transmit(Mac::TxFrame &aFrame);
577 
578     /**
579      * Gets the most recent RSSI measurement.
580      *
581      * @returns The RSSI in dBm when it is valid.  127 when RSSI is invalid.
582      *
583      */
584     int8_t GetRssi(void);
585 
586     /**
587      * Begins the energy scan sequence on the radio.
588      *
589      * Is used when radio provides OT_RADIO_CAPS_ENERGY_SCAN capability.
590      *
591      * @param[in] aScanChannel   The channel to perform the energy scan on.
592      * @param[in] aScanDuration  The duration, in milliseconds, for the channel to be scanned.
593      *
594      * @retval kErrorNone            Successfully started scanning the channel.
595      * @retval kErrorBusy            The radio is performing energy scanning.
596      * @retval kErrorNotImplemented  The radio doesn't support energy scanning.
597      *
598      */
599     Error EnergyScan(uint8_t aScanChannel, uint16_t aScanDuration);
600 
601     /**
602      * Enables/disables source address match feature.
603      *
604      * The source address match feature controls how the radio layer decides the "frame pending" bit for acks sent in
605      * response to data request commands from children.
606      *
607      * If disabled, the radio layer must set the "frame pending" on all acks to data request commands.
608      *
609      * If enabled, the radio layer uses the source address match table to determine whether to set or clear the "frame
610      * pending" bit in an ack to a data request command.
611      *
612      * The source address match table provides the list of children for which there is a pending frame. Either a short
613      * address or an extended/long address can be added to the source address match table.
614      *
615      * @param[in]  aEnable     Enable/disable source address match feature.
616      *
617      */
618     void EnableSrcMatch(bool aEnable);
619 
620     /**
621      * Adds a short address to the source address match table.
622      *
623      * @param[in]  aShortAddress  The short address to be added.
624      *
625      * @retval kErrorNone     Successfully added short address to the source match table.
626      * @retval kErrorNoBufs   No available entry in the source match table.
627      *
628      */
629     Error AddSrcMatchShortEntry(Mac::ShortAddress aShortAddress);
630 
631     /**
632      * Adds an extended address to the source address match table.
633      *
634      * @param[in]  aExtAddress  The extended address to be added stored in little-endian byte order.
635      *
636      * @retval kErrorNone     Successfully added extended address to the source match table.
637      * @retval kErrorNoBufs   No available entry in the source match table.
638      *
639      */
640     Error AddSrcMatchExtEntry(const Mac::ExtAddress &aExtAddress);
641 
642     /**
643      * Removes a short address from the source address match table.
644      *
645      * @param[in]  aShortAddress  The short address to be removed.
646      *
647      * @retval kErrorNone       Successfully removed short address from the source match table.
648      * @retval kErrorNoAddress  The short address is not in source address match table.
649      *
650      */
651     Error ClearSrcMatchShortEntry(Mac::ShortAddress aShortAddress);
652 
653     /**
654      * Removes an extended address from the source address match table.
655      *
656      * @param[in]  aExtAddress  The extended address to be removed stored in little-endian byte order.
657      *
658      * @retval kErrorNone       Successfully removed the extended address from the source match table.
659      * @retval kErrorNoAddress  The extended address is not in source address match table.
660      *
661      */
662     Error ClearSrcMatchExtEntry(const Mac::ExtAddress &aExtAddress);
663 
664     /**
665      * Clears all short addresses from the source address match table.
666      *
667      */
668     void ClearSrcMatchShortEntries(void);
669 
670     /**
671      * Clears all the extended/long addresses from source address match table.
672      *
673      */
674     void ClearSrcMatchExtEntries(void);
675 
676     /**
677      * Gets the radio supported channel mask that the device is allowed to be on.
678      *
679      * @returns The radio supported channel mask.
680      *
681      */
682     uint32_t GetSupportedChannelMask(void);
683 
684     /**
685      * Gets the radio preferred channel mask that the device prefers to form on.
686      *
687      * @returns The radio preferred channel mask.
688      *
689      */
690     uint32_t GetPreferredChannelMask(void);
691 
692 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
693     /**
694      * Enables/disables or updates Enhanced-ACK Based Probing in radio for a specific Initiator.
695      *
696      * After Enhanced-ACK Based Probing is configured by a specific Probing Initiator, the Enhanced-ACK sent to that
697      * node should include Vendor-Specific IE containing Link Metrics data. This method informs the radio to
698      * starts/stops to collect Link Metrics data and include Vendor-Specific IE that containing the data
699      * in Enhanced-ACK sent to that Probing Initiator.
700      *
701      * @param[in]  aLinkMetrics  This parameter specifies what metrics to query. Per spec 4.11.3.4.4.6, at most 2
702      *                           metrics can be specified. The probing would be disabled if @p `aLinkMetrics` is
703      *                           bitwise 0.
704      * @param[in]  aShortAddress The short address of the the probing Initiator.
705      * @param[in]  aExtAddress   The extended source address of the probing Initiator.
706      *
707      * @retval kErrorNone            Successfully enable/disable or update Enhanced-ACK Based Probing for a specific
708      *                               Initiator.
709      * @retval kErrorInvalidArgs     @p aDataLength or @p aExtAddr is not valid.
710      * @retval kErrorNotFound        The Initiator indicated by @p aShortAddress is not found when trying to clear.
711      * @retval kErrorNoBufs          No more Initiator can be supported.
712      * @retval kErrorNotImplemented  Radio driver doesn't support Enhanced-ACK Probing.
713      *
714      */
ConfigureEnhAckProbing(otLinkMetrics aLinkMetrics,const Mac::ShortAddress & aShortAddress,const Mac::ExtAddress & aExtAddress)715     Error ConfigureEnhAckProbing(otLinkMetrics            aLinkMetrics,
716                                  const Mac::ShortAddress &aShortAddress,
717                                  const Mac::ExtAddress   &aExtAddress)
718     {
719         return otPlatRadioConfigureEnhAckProbing(GetInstancePtr(), aLinkMetrics, aShortAddress, &aExtAddress);
720     }
721 #endif // OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
722 
723     /**
724      * Checks if a given channel is valid as a CSL channel.
725      *
726      * @retval true   The channel is valid.
727      * @retval false  The channel is invalid.
728      *
729      */
IsCslChannelValid(uint8_t aCslChannel)730     static bool IsCslChannelValid(uint8_t aCslChannel)
731     {
732         return ((aCslChannel == 0) ||
733                 ((kChannelMin == aCslChannel) || ((kChannelMin < aCslChannel) && (aCslChannel <= kChannelMax))));
734     }
735 
736 private:
GetInstancePtr(void) const737     otInstance *GetInstancePtr(void) const { return reinterpret_cast<otInstance *>(&InstanceLocator::GetInstance()); }
738 
739     Callbacks mCallbacks;
740 #if OPENTHREAD_CONFIG_RADIO_STATS_ENABLE && (OPENTHREAD_FTD || OPENTHREAD_MTD)
741     RadioStatistics mRadioStatistics;
742 #endif
743 };
744 
745 //---------------------------------------------------------------------------------------------------------------------
746 // Radio APIs that are always mapped to the same `otPlatRadio` function (independent of the link type)
747 
GetVersionString(void)748 inline const char *Radio::GetVersionString(void) { return otPlatRadioGetVersionString(GetInstancePtr()); }
749 
GetIeeeEui64(Mac::ExtAddress & aIeeeEui64)750 inline void Radio::GetIeeeEui64(Mac::ExtAddress &aIeeeEui64)
751 {
752     otPlatRadioGetIeeeEui64(GetInstancePtr(), aIeeeEui64.m8);
753 }
754 
GetSupportedChannelMask(void)755 inline uint32_t Radio::GetSupportedChannelMask(void) { return otPlatRadioGetSupportedChannelMask(GetInstancePtr()); }
756 
GetPreferredChannelMask(void)757 inline uint32_t Radio::GetPreferredChannelMask(void) { return otPlatRadioGetPreferredChannelMask(GetInstancePtr()); }
758 
759 //---------------------------------------------------------------------------------------------------------------------
760 // If IEEE 802.15.4 is among supported radio links, provide inline
761 // mapping of `Radio` method to related `otPlatRadio` functions.
762 
763 #if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
764 
GetCaps(void)765 inline otRadioCaps Radio::GetCaps(void) { return otPlatRadioGetCaps(GetInstancePtr()); }
766 
GetReceiveSensitivity(void) const767 inline int8_t Radio::GetReceiveSensitivity(void) const { return otPlatRadioGetReceiveSensitivity(GetInstancePtr()); }
768 
SetPanId(Mac::PanId aPanId)769 inline void Radio::SetPanId(Mac::PanId aPanId) { otPlatRadioSetPanId(GetInstancePtr(), aPanId); }
770 
SetMacKey(uint8_t aKeyIdMode,uint8_t aKeyId,const Mac::KeyMaterial & aPrevKey,const Mac::KeyMaterial & aCurrKey,const Mac::KeyMaterial & aNextKey)771 inline void Radio::SetMacKey(uint8_t                 aKeyIdMode,
772                              uint8_t                 aKeyId,
773                              const Mac::KeyMaterial &aPrevKey,
774                              const Mac::KeyMaterial &aCurrKey,
775                              const Mac::KeyMaterial &aNextKey)
776 {
777     otRadioKeyType aKeyType;
778 
779 #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE
780     aKeyType = OT_KEY_TYPE_KEY_REF;
781 #else
782     aKeyType = OT_KEY_TYPE_LITERAL_KEY;
783 #endif
784 
785     otPlatRadioSetMacKey(GetInstancePtr(), aKeyIdMode, aKeyId, &aPrevKey, &aCurrKey, &aNextKey, aKeyType);
786 }
787 
GetTransmitPower(int8_t & aPower)788 inline Error Radio::GetTransmitPower(int8_t &aPower) { return otPlatRadioGetTransmitPower(GetInstancePtr(), &aPower); }
789 
SetTransmitPower(int8_t aPower)790 inline Error Radio::SetTransmitPower(int8_t aPower) { return otPlatRadioSetTransmitPower(GetInstancePtr(), aPower); }
791 
GetCcaEnergyDetectThreshold(int8_t & aThreshold)792 inline Error Radio::GetCcaEnergyDetectThreshold(int8_t &aThreshold)
793 {
794     return otPlatRadioGetCcaEnergyDetectThreshold(GetInstancePtr(), &aThreshold);
795 }
796 
SetCcaEnergyDetectThreshold(int8_t aThreshold)797 inline Error Radio::SetCcaEnergyDetectThreshold(int8_t aThreshold)
798 {
799     return otPlatRadioSetCcaEnergyDetectThreshold(GetInstancePtr(), aThreshold);
800 }
801 
GetPromiscuous(void)802 inline bool Radio::GetPromiscuous(void) { return otPlatRadioGetPromiscuous(GetInstancePtr()); }
803 
SetPromiscuous(bool aEnable)804 inline void Radio::SetPromiscuous(bool aEnable) { otPlatRadioSetPromiscuous(GetInstancePtr(), aEnable); }
805 
GetState(void)806 inline otRadioState Radio::GetState(void) { return otPlatRadioGetState(GetInstancePtr()); }
807 
Enable(void)808 inline Error Radio::Enable(void)
809 {
810 #if OPENTHREAD_CONFIG_RADIO_STATS_ENABLE && (OPENTHREAD_FTD || OPENTHREAD_MTD)
811     mRadioStatistics.RecordStateChange(RadioStatistics::kSleep);
812 #endif
813     return otPlatRadioEnable(GetInstancePtr());
814 }
815 
Disable(void)816 inline Error Radio::Disable(void)
817 {
818 #if OPENTHREAD_CONFIG_RADIO_STATS_ENABLE && (OPENTHREAD_FTD || OPENTHREAD_MTD)
819     mRadioStatistics.RecordStateChange(RadioStatistics::kDisabled);
820 #endif
821     return otPlatRadioDisable(GetInstancePtr());
822 }
823 
IsEnabled(void)824 inline bool Radio::IsEnabled(void) { return otPlatRadioIsEnabled(GetInstancePtr()); }
825 
Sleep(void)826 inline Error Radio::Sleep(void)
827 {
828 #if OPENTHREAD_CONFIG_RADIO_STATS_ENABLE && (OPENTHREAD_FTD || OPENTHREAD_MTD)
829     mRadioStatistics.RecordStateChange(RadioStatistics::kSleep);
830 #endif
831     return otPlatRadioSleep(GetInstancePtr());
832 }
833 
Receive(uint8_t aChannel)834 inline Error Radio::Receive(uint8_t aChannel)
835 {
836 #if OPENTHREAD_CONFIG_RADIO_STATS_ENABLE && (OPENTHREAD_FTD || OPENTHREAD_MTD)
837     mRadioStatistics.RecordStateChange(RadioStatistics::kReceive);
838 #endif
839     return otPlatRadioReceive(GetInstancePtr(), aChannel);
840 }
841 
842 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
UpdateCslSampleTime(uint32_t aCslSampleTime)843 inline void Radio::UpdateCslSampleTime(uint32_t aCslSampleTime)
844 {
845     otPlatRadioUpdateCslSampleTime(GetInstancePtr(), aCslSampleTime);
846 }
847 
ReceiveAt(uint8_t aChannel,uint32_t aStart,uint32_t aDuration)848 inline Error Radio::ReceiveAt(uint8_t aChannel, uint32_t aStart, uint32_t aDuration)
849 {
850     Error error = otPlatRadioReceiveAt(GetInstancePtr(), aChannel, aStart, aDuration);
851 #if OPENTHREAD_CONFIG_RADIO_STATS_ENABLE && (OPENTHREAD_FTD || OPENTHREAD_MTD)
852     if (error == kErrorNone)
853     {
854         mRadioStatistics.HandleReceiveAt(aDuration);
855     }
856 #endif
857     return error;
858 }
859 
EnableCsl(uint32_t aCslPeriod,otShortAddress aShortAddr,const otExtAddress * aExtAddr)860 inline Error Radio::EnableCsl(uint32_t aCslPeriod, otShortAddress aShortAddr, const otExtAddress *aExtAddr)
861 {
862     return otPlatRadioEnableCsl(GetInstancePtr(), aCslPeriod, aShortAddr, aExtAddr);
863 }
864 #endif
865 
866 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE || OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
GetCslAccuracy(void)867 inline uint8_t Radio::GetCslAccuracy(void) { return otPlatRadioGetCslAccuracy(GetInstancePtr()); }
868 #endif
869 
870 #if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
GetCslUncertainty(void)871 inline uint8_t Radio::GetCslUncertainty(void) { return otPlatRadioGetCslUncertainty(GetInstancePtr()); }
872 #endif
873 
GetTransmitBuffer(void)874 inline Mac::TxFrame &Radio::GetTransmitBuffer(void)
875 {
876     return *static_cast<Mac::TxFrame *>(otPlatRadioGetTransmitBuffer(GetInstancePtr()));
877 }
878 
GetRssi(void)879 inline int8_t Radio::GetRssi(void) { return otPlatRadioGetRssi(GetInstancePtr()); }
880 
EnergyScan(uint8_t aScanChannel,uint16_t aScanDuration)881 inline Error Radio::EnergyScan(uint8_t aScanChannel, uint16_t aScanDuration)
882 {
883     return otPlatRadioEnergyScan(GetInstancePtr(), aScanChannel, aScanDuration);
884 }
885 
EnableSrcMatch(bool aEnable)886 inline void Radio::EnableSrcMatch(bool aEnable) { otPlatRadioEnableSrcMatch(GetInstancePtr(), aEnable); }
887 
AddSrcMatchShortEntry(Mac::ShortAddress aShortAddress)888 inline Error Radio::AddSrcMatchShortEntry(Mac::ShortAddress aShortAddress)
889 {
890     return otPlatRadioAddSrcMatchShortEntry(GetInstancePtr(), aShortAddress);
891 }
892 
AddSrcMatchExtEntry(const Mac::ExtAddress & aExtAddress)893 inline Error Radio::AddSrcMatchExtEntry(const Mac::ExtAddress &aExtAddress)
894 {
895     return otPlatRadioAddSrcMatchExtEntry(GetInstancePtr(), &aExtAddress);
896 }
897 
ClearSrcMatchShortEntry(Mac::ShortAddress aShortAddress)898 inline Error Radio::ClearSrcMatchShortEntry(Mac::ShortAddress aShortAddress)
899 {
900     return otPlatRadioClearSrcMatchShortEntry(GetInstancePtr(), aShortAddress);
901 }
902 
ClearSrcMatchExtEntry(const Mac::ExtAddress & aExtAddress)903 inline Error Radio::ClearSrcMatchExtEntry(const Mac::ExtAddress &aExtAddress)
904 {
905     return otPlatRadioClearSrcMatchExtEntry(GetInstancePtr(), &aExtAddress);
906 }
907 
ClearSrcMatchShortEntries(void)908 inline void Radio::ClearSrcMatchShortEntries(void) { otPlatRadioClearSrcMatchShortEntries(GetInstancePtr()); }
909 
ClearSrcMatchExtEntries(void)910 inline void Radio::ClearSrcMatchExtEntries(void) { otPlatRadioClearSrcMatchExtEntries(GetInstancePtr()); }
911 
912 #else //----------------------------------------------------------------------------------------------------------------
913 
GetCaps(void)914 inline otRadioCaps Radio::GetCaps(void)
915 {
916     return OT_RADIO_CAPS_ACK_TIMEOUT | OT_RADIO_CAPS_CSMA_BACKOFF | OT_RADIO_CAPS_TRANSMIT_RETRIES;
917 }
918 
GetReceiveSensitivity(void) const919 inline int8_t Radio::GetReceiveSensitivity(void) const { return kDefaultReceiveSensitivity; }
920 
SetPanId(Mac::PanId)921 inline void Radio::SetPanId(Mac::PanId) {}
922 
SetExtendedAddress(const Mac::ExtAddress &)923 inline void Radio::SetExtendedAddress(const Mac::ExtAddress &) {}
924 
SetShortAddress(Mac::ShortAddress)925 inline void Radio::SetShortAddress(Mac::ShortAddress) {}
926 
SetMacKey(uint8_t,uint8_t,const Mac::KeyMaterial &,const Mac::KeyMaterial &,const Mac::KeyMaterial &)927 inline void Radio::SetMacKey(uint8_t,
928                              uint8_t,
929                              const Mac::KeyMaterial &,
930                              const Mac::KeyMaterial &,
931                              const Mac::KeyMaterial &)
932 {
933 }
934 
GetTransmitPower(int8_t &)935 inline Error Radio::GetTransmitPower(int8_t &) { return kErrorNotImplemented; }
936 
SetTransmitPower(int8_t)937 inline Error Radio::SetTransmitPower(int8_t) { return kErrorNotImplemented; }
938 
GetCcaEnergyDetectThreshold(int8_t &)939 inline Error Radio::GetCcaEnergyDetectThreshold(int8_t &) { return kErrorNotImplemented; }
940 
SetCcaEnergyDetectThreshold(int8_t)941 inline Error Radio::SetCcaEnergyDetectThreshold(int8_t) { return kErrorNotImplemented; }
942 
GetPromiscuous(void)943 inline bool Radio::GetPromiscuous(void) { return false; }
944 
SetPromiscuous(bool)945 inline void Radio::SetPromiscuous(bool) {}
946 
GetState(void)947 inline otRadioState Radio::GetState(void) { return OT_RADIO_STATE_DISABLED; }
948 
Enable(void)949 inline Error Radio::Enable(void) { return kErrorNone; }
950 
Disable(void)951 inline Error Radio::Disable(void) { return kErrorInvalidState; }
952 
IsEnabled(void)953 inline bool Radio::IsEnabled(void) { return true; }
954 
Sleep(void)955 inline Error Radio::Sleep(void) { return kErrorNone; }
956 
Receive(uint8_t)957 inline Error Radio::Receive(uint8_t) { return kErrorNone; }
958 
959 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
UpdateCslSampleTime(uint32_t)960 inline void Radio::UpdateCslSampleTime(uint32_t) {}
961 
ReceiveAt(uint8_t,uint32_t,uint32_t)962 inline Error Radio::ReceiveAt(uint8_t, uint32_t, uint32_t) { return kErrorNone; }
963 
EnableCsl(uint32_t,otShortAddress aShortAddr,const otExtAddress *)964 inline Error Radio::EnableCsl(uint32_t, otShortAddress aShortAddr, const otExtAddress *)
965 {
966     return kErrorNotImplemented;
967 }
968 #endif
969 
970 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE || OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
GetCslAccuracy(void)971 inline uint8_t Radio::GetCslAccuracy(void) { return UINT8_MAX; }
972 
GetCslUncertainty(void)973 inline uint8_t Radio::GetCslUncertainty(void) { return UINT8_MAX; }
974 #endif
975 
GetTransmitBuffer(void)976 inline Mac::TxFrame &Radio::GetTransmitBuffer(void)
977 {
978     return *static_cast<Mac::TxFrame *>(otPlatRadioGetTransmitBuffer(GetInstancePtr()));
979 }
980 
Transmit(Mac::TxFrame &)981 inline Error Radio::Transmit(Mac::TxFrame &) { return kErrorAbort; }
982 
GetRssi(void)983 inline int8_t Radio::GetRssi(void) { return kInvalidRssi; }
984 
EnergyScan(uint8_t,uint16_t)985 inline Error Radio::EnergyScan(uint8_t, uint16_t) { return kErrorNotImplemented; }
986 
EnableSrcMatch(bool)987 inline void Radio::EnableSrcMatch(bool) {}
988 
AddSrcMatchShortEntry(Mac::ShortAddress)989 inline Error Radio::AddSrcMatchShortEntry(Mac::ShortAddress) { return kErrorNone; }
990 
AddSrcMatchExtEntry(const Mac::ExtAddress &)991 inline Error Radio::AddSrcMatchExtEntry(const Mac::ExtAddress &) { return kErrorNone; }
992 
ClearSrcMatchShortEntry(Mac::ShortAddress)993 inline Error Radio::ClearSrcMatchShortEntry(Mac::ShortAddress) { return kErrorNone; }
994 
ClearSrcMatchExtEntry(const Mac::ExtAddress &)995 inline Error Radio::ClearSrcMatchExtEntry(const Mac::ExtAddress &) { return kErrorNone; }
996 
ClearSrcMatchShortEntries(void)997 inline void Radio::ClearSrcMatchShortEntries(void) {}
998 
ClearSrcMatchExtEntries(void)999 inline void Radio::ClearSrcMatchExtEntries(void) {}
1000 
1001 #endif // #if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
1002 
1003 } // namespace ot
1004 
1005 #endif // RADIO_HPP_
1006