• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2016-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 IEEE 802.15.4 MAC layer (sub-MAC).
32  */
33 
34 #ifndef SUB_MAC_HPP_
35 #define SUB_MAC_HPP_
36 
37 #include "openthread-core-config.h"
38 
39 #include <openthread/link.h>
40 
41 #include <openthread/platform/crypto.h>
42 
43 #include "common/callback.hpp"
44 #include "common/locator.hpp"
45 #include "common/non_copyable.hpp"
46 #include "common/timer.hpp"
47 #include "mac/mac_frame.hpp"
48 #include "radio/radio.hpp"
49 
50 namespace ot {
51 
52 /**
53  * @addtogroup core-mac
54  *
55  * @brief
56  *   This module includes definitions for the IEEE 802.15.4 MAC (sub-MAC).
57  *
58  * @{
59  */
60 
61 namespace Mac {
62 
63 #if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE && (OPENTHREAD_CONFIG_THREAD_VERSION < OT_THREAD_VERSION_1_2)
64 #error "Thread 1.2 or higher version is required for OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE."
65 #endif
66 
67 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
68 
69 #if (OPENTHREAD_CONFIG_THREAD_VERSION < OT_THREAD_VERSION_1_2)
70 #error "Thread 1.2 or higher version is required for OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE."
71 #endif
72 
73 #if !OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE
74 #error "Microsecond timer OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE is required for "\
75     "OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE"
76 #endif
77 
78 #endif
79 
80 #if OPENTHREAD_CONFIG_MAC_CSL_DEBUG_ENABLE && !OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
81 #error "OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE is required for OPENTHREAD_CONFIG_MAC_CSL_DEBUG_ENABLE."
82 #endif
83 
84 #if OPENTHREAD_RADIO || OPENTHREAD_CONFIG_LINK_RAW_ENABLE
85 class LinkRaw;
86 #endif
87 
88 /**
89  * Implements the IEEE 802.15.4 MAC (sub-MAC).
90  *
91  * Sub-MAC layer implements a subset of IEEE802.15.4 MAC primitives which are shared by both MAC layer (in FTD/MTD
92  * modes) and Raw Link (Radio only mode).
93 
94  * The sub-MAC layer handles the following (if not provided by radio platform):
95  *
96  *    - Ack timeout for frame transmission,
97  *    - CSMA backoff logic,
98  *    - Frame re-transmissions,
99  *    - Energy scan on a single channel and RSSI sampling.
100  *
101  * It also act as the interface (to radio platform) for setting/getting radio configurations such as short or extended
102  * addresses and PAN Id.
103  */
104 class SubMac : public InstanceLocator, private NonCopyable
105 {
106     friend class Radio::Callbacks;
107     friend class LinkRaw;
108 
109 public:
110     /**
111      * Defines the callbacks notifying `SubMac` user of changes and events.
112      */
113     class Callbacks : public InstanceLocator
114     {
115     public:
116         /**
117          * Initializes the `Callbacks` object.
118          *
119          * @param[in]  aInstance  A reference to the OpenThread instance.
120          */
121         explicit Callbacks(Instance &aInstance);
122 
123         /**
124          * Notifies user of `SubMac` of a received frame.
125          *
126          * @param[in]  aFrame    A pointer to the received frame or `nullptr` if the receive operation failed.
127          * @param[in]  aError    kErrorNone when successfully received a frame,
128          *                       kErrorAbort when reception was aborted and a frame was not received,
129          *                       kErrorNoBufs when a frame could not be received due to lack of rx buffer space.
130          */
131         void ReceiveDone(RxFrame *aFrame, Error aError);
132 
133         /**
134          * Notifies user of `SubMac` of CCA status (success/failure) for a frame transmission attempt.
135          *
136          * This is intended for updating counters, logging, and/or tracking CCA failure rate statistics.
137          *
138          * @param[in] aCcaSuccess   TRUE if the CCA succeeded, FALSE otherwise.
139          * @param[in] aChannel      The channel on which CCA was performed.
140          */
141         void RecordCcaStatus(bool aCcaSuccess, uint8_t aChannel);
142 
143         /**
144          * Notifies user of `SubMac` of the status of a frame transmission attempt.
145          *
146          * This is intended for updating counters, logging, and/or collecting statistics.
147          *
148          * @note Unlike `TransmitDone` which is invoked after all re-transmission attempts to indicate the final status
149          * of a frame transmission, this method is invoked on all frame transmission attempts.
150          *
151          * @param[in] aFrame      The transmitted frame.
152          * @param[in] aError      kErrorNone when the frame was transmitted successfully,
153          *                        kErrorNoAck when the frame was transmitted but no ACK was received,
154          *                        kErrorChannelAccessFailure tx failed due to activity on the channel,
155          *                        kErrorAbort when transmission was aborted for other reasons.
156          * @param[in] aRetryCount Current retry count. This is valid only when sub-mac handles frame re-transmissions.
157          * @param[in] aWillRetx   Indicates whether frame will be retransmitted or not. This is applicable only
158          *                        when there was an error in current transmission attempt.
159          */
160         void RecordFrameTransmitStatus(const TxFrame &aFrame, Error aError, uint8_t aRetryCount, bool aWillRetx);
161 
162         /**
163          * The method notifies user of `SubMac` that the transmit operation has completed, providing, if applicable,
164          * the received ACK frame.
165          *
166          * @param[in]  aFrame     The transmitted frame.
167          * @param[in]  aAckFrame  A pointer to the ACK frame, `nullptr` if no ACK was received.
168          * @param[in]  aError     kErrorNone when the frame was transmitted,
169          *                        kErrorNoAck when the frame was transmitted but no ACK was received,
170          *                        kErrorChannelAccessFailure tx failed due to activity on the channel,
171          *                        kErrorAbort when transmission was aborted for other reasons.
172          */
173         void TransmitDone(TxFrame &aFrame, RxFrame *aAckFrame, Error aError);
174 
175         /**
176          * Notifies user of `SubMac` that energy scan is complete.
177          *
178          * @param[in]  aMaxRssi  Maximum RSSI seen on the channel, or `Radio::kInvalidRssi` if failed.
179          */
180         void EnergyScanDone(int8_t aMaxRssi);
181 
182         /**
183          * Notifies user of `SubMac` that a specific MAC frame counter is used for transmission.
184          *
185          * It is possible that this callback is invoked out of order in terms of counter values (i.e., called for a
186          * smaller counter value after a call for a larger counter value).
187          *
188          * @param[in]  aFrameCounter  The MAC frame counter value which was used.
189          */
190         void FrameCounterUsed(uint32_t aFrameCounter);
191     };
192 
193     /**
194      * Initializes the `SubMac` object.
195      *
196      * @param[in]  aInstance  A reference to the OpenThread instance.
197      */
198     explicit SubMac(Instance &aInstance);
199 
200     /**
201      * Gets the capabilities provided by platform radio.
202      *
203      * @returns The capability bit vector (see `OT_RADIO_CAP_*` definitions).
204      */
GetRadioCaps(void) const205     otRadioCaps GetRadioCaps(void) const { return mRadioCaps; }
206 
207     /**
208      * Gets the capabilities provided by `SubMac` layer.
209      *
210      * @returns The capability bit vector (see `OT_RADIO_CAP_*` definitions).
211      */
212     otRadioCaps GetCaps(void) const;
213 
214     /**
215      * Sets the PAN ID.
216      *
217      * @param[in] aPanId  The PAN ID.
218      */
219     void SetPanId(PanId aPanId);
220 
221     /**
222      * Gets the short address.
223      *
224      * @returns The short address.
225      */
GetShortAddress(void) const226     ShortAddress GetShortAddress(void) const { return mShortAddress; }
227 
228     /**
229      * Sets the short address.
230      *
231      * @param[in] aShortAddress   The short address.
232      */
233     void SetShortAddress(ShortAddress aShortAddress);
234 
235     /**
236      * Gets the alternate short address.
237      *
238      * @returns The alternate short address, or `kShortAddrInvalid` if there is no alternate address.
239      */
GetAlternateShortAddress(void) const240     ShortAddress GetAlternateShortAddress(void) const { return mAlternateShortAddress; }
241 
242     /**
243      * Sets the alternate short address.
244      *
245      * @param[in] aShortAddress   The short address. Use `kShortAddrInvalid` to clear it.
246      */
247     void SetAlternateShortAddress(ShortAddress aShortAddress);
248 
249     /**
250      * Gets the extended address.
251      *
252      * @returns A reference to the extended address.
253      */
GetExtAddress(void) const254     const ExtAddress &GetExtAddress(void) const { return mExtAddress; }
255 
256     /**
257      * Sets extended address.
258      *
259      * @param[in] aExtAddress  The extended address.
260      */
261     void SetExtAddress(const ExtAddress &aExtAddress);
262 
263     /**
264      * Registers a callback to provide received packet capture for IEEE 802.15.4 frames.
265      *
266      * @param[in]  aPcapCallback     A pointer to a function that is called when receiving an IEEE 802.15.4 link frame
267      *                               or `nullptr` to disable the callback.
268      * @param[in]  aCallbackContext  A pointer to application-specific context.
269      */
SetPcapCallback(otLinkPcapCallback aPcapCallback,void * aCallbackContext)270     void SetPcapCallback(otLinkPcapCallback aPcapCallback, void *aCallbackContext)
271     {
272         mPcapCallback.Set(aPcapCallback, aCallbackContext);
273     }
274 
275     /**
276      * Indicates whether radio should stay in Receive or Sleep during idle periods.
277      *
278      * @param[in]  aRxOnWhenIdle  TRUE to keep radio in Receive, FALSE to put to Sleep during idle periods.
279      */
280     void SetRxOnWhenIdle(bool aRxOnWhenIdle);
281 
282     /**
283      * Enables the radio.
284      *
285      * @retval kErrorNone     Successfully enabled.
286      * @retval kErrorFailed   The radio could not be enabled.
287      */
288     Error Enable(void);
289 
290     /**
291      * Disables the radio.
292      *
293      * @retval kErrorNone     Successfully disabled the radio.
294      */
295     Error Disable(void);
296 
297     /**
298      * Transitions the radio to Sleep.
299      *
300      * @retval kErrorNone          Successfully transitioned to Sleep.
301      * @retval kErrorBusy          The radio was transmitting.
302      * @retval kErrorInvalidState  The radio was disabled.
303      */
304     Error Sleep(void);
305 
306     /**
307      * Indicates whether the sub-mac is busy transmitting or scanning.
308      *
309      * @retval TRUE if the sub-mac is busy transmitting or scanning.
310      * @retval FALSE if the sub-mac is not busy transmitting or scanning.
311      */
IsTransmittingOrScanning(void) const312     bool IsTransmittingOrScanning(void) const { return (mState == kStateTransmit) || (mState == kStateEnergyScan); }
313 
314     /**
315      * Transitions the radio to Receive.
316      *
317      * @param[in]  aChannel   The channel to use for receiving.
318      *
319      * @retval kErrorNone          Successfully transitioned to Receive.
320      * @retval kErrorInvalidState  The radio was disabled or transmitting.
321      */
322     Error Receive(uint8_t aChannel);
323 
324     /**
325      * Gets the radio transmit frame.
326      *
327      * @returns The transmit frame.
328      */
GetTransmitFrame(void)329     TxFrame &GetTransmitFrame(void) { return mTransmitFrame; }
330 
331     /**
332      * Sends a prepared frame.
333      *
334      * The frame should be placed in `GetTransmitFrame()` frame.
335      *
336      * The `SubMac` layer handles Ack timeout, CSMA backoff, and frame retransmission.
337      *
338      * @retval kErrorNone          Successfully started the frame transmission
339      * @retval kErrorInvalidState  The radio was disabled or transmitting.
340      */
341     Error Send(void);
342 
343     /**
344      * Gets the number of transmit retries of last transmitted frame.
345      *
346      * @returns Number of transmit retries.
347      */
GetTransmitRetries(void) const348     uint8_t GetTransmitRetries(void) const { return mTransmitRetries; }
349 
350     /**
351      * Gets the most recent RSSI measurement.
352      *
353      * @returns The RSSI in dBm when it is valid. `Radio::kInvalidRssi` when RSSI is invalid.
354      */
355     int8_t GetRssi(void) const;
356 
357     /**
358      * Begins energy scan.
359      *
360      * @param[in] aScanChannel   The channel to perform the energy scan on.
361      * @param[in] aScanDuration  The duration, in milliseconds, for the channel to be scanned.
362      *
363      * @retval kErrorNone            Successfully started scanning the channel.
364      * @retval kErrorBusy            The radio is performing energy scanning.
365      * @retval kErrorInvalidState    The radio was disabled or transmitting.
366      * @retval kErrorNotImplemented  Energy scan is not supported (applicable in link-raw/radio mode only).
367      */
368     Error EnergyScan(uint8_t aScanChannel, uint16_t aScanDuration);
369 
370     /**
371      * Returns the noise floor value (currently use the radio receive sensitivity value).
372      *
373      * @returns The noise floor value in dBm.
374      */
375     int8_t GetNoiseFloor(void) const;
376 
377 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
378     /**
379      * Configures CSL parameters in 'SubMac'.
380      *
381      * @param[in]  aPeriod    The CSL period (in unit of 10 symbols).
382      * @param[in]  aChannel   The CSL channel.
383      * @param[in]  aShortAddr The short source address of CSL receiver's peer.
384      * @param[in]  aExtAddr   The extended source address of CSL receiver's peer.
385      *
386      * @retval  TRUE if CSL Period or CSL Channel changed.
387      * @retval  FALSE if CSL Period and CSL Channel did not change.
388      */
389     bool UpdateCsl(uint16_t aPeriod, uint8_t aChannel, ShortAddress aShortAddr, const ExtAddress &aExtAddr);
390 
391     /**
392      * Returns parent CSL accuracy (clock accuracy and uncertainty).
393      *
394      * @returns The parent CSL accuracy.
395      */
GetCslParentAccuracy(void) const396     const CslAccuracy &GetCslParentAccuracy(void) const { return mCslParentAccuracy; }
397 
398     /**
399      * Sets parent CSL accuracy.
400      *
401      * @param[in] aCslAccuracy  The parent CSL accuracy.
402      */
SetCslParentAccuracy(const CslAccuracy & aCslAccuracy)403     void SetCslParentAccuracy(const CslAccuracy &aCslAccuracy) { mCslParentAccuracy = aCslAccuracy; }
404 
405 #endif // OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
406 
407     /**
408      * Sets MAC keys and key index.
409      *
410      * @param[in] aKeyIdMode  MAC key ID mode.
411      * @param[in] aKeyId      The key ID.
412      * @param[in] aPrevKey    The previous MAC key.
413      * @param[in] aCurrKey    The current MAC key.
414      * @param[in] aNextKey    The next MAC key.
415      */
416     void SetMacKey(uint8_t            aKeyIdMode,
417                    uint8_t            aKeyId,
418                    const KeyMaterial &aPrevKey,
419                    const KeyMaterial &aCurrKey,
420                    const KeyMaterial &aNextKey);
421 
422     /**
423      * Returns a reference to the current MAC key.
424      *
425      * @returns A reference to the current MAC key.
426      */
GetCurrentMacKey(void) const427     const KeyMaterial &GetCurrentMacKey(void) const { return mCurrKey; }
428 
429     /**
430      * Returns a reference to the previous MAC key.
431      *
432      * @returns A reference to the previous MAC key.
433      */
GetPreviousMacKey(void) const434     const KeyMaterial &GetPreviousMacKey(void) const { return mPrevKey; }
435 
436     /**
437      * Returns a reference to the next MAC key.
438      *
439      * @returns A reference to the next MAC key.
440      */
GetNextMacKey(void) const441     const KeyMaterial &GetNextMacKey(void) const { return mNextKey; }
442 
443     /**
444      * Clears the stored MAC keys.
445      */
ClearMacKeys(void)446     void ClearMacKeys(void)
447     {
448         mPrevKey.Clear();
449         mCurrKey.Clear();
450         mNextKey.Clear();
451     }
452 
453     /**
454      * Returns the current MAC frame counter value.
455      *
456      * @returns The current MAC frame counter value.
457      */
GetFrameCounter(void) const458     uint32_t GetFrameCounter(void) const { return mFrameCounter; }
459 
460     /**
461      * Sets the current MAC Frame Counter value.
462      *
463      * @param[in] aFrameCounter  The MAC Frame Counter value.
464      * @param[in] aSetIfLarger   If `true`, set only if the new value @p aFrameCounter is larger than the current value.
465      *                           If `false`, set the new value independent of the current value.
466      */
467     void SetFrameCounter(uint32_t aFrameCounter, bool aSetIfLarger);
468 
469 #if OPENTHREAD_CONFIG_MAC_FILTER_ENABLE
470     /**
471      * Enables/disables the radio filter.
472      *
473      * When radio filter is enabled, radio is put to sleep instead of receive (to ensure device does not receive any
474      * frame and/or potentially send ack). Also the frame transmission requests return immediately without sending the
475      * frame over the air (return "no ack" error if ack is requested, otherwise return success).
476      *
477      * @param[in] aFilterEnabled    TRUE to enable radio filter, FALSE to disable.
478      */
SetRadioFilterEnabled(bool aFilterEnabled)479     void SetRadioFilterEnabled(bool aFilterEnabled) { mRadioFilterEnabled = aFilterEnabled; }
480 
481     /**
482      * Indicates whether the radio filter is enabled or not.
483      *
484      * @retval TRUE   If the radio filter is enabled.
485      * @retval FALSE  If the radio filter is disabled.
486      */
IsRadioFilterEnabled(void) const487     bool IsRadioFilterEnabled(void) const { return mRadioFilterEnabled; }
488 #endif
489 
490 #if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
491     /**
492      * Configures wake-up listening parameters in all radios.
493      *
494      * @param[in]  aEnable    Whether to enable or disable wake-up listening.
495      * @param[in]  aInterval  The wake-up listen interval in microseconds.
496      * @param[in]  aDuration  The wake-up listen duration in microseconds.
497      * @param[in]  aChannel   The wake-up channel.
498      */
499     void UpdateWakeupListening(bool aEnable, uint32_t aInterval, uint32_t aDuration, uint8_t aChannel);
500 #endif
501 
502 private:
503 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
504     void        CslInit(void);
505     void        CslSample(void);
506     void        UpdateCslLastSyncTimestamp(TxFrame &aFrame, RxFrame *aAckFrame);
507     void        UpdateCslLastSyncTimestamp(RxFrame *aFrame, Error aError);
508     static void HandleCslTimer(Timer &aTimer);
509     void        HandleCslTimer(void);
510     void        GetCslWindowEdges(uint32_t &aAhead, uint32_t &aAfter);
511     uint32_t    GetLocalTime(void);
IsCslEnabled(void) const512     bool        IsCslEnabled(void) const { return mCslPeriod > 0; }
513 #if OPENTHREAD_CONFIG_MAC_CSL_DEBUG_ENABLE
514     void LogReceived(RxFrame *aFrame);
515 #endif
516     void HandleCslReceiveAt(uint32_t aTimeAhead, uint32_t aTimeAfter);
517     void HandleCslReceiveOrSleep(uint32_t aTimeAhead, uint32_t aTimeAfter);
518     void LogCslWindow(uint32_t aWinStart, uint32_t aWinDuration);
519 #endif
520 #if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
521     void        WedInit(void);
522     static void HandleWedTimer(Timer &aTimer);
523     void        HandleWedTimer(void);
524 #endif
525 
526     static constexpr uint8_t  kCsmaMinBe         = 3;                  // macMinBE (IEEE 802.15.4-2006).
527     static constexpr uint8_t  kCsmaMaxBe         = 5;                  // macMaxBE (IEEE 802.15.4-2006).
528     static constexpr uint32_t kUnitBackoffPeriod = 20;                 // Number of symbols (IEEE 802.15.4-2006).
529     static constexpr uint32_t kAckTimeout = 16 * Time::kOneMsecInUsec; // Timeout for waiting on an ACK (in usec).
530     static constexpr uint32_t kCcaSampleInterval = 128;                // CCA sample interval, 128 usec.
531 
532 #if OPENTHREAD_CONFIG_MAC_ADD_DELAY_ON_NO_ACK_ERROR_BEFORE_RETRY
533     static constexpr uint8_t kRetxDelayMinBackoffExponent = OPENTHREAD_CONFIG_MAC_RETX_DELAY_MIN_BACKOFF_EXPONENT;
534     static constexpr uint8_t kRetxDelayMaxBackoffExponent = OPENTHREAD_CONFIG_MAC_RETX_DELAY_MAX_BACKOFF_EXPONENT;
535 #endif
536 
537 #if OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE
538     static constexpr uint32_t kEnergyScanRssiSampleInterval = 128; // RSSI sample interval for energy scan, in usec
539 #else
540     static constexpr uint32_t kEnergyScanRssiSampleInterval = 1000; // RSSI sample interval for energy scan, in usec
541 #endif
542 
543     enum State : uint8_t
544     {
545         kStateDisabled,    // Radio is disabled.
546         kStateSleep,       // Radio is in sleep.
547         kStateReceive,     // Radio in in receive.
548         kStateCsmaBackoff, // CSMA backoff before transmission.
549         kStateTransmit,    // Radio is transmitting.
550         kStateEnergyScan,  // Energy scan.
551 #if OPENTHREAD_CONFIG_MAC_ADD_DELAY_ON_NO_ACK_ERROR_BEFORE_RETRY
552         kStateDelayBeforeRetx, // Delay before retx
553 #endif
554 #if !OPENTHREAD_MTD && OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
555         kStateCslTransmit, // CSL transmission.
556 #endif
557 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
558         kStateCslSample, // CSL receive.
559 #endif
560     };
561 
562 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE || OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
563     // Radio on times needed before and after MHR time for proper frame detection
564     static constexpr uint32_t kMinReceiveOnAhead = OPENTHREAD_CONFIG_MIN_RECEIVE_ON_AHEAD;
565     static constexpr uint32_t kMinReceiveOnAfter = OPENTHREAD_CONFIG_MIN_RECEIVE_ON_AFTER;
566 
567     // CSL/wake-up listening receivers would wake up `kCslReceiveTimeAhead` earlier
568     // than expected sample window. The value is in usec.
569     static constexpr uint32_t kCslReceiveTimeAhead = OPENTHREAD_CONFIG_CSL_RECEIVE_TIME_AHEAD;
570 #endif
571 
572 #if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
573     // Margin to be applied after the end of a wake-up listen duration to schedule the next listen interval.
574     // The value is in usec.
575     static constexpr uint32_t kWedReceiveTimeAfter = OPENTHREAD_CONFIG_WED_RECEIVE_TIME_AFTER;
576 #endif
577 
578 #if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
579     // CSL transmitter would schedule delayed transmission `kCslTransmitTimeAhead` earlier
580     // than expected delayed transmit time. The value is in usec.
581     // Only for radios not supporting OT_RADIO_CAPS_TRANSMIT_TIMING.
582     static constexpr uint32_t kCslTransmitTimeAhead = OPENTHREAD_CONFIG_CSL_TRANSMIT_TIME_AHEAD;
583 #endif
584 
585     /**
586      * Initializes the states of the sub-MAC layer.
587      */
588     void Init(void);
589 
RadioSupportsCsmaBackoff(void) const590     bool RadioSupportsCsmaBackoff(void) const
591     {
592         return ((mRadioCaps & (OT_RADIO_CAPS_CSMA_BACKOFF | OT_RADIO_CAPS_TRANSMIT_RETRIES)) != 0);
593     }
594 
RadioSupportsTransmitSecurity(void) const595     bool RadioSupportsTransmitSecurity(void) const { return ((mRadioCaps & OT_RADIO_CAPS_TRANSMIT_SEC) != 0); }
RadioSupportsRetries(void) const596     bool RadioSupportsRetries(void) const { return ((mRadioCaps & OT_RADIO_CAPS_TRANSMIT_RETRIES) != 0); }
RadioSupportsAckTimeout(void) const597     bool RadioSupportsAckTimeout(void) const { return ((mRadioCaps & OT_RADIO_CAPS_ACK_TIMEOUT) != 0); }
RadioSupportsEnergyScan(void) const598     bool RadioSupportsEnergyScan(void) const { return ((mRadioCaps & OT_RADIO_CAPS_ENERGY_SCAN) != 0); }
RadioSupportsTransmitTiming(void) const599     bool RadioSupportsTransmitTiming(void) const { return ((mRadioCaps & OT_RADIO_CAPS_TRANSMIT_TIMING) != 0); }
RadioSupportsReceiveTiming(void) const600     bool RadioSupportsReceiveTiming(void) const { return ((mRadioCaps & OT_RADIO_CAPS_RECEIVE_TIMING) != 0); }
RadioSupportsRxOnWhenIdle(void) const601     bool RadioSupportsRxOnWhenIdle(void) const { return ((mRadioCaps & OT_RADIO_CAPS_RX_ON_WHEN_IDLE) != 0); }
602 
603     bool ShouldHandleTransmitSecurity(void) const;
604     bool ShouldHandleCsmaBackOff(void) const;
605     bool ShouldHandleAckTimeout(void) const;
606     bool ShouldHandleRetries(void) const;
607     bool ShouldHandleEnergyScan(void) const;
608     bool ShouldHandleTransmitTargetTime(void) const;
609     bool ShouldHandleTransitionToSleep(void) const;
610 
611     void ProcessTransmitSecurity(void);
612     void SignalFrameCounterUsed(uint32_t aFrameCounter, uint8_t aKeyId);
613     void StartCsmaBackoff(void);
614     void StartTimerForBackoff(uint8_t aBackoffExponent);
615     void BeginTransmit(void);
616     void SampleRssi(void);
617     void StartTimer(uint32_t aDelayUs);
618     void StartTimerAt(Time aStartTime, uint32_t aDelayUs);
619 
620     void HandleReceiveDone(RxFrame *aFrame, Error aError);
621     void HandleTransmitStarted(TxFrame &aFrame);
622     void HandleTransmitDone(TxFrame &aFrame, RxFrame *aAckFrame, Error aError);
623     void SignalFrameCounterUsedOnTxDone(const TxFrame &aFrame);
624     void HandleEnergyScanDone(int8_t aMaxRssi);
625     void HandleTimer(void);
626 
627     Error RadioSleep(void);
628 
629     void               SetState(State aState);
630     static const char *StateToString(State aState);
631 
632     using SubMacTimer =
633 #if OPENTHREAD_CONFIG_PLATFORM_USEC_TIMER_ENABLE
634         TimerMicroIn<SubMac, &SubMac::HandleTimer>;
635 #else
636         TimerMilliIn<SubMac, &SubMac::HandleTimer>;
637 #endif
638 
639     otRadioCaps  mRadioCaps;
640     State        mState;
641     uint8_t      mCsmaBackoffs;
642     uint8_t      mTransmitRetries;
643     ShortAddress mShortAddress;
644     ShortAddress mAlternateShortAddress;
645     ExtAddress   mExtAddress;
646     bool         mRxOnWhenIdle : 1;
647 #if OPENTHREAD_CONFIG_MAC_FILTER_ENABLE
648     bool mRadioFilterEnabled : 1;
649 #endif
650     int8_t                       mEnergyScanMaxRssi;
651     TimeMilli                    mEnergyScanEndTime;
652     TxFrame                     &mTransmitFrame;
653     Callbacks                    mCallbacks;
654     Callback<otLinkPcapCallback> mPcapCallback;
655     KeyMaterial                  mPrevKey;
656     KeyMaterial                  mCurrKey;
657     KeyMaterial                  mNextKey;
658     uint32_t                     mFrameCounter;
659     uint8_t                      mKeyId;
660 #if OPENTHREAD_CONFIG_MAC_ADD_DELAY_ON_NO_ACK_ERROR_BEFORE_RETRY
661     uint8_t mRetxDelayBackOffExponent;
662 #endif
663     SubMacTimer mTimer;
664 
665 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
666     uint16_t mCslPeriod;            // The CSL sample period, in units of 10 symbols (160 microseconds).
667     uint8_t  mCslChannel : 7;       // The CSL sample channel.
668     bool     mIsCslSampling : 1;    // Indicates that the radio is receiving in CSL state for platforms not supporting
669                                     // delayed reception.
670     uint16_t    mCslPeerShort;      // The CSL peer short address.
671     TimeMicro   mCslSampleTime;     // The CSL sample time of the current period relative to the local radio clock.
672     TimeMicro   mCslLastSync;       // The timestamp of the last successful CSL synchronization.
673     CslAccuracy mCslParentAccuracy; // The parent's CSL accuracy (clock accuracy and uncertainty).
674     TimerMicro  mCslTimer;
675 #endif
676 
677 #if OPENTHREAD_CONFIG_WAKEUP_END_DEVICE_ENABLE
678     uint32_t   mWakeupListenInterval; // The wake-up listen interval, in microseconds.
679     uint32_t   mWakeupListenDuration; // The wake-up listen duration, in microseconds.
680     uint8_t    mWakeupChannel;        // The wake-up sample channel.
681     TimeMicro  mWedSampleTime;        // The WED sample time of the current interval in local time.
682     uint64_t   mWedSampleTimeRadio;   // The WED sample time of the current interval in radio time.
683     TimerMicro mWedTimer;
684 #endif
685 };
686 
687 /**
688  * @}
689  */
690 
691 } // namespace Mac
692 } // namespace ot
693 
694 #endif // SUB_MAC_HPP_
695