1 /*
2 * Copyright (c) 2019, 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" AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 /**
29 * @file
30 * This file implements the radio platform callbacks into OpenThread and default/weak radio platform APIs.
31 */
32
33 #include <openthread/instance.h>
34 #include <openthread/platform/radio.h>
35 #include <openthread/platform/time.h>
36
37 #include "instance/instance.hpp"
38
39 using namespace ot;
40
41 //---------------------------------------------------------------------------------------------------------------------
42 // otPlatRadio callbacks
43
44 #if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
45
otPlatRadioReceiveDone(otInstance * aInstance,otRadioFrame * aFrame,otError aError)46 extern "C" void otPlatRadioReceiveDone(otInstance *aInstance, otRadioFrame *aFrame, otError aError)
47 {
48 Instance &instance = AsCoreType(aInstance);
49 Mac::RxFrame *rxFrame = static_cast<Mac::RxFrame *>(aFrame);
50
51 VerifyOrExit(instance.IsInitialized());
52
53 #if OPENTHREAD_CONFIG_MULTI_RADIO
54 if (rxFrame != nullptr)
55 {
56 rxFrame->SetRadioType(Mac::kRadioTypeIeee802154);
57 }
58 #endif
59
60 instance.Get<Radio::Callbacks>().HandleReceiveDone(rxFrame, aError);
61
62 exit:
63 return;
64 }
65
otPlatRadioTxStarted(otInstance * aInstance,otRadioFrame * aFrame)66 extern "C" void otPlatRadioTxStarted(otInstance *aInstance, otRadioFrame *aFrame)
67 {
68 Instance &instance = AsCoreType(aInstance);
69 Mac::TxFrame &txFrame = *static_cast<Mac::TxFrame *>(aFrame);
70
71 VerifyOrExit(instance.IsInitialized());
72
73 #if OPENTHREAD_CONFIG_MULTI_RADIO
74 txFrame.SetRadioType(Mac::kRadioTypeIeee802154);
75 #endif
76
77 instance.Get<Radio::Callbacks>().HandleTransmitStarted(txFrame);
78
79 exit:
80 return;
81 }
82
otPlatRadioTxDone(otInstance * aInstance,otRadioFrame * aFrame,otRadioFrame * aAckFrame,otError aError)83 extern "C" void otPlatRadioTxDone(otInstance *aInstance, otRadioFrame *aFrame, otRadioFrame *aAckFrame, otError aError)
84 {
85 Instance &instance = AsCoreType(aInstance);
86 Mac::TxFrame &txFrame = *static_cast<Mac::TxFrame *>(aFrame);
87 Mac::RxFrame *ackFrame = static_cast<Mac::RxFrame *>(aAckFrame);
88
89 VerifyOrExit(instance.IsInitialized());
90
91 #if OPENTHREAD_CONFIG_MULTI_RADIO
92 if (ackFrame != nullptr)
93 {
94 ackFrame->SetRadioType(Mac::kRadioTypeIeee802154);
95 }
96
97 txFrame.SetRadioType(Mac::kRadioTypeIeee802154);
98 #endif
99
100 instance.Get<Radio::Callbacks>().HandleTransmitDone(txFrame, ackFrame, aError);
101
102 exit:
103 return;
104 }
105
otPlatRadioEnergyScanDone(otInstance * aInstance,int8_t aEnergyScanMaxRssi)106 extern "C" void otPlatRadioEnergyScanDone(otInstance *aInstance, int8_t aEnergyScanMaxRssi)
107 {
108 Instance &instance = AsCoreType(aInstance);
109
110 VerifyOrExit(instance.IsInitialized());
111 instance.Get<Radio::Callbacks>().HandleEnergyScanDone(aEnergyScanMaxRssi);
112
113 exit:
114 return;
115 }
116
otPlatRadioBusLatencyChanged(otInstance * aInstance)117 extern "C" void otPlatRadioBusLatencyChanged(otInstance *aInstance)
118 {
119 Instance &instance = AsCoreType(aInstance);
120
121 VerifyOrExit(instance.IsInitialized());
122 instance.Get<Radio::Callbacks>().HandleBusLatencyChanged();
123
124 exit:
125 return;
126 }
127
128 #if OPENTHREAD_CONFIG_DIAG_ENABLE
otPlatDiagRadioReceiveDone(otInstance * aInstance,otRadioFrame * aFrame,otError aError)129 extern "C" void otPlatDiagRadioReceiveDone(otInstance *aInstance, otRadioFrame *aFrame, otError aError)
130 {
131 Mac::RxFrame *rxFrame = static_cast<Mac::RxFrame *>(aFrame);
132
133 #if OPENTHREAD_CONFIG_MULTI_RADIO
134 if (rxFrame != nullptr)
135 {
136 rxFrame->SetRadioType(Mac::kRadioTypeIeee802154);
137 }
138 #endif
139
140 AsCoreType(aInstance).Get<Radio::Callbacks>().HandleDiagsReceiveDone(rxFrame, aError);
141 }
142
otPlatDiagRadioTransmitDone(otInstance * aInstance,otRadioFrame * aFrame,otError aError)143 extern "C" void otPlatDiagRadioTransmitDone(otInstance *aInstance, otRadioFrame *aFrame, otError aError)
144 {
145 Mac::TxFrame &txFrame = *static_cast<Mac::TxFrame *>(aFrame);
146 #if OPENTHREAD_RADIO
147 uint8_t channel = txFrame.mInfo.mTxInfo.mRxChannelAfterTxDone;
148
149 if (channel != aFrame->mChannel)
150 {
151 OT_ASSERT((otPlatRadioGetSupportedChannelMask(aInstance) & (1UL << channel)) != 0);
152 IgnoreError(otPlatRadioReceive(aInstance, channel));
153 }
154 #endif
155 #if OPENTHREAD_CONFIG_MULTI_RADIO
156 txFrame.SetRadioType(Mac::kRadioTypeIeee802154);
157 #endif
158
159 AsCoreType(aInstance).Get<Radio::Callbacks>().HandleDiagsTransmitDone(txFrame, aError);
160 }
161 #endif
162
163 #else // #if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
164
otPlatRadioReceiveDone(otInstance *,otRadioFrame *,otError)165 extern "C" void otPlatRadioReceiveDone(otInstance *, otRadioFrame *, otError) {}
166
otPlatRadioTxStarted(otInstance *,otRadioFrame *)167 extern "C" void otPlatRadioTxStarted(otInstance *, otRadioFrame *) {}
168
otPlatRadioTxDone(otInstance *,otRadioFrame *,otRadioFrame *,otError)169 extern "C" void otPlatRadioTxDone(otInstance *, otRadioFrame *, otRadioFrame *, otError) {}
170
otPlatRadioEnergyScanDone(otInstance *,int8_t)171 extern "C" void otPlatRadioEnergyScanDone(otInstance *, int8_t) {}
172
otPlatRadioBusLatencyChanged(otInstance *)173 extern "C" void otPlatRadioBusLatencyChanged(otInstance *) {}
174
175 #if OPENTHREAD_CONFIG_DIAG_ENABLE
otPlatDiagRadioReceiveDone(otInstance *,otRadioFrame *,otError)176 extern "C" void otPlatDiagRadioReceiveDone(otInstance *, otRadioFrame *, otError) {}
177
otPlatDiagRadioTransmitDone(otInstance *,otRadioFrame *,otError)178 extern "C" void otPlatDiagRadioTransmitDone(otInstance *, otRadioFrame *, otError) {}
179 #endif
180
181 #endif // // #if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
182
183 //---------------------------------------------------------------------------------------------------------------------
184 // Default/weak implementation of radio platform APIs
185
otPlatRadioSetAlternateShortAddress(otInstance * aInstance,otShortAddress aShortAddress)186 extern "C" OT_TOOL_WEAK void otPlatRadioSetAlternateShortAddress(otInstance *aInstance, otShortAddress aShortAddress)
187 {
188 OT_UNUSED_VARIABLE(aInstance);
189 OT_UNUSED_VARIABLE(aShortAddress);
190 }
191
otPlatRadioGetSupportedChannelMask(otInstance * aInstance)192 extern "C" OT_TOOL_WEAK uint32_t otPlatRadioGetSupportedChannelMask(otInstance *aInstance)
193 {
194 OT_UNUSED_VARIABLE(aInstance);
195
196 return Radio::kSupportedChannels;
197 }
198
otPlatRadioGetPreferredChannelMask(otInstance * aInstance)199 extern "C" OT_TOOL_WEAK uint32_t otPlatRadioGetPreferredChannelMask(otInstance *aInstance)
200 {
201 return otPlatRadioGetSupportedChannelMask(aInstance);
202 }
203
otPlatRadioGetVersionString(otInstance * aInstance)204 extern "C" OT_TOOL_WEAK const char *otPlatRadioGetVersionString(otInstance *aInstance)
205 {
206 OT_UNUSED_VARIABLE(aInstance);
207 return otGetVersionString();
208 }
209
otPlatRadioGetState(otInstance * aInstance)210 extern "C" OT_TOOL_WEAK otRadioState otPlatRadioGetState(otInstance *aInstance)
211 {
212 OT_UNUSED_VARIABLE(aInstance);
213
214 return OT_RADIO_STATE_INVALID;
215 }
216
otPlatRadioSetMacKey(otInstance * aInstance,uint8_t aKeyIdMode,uint8_t aKeyId,const otMacKeyMaterial * aPrevKey,const otMacKeyMaterial * aCurrKey,const otMacKeyMaterial * aNextKey,otRadioKeyType aKeyType)217 extern "C" OT_TOOL_WEAK void otPlatRadioSetMacKey(otInstance *aInstance,
218 uint8_t aKeyIdMode,
219 uint8_t aKeyId,
220 const otMacKeyMaterial *aPrevKey,
221 const otMacKeyMaterial *aCurrKey,
222 const otMacKeyMaterial *aNextKey,
223 otRadioKeyType aKeyType)
224 {
225 OT_UNUSED_VARIABLE(aInstance);
226 OT_UNUSED_VARIABLE(aKeyIdMode);
227 OT_UNUSED_VARIABLE(aKeyId);
228 OT_UNUSED_VARIABLE(aPrevKey);
229 OT_UNUSED_VARIABLE(aCurrKey);
230 OT_UNUSED_VARIABLE(aNextKey);
231 OT_UNUSED_VARIABLE(aKeyType);
232 }
233
otPlatRadioSetMacFrameCounter(otInstance * aInstance,uint32_t aMacFrameCounter)234 extern "C" OT_TOOL_WEAK void otPlatRadioSetMacFrameCounter(otInstance *aInstance, uint32_t aMacFrameCounter)
235 {
236 OT_UNUSED_VARIABLE(aInstance);
237 OT_UNUSED_VARIABLE(aMacFrameCounter);
238 }
239
otPlatRadioSetMacFrameCounterIfLarger(otInstance * aInstance,uint32_t aMacFrameCounter)240 extern "C" OT_TOOL_WEAK void otPlatRadioSetMacFrameCounterIfLarger(otInstance *aInstance, uint32_t aMacFrameCounter)
241 {
242 // Radio platforms that support `OT_RADIO_CAPS_TRANSMIT_SEC` should
243 // provide this radio platform function.
244 //
245 // This function helps address an edge-case where OT stack may not
246 // yet know the latest frame counter values used by radio platform
247 // (e.g., due to enhanced acks processed by radio platform directly
248 // or due to delay between RCP and host) and then setting the value
249 // from OT stack may cause the counter value on radio to move back
250 // (OT stack will set the counter after appending it in
251 // `LinkFrameCounterTlv` on all radios when multi-radio links
252 // feature is enabled).
253 //
254 // The weak implementation here is intended as a solution to ensure
255 // temporary compatibility with radio platforms that may not yet
256 // implement it. If this weak implementation is used, the edge-case
257 // above may still happen.
258
259 otPlatRadioSetMacFrameCounter(aInstance, aMacFrameCounter);
260 }
261
otPlatTimeGet(void)262 extern "C" OT_TOOL_WEAK uint64_t otPlatTimeGet(void) { return UINT64_MAX; }
263
otPlatRadioGetNow(otInstance * aInstance)264 extern "C" OT_TOOL_WEAK uint64_t otPlatRadioGetNow(otInstance *aInstance)
265 {
266 OT_UNUSED_VARIABLE(aInstance);
267
268 return otPlatTimeGet();
269 }
270
otPlatRadioGetBusSpeed(otInstance * aInstance)271 extern "C" OT_TOOL_WEAK uint32_t otPlatRadioGetBusSpeed(otInstance *aInstance)
272 {
273 OT_UNUSED_VARIABLE(aInstance);
274
275 return 0;
276 }
277
otPlatRadioGetBusLatency(otInstance * aInstance)278 extern "C" OT_TOOL_WEAK uint32_t otPlatRadioGetBusLatency(otInstance *aInstance)
279 {
280 OT_UNUSED_VARIABLE(aInstance);
281
282 return 0;
283 }
284
285 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
otPlatRadioResetCsl(otInstance * aInstance)286 extern "C" OT_TOOL_WEAK otError otPlatRadioResetCsl(otInstance *aInstance)
287 {
288 return otPlatRadioEnableCsl(aInstance, 0, Mac::kShortAddrInvalid, nullptr);
289 }
290 #endif
291
otPlatRadioGetCslAccuracy(otInstance * aInstance)292 extern "C" OT_TOOL_WEAK uint8_t otPlatRadioGetCslAccuracy(otInstance *aInstance)
293 {
294 OT_UNUSED_VARIABLE(aInstance);
295
296 return NumericLimits<uint8_t>::kMax;
297 }
298
otPlatRadioGetCslUncertainty(otInstance * aInstance)299 extern "C" OT_TOOL_WEAK uint8_t otPlatRadioGetCslUncertainty(otInstance *aInstance)
300 {
301 OT_UNUSED_VARIABLE(aInstance);
302
303 return NumericLimits<uint8_t>::kMax;
304 }
305
otPlatRadioGetFemLnaGain(otInstance * aInstance,int8_t * aGain)306 extern "C" OT_TOOL_WEAK otError otPlatRadioGetFemLnaGain(otInstance *aInstance, int8_t *aGain)
307 {
308 OT_UNUSED_VARIABLE(aInstance);
309 OT_UNUSED_VARIABLE(aGain);
310
311 return kErrorNotImplemented;
312 }
313
otPlatRadioSetFemLnaGain(otInstance * aInstance,int8_t aGain)314 extern "C" OT_TOOL_WEAK otError otPlatRadioSetFemLnaGain(otInstance *aInstance, int8_t aGain)
315 {
316 OT_UNUSED_VARIABLE(aInstance);
317 OT_UNUSED_VARIABLE(aGain);
318
319 return kErrorNotImplemented;
320 }
321
otPlatRadioSetChannelMaxTransmitPower(otInstance * aInstance,uint8_t aChannel,int8_t aMaxPower)322 extern "C" OT_TOOL_WEAK otError otPlatRadioSetChannelMaxTransmitPower(otInstance *aInstance,
323 uint8_t aChannel,
324 int8_t aMaxPower)
325 {
326 OT_UNUSED_VARIABLE(aInstance);
327 OT_UNUSED_VARIABLE(aChannel);
328 OT_UNUSED_VARIABLE(aMaxPower);
329
330 return kErrorNotImplemented;
331 }
332
otPlatRadioSetRegion(otInstance * aInstance,uint16_t aRegionCode)333 extern "C" OT_TOOL_WEAK otError otPlatRadioSetRegion(otInstance *aInstance, uint16_t aRegionCode)
334 {
335 OT_UNUSED_VARIABLE(aInstance);
336 OT_UNUSED_VARIABLE(aRegionCode);
337
338 return kErrorNotImplemented;
339 }
340
otPlatRadioGetRegion(otInstance * aInstance,uint16_t * aRegionCode)341 extern "C" OT_TOOL_WEAK otError otPlatRadioGetRegion(otInstance *aInstance, uint16_t *aRegionCode)
342 {
343 OT_UNUSED_VARIABLE(aInstance);
344 OT_UNUSED_VARIABLE(aRegionCode);
345
346 return kErrorNotImplemented;
347 }
348
otPlatRadioReceiveAt(otInstance * aInstance,uint8_t aChannel,uint32_t aStart,uint32_t aDuration)349 extern "C" OT_TOOL_WEAK otError otPlatRadioReceiveAt(otInstance *aInstance,
350 uint8_t aChannel,
351 uint32_t aStart,
352 uint32_t aDuration)
353 {
354 OT_UNUSED_VARIABLE(aInstance);
355 OT_UNUSED_VARIABLE(aChannel);
356 OT_UNUSED_VARIABLE(aStart);
357 OT_UNUSED_VARIABLE(aDuration);
358
359 return kErrorNotImplemented;
360 }
361
otPlatRadioSetRxOnWhenIdle(otInstance * aInstance,bool aEnable)362 extern "C" OT_TOOL_WEAK void otPlatRadioSetRxOnWhenIdle(otInstance *aInstance, bool aEnable)
363 {
364 OT_UNUSED_VARIABLE(aInstance);
365 OT_UNUSED_VARIABLE(aEnable);
366 }
367