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