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