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