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 "common/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
119 #if OPENTHREAD_CONFIG_DIAG_ENABLE
otPlatDiagRadioReceiveDone(otInstance * aInstance,otRadioFrame * aFrame,otError aError)120 extern "C" void otPlatDiagRadioReceiveDone(otInstance *aInstance, otRadioFrame *aFrame, otError aError)
121 {
122 Mac::RxFrame *rxFrame = static_cast<Mac::RxFrame *>(aFrame);
123
124 #if OPENTHREAD_CONFIG_MULTI_RADIO
125 if (rxFrame != nullptr)
126 {
127 rxFrame->SetRadioType(Mac::kRadioTypeIeee802154);
128 }
129 #endif
130
131 AsCoreType(aInstance).Get<Radio::Callbacks>().HandleDiagsReceiveDone(rxFrame, aError);
132 }
133
otPlatDiagRadioTransmitDone(otInstance * aInstance,otRadioFrame * aFrame,otError aError)134 extern "C" void otPlatDiagRadioTransmitDone(otInstance *aInstance, otRadioFrame *aFrame, otError aError)
135 {
136 Mac::TxFrame &txFrame = *static_cast<Mac::TxFrame *>(aFrame);
137
138 #if OPENTHREAD_CONFIG_MULTI_RADIO
139 txFrame.SetRadioType(Mac::kRadioTypeIeee802154);
140 #endif
141
142 AsCoreType(aInstance).Get<Radio::Callbacks>().HandleDiagsTransmitDone(txFrame, aError);
143 }
144 #endif
145
146 #else // #if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
147
otPlatRadioReceiveDone(otInstance *,otRadioFrame *,otError)148 extern "C" void otPlatRadioReceiveDone(otInstance *, otRadioFrame *, otError) {}
149
otPlatRadioTxStarted(otInstance *,otRadioFrame *)150 extern "C" void otPlatRadioTxStarted(otInstance *, otRadioFrame *) {}
151
otPlatRadioTxDone(otInstance *,otRadioFrame *,otRadioFrame *,otError)152 extern "C" void otPlatRadioTxDone(otInstance *, otRadioFrame *, otRadioFrame *, otError) {}
153
otPlatRadioEnergyScanDone(otInstance *,int8_t)154 extern "C" void otPlatRadioEnergyScanDone(otInstance *, int8_t) {}
155
156 #if OPENTHREAD_CONFIG_DIAG_ENABLE
otPlatDiagRadioReceiveDone(otInstance *,otRadioFrame *,otError)157 extern "C" void otPlatDiagRadioReceiveDone(otInstance *, otRadioFrame *, otError) {}
158
otPlatDiagRadioTransmitDone(otInstance *,otRadioFrame *,otError)159 extern "C" void otPlatDiagRadioTransmitDone(otInstance *, otRadioFrame *, otError) {}
160 #endif
161
162 #endif // // #if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
163
164 //---------------------------------------------------------------------------------------------------------------------
165 // Default/weak implementation of radio platform APIs
166
otPlatRadioGetSupportedChannelMask(otInstance * aInstance)167 OT_TOOL_WEAK uint32_t otPlatRadioGetSupportedChannelMask(otInstance *aInstance)
168 {
169 OT_UNUSED_VARIABLE(aInstance);
170
171 return Radio::kSupportedChannels;
172 }
173
otPlatRadioGetPreferredChannelMask(otInstance * aInstance)174 OT_TOOL_WEAK uint32_t otPlatRadioGetPreferredChannelMask(otInstance *aInstance)
175 {
176 return otPlatRadioGetSupportedChannelMask(aInstance);
177 }
178
otPlatRadioGetVersionString(otInstance * aInstance)179 OT_TOOL_WEAK const char *otPlatRadioGetVersionString(otInstance *aInstance)
180 {
181 OT_UNUSED_VARIABLE(aInstance);
182 return otGetVersionString();
183 }
184
otPlatRadioGetState(otInstance * aInstance)185 OT_TOOL_WEAK otRadioState otPlatRadioGetState(otInstance *aInstance)
186 {
187 OT_UNUSED_VARIABLE(aInstance);
188
189 return OT_RADIO_STATE_INVALID;
190 }
191
otPlatRadioSetMacKey(otInstance * aInstance,uint8_t aKeyIdMode,uint8_t aKeyId,const otMacKeyMaterial * aPrevKey,const otMacKeyMaterial * aCurrKey,const otMacKeyMaterial * aNextKey,otRadioKeyType aKeyType)192 OT_TOOL_WEAK void otPlatRadioSetMacKey(otInstance *aInstance,
193 uint8_t aKeyIdMode,
194 uint8_t aKeyId,
195 const otMacKeyMaterial *aPrevKey,
196 const otMacKeyMaterial *aCurrKey,
197 const otMacKeyMaterial *aNextKey,
198 otRadioKeyType aKeyType)
199 {
200 OT_UNUSED_VARIABLE(aInstance);
201 OT_UNUSED_VARIABLE(aKeyIdMode);
202 OT_UNUSED_VARIABLE(aKeyId);
203 OT_UNUSED_VARIABLE(aPrevKey);
204 OT_UNUSED_VARIABLE(aCurrKey);
205 OT_UNUSED_VARIABLE(aNextKey);
206 OT_UNUSED_VARIABLE(aKeyType);
207 }
208
otPlatRadioSetMacFrameCounter(otInstance * aInstance,uint32_t aMacFrameCounter)209 OT_TOOL_WEAK void otPlatRadioSetMacFrameCounter(otInstance *aInstance, uint32_t aMacFrameCounter)
210 {
211 OT_UNUSED_VARIABLE(aInstance);
212 OT_UNUSED_VARIABLE(aMacFrameCounter);
213 }
214
otPlatRadioSetMacFrameCounterIfLarger(otInstance * aInstance,uint32_t aMacFrameCounter)215 OT_TOOL_WEAK void otPlatRadioSetMacFrameCounterIfLarger(otInstance *aInstance, uint32_t aMacFrameCounter)
216 {
217 // Radio platforms that support `OT_RADIO_CAPS_TRANSMIT_SEC` should
218 // provide this radio platform function.
219 //
220 // This function helps address an edge-case where OT stack may not
221 // yet know the latest frame counter values used by radio platform
222 // (e.g., due to enhanced acks processed by radio platform directly
223 // or due to delay between RCP and host) and then setting the value
224 // from OT stack may cause the counter value on radio to move back
225 // (OT stack will set the counter after appending it in
226 // `LinkFrameCounterTlv` on all radios when multi-radio links
227 // feature is enabled).
228 //
229 // The weak implementation here is intended as a solution to ensure
230 // temporary compatibility with radio platforms that may not yet
231 // implement it. If this weak implementation is used, the edge-case
232 // above may still happen.
233
234 otPlatRadioSetMacFrameCounter(aInstance, aMacFrameCounter);
235 }
236
otPlatTimeGet(void)237 OT_TOOL_WEAK uint64_t otPlatTimeGet(void) { return UINT64_MAX; }
238
otPlatRadioGetNow(otInstance * aInstance)239 OT_TOOL_WEAK uint64_t otPlatRadioGetNow(otInstance *aInstance)
240 {
241 OT_UNUSED_VARIABLE(aInstance);
242
243 return UINT64_MAX;
244 }
245
otPlatRadioGetBusSpeed(otInstance * aInstance)246 OT_TOOL_WEAK uint32_t otPlatRadioGetBusSpeed(otInstance *aInstance)
247 {
248 OT_UNUSED_VARIABLE(aInstance);
249
250 return 0;
251 }
252
otPlatRadioGetCslAccuracy(otInstance * aInstance)253 OT_TOOL_WEAK uint8_t otPlatRadioGetCslAccuracy(otInstance *aInstance)
254 {
255 OT_UNUSED_VARIABLE(aInstance);
256
257 return UINT8_MAX;
258 }
259
otPlatRadioGetCslUncertainty(otInstance * aInstance)260 OT_TOOL_WEAK uint8_t otPlatRadioGetCslUncertainty(otInstance *aInstance)
261 {
262 OT_UNUSED_VARIABLE(aInstance);
263
264 return UINT8_MAX;
265 }
266
otPlatRadioGetFemLnaGain(otInstance * aInstance,int8_t * aGain)267 OT_TOOL_WEAK otError otPlatRadioGetFemLnaGain(otInstance *aInstance, int8_t *aGain)
268 {
269 OT_UNUSED_VARIABLE(aInstance);
270 OT_UNUSED_VARIABLE(aGain);
271
272 return kErrorNotImplemented;
273 }
274
otPlatRadioSetFemLnaGain(otInstance * aInstance,int8_t aGain)275 OT_TOOL_WEAK otError otPlatRadioSetFemLnaGain(otInstance *aInstance, int8_t aGain)
276 {
277 OT_UNUSED_VARIABLE(aInstance);
278 OT_UNUSED_VARIABLE(aGain);
279
280 return kErrorNotImplemented;
281 }
282
otPlatRadioSetChannelMaxTransmitPower(otInstance * aInstance,uint8_t aChannel,int8_t aMaxPower)283 OT_TOOL_WEAK otError otPlatRadioSetChannelMaxTransmitPower(otInstance *aInstance, uint8_t aChannel, int8_t aMaxPower)
284 {
285 OT_UNUSED_VARIABLE(aInstance);
286 OT_UNUSED_VARIABLE(aChannel);
287 OT_UNUSED_VARIABLE(aMaxPower);
288
289 return kErrorNotImplemented;
290 }
291
otPlatRadioSetRegion(otInstance * aInstance,uint16_t aRegionCode)292 OT_TOOL_WEAK otError otPlatRadioSetRegion(otInstance *aInstance, uint16_t aRegionCode)
293 {
294 OT_UNUSED_VARIABLE(aInstance);
295 OT_UNUSED_VARIABLE(aRegionCode);
296
297 return kErrorNotImplemented;
298 }
299
otPlatRadioGetRegion(otInstance * aInstance,uint16_t * aRegionCode)300 OT_TOOL_WEAK otError otPlatRadioGetRegion(otInstance *aInstance, uint16_t *aRegionCode)
301 {
302 OT_UNUSED_VARIABLE(aInstance);
303 OT_UNUSED_VARIABLE(aRegionCode);
304
305 return kErrorNotImplemented;
306 }
307
otPlatRadioReceiveAt(otInstance * aInstance,uint8_t aChannel,uint32_t aStart,uint32_t aDuration)308 OT_TOOL_WEAK otError otPlatRadioReceiveAt(otInstance *aInstance, uint8_t aChannel, uint32_t aStart, uint32_t aDuration)
309 {
310 OT_UNUSED_VARIABLE(aInstance);
311 OT_UNUSED_VARIABLE(aChannel);
312 OT_UNUSED_VARIABLE(aStart);
313 OT_UNUSED_VARIABLE(aDuration);
314
315 return kErrorNotImplemented;
316 }
317