1 /*
2 * Copyright (c) 2020, 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 "radio.hpp"
30
31 #include "common/code_utils.hpp"
32 #include "common/locator_getters.hpp"
33 #include "common/timer.hpp"
34 #include "mac/mac_frame.hpp"
35 #include "utils/otns.hpp"
36
37 namespace ot {
38
39 const uint8_t Radio::kSupportedChannelPages[kNumChannelPages] = {
40 #if OPENTHREAD_CONFIG_RADIO_2P4GHZ_OQPSK_SUPPORT
41 kChannelPage0,
42 #endif
43 #if OPENTHREAD_CONFIG_RADIO_915MHZ_OQPSK_SUPPORT
44 kChannelPage2,
45 #endif
46 #if OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_SUPPORT
47 OPENTHREAD_CONFIG_PLATFORM_RADIO_PROPRIETARY_CHANNEL_PAGE,
48 #endif
49 };
50
51 #if OPENTHREAD_RADIO
Init(void)52 void Radio::Init(void)
53 {
54 #if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
55 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
56 SuccessOrAssert(ResetCsl());
57 #endif
58
59 EnableSrcMatch(false);
60 ClearSrcMatchShortEntries();
61 ClearSrcMatchExtEntries();
62
63 if (IsEnabled())
64 {
65 SuccessOrAssert(Sleep());
66 SuccessOrAssert(Disable());
67 }
68
69 SetPanId(Mac::kPanIdBroadcast);
70 SetExtendedAddress(Mac::ExtAddress{});
71 SetShortAddress(Mac::kShortAddrInvalid);
72 SetMacKey(0, 0, Mac::KeyMaterial{}, Mac::KeyMaterial{}, Mac::KeyMaterial{});
73 SetMacFrameCounter(0);
74
75 SetPromiscuous(false);
76 SetRxOnWhenIdle(true);
77 #endif // OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
78 }
79 #endif // OPENTHREAD_RADIO
80
81 #if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
82
SetExtendedAddress(const Mac::ExtAddress & aExtAddress)83 void Radio::SetExtendedAddress(const Mac::ExtAddress &aExtAddress)
84 {
85 otPlatRadioSetExtendedAddress(GetInstancePtr(), &aExtAddress);
86
87 #if (OPENTHREAD_MTD || OPENTHREAD_FTD) && OPENTHREAD_CONFIG_OTNS_ENABLE
88 Get<Utils::Otns>().EmitExtendedAddress(aExtAddress);
89 #endif
90 }
91
SetShortAddress(Mac::ShortAddress aShortAddress)92 void Radio::SetShortAddress(Mac::ShortAddress aShortAddress)
93 {
94 otPlatRadioSetShortAddress(GetInstancePtr(), aShortAddress);
95
96 #if (OPENTHREAD_MTD || OPENTHREAD_FTD) && OPENTHREAD_CONFIG_OTNS_ENABLE
97 Get<Utils::Otns>().EmitShortAddress(aShortAddress);
98 #endif
99 }
100
Transmit(Mac::TxFrame & aFrame)101 Error Radio::Transmit(Mac::TxFrame &aFrame)
102 {
103 #if (OPENTHREAD_MTD || OPENTHREAD_FTD) && OPENTHREAD_CONFIG_OTNS_ENABLE
104 Get<Utils::Otns>().EmitTransmit(aFrame);
105 #endif
106
107 return otPlatRadioTransmit(GetInstancePtr(), &aFrame);
108 }
109 #endif // OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
110
111 #if OPENTHREAD_CONFIG_RADIO_STATS_ENABLE && (OPENTHREAD_FTD || OPENTHREAD_MTD)
UintSafeMinus(uint64_t aLhs,uint64_t aRhs)112 inline uint64_t UintSafeMinus(uint64_t aLhs, uint64_t aRhs) { return aLhs > aRhs ? (aLhs - aRhs) : 0; }
113
RadioStatistics(void)114 RadioStatistics::RadioStatistics(void)
115 : mStatus(kDisabled)
116 {
117 ResetTime();
118 }
119
RecordStateChange(Status aStatus)120 void RadioStatistics::RecordStateChange(Status aStatus)
121 {
122 UpdateTime();
123 mStatus = aStatus;
124 }
125
HandleReceiveAt(uint32_t aDurationUs)126 void RadioStatistics::HandleReceiveAt(uint32_t aDurationUs)
127 {
128 // The actual rx time of ReceiveAt cannot be obtained from software level. This is a workaround.
129 if (mStatus == kSleep)
130 {
131 mTimeStats.mRxTime += aDurationUs;
132 }
133 }
134
RecordTxDone(otError aError,uint16_t aPsduLength)135 void RadioStatistics::RecordTxDone(otError aError, uint16_t aPsduLength)
136 {
137 if (aError == kErrorNone || aError == kErrorNoAck)
138 {
139 uint32_t txTimeUs = (aPsduLength + Mac::Frame::kPhyHeaderSize) * Radio::kSymbolsPerOctet * Radio::kSymbolTime;
140 uint32_t rxAckTimeUs = (Mac::Frame::kImmAckLength + Mac::Frame::kPhyHeaderSize) * Radio::kPhyUsPerByte;
141
142 UpdateTime();
143 mTimeStats.mTxTime += txTimeUs;
144
145 if (mStatus == kReceive)
146 {
147 mTimeStats.mRxTime = UintSafeMinus(mTimeStats.mRxTime, txTimeUs);
148 }
149 else if (mStatus == kSleep)
150 {
151 mTimeStats.mSleepTime = UintSafeMinus(mTimeStats.mSleepTime, txTimeUs);
152 if (aError == kErrorNone)
153 {
154 mTimeStats.mRxTime += rxAckTimeUs;
155 mTimeStats.mSleepTime = UintSafeMinus(mTimeStats.mSleepTime, rxAckTimeUs);
156 }
157 }
158 }
159 }
160
RecordRxDone(otError aError)161 void RadioStatistics::RecordRxDone(otError aError)
162 {
163 uint32_t ackTimeUs;
164
165 VerifyOrExit(aError == kErrorNone);
166
167 UpdateTime();
168 // Currently we cannot know the actual length of ACK. So assume the ACK is an immediate ACK.
169 ackTimeUs = (Mac::Frame::kImmAckLength + Mac::Frame::kPhyHeaderSize) * Radio::kPhyUsPerByte;
170 mTimeStats.mTxTime += ackTimeUs;
171 if (mStatus == kReceive)
172 {
173 mTimeStats.mRxTime = UintSafeMinus(mTimeStats.mRxTime, ackTimeUs);
174 }
175
176 exit:
177 return;
178 }
179
GetStats(void)180 const otRadioTimeStats &RadioStatistics::GetStats(void)
181 {
182 UpdateTime();
183
184 return mTimeStats;
185 }
186
ResetTime(void)187 void RadioStatistics::ResetTime(void)
188 {
189 mTimeStats.mDisabledTime = 0;
190 mTimeStats.mSleepTime = 0;
191 mTimeStats.mRxTime = 0;
192 mTimeStats.mTxTime = 0;
193 mLastUpdateTime = TimerMicro::GetNow();
194 }
195
UpdateTime(void)196 void RadioStatistics::UpdateTime(void)
197 {
198 TimeMicro nowTime = TimerMicro::GetNow();
199 uint32_t timeElapsed = nowTime - mLastUpdateTime;
200
201 switch (mStatus)
202 {
203 case kSleep:
204 mTimeStats.mSleepTime += timeElapsed;
205 break;
206 case kReceive:
207 mTimeStats.mRxTime += timeElapsed;
208 break;
209 case kDisabled:
210 mTimeStats.mDisabledTime += timeElapsed;
211 break;
212 }
213 mLastUpdateTime = nowTime;
214 }
215
216 #endif // OPENTHREAD_CONFIG_RADIO_STATS_ENABLE && (OPENTHREAD_FTD || OPENTHREAD_MTD)
217
218 } // namespace ot
219