• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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