1 /*
2 * Copyright (c) 2024, 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 <openthread/platform/radio.h>
30
31 #include "nexus_core.hpp"
32 #include "nexus_node.hpp"
33
34 namespace ot {
35 namespace Nexus {
36
37 //---------------------------------------------------------------------------------------------------------------------
38 // otPlatRadio APIs
39
40 extern "C" {
41
otPlatRadioGetCaps(otInstance * aInstance)42 otRadioCaps otPlatRadioGetCaps(otInstance *aInstance)
43 {
44 OT_UNUSED_VARIABLE(aInstance);
45 return OT_RADIO_CAPS_NONE;
46 }
47
otPlatRadioGetReceiveSensitivity(otInstance * aInstance)48 int8_t otPlatRadioGetReceiveSensitivity(otInstance *aInstance)
49 {
50 OT_UNUSED_VARIABLE(aInstance);
51 return Radio::kRadioSensetivity;
52 }
53
otPlatRadioGetIeeeEui64(otInstance * aInstance,uint8_t * aIeeeEui64)54 void otPlatRadioGetIeeeEui64(otInstance *aInstance, uint8_t *aIeeeEui64)
55 {
56 uint32_t nodeId = AsNode(aInstance).GetInstance().GetId();
57
58 memset(aIeeeEui64, 0, sizeof(Mac::ExtAddress));
59
60 aIeeeEui64[6] = (nodeId >> 8) & 0xff;
61 aIeeeEui64[7] = nodeId & 0xff;
62 }
63
otPlatRadioSetPanId(otInstance * aInstance,otPanId aPanId)64 void otPlatRadioSetPanId(otInstance *aInstance, otPanId aPanId) { AsNode(aInstance).mRadio.mPanId = aPanId; }
65
otPlatRadioSetExtendedAddress(otInstance * aInstance,const otExtAddress * aExtAddress)66 void otPlatRadioSetExtendedAddress(otInstance *aInstance, const otExtAddress *aExtAddress)
67 {
68 AsNode(aInstance).mRadio.mExtAddress.Set(aExtAddress->m8, Mac::ExtAddress::kReverseByteOrder);
69 }
70
otPlatRadioSetShortAddress(otInstance * aInstance,otShortAddress aShortAddress)71 void otPlatRadioSetShortAddress(otInstance *aInstance, otShortAddress aShortAddress)
72 {
73 AsNode(aInstance).mRadio.mShortAddress = aShortAddress;
74 }
75
otPlatRadioGetPromiscuous(otInstance * aInstance)76 bool otPlatRadioGetPromiscuous(otInstance *aInstance) { return AsNode(aInstance).mRadio.mPromiscuous; }
77
otPlatRadioSetPromiscuous(otInstance * aInstance,bool aEnable)78 void otPlatRadioSetPromiscuous(otInstance *aInstance, bool aEnable) { AsNode(aInstance).mRadio.mPromiscuous = aEnable; }
79
otPlatRadioGetState(otInstance * aInstance)80 otRadioState otPlatRadioGetState(otInstance *aInstance) { return AsNode(aInstance).mRadio.mState; }
81
otPlatRadioEnable(otInstance * aInstance)82 otError otPlatRadioEnable(otInstance *aInstance)
83 {
84 Error error = kErrorNone;
85 Radio &radio = AsNode(aInstance).mRadio;
86
87 VerifyOrExit(radio.mState == Radio::kStateDisabled, error = kErrorFailed);
88 radio.mState = Radio::kStateSleep;
89
90 exit:
91 return error;
92 }
93
otPlatRadioDisable(otInstance * aInstance)94 otError otPlatRadioDisable(otInstance *aInstance)
95 {
96 AsNode(aInstance).mRadio.mState = Radio::kStateDisabled;
97 return kErrorNone;
98 }
99
otPlatRadioIsEnabled(otInstance * aInstance)100 bool otPlatRadioIsEnabled(otInstance *aInstance) { return AsNode(aInstance).mRadio.mState != Radio::kStateDisabled; }
101
otPlatRadioSleep(otInstance * aInstance)102 otError otPlatRadioSleep(otInstance *aInstance)
103 {
104 Error error = kErrorNone;
105 Radio &radio = AsNode(aInstance).mRadio;
106
107 VerifyOrExit(radio.mState != Radio::kStateDisabled, error = kErrorInvalidState);
108 VerifyOrExit(radio.mState != Radio::kStateTransmit, error = kErrorBusy);
109 radio.mState = Radio::kStateSleep;
110
111 exit:
112 return error;
113 }
114
otPlatRadioReceive(otInstance * aInstance,uint8_t aChannel)115 otError otPlatRadioReceive(otInstance *aInstance, uint8_t aChannel)
116 {
117 Error error = kErrorNone;
118 Radio &radio = AsNode(aInstance).mRadio;
119
120 VerifyOrExit(radio.mState != Radio::kStateDisabled, error = kErrorInvalidState);
121 radio.mState = Radio::kStateReceive;
122 radio.mChannel = aChannel;
123
124 exit:
125 return error;
126 }
127
otPlatRadioGetTransmitBuffer(otInstance * aInstance)128 otRadioFrame *otPlatRadioGetTransmitBuffer(otInstance *aInstance) { return &AsNode(aInstance).mRadio.mTxFrame; }
129
otPlatRadioTransmit(otInstance * aInstance,otRadioFrame * aFrame)130 otError otPlatRadioTransmit(otInstance *aInstance, otRadioFrame *aFrame)
131 {
132 Error error = kErrorNone;
133 Radio &radio = AsNode(aInstance).mRadio;
134
135 VerifyOrExit(radio.mState == Radio::kStateReceive, error = kErrorInvalidState);
136 OT_ASSERT(aFrame == &AsNode(aInstance).mRadio.mTxFrame);
137 radio.mState = Radio::kStateTransmit;
138
139 Core::Get().MarkPendingAction();
140
141 exit:
142 return error;
143 }
144
otPlatRadioGetRssi(otInstance * aInstance)145 int8_t otPlatRadioGetRssi(otInstance *aInstance)
146 {
147 OT_UNUSED_VARIABLE(aInstance);
148 return Radio::kRadioSensetivity;
149 }
150
otPlatRadioEnableSrcMatch(otInstance * aInstance,bool aEnable)151 void otPlatRadioEnableSrcMatch(otInstance *aInstance, bool aEnable)
152 {
153 AsNode(aInstance).mRadio.mSrcMatchEnabled = aEnable;
154 }
155
otPlatRadioAddSrcMatchShortEntry(otInstance * aInstance,otShortAddress aShortAddress)156 otError otPlatRadioAddSrcMatchShortEntry(otInstance *aInstance, otShortAddress aShortAddress)
157 {
158 Error error = kErrorNone;
159 Radio &radio = AsNode(aInstance).mRadio;
160
161 VerifyOrExit(!radio.mSrcMatchShortEntries.Contains(aShortAddress));
162 error = radio.mSrcMatchShortEntries.PushBack(aShortAddress);
163
164 exit:
165 return error;
166 }
167
otPlatRadioAddSrcMatchExtEntry(otInstance * aInstance,const otExtAddress * aExtAddress)168 otError otPlatRadioAddSrcMatchExtEntry(otInstance *aInstance, const otExtAddress *aExtAddress)
169 {
170 Error error = kErrorNone;
171 Radio &radio = AsNode(aInstance).mRadio;
172 Mac::ExtAddress extAddress;
173
174 extAddress.Set(aExtAddress->m8, Mac::ExtAddress::kReverseByteOrder);
175
176 VerifyOrExit(!radio.mSrcMatchExtEntries.Contains(extAddress));
177 error = radio.mSrcMatchExtEntries.PushBack(extAddress);
178
179 exit:
180 return error;
181 }
182
otPlatRadioClearSrcMatchShortEntry(otInstance * aInstance,otShortAddress aShortAddress)183 otError otPlatRadioClearSrcMatchShortEntry(otInstance *aInstance, otShortAddress aShortAddress)
184 {
185 Error error = kErrorNone;
186 Radio &radio = AsNode(aInstance).mRadio;
187 uint16_t *entry;
188
189 entry = radio.mSrcMatchShortEntries.Find(aShortAddress);
190 VerifyOrExit(entry != nullptr, error = kErrorNoAddress);
191
192 radio.mSrcMatchShortEntries.Remove(*entry);
193
194 exit:
195 return error;
196 }
197
otPlatRadioClearSrcMatchExtEntry(otInstance * aInstance,const otExtAddress * aExtAddress)198 otError otPlatRadioClearSrcMatchExtEntry(otInstance *aInstance, const otExtAddress *aExtAddress)
199 {
200 Error error = kErrorNone;
201 Radio &radio = AsNode(aInstance).mRadio;
202 Mac::ExtAddress extAddress;
203 Mac::ExtAddress *entry;
204
205 extAddress.Set(aExtAddress->m8, Mac::ExtAddress::kReverseByteOrder);
206
207 entry = radio.mSrcMatchExtEntries.Find(extAddress);
208 VerifyOrExit(entry != nullptr, error = kErrorNoAddress);
209
210 radio.mSrcMatchExtEntries.Remove(*entry);
211
212 exit:
213 return error;
214 }
215
otPlatRadioClearSrcMatchShortEntries(otInstance * aInstance)216 void otPlatRadioClearSrcMatchShortEntries(otInstance *aInstance)
217 {
218 AsNode(aInstance).mRadio.mSrcMatchShortEntries.Clear();
219 }
220
otPlatRadioClearSrcMatchExtEntries(otInstance * aInstance)221 void otPlatRadioClearSrcMatchExtEntries(otInstance *aInstance) { AsNode(aInstance).mRadio.mSrcMatchExtEntries.Clear(); }
222
223 // Not supported
224
otPlatRadioEnergyScan(otInstance *,uint8_t,uint16_t)225 otError otPlatRadioEnergyScan(otInstance *, uint8_t, uint16_t) { return kErrorNotImplemented; }
226
otPlatRadioGetTransmitPower(otInstance *,int8_t *)227 otError otPlatRadioGetTransmitPower(otInstance *, int8_t *) { return kErrorNotImplemented; }
otPlatRadioSetTransmitPower(otInstance *,int8_t)228 otError otPlatRadioSetTransmitPower(otInstance *, int8_t) { return kErrorNotImplemented; }
otPlatRadioGetCcaEnergyDetectThreshold(otInstance *,int8_t *)229 otError otPlatRadioGetCcaEnergyDetectThreshold(otInstance *, int8_t *) { return kErrorNotImplemented; }
otPlatRadioSetCcaEnergyDetectThreshold(otInstance *,int8_t)230 otError otPlatRadioSetCcaEnergyDetectThreshold(otInstance *, int8_t) { return kErrorNotImplemented; }
otPlatRadioGetFemLnaGain(otInstance *,int8_t *)231 otError otPlatRadioGetFemLnaGain(otInstance *, int8_t *) { return kErrorNotImplemented; }
otPlatRadioSetFemLnaGain(otInstance *,int8_t)232 otError otPlatRadioSetFemLnaGain(otInstance *, int8_t) { return kErrorNotImplemented; }
otPlatRadioIsCoexEnabled(otInstance *)233 bool otPlatRadioIsCoexEnabled(otInstance *) { return false; }
otPlatRadioSetCoexEnabled(otInstance *,bool)234 otError otPlatRadioSetCoexEnabled(otInstance *, bool) { return kErrorNotImplemented; }
otPlatRadioGetCoexMetrics(otInstance *,otRadioCoexMetrics *)235 otError otPlatRadioGetCoexMetrics(otInstance *, otRadioCoexMetrics *) { return kErrorNotImplemented; }
otPlatRadioEnableCsl(otInstance *,uint32_t,otShortAddress,const otExtAddress *)236 otError otPlatRadioEnableCsl(otInstance *, uint32_t, otShortAddress, const otExtAddress *) { return kErrorNone; }
otPlatRadioResetCsl(otInstance *)237 otError otPlatRadioResetCsl(otInstance *) { return kErrorNotImplemented; }
otPlatRadioUpdateCslSampleTime(otInstance *,uint32_t)238 void otPlatRadioUpdateCslSampleTime(otInstance *, uint32_t) {}
otPlatRadioGetCslAccuracy(otInstance *)239 uint8_t otPlatRadioGetCslAccuracy(otInstance *) { return 0; }
otPlatRadioSetChannelTargetPower(otInstance *,uint8_t,int16_t)240 otError otPlatRadioSetChannelTargetPower(otInstance *, uint8_t, int16_t) { return kErrorNotImplemented; }
otPlatRadioClearCalibratedPowers(otInstance *)241 otError otPlatRadioClearCalibratedPowers(otInstance *) { return kErrorNotImplemented; }
otPlatRadioAddCalibratedPower(otInstance *,uint8_t,int16_t,const uint8_t *,uint16_t)242 otError otPlatRadioAddCalibratedPower(otInstance *, uint8_t, int16_t, const uint8_t *, uint16_t)
243 {
244 return kErrorNotImplemented;
245 }
246
247 } // extern "C"
248
249 //---------------------------------------------------------------------------------------------------------------------
250 // Radio
251
CanReceiveOnChannel(uint8_t aChannel) const252 bool Radio::CanReceiveOnChannel(uint8_t aChannel) const
253 {
254 bool canRx = false;
255
256 switch (mState)
257 {
258 case kStateReceive:
259 case kStateTransmit:
260 break;
261 default:
262 ExitNow();
263 }
264
265 VerifyOrExit(mChannel == aChannel);
266 canRx = true;
267
268 exit:
269 return canRx;
270 }
271
Matches(const Mac::Address & aAddress,Mac::PanId aPanId) const272 bool Radio::Matches(const Mac::Address &aAddress, Mac::PanId aPanId) const
273 {
274 bool matches = false;
275
276 if (aAddress.IsShort())
277 {
278 VerifyOrExit(aAddress.IsBroadcast() || aAddress.GetShort() == mShortAddress);
279 }
280 else if (aAddress.IsExtended())
281 {
282 VerifyOrExit(aAddress.GetExtended() == mExtAddress);
283 }
284
285 if ((aPanId != Mac::kPanIdBroadcast) && (mPanId != Mac::kPanIdBroadcast))
286 {
287 VerifyOrExit(mPanId == aPanId);
288 }
289
290 matches = true;
291
292 exit:
293 return matches;
294 }
295
HasFramePendingFor(const Mac::Address & aAddress) const296 bool Radio::HasFramePendingFor(const Mac::Address &aAddress) const
297 {
298 bool hasPending = false;
299
300 if (!mSrcMatchEnabled)
301 {
302 // Always mark frame pending when `SrcMatch` is disabled.
303 hasPending = true;
304 ExitNow();
305 }
306
307 if (aAddress.IsShort())
308 {
309 hasPending = mSrcMatchShortEntries.Contains(aAddress.GetShort());
310 }
311 else if (aAddress.IsExtended())
312 {
313 hasPending = mSrcMatchExtEntries.Contains(aAddress.GetExtended());
314 }
315
316 exit:
317 return hasPending;
318 }
319
320 //---------------------------------------------------------------------------------------------------------------------
321 // Radio::Frame
322
Frame(void)323 Radio::Frame::Frame(void)
324 {
325 ClearAllBytes(*this);
326 mPsdu = &mPsduBuffer[0];
327 }
328
Frame(const Frame & aFrame)329 Radio::Frame::Frame(const Frame &aFrame)
330 {
331 ClearAllBytes(*this);
332 mPsdu = &mPsduBuffer[0];
333
334 mLength = aFrame.mLength;
335 mChannel = aFrame.mChannel;
336 mRadioType = aFrame.mRadioType;
337 memcpy(mPsdu, aFrame.mPsdu, mLength);
338 }
339
340 } // namespace Nexus
341 } // namespace ot
342