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 }
Transmit(Mac::TxFrame & aFrame)107 Error Radio::Transmit(Mac::TxFrame &aFrame)
108 {
109 #if (OPENTHREAD_MTD || OPENTHREAD_FTD) && OPENTHREAD_CONFIG_OTNS_ENABLE
110 Get<Utils::Otns>().EmitTransmit(aFrame);
111 #endif
112
113 return otPlatRadioTransmit(GetInstancePtr(), &aFrame);
114 }
115 #endif // OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
116
117 #if OPENTHREAD_CONFIG_RADIO_STATS_ENABLE && (OPENTHREAD_FTD || OPENTHREAD_MTD)
UintSafeMinus(uint64_t aLhs,uint64_t aRhs)118 inline uint64_t UintSafeMinus(uint64_t aLhs, uint64_t aRhs) { return aLhs > aRhs ? (aLhs - aRhs) : 0; }
119
Statistics(void)120 Radio::Statistics::Statistics(void)
121 : mStatus(kDisabled)
122 {
123 ResetTime();
124 }
125
RecordStateChange(Status aStatus)126 void Radio::Statistics::RecordStateChange(Status aStatus)
127 {
128 UpdateTime();
129 mStatus = aStatus;
130 }
131
HandleReceiveAt(uint32_t aDurationUs)132 void Radio::Statistics::HandleReceiveAt(uint32_t aDurationUs)
133 {
134 // The actual rx time of ReceiveAt cannot be obtained from software level. This is a workaround.
135 if (mStatus == kSleep)
136 {
137 mTimeStats.mRxTime += aDurationUs;
138 }
139 }
140
RecordTxDone(otError aError,uint16_t aPsduLength)141 void Radio::Statistics::RecordTxDone(otError aError, uint16_t aPsduLength)
142 {
143 if (aError == kErrorNone || aError == kErrorNoAck)
144 {
145 uint32_t txTimeUs = (aPsduLength + Mac::Frame::kPhyHeaderSize) * Radio::kSymbolsPerOctet * Radio::kSymbolTime;
146 uint32_t rxAckTimeUs = (Mac::Frame::kImmAckLength + Mac::Frame::kPhyHeaderSize) * Radio::kPhyUsPerByte;
147
148 UpdateTime();
149 mTimeStats.mTxTime += txTimeUs;
150
151 if (mStatus == kReceive)
152 {
153 mTimeStats.mRxTime = UintSafeMinus(mTimeStats.mRxTime, txTimeUs);
154 }
155 else if (mStatus == kSleep)
156 {
157 mTimeStats.mSleepTime = UintSafeMinus(mTimeStats.mSleepTime, txTimeUs);
158 if (aError == kErrorNone)
159 {
160 mTimeStats.mRxTime += rxAckTimeUs;
161 mTimeStats.mSleepTime = UintSafeMinus(mTimeStats.mSleepTime, rxAckTimeUs);
162 }
163 }
164 }
165 }
166
RecordRxDone(otError aError)167 void Radio::Statistics::RecordRxDone(otError aError)
168 {
169 uint32_t ackTimeUs;
170
171 VerifyOrExit(aError == kErrorNone);
172
173 UpdateTime();
174 // Currently we cannot know the actual length of ACK. So assume the ACK is an immediate ACK.
175 ackTimeUs = (Mac::Frame::kImmAckLength + Mac::Frame::kPhyHeaderSize) * Radio::kPhyUsPerByte;
176 mTimeStats.mTxTime += ackTimeUs;
177 if (mStatus == kReceive)
178 {
179 mTimeStats.mRxTime = UintSafeMinus(mTimeStats.mRxTime, ackTimeUs);
180 }
181
182 exit:
183 return;
184 }
185
GetStats(void)186 const Radio::Statistics::TimeStats &Radio::Statistics::GetStats(void)
187 {
188 UpdateTime();
189
190 return mTimeStats;
191 }
192
ResetTime(void)193 void Radio::Statistics::ResetTime(void)
194 {
195 ClearAllBytes(mTimeStats);
196 mLastUpdateTime = TimerMicro::GetNow();
197 }
198
UpdateTime(void)199 void Radio::Statistics::UpdateTime(void)
200 {
201 TimeMicro nowTime = TimerMicro::GetNow();
202 uint32_t timeElapsed = nowTime - mLastUpdateTime;
203
204 switch (mStatus)
205 {
206 case kSleep:
207 mTimeStats.mSleepTime += timeElapsed;
208 break;
209 case kReceive:
210 mTimeStats.mRxTime += timeElapsed;
211 break;
212 case kDisabled:
213 mTimeStats.mDisabledTime += timeElapsed;
214 break;
215 }
216 mLastUpdateTime = nowTime;
217 }
218
219 #endif // OPENTHREAD_CONFIG_RADIO_STATS_ENABLE && (OPENTHREAD_FTD || OPENTHREAD_MTD)
220
221 } // namespace ot
222