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