• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2024, 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 #include "wakeup_tx_scheduler.hpp"
30 
31 #if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE
32 
33 #include "common/code_utils.hpp"
34 #include "common/log.hpp"
35 #include "common/num_utils.hpp"
36 #include "common/time.hpp"
37 #include "core/instance/instance.hpp"
38 #include "radio/radio.hpp"
39 
40 namespace ot {
41 
42 RegisterLogModule("WakeupTxSched");
43 
WakeupTxScheduler(Instance & aInstance)44 WakeupTxScheduler::WakeupTxScheduler(Instance &aInstance)
45     : InstanceLocator(aInstance)
46     , mTxTimeUs(0)
47     , mTxEndTimeUs(0)
48     , mTimer(aInstance)
49     , mIsRunning(false)
50 {
51     UpdateFrameRequestAhead();
52 }
53 
WakeUp(const Mac::ExtAddress & aWedAddress,uint16_t aIntervalUs,uint16_t aDurationMs)54 Error WakeupTxScheduler::WakeUp(const Mac::ExtAddress &aWedAddress, uint16_t aIntervalUs, uint16_t aDurationMs)
55 {
56     Error error = kErrorNone;
57 
58     VerifyOrExit(!mIsRunning, error = kErrorInvalidState);
59 
60     mWedAddress  = aWedAddress;
61     mTxTimeUs    = TimerMicro::GetNow() + mTxRequestAheadTimeUs;
62     mTxEndTimeUs = mTxTimeUs + aDurationMs * Time::kOneMsecInUsec + aIntervalUs;
63     mIntervalUs  = aIntervalUs;
64     mIsRunning   = true;
65 
66     LogInfo("Started wake-up sequence to %s", aWedAddress.ToString().AsCString());
67 
68     ScheduleTimer();
69 
70 exit:
71     return error;
72 }
73 
RequestWakeupFrameTransmission(void)74 void WakeupTxScheduler::RequestWakeupFrameTransmission(void) { Get<Mac::Mac>().RequestWakeupFrameTransmission(); }
75 
76 #if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
77 
PrepareWakeupFrame(Mac::TxFrames & aTxFrames)78 Mac::TxFrame *WakeupTxScheduler::PrepareWakeupFrame(Mac::TxFrames &aTxFrames)
79 {
80     Mac::TxFrame      *frame = nullptr;
81     Mac::Address       target;
82     Mac::Address       source;
83     uint32_t           radioTxDelay;
84     uint32_t           rendezvousTimeUs;
85     TimeMicro          nowUs = TimerMicro::GetNow();
86     Mac::ConnectionIe *connectionIe;
87 
88     VerifyOrExit(mIsRunning);
89 
90     target.SetExtended(mWedAddress);
91     source.SetExtended(Get<Mac::Mac>().GetExtAddress());
92     VerifyOrExit(mTxTimeUs >= nowUs);
93     radioTxDelay = mTxTimeUs - nowUs;
94 
95 #if OPENTHREAD_CONFIG_MULTI_RADIO
96     frame = &aTxFrames.GetTxFrame(Mac::kRadioTypeIeee802154);
97 #else
98     frame = &aTxFrames.GetTxFrame();
99 #endif
100 
101     VerifyOrExit(frame->GenerateWakeupFrame(Get<Mac::Mac>().GetPanId(), target, source) == kErrorNone, frame = nullptr);
102     frame->SetTxDelayBaseTime(static_cast<uint32_t>(Get<Radio>().GetNow()));
103     frame->SetTxDelay(radioTxDelay);
104     frame->SetCsmaCaEnabled(kWakeupFrameTxCca);
105     frame->SetMaxCsmaBackoffs(0);
106     frame->SetMaxFrameRetries(0);
107 
108     // Rendezvous Time is the time between the end of a wake-up frame and the start of the first payload frame.
109     // For the n-th wake-up frame, set the Rendezvous Time so that the expected reception of a Parent Request happens in
110     // the "free space" between the "n+1"-th and "n+2"-th wake-up frame.
111     rendezvousTimeUs = mIntervalUs;
112     rendezvousTimeUs += (mIntervalUs - (kWakeupFrameLength + kParentRequestLength) * kOctetDuration) / 2;
113     frame->GetRendezvousTimeIe()->SetRendezvousTime(rendezvousTimeUs / kUsPerTenSymbols);
114 
115     connectionIe = frame->GetConnectionIe();
116     connectionIe->SetRetryInterval(kConnectionRetryInterval);
117     connectionIe->SetRetryCount(kConnectionRetryCount);
118 
119     // Advance to the time of the next wake-up frame.
120     mTxTimeUs = Max(mTxTimeUs + mIntervalUs, TimerMicro::GetNow() + mTxRequestAheadTimeUs);
121 
122     // Schedule the next timer right away before waiting for the transmission completion
123     // to keep up with the high rate of wake-up frames in the RCP architecture.
124     ScheduleTimer();
125 
126 exit:
127     return frame;
128 }
129 
130 #else // OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
131 
PrepareWakeupFrame(Mac::TxFrames &)132 Mac::TxFrame *WakeupTxScheduler::PrepareWakeupFrame(Mac::TxFrames &) { return nullptr; }
133 
134 #endif // OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
135 
ScheduleTimer(void)136 void WakeupTxScheduler::ScheduleTimer(void)
137 {
138     if (mTxTimeUs >= mTxEndTimeUs)
139     {
140         mIsRunning = false;
141         LogInfo("Stopped wake-up sequence");
142         ExitNow();
143     }
144 
145     mTimer.FireAt(mTxTimeUs - mTxRequestAheadTimeUs);
146 
147 exit:
148     return;
149 }
150 
Stop(void)151 void WakeupTxScheduler::Stop(void)
152 {
153     mIsRunning = false;
154     mTimer.Stop();
155 }
156 
UpdateFrameRequestAhead(void)157 void WakeupTxScheduler::UpdateFrameRequestAhead(void)
158 {
159     // A rough estimate of the size of data that has to be exchanged with the radio to schedule a wake-up frame TX.
160     // This is used to make sure that a wake-up frame is received by the radio early enough to be transmitted on time.
161     constexpr uint32_t kWakeupFrameSize = 100;
162 
163     mTxRequestAheadTimeUs = Mac::kCslRequestAhead + Get<Mac::Mac>().CalculateRadioBusTransferTime(kWakeupFrameSize);
164 }
165 
166 } // namespace ot
167 
168 #endif // OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE
169