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