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