ad2ce7991dd270c0064ad5e55cd350140838b54f
[platform/upstream/connectedhomeip.git] / third_party / openthread / repo / examples / platforms / efr32mg12 / radio.c
1 /*
2  *  Copyright (c) 2020, 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"
17  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  *  POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 /**
30  * @file
31  *   This file implements the OpenThread platform abstraction for radio communication.
32  *
33  */
34
35 #include <openthread-core-config.h>
36 #include <openthread/config.h>
37
38 #include <assert.h>
39
40 #include "openthread-system.h"
41 #include <openthread/config.h>
42 #include <openthread/platform/alarm-milli.h>
43 #include <openthread/platform/diag.h>
44 #include <openthread/platform/radio.h>
45
46 #include "common/logging.hpp"
47 #include "utils/code_utils.h"
48
49 #include "utils/soft_source_match_table.h"
50
51 #include "board_config.h"
52 #include "em_cmu.h"
53 #include "em_core.h"
54 #include "em_system.h"
55 #include "hal-config.h"
56 #include "pa_conversions_efr32.h"
57 #include "platform-band.h"
58 #include "rail.h"
59 #include "rail_config.h"
60 #include "rail_ieee802154.h"
61
62 enum
63 {
64     IEEE802154_MIN_LENGTH = 5,
65     IEEE802154_MAX_LENGTH = 127,
66     IEEE802154_ACK_LENGTH = 5,
67
68     // FCF + DSN + dest PANID + dest addr + src PANID + src addr (without security header)
69     IEEE802154_MAX_MHR_LENGTH = 2 + 1 + 2 + 8 + 2 + 8,
70
71     IEEE802154_FRAME_TYPE_MASK        = 0x7,
72     IEEE802154_FRAME_TYPE_ACK         = 0x2,
73     IEEE802154_FRAME_TYPE_MAC_COMMAND = 0x3,
74     IEEE802154_ACK_REQUEST            = 1 << 5,
75     IEEE802154_DSN_OFFSET             = 2,
76     IEEE802154_FCF_OFFSET             = 0,
77 };
78
79 enum
80 {
81     EFR32_RECEIVE_SENSITIVITY    = -100, // dBm
82     EFR32_RSSI_AVERAGING_TIME    = 16,   // us
83     EFR32_RSSI_AVERAGING_TIMEOUT = 300,  // us
84 };
85
86 enum
87 {
88     EFR32_SCHEDULER_SAMPLE_RSSI_PRIORITY = 10, // High priority
89     EFR32_SCHEDULER_TX_PRIORITY          = 10, // High priority
90     EFR32_SCHEDULER_RX_PRIORITY          = 20, // Low priority
91 };
92
93 enum
94 {
95 #if RADIO_CONFIG_2P4GHZ_OQPSK_SUPPORT && RADIO_CONFIG_915MHZ_OQPSK_SUPPORT
96     EFR32_NUM_BAND_CONFIGS = 2,
97 #else
98     EFR32_NUM_BAND_CONFIGS = 1,
99 #endif
100 };
101
102 typedef enum
103 {
104     ENERGY_SCAN_STATUS_IDLE,
105     ENERGY_SCAN_STATUS_IN_PROGRESS,
106     ENERGY_SCAN_STATUS_COMPLETED
107 } energyScanStatus;
108
109 typedef enum
110 {
111     ENERGY_SCAN_MODE_SYNC,
112     ENERGY_SCAN_MODE_ASYNC
113 } energyScanMode;
114
115 RAIL_Handle_t gRailHandle;
116
117 static volatile bool sTransmitBusy = false;
118 static bool          sPromiscuous  = false;
119 static otRadioState  sState        = OT_RADIO_STATE_DISABLED;
120
121 enum
122 {
123     ACKED_WITH_FP_MATCH_LENGTH = 1 + IEEE802154_MAX_MHR_LENGTH, // PHR and MHR
124     ACKED_WITH_FP_SLOTS = 16, // maximum number of Data Request packets in the RX FIFO. Length should be a power of 2.
125 };
126
127 typedef struct efr32AckedWithFP
128 {
129     uint8_t mLength;
130     uint8_t mPacket[ACKED_WITH_FP_MATCH_LENGTH];
131 } efr32AckedWithFP;
132 static bool              sIsSrcMatchEnabled = false;
133 static efr32AckedWithFP  sAckedWithFPFifo[ACKED_WITH_FP_SLOTS];
134 static uint32_t          sAckedWithFPReadIndex;
135 static volatile uint32_t sAckedWithFPWriteIndex;
136
137 static uint8_t      sReceivePsdu[IEEE802154_MAX_LENGTH];
138 static otRadioFrame sReceiveFrame;
139 static otError      sReceiveError;
140
141 static otRadioFrame     sTransmitFrame;
142 static uint8_t          sTransmitPsdu[IEEE802154_MAX_LENGTH];
143 static volatile otError sTransmitError;
144
145 static efr32CommonConfig sCommonConfig;
146 static efr32BandConfig   sBandConfigs[EFR32_NUM_BAND_CONFIGS];
147
148 #if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT
149 static efr32RadioCounters sRailDebugCounters;
150 #endif
151
152 static volatile energyScanStatus sEnergyScanStatus;
153 static volatile int8_t           sEnergyScanResultDbm;
154 static energyScanMode            sEnergyScanMode;
155
156 #define QUARTER_DBM_IN_DBM 4
157 #define US_IN_MS 1000
158
159 static void RAILCb_Generic(RAIL_Handle_t aRailHandle, RAIL_Events_t aEvents);
160
161 static const RAIL_IEEE802154_Config_t sRailIeee802154Config = {
162     .addresses = NULL,
163     .ackConfig =
164         {
165             .enable     = true,
166             .ackTimeout = 864,
167             .rxTransitions =
168                 {
169                     .success = RAIL_RF_STATE_RX,
170                     .error   = RAIL_RF_STATE_RX,
171                 },
172             .txTransitions =
173                 {
174                     .success = RAIL_RF_STATE_RX,
175                     .error   = RAIL_RF_STATE_RX,
176                 },
177         },
178     .timings =
179         {
180             .idleToRx            = 100,
181             .txToRx              = 192 - 10,
182             .idleToTx            = 100,
183             .rxToTx              = 192,
184             .rxSearchTimeout     = 0,
185             .txToRxSearchTimeout = 0,
186         },
187     .framesMask       = RAIL_IEEE802154_ACCEPT_STANDARD_FRAMES,
188     .promiscuousMode  = false,
189     .isPanCoordinator = false,
190 };
191
192 #if RADIO_CONFIG_PA_USES_DCDC
193 RAIL_DECLARE_TX_POWER_DCDC_CURVES(piecewiseSegments, curvesSg, curves24Hp, curves24Lp);
194 #else
195 RAIL_DECLARE_TX_POWER_VBAT_CURVES(piecewiseSegments, curvesSg, curves24Hp, curves24Lp);
196 #endif
197
198 static int8_t sTxPowerDbm = OPENTHREAD_CONFIG_DEFAULT_TRANSMIT_POWER;
199
200 static int8_t sCcaThresholdDbm = -75; // default -75dBm energy detect threshold
201
202 static efr32BandConfig *sCurrentBandConfig = NULL;
203
204 static RAIL_Handle_t efr32RailInit(efr32CommonConfig *aCommonConfig)
205 {
206     RAIL_Status_t status;
207     RAIL_Handle_t handle;
208
209     handle = RAIL_Init(&aCommonConfig->mRailConfig, NULL);
210     assert(handle != NULL);
211
212     status = RAIL_ConfigCal(handle, RAIL_CAL_ALL);
213     assert(status == RAIL_STATUS_NO_ERROR);
214
215     status = RAIL_IEEE802154_Init(handle, &sRailIeee802154Config);
216     assert(status == RAIL_STATUS_NO_ERROR);
217
218     status = RAIL_ConfigEvents(handle, RAIL_EVENTS_ALL,
219                                RAIL_EVENT_RX_ACK_TIMEOUT |                      //
220                                    RAIL_EVENTS_TX_COMPLETION |                  //
221                                    RAIL_EVENT_RX_PACKET_RECEIVED |              //
222                                    RAIL_EVENT_RSSI_AVERAGE_DONE |               //
223                                    RAIL_EVENT_IEEE802154_DATA_REQUEST_COMMAND | //
224                                    RAIL_EVENT_CAL_NEEDED |                      //
225 #if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT
226                                    RAIL_EVENT_CONFIG_SCHEDULED |   //
227                                    RAIL_EVENT_CONFIG_UNSCHEDULED | //
228 #endif
229                                    RAIL_EVENT_SCHEDULER_STATUS //
230     );
231     assert(status == RAIL_STATUS_NO_ERROR);
232
233     uint16_t actualLenth = RAIL_SetTxFifo(handle, aCommonConfig->mRailTxFifo, 0, sizeof(aCommonConfig->mRailTxFifo));
234     assert(actualLenth == sizeof(aCommonConfig->mRailTxFifo));
235
236     return handle;
237 }
238
239 static void efr32RailConfigLoad(efr32BandConfig *aBandConfig)
240 {
241     RAIL_Status_t status;
242 #if HAL_PA_2P4_LOWPOWER == 1
243     RAIL_TxPowerConfig_t txPowerConfig = {RAIL_TX_POWER_MODE_2P4_LP, HAL_PA_VOLTAGE, 10};
244 #else
245     RAIL_TxPowerConfig_t txPowerConfig = {RAIL_TX_POWER_MODE_2P4_HP, HAL_PA_VOLTAGE, 10};
246 #endif
247     if (aBandConfig->mChannelConfig != NULL)
248     {
249         uint16_t firstChannel = RAIL_ConfigChannels(gRailHandle, aBandConfig->mChannelConfig, NULL);
250         assert(firstChannel == aBandConfig->mChannelMin);
251
252         txPowerConfig.mode = RAIL_TX_POWER_MODE_SUBGIG;
253     }
254     else
255     {
256         status = RAIL_IEEE802154_Config2p4GHzRadio(gRailHandle);
257         assert(status == RAIL_STATUS_NO_ERROR);
258     }
259     status = RAIL_ConfigTxPower(gRailHandle, &txPowerConfig);
260     assert(status == RAIL_STATUS_NO_ERROR);
261 }
262
263 static void efr32RadioSetTxPower(int8_t aPowerDbm)
264 {
265     RAIL_Status_t              status;
266     RAIL_TxPowerCurvesConfig_t txPowerCurvesConfig = {curves24Hp, curvesSg, curves24Lp, piecewiseSegments};
267
268     status = RAIL_InitTxPowerCurves(&txPowerCurvesConfig);
269     assert(status == RAIL_STATUS_NO_ERROR);
270
271     status = RAIL_SetTxPowerDbm(gRailHandle, ((RAIL_TxPower_t)aPowerDbm) * 10);
272     assert(status == RAIL_STATUS_NO_ERROR);
273 }
274
275 static efr32BandConfig *efr32RadioGetBandConfig(uint8_t aChannel)
276 {
277     efr32BandConfig *config = NULL;
278
279     for (uint8_t i = 0; i < EFR32_NUM_BAND_CONFIGS; i++)
280     {
281         if ((sBandConfigs[i].mChannelMin <= aChannel) && (aChannel <= sBandConfigs[i].mChannelMax))
282         {
283             config = &sBandConfigs[i];
284             break;
285         }
286     }
287
288     return config;
289 }
290
291 static void efr32ConfigInit(void (*aEventCallback)(RAIL_Handle_t railHandle, RAIL_Events_t events))
292 {
293     sCommonConfig.mRailConfig.eventsCallback = aEventCallback;
294     sCommonConfig.mRailConfig.protocol       = NULL; // only used by Bluetooth stack
295 #if RADIO_CONFIG_DMP_SUPPORT
296     sCommonConfig.mRailConfig.scheduler = &(sCommonConfig.railSchedState);
297 #else
298     sCommonConfig.mRailConfig.scheduler = NULL; // only needed for DMP
299 #endif
300
301     uint8_t index = 0;
302
303 #if RADIO_CONFIG_2P4GHZ_OQPSK_SUPPORT
304     sBandConfigs[index].mChannelConfig = NULL;
305     sBandConfigs[index].mChannelMin    = OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MIN;
306     sBandConfigs[index].mChannelMax    = OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MAX;
307
308     index++;
309 #endif
310
311 #if RADIO_CONFIG_915MHZ_OQPSK_SUPPORT
312     sBandConfigs[index].mChannelConfig = channelConfigs[0];
313     sBandConfigs[index].mChannelMin    = OT_RADIO_915MHZ_OQPSK_CHANNEL_MIN;
314     sBandConfigs[index].mChannelMax    = OT_RADIO_915MHZ_OQPSK_CHANNEL_MAX;
315 #endif
316
317 #if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT
318     memset(&sRailDebugCounters, 0x00, sizeof(efr32RadioCounters));
319 #endif
320
321     gRailHandle = efr32RailInit(&sCommonConfig);
322     assert(gRailHandle != NULL);
323     efr32RailConfigLoad(&(sBandConfigs[0]));
324 }
325
326 void efr32RadioInit(void)
327 {
328     RAIL_Status_t status;
329
330     // check if RAIL_TX_FIFO_SIZE is power of two..
331     assert((RAIL_TX_FIFO_SIZE & (RAIL_TX_FIFO_SIZE - 1)) == 0);
332
333     // check the limits of the RAIL_TX_FIFO_SIZE.
334     assert((RAIL_TX_FIFO_SIZE >= 64) || (RAIL_TX_FIFO_SIZE <= 4096));
335
336     efr32ConfigInit(RAILCb_Generic);
337
338     CMU_ClockEnable(cmuClock_PRS, true);
339
340     status = RAIL_ConfigSleep(gRailHandle, RAIL_SLEEP_CONFIG_TIMERSYNC_ENABLED);
341     assert(status == RAIL_STATUS_NO_ERROR);
342
343     sReceiveFrame.mLength  = 0;
344     sReceiveFrame.mPsdu    = sReceivePsdu;
345     sTransmitFrame.mLength = 0;
346     sTransmitFrame.mPsdu   = sTransmitPsdu;
347
348     sCurrentBandConfig = efr32RadioGetBandConfig(OPENTHREAD_CONFIG_DEFAULT_CHANNEL);
349     assert(sCurrentBandConfig != NULL);
350
351     memset(sAckedWithFPFifo, 0, sizeof(sAckedWithFPFifo));
352     sAckedWithFPWriteIndex = 0;
353     sAckedWithFPReadIndex  = 0;
354
355     efr32RadioSetTxPower(sTxPowerDbm);
356
357     sEnergyScanStatus = ENERGY_SCAN_STATUS_IDLE;
358     sTransmitError    = OT_ERROR_NONE;
359     sTransmitBusy     = false;
360
361     otLogInfoPlat("Initialized", NULL);
362 }
363
364 void efr32RadioDeinit(void)
365 {
366     RAIL_Status_t status;
367
368     RAIL_Idle(gRailHandle, RAIL_IDLE_ABORT, true);
369     status = RAIL_ConfigEvents(gRailHandle, RAIL_EVENTS_ALL, 0);
370     assert(status == RAIL_STATUS_NO_ERROR);
371
372     sCurrentBandConfig = NULL;
373 }
374
375 static otError efr32StartEnergyScan(energyScanMode aMode, uint16_t aChannel, RAIL_Time_t aAveragingTimeUs)
376 {
377     RAIL_Status_t    status;
378     otError          error  = OT_ERROR_NONE;
379     efr32BandConfig *config = NULL;
380
381     otEXPECT_ACTION(sEnergyScanStatus == ENERGY_SCAN_STATUS_IDLE, error = OT_ERROR_BUSY);
382
383     sEnergyScanStatus = ENERGY_SCAN_STATUS_IN_PROGRESS;
384     sEnergyScanMode   = aMode;
385
386     RAIL_Idle(gRailHandle, RAIL_IDLE, true);
387
388     config = efr32RadioGetBandConfig(aChannel);
389     otEXPECT_ACTION(config != NULL, error = OT_ERROR_INVALID_ARGS);
390
391     if (sCurrentBandConfig != config)
392     {
393         efr32RailConfigLoad(config);
394         sCurrentBandConfig = config;
395     }
396
397     RAIL_SchedulerInfo_t scanSchedulerInfo = {.priority        = RADIO_SCHEDULER_CHANNEL_SCAN_PRIORITY,
398                                               .slipTime        = RADIO_SCHEDULER_CHANNEL_SLIP_TIME,
399                                               .transactionTime = aAveragingTimeUs};
400
401     status = RAIL_StartAverageRssi(gRailHandle, aChannel, aAveragingTimeUs, &scanSchedulerInfo);
402     otEXPECT_ACTION(status == RAIL_STATUS_NO_ERROR, error = OT_ERROR_FAILED);
403
404 exit:
405     return error;
406 }
407
408 void otPlatRadioGetIeeeEui64(otInstance *aInstance, uint8_t *aIeeeEui64)
409 {
410     OT_UNUSED_VARIABLE(aInstance);
411
412     uint64_t eui64;
413     uint8_t *eui64Ptr = NULL;
414
415     eui64    = SYSTEM_GetUnique();
416     eui64Ptr = (uint8_t *)&eui64;
417
418     for (uint8_t i = 0; i < OT_EXT_ADDRESS_SIZE; i++)
419     {
420         aIeeeEui64[i] = eui64Ptr[(OT_EXT_ADDRESS_SIZE - 1) - i];
421     }
422 }
423
424 void otPlatRadioSetPanId(otInstance *aInstance, uint16_t aPanId)
425 {
426     OT_UNUSED_VARIABLE(aInstance);
427
428     RAIL_Status_t status;
429
430     otLogInfoPlat("PANID=%X", aPanId);
431
432     utilsSoftSrcMatchSetPanId(aPanId);
433
434     status = RAIL_IEEE802154_SetPanId(gRailHandle, aPanId, 0);
435     assert(status == RAIL_STATUS_NO_ERROR);
436 }
437
438 void otPlatRadioSetExtendedAddress(otInstance *aInstance, const otExtAddress *aAddress)
439 {
440     OT_UNUSED_VARIABLE(aInstance);
441
442     RAIL_Status_t status;
443
444     otLogInfoPlat("ExtAddr=%X%X%X%X%X%X%X%X", aAddress->m8[7], aAddress->m8[6], aAddress->m8[5], aAddress->m8[4],
445                   aAddress->m8[3], aAddress->m8[2], aAddress->m8[1], aAddress->m8[0]);
446
447     status = RAIL_IEEE802154_SetLongAddress(gRailHandle, (uint8_t *)aAddress->m8, 0);
448     assert(status == RAIL_STATUS_NO_ERROR);
449 }
450
451 void otPlatRadioSetShortAddress(otInstance *aInstance, uint16_t aAddress)
452 {
453     OT_UNUSED_VARIABLE(aInstance);
454
455     RAIL_Status_t status;
456
457     otLogInfoPlat("ShortAddr=%X", aAddress);
458
459     status = RAIL_IEEE802154_SetShortAddress(gRailHandle, aAddress, 0);
460     assert(status == RAIL_STATUS_NO_ERROR);
461 }
462
463 bool otPlatRadioIsEnabled(otInstance *aInstance)
464 {
465     OT_UNUSED_VARIABLE(aInstance);
466
467     return (sState != OT_RADIO_STATE_DISABLED);
468 }
469
470 otError otPlatRadioEnable(otInstance *aInstance)
471 {
472     otEXPECT(!otPlatRadioIsEnabled(aInstance));
473
474     otLogInfoPlat("State=OT_RADIO_STATE_SLEEP", NULL);
475     sState = OT_RADIO_STATE_SLEEP;
476
477 exit:
478     return OT_ERROR_NONE;
479 }
480
481 otError otPlatRadioDisable(otInstance *aInstance)
482 {
483     otEXPECT(otPlatRadioIsEnabled(aInstance));
484
485     otLogInfoPlat("State=OT_RADIO_STATE_DISABLED", NULL);
486     sState = OT_RADIO_STATE_DISABLED;
487
488 exit:
489     return OT_ERROR_NONE;
490 }
491
492 otError otPlatRadioSleep(otInstance *aInstance)
493 {
494     OT_UNUSED_VARIABLE(aInstance);
495
496     otError error = OT_ERROR_NONE;
497
498     otEXPECT_ACTION((sState != OT_RADIO_STATE_TRANSMIT) && (sState != OT_RADIO_STATE_DISABLED),
499                     error = OT_ERROR_INVALID_STATE);
500
501     otLogInfoPlat("State=OT_RADIO_STATE_SLEEP", NULL);
502
503     RAIL_Idle(gRailHandle, RAIL_IDLE, true);
504     sState = OT_RADIO_STATE_SLEEP;
505
506 exit:
507     return error;
508 }
509
510 otError otPlatRadioReceive(otInstance *aInstance, uint8_t aChannel)
511 {
512     otError          error = OT_ERROR_NONE;
513     RAIL_Status_t    status;
514     efr32BandConfig *config;
515
516     OT_UNUSED_VARIABLE(aInstance);
517     otEXPECT_ACTION(sState != OT_RADIO_STATE_DISABLED, error = OT_ERROR_INVALID_STATE);
518
519     config = efr32RadioGetBandConfig(aChannel);
520     otEXPECT_ACTION(config != NULL, error = OT_ERROR_INVALID_ARGS);
521
522     if (sCurrentBandConfig != config)
523     {
524         RAIL_Idle(gRailHandle, RAIL_IDLE, true);
525         efr32RailConfigLoad(config);
526         sCurrentBandConfig = config;
527     }
528
529     RAIL_SchedulerInfo_t bgRxSchedulerInfo = {
530         .priority = RADIO_SCHEDULER_BACKGROUND_RX_PRIORITY,
531         // sliptime/transaction time is not used for bg rx
532     };
533
534     status = RAIL_StartRx(gRailHandle, aChannel, &bgRxSchedulerInfo);
535     otEXPECT_ACTION(status == RAIL_STATUS_NO_ERROR, error = OT_ERROR_FAILED);
536
537     otLogInfoPlat("State=OT_RADIO_STATE_RECEIVE", NULL);
538     sState                 = OT_RADIO_STATE_RECEIVE;
539     sReceiveFrame.mChannel = aChannel;
540
541 exit:
542     return error;
543 }
544
545 otError otPlatRadioTransmit(otInstance *aInstance, otRadioFrame *aFrame)
546 {
547     otError           error      = OT_ERROR_NONE;
548     RAIL_CsmaConfig_t csmaConfig = RAIL_CSMA_CONFIG_802_15_4_2003_2p4_GHz_OQPSK_CSMA;
549     RAIL_TxOptions_t  txOptions  = RAIL_TX_OPTIONS_DEFAULT;
550     efr32BandConfig * config;
551     RAIL_Status_t     status;
552     uint8_t           frameLength;
553
554 #if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT
555     sRailDebugCounters.mRailPlatTxTriggered++;
556 #endif
557
558     assert(sTransmitBusy == false);
559
560     otEXPECT_ACTION((sState != OT_RADIO_STATE_DISABLED) && (sState != OT_RADIO_STATE_TRANSMIT),
561                     error = OT_ERROR_INVALID_STATE);
562
563     config = efr32RadioGetBandConfig(aFrame->mChannel);
564     otEXPECT_ACTION(config != NULL, error = OT_ERROR_INVALID_ARGS);
565
566     sState         = OT_RADIO_STATE_TRANSMIT;
567     sTransmitError = OT_ERROR_NONE;
568     sTransmitBusy  = true;
569
570     if (sCurrentBandConfig != config)
571     {
572         RAIL_Idle(gRailHandle, RAIL_IDLE, true);
573         efr32RailConfigLoad(config);
574         sCurrentBandConfig = config;
575     }
576
577     frameLength = (uint8_t)aFrame->mLength;
578     RAIL_WriteTxFifo(gRailHandle, &frameLength, sizeof frameLength, true);
579     RAIL_WriteTxFifo(gRailHandle, aFrame->mPsdu, frameLength - 2, false);
580
581     RAIL_SchedulerInfo_t txSchedulerInfo = {
582         .priority        = RADIO_SCHEDULER_TX_PRIORITY,
583         .slipTime        = RADIO_SCHEDULER_CHANNEL_SLIP_TIME,
584         .transactionTime = 0, // will be calculated later if DMP is used
585     };
586
587     if (aFrame->mPsdu[0] & IEEE802154_ACK_REQUEST)
588     {
589         txOptions |= RAIL_TX_OPTION_WAIT_FOR_ACK;
590
591 #if RADIO_CONFIG_DMP_SUPPORT
592         // time we wait for ACK
593         if (RAIL_GetSymbolRate(gRailHandle) > 0)
594         {
595             txSchedulerInfo.transactionTime += 12 * 1e6 / RAIL_GetSymbolRate(gRailHandle);
596         }
597         else
598         {
599             txSchedulerInfo.transactionTime += 12 * RADIO_TIMING_DEFAULT_SYMBOLTIME_US;
600         }
601 #endif
602     }
603
604 #if RADIO_CONFIG_DMP_SUPPORT
605     // time needed for the frame itself
606     // 4B preamble, 1B SFD, 1B PHR is not counted in frameLength
607     if (RAIL_GetBitRate(gRailHandle) > 0)
608     {
609         txSchedulerInfo.transactionTime = (frameLength + 4 + 1 + 1) * 8 * 1e6 / RAIL_GetBitRate(gRailHandle);
610     }
611     else
612     { // assume 250kbps
613         txSchedulerInfo.transactionTime = (frameLength + 4 + 1 + 1) * RADIO_TIMING_DEFAULT_BYTETIME_US;
614     }
615 #endif
616
617     if (aFrame->mInfo.mTxInfo.mCsmaCaEnabled)
618     {
619 #if RADIO_CONFIG_DMP_SUPPORT
620         // time needed for CSMA/CA
621         txSchedulerInfo.transactionTime += RADIO_TIMING_CSMA_OVERHEAD_US;
622 #endif
623         csmaConfig.csmaTries    = aFrame->mInfo.mTxInfo.mMaxCsmaBackoffs;
624         csmaConfig.ccaThreshold = sCcaThresholdDbm;
625
626         status = RAIL_StartCcaCsmaTx(gRailHandle, aFrame->mChannel, txOptions, &csmaConfig, &txSchedulerInfo);
627     }
628     else
629     {
630         status = RAIL_StartTx(gRailHandle, aFrame->mChannel, txOptions, &txSchedulerInfo);
631     }
632
633     if (status == RAIL_STATUS_NO_ERROR)
634     {
635 #if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT
636         sRailDebugCounters.mRailTxStarted++;
637 #endif
638         otPlatRadioTxStarted(aInstance, aFrame);
639     }
640     else
641     {
642 #if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT
643         sRailDebugCounters.mRailTxStartFailed++;
644 #endif
645         sTransmitError = OT_ERROR_CHANNEL_ACCESS_FAILURE;
646         sTransmitBusy  = false;
647         otSysEventSignalPending();
648     }
649
650 exit:
651     return error;
652 }
653
654 otRadioFrame *otPlatRadioGetTransmitBuffer(otInstance *aInstance)
655 {
656     OT_UNUSED_VARIABLE(aInstance);
657
658     return &sTransmitFrame;
659 }
660
661 int8_t otPlatRadioGetRssi(otInstance *aInstance)
662 {
663     otError  error;
664     uint32_t start;
665     int8_t   rssi = OT_RADIO_RSSI_INVALID;
666
667     OT_UNUSED_VARIABLE(aInstance);
668
669     error = efr32StartEnergyScan(ENERGY_SCAN_MODE_SYNC, sReceiveFrame.mChannel, EFR32_RSSI_AVERAGING_TIME);
670     otEXPECT(error == OT_ERROR_NONE);
671
672     start = RAIL_GetTime();
673
674     // waiting for the event RAIL_EVENT_RSSI_AVERAGE_DONE
675     while (sEnergyScanStatus == ENERGY_SCAN_STATUS_IN_PROGRESS &&
676            ((RAIL_GetTime() - start) < EFR32_RSSI_AVERAGING_TIMEOUT))
677         ;
678
679     if (sEnergyScanStatus == ENERGY_SCAN_STATUS_COMPLETED)
680     {
681         rssi = sEnergyScanResultDbm;
682     }
683
684     sEnergyScanStatus = ENERGY_SCAN_STATUS_IDLE;
685 exit:
686     return rssi;
687 }
688
689 otRadioCaps otPlatRadioGetCaps(otInstance *aInstance)
690 {
691     OT_UNUSED_VARIABLE(aInstance);
692
693     return OT_RADIO_CAPS_ACK_TIMEOUT | OT_RADIO_CAPS_CSMA_BACKOFF | OT_RADIO_CAPS_ENERGY_SCAN;
694 }
695
696 bool otPlatRadioGetPromiscuous(otInstance *aInstance)
697 {
698     OT_UNUSED_VARIABLE(aInstance);
699
700     return sPromiscuous;
701 }
702
703 void otPlatRadioSetPromiscuous(otInstance *aInstance, bool aEnable)
704 {
705     OT_UNUSED_VARIABLE(aInstance);
706
707     RAIL_Status_t status;
708
709     sPromiscuous = aEnable;
710
711     status = RAIL_IEEE802154_SetPromiscuousMode(gRailHandle, aEnable);
712     assert(status == RAIL_STATUS_NO_ERROR);
713 }
714
715 void otPlatRadioEnableSrcMatch(otInstance *aInstance, bool aEnable)
716 {
717     OT_UNUSED_VARIABLE(aInstance);
718
719     // set Frame Pending bit for all outgoing ACKs if aEnable is false
720     sIsSrcMatchEnabled = aEnable;
721 }
722
723 static bool sAckedWithFPFifoIsFull(void)
724 {
725     return (uint32_t)(sAckedWithFPWriteIndex - sAckedWithFPReadIndex) == otARRAY_LENGTH(sAckedWithFPFifo);
726 }
727
728 static bool sAckedWithFPFifoIsEmpty(void)
729 {
730     return (uint32_t)(sAckedWithFPWriteIndex - sAckedWithFPReadIndex) == 0;
731 }
732
733 static efr32AckedWithFP *sAckedWithFPFifoGetWriteSlot(void)
734 {
735     uint32_t idx = sAckedWithFPWriteIndex & (otARRAY_LENGTH(sAckedWithFPFifo) - 1);
736     return &sAckedWithFPFifo[idx];
737 }
738
739 static const efr32AckedWithFP *sAckedWithFPFifoGetReadSlot(void)
740 {
741     uint32_t idx = sAckedWithFPReadIndex & (otARRAY_LENGTH(sAckedWithFPFifo) - 1);
742     return &sAckedWithFPFifo[idx];
743 }
744
745 static void insertIeee802154DataRequestCommand(RAIL_Handle_t aRailHandle)
746 {
747     assert(!sAckedWithFPFifoIsFull());
748     efr32AckedWithFP *const slot = sAckedWithFPFifoGetWriteSlot();
749
750     RAIL_RxPacketInfo_t packetInfo;
751
752     RAIL_GetRxIncomingPacketInfo(aRailHandle, &packetInfo);
753     assert(packetInfo.packetBytes >= 4); // PHR + FCF + DSN
754
755     if (packetInfo.packetBytes > sizeof(slot->mPacket))
756     {
757         packetInfo.packetBytes = sizeof(slot->mPacket);
758         if (packetInfo.firstPortionBytes >= sizeof(slot->mPacket))
759         {
760             packetInfo.firstPortionBytes = sizeof(slot->mPacket);
761             packetInfo.lastPortionData   = NULL;
762         }
763     }
764     slot->mLength = packetInfo.packetBytes;
765     RAIL_CopyRxPacket(slot->mPacket, &packetInfo);
766
767     ++sAckedWithFPWriteIndex;
768 }
769
770 static bool wasAckedWithFramePending(const uint8_t *aPsdu, uint8_t aPsduLength)
771 {
772     bool     ackedWithFramePending = false;
773     uint16_t fcf                   = aPsdu[IEEE802154_FCF_OFFSET] | (aPsdu[IEEE802154_FCF_OFFSET + 1] << 8);
774
775     otEXPECT((fcf & IEEE802154_FRAME_TYPE_MASK) == IEEE802154_FRAME_TYPE_MAC_COMMAND);
776
777     while (!(ackedWithFramePending || sAckedWithFPFifoIsEmpty()))
778     {
779         const efr32AckedWithFP *const slot = sAckedWithFPFifoGetReadSlot();
780         if ((slot->mPacket[0] == aPsduLength) && (memcmp(slot->mPacket + 1, aPsdu, slot->mLength - 1) == 0))
781         {
782             ackedWithFramePending = true;
783         }
784         ++sAckedWithFPReadIndex;
785     }
786
787 exit:
788     return ackedWithFramePending;
789 }
790
791 static void processNextRxPacket(otInstance *aInstance)
792 {
793     RAIL_RxPacketHandle_t  packetHandle = RAIL_RX_PACKET_HANDLE_INVALID;
794     RAIL_RxPacketInfo_t    packetInfo;
795     RAIL_RxPacketDetails_t packetDetails;
796     RAIL_Status_t          status;
797     uint16_t               length;
798
799     packetHandle = RAIL_GetRxPacketInfo(gRailHandle, RAIL_RX_PACKET_HANDLE_OLDEST, &packetInfo);
800
801     otEXPECT_ACTION(packetHandle != RAIL_RX_PACKET_HANDLE_INVALID &&
802                         packetInfo.packetStatus == RAIL_RX_PACKET_READY_SUCCESS,
803                     packetHandle = RAIL_RX_PACKET_HANDLE_INVALID);
804
805     status = RAIL_GetRxPacketDetailsAlt(gRailHandle, packetHandle, &packetDetails);
806     otEXPECT(status == RAIL_STATUS_NO_ERROR);
807
808     length = packetInfo.packetBytes + 1;
809
810     // check the length in recv packet info structure; RAIL should take care of this.
811     assert(length == packetInfo.firstPortionData[0]);
812
813     // check the length validity of recv packet; RAIL should take care of this.
814     assert(length >= IEEE802154_MIN_LENGTH && length <= IEEE802154_MAX_LENGTH);
815
816     otLogInfoPlat("Received data:%d", length);
817
818     // skip length byte
819     assert(packetInfo.firstPortionBytes > 0);
820     packetInfo.firstPortionData++;
821     packetInfo.firstPortionBytes--;
822     packetInfo.packetBytes--;
823
824     // read packet
825     RAIL_CopyRxPacket(sReceiveFrame.mPsdu, &packetInfo);
826
827     status = RAIL_ReleaseRxPacket(gRailHandle, packetHandle);
828     if (status == RAIL_STATUS_NO_ERROR)
829     {
830         packetHandle = RAIL_RX_PACKET_HANDLE_INVALID;
831     }
832
833     sReceiveFrame.mLength = length;
834
835     if (packetDetails.isAck)
836     {
837         assert((length == IEEE802154_ACK_LENGTH) &&
838                (sReceiveFrame.mPsdu[0] & IEEE802154_FRAME_TYPE_MASK) == IEEE802154_FRAME_TYPE_ACK);
839
840         RAIL_YieldRadio(gRailHandle);
841         sTransmitBusy = false;
842
843         if (sReceiveFrame.mPsdu[IEEE802154_DSN_OFFSET] == sTransmitFrame.mPsdu[IEEE802154_DSN_OFFSET])
844         {
845             sTransmitError = OT_ERROR_NONE;
846         }
847         else
848         {
849             sTransmitError = OT_ERROR_NO_ACK;
850         }
851     }
852     else
853     {
854         // signal MAC layer for each received frame if promiscuous is enabled
855         // otherwise only signal MAC layer for non-ACK frame
856         otEXPECT(sPromiscuous || (length != IEEE802154_ACK_LENGTH));
857
858         sReceiveError = OT_ERROR_NONE;
859
860         sReceiveFrame.mInfo.mRxInfo.mRssi = packetDetails.rssi;
861         sReceiveFrame.mInfo.mRxInfo.mLqi  = packetDetails.lqi;
862
863         // Get the timestamp when the SFD was received
864         assert(packetDetails.timeReceived.timePosition != RAIL_PACKET_TIME_INVALID);
865         packetDetails.timeReceived.totalPacketBytes = length + 1;
866
867         status = RAIL_GetRxTimeSyncWordEndAlt(gRailHandle, &packetDetails);
868         assert(status == RAIL_STATUS_NO_ERROR);
869         sReceiveFrame.mInfo.mRxInfo.mTimestamp = packetDetails.timeReceived.packetTime;
870
871         // Set this flag only when the packet is really acknowledged with frame pending set.
872         sReceiveFrame.mInfo.mRxInfo.mAckedWithFramePending =
873             wasAckedWithFramePending(sReceiveFrame.mPsdu, sReceiveFrame.mLength);
874
875 #if OPENTHREAD_CONFIG_DIAG_ENABLE
876
877         if (otPlatDiagModeGet())
878         {
879             otPlatDiagRadioReceiveDone(aInstance, &sReceiveFrame, sReceiveError);
880         }
881         else
882 #endif
883         {
884             otLogInfoPlat("Received %d bytes", sReceiveFrame.mLength);
885             otPlatRadioReceiveDone(aInstance, &sReceiveFrame, sReceiveError);
886 #if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT
887             sRailDebugCounters.mRailPlatRadioReceiveDoneCbCount++;
888 #endif
889         }
890     }
891
892     otSysEventSignalPending();
893
894 exit:
895
896     if (packetHandle != RAIL_RX_PACKET_HANDLE_INVALID)
897     {
898         RAIL_ReleaseRxPacket(gRailHandle, packetHandle);
899     }
900 }
901
902 static void ieee802154DataRequestCommand(RAIL_Handle_t aRailHandle)
903 {
904     RAIL_Status_t status;
905
906     if (sIsSrcMatchEnabled)
907     {
908         RAIL_IEEE802154_Address_t sourceAddress;
909
910         status = RAIL_IEEE802154_GetAddress(aRailHandle, &sourceAddress);
911         assert(status == RAIL_STATUS_NO_ERROR);
912
913         if ((sourceAddress.length == RAIL_IEEE802154_LongAddress &&
914              utilsSoftSrcMatchExtFindEntry((otExtAddress *)sourceAddress.longAddress) >= 0) ||
915             (sourceAddress.length == RAIL_IEEE802154_ShortAddress &&
916              utilsSoftSrcMatchShortFindEntry(sourceAddress.shortAddress) >= 0))
917         {
918             status = RAIL_IEEE802154_SetFramePending(aRailHandle);
919             assert(status == RAIL_STATUS_NO_ERROR);
920             insertIeee802154DataRequestCommand(aRailHandle);
921         }
922     }
923     else
924     {
925         status = RAIL_IEEE802154_SetFramePending(aRailHandle);
926         assert(status == RAIL_STATUS_NO_ERROR);
927         insertIeee802154DataRequestCommand(aRailHandle);
928     }
929 }
930
931 static void RAILCb_Generic(RAIL_Handle_t aRailHandle, RAIL_Events_t aEvents)
932 {
933 #if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT
934     if (aEvents & RAIL_EVENT_CONFIG_SCHEDULED)
935     {
936         sRailDebugCounters.mRailEventConfigScheduled++;
937     }
938     if (aEvents & RAIL_EVENT_CONFIG_UNSCHEDULED)
939     {
940         sRailDebugCounters.mRailEventConfigUnScheduled++;
941     }
942 #endif
943     if (aEvents & RAIL_EVENT_IEEE802154_DATA_REQUEST_COMMAND)
944     {
945         ieee802154DataRequestCommand(aRailHandle);
946     }
947
948     if (aEvents & RAIL_EVENTS_TX_COMPLETION)
949     {
950         if (aEvents & RAIL_EVENT_TX_PACKET_SENT)
951         {
952             if ((sTransmitFrame.mPsdu[0] & IEEE802154_ACK_REQUEST) == 0)
953             {
954                 RAIL_YieldRadio(aRailHandle);
955                 sTransmitError = OT_ERROR_NONE;
956                 sTransmitBusy  = false;
957             }
958 #if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT
959             sRailDebugCounters.mRailEventPacketSent++;
960 #endif
961         }
962         else if (aEvents & RAIL_EVENT_TX_CHANNEL_BUSY)
963         {
964             RAIL_YieldRadio(aRailHandle);
965             sTransmitError = OT_ERROR_CHANNEL_ACCESS_FAILURE;
966             sTransmitBusy  = false;
967 #if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT
968             sRailDebugCounters.mRailEventChannelBusy++;
969 #endif
970         }
971         else
972         {
973             RAIL_YieldRadio(aRailHandle);
974             sTransmitError = OT_ERROR_ABORT;
975             sTransmitBusy  = false;
976 #if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT
977             sRailDebugCounters.mRailEventTxAbort++;
978 #endif
979         }
980     }
981
982     if (aEvents & RAIL_EVENT_RX_ACK_TIMEOUT)
983     {
984         RAIL_YieldRadio(aRailHandle);
985         sTransmitError = OT_ERROR_NO_ACK;
986         sTransmitBusy  = false;
987 #if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT
988         sRailDebugCounters.mRailEventNoAck++;
989 #endif
990     }
991
992     if (aEvents & RAIL_EVENT_RX_PACKET_RECEIVED)
993     {
994         RAIL_HoldRxPacket(aRailHandle);
995 #if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT
996         sRailDebugCounters.mRailEventPacketReceived++;
997 #endif
998     }
999
1000     if (aEvents & RAIL_EVENT_CAL_NEEDED)
1001     {
1002         RAIL_Status_t status;
1003
1004         status = RAIL_Calibrate(aRailHandle, NULL, RAIL_CAL_ALL_PENDING);
1005         assert(status == RAIL_STATUS_NO_ERROR);
1006
1007 #if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT
1008         sRailDebugCounters.mRailEventCalNeeded++;
1009 #endif
1010     }
1011
1012     if (aEvents & RAIL_EVENT_RSSI_AVERAGE_DONE)
1013     {
1014         const int16_t energyScanResultQuarterDbm = RAIL_GetAverageRssi(aRailHandle);
1015         RAIL_YieldRadio(aRailHandle);
1016
1017         sEnergyScanStatus = ENERGY_SCAN_STATUS_COMPLETED;
1018
1019         if (energyScanResultQuarterDbm == RAIL_RSSI_INVALID)
1020         {
1021             sEnergyScanResultDbm = OT_RADIO_RSSI_INVALID;
1022         }
1023         else
1024         {
1025             sEnergyScanResultDbm = energyScanResultQuarterDbm / QUARTER_DBM_IN_DBM;
1026         }
1027
1028 #if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT
1029         sRailDebugCounters.mRailPlatRadioEnergyScanDoneCbCount++;
1030 #endif
1031     }
1032     if (aEvents & RAIL_EVENT_SCHEDULER_STATUS)
1033     {
1034         RAIL_SchedulerStatus_t status = RAIL_GetSchedulerStatus(aRailHandle);
1035
1036         assert(status != RAIL_SCHEDULER_STATUS_INTERNAL_ERROR);
1037
1038         if (status == RAIL_SCHEDULER_STATUS_CCA_CSMA_TX_FAIL || status == RAIL_SCHEDULER_STATUS_SINGLE_TX_FAIL ||
1039             status == RAIL_SCHEDULER_STATUS_SCHEDULED_TX_FAIL ||
1040             (status == RAIL_SCHEDULER_STATUS_SCHEDULE_FAIL && sTransmitBusy) ||
1041             (status == RAIL_SCHEDULER_STATUS_EVENT_INTERRUPTED && sTransmitBusy))
1042         {
1043             sTransmitError = OT_ERROR_ABORT;
1044             sTransmitBusy  = false;
1045 #if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT
1046             sRailDebugCounters.mRailEventSchedulerStatusError++;
1047 #endif
1048         }
1049         else if (status == RAIL_SCHEDULER_STATUS_AVERAGE_RSSI_FAIL)
1050         {
1051             sEnergyScanStatus    = ENERGY_SCAN_STATUS_COMPLETED;
1052             sEnergyScanResultDbm = OT_RADIO_RSSI_INVALID;
1053         }
1054 #if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT
1055         else if (sTransmitBusy)
1056         {
1057             sRailDebugCounters.mRailEventsSchedulerStatusLastStatus = status;
1058             sRailDebugCounters.mRailEventsSchedulerStatusTransmitBusy++;
1059         }
1060 #endif
1061     }
1062
1063     otSysEventSignalPending();
1064 }
1065
1066 otError otPlatRadioEnergyScan(otInstance *aInstance, uint8_t aScanChannel, uint16_t aScanDuration)
1067 {
1068     OT_UNUSED_VARIABLE(aInstance);
1069
1070     return efr32StartEnergyScan(ENERGY_SCAN_MODE_ASYNC, aScanChannel, (RAIL_Time_t)aScanDuration * US_IN_MS);
1071 }
1072
1073 void efr32RadioProcess(otInstance *aInstance)
1074 {
1075     // We should process the received packet first. Adding it at the end of this function,
1076     // will delay the stack notification until the next call to efr32RadioProcess()
1077     processNextRxPacket(aInstance);
1078
1079     if (sState == OT_RADIO_STATE_TRANSMIT && sTransmitBusy == false)
1080     {
1081         if (sTransmitError != OT_ERROR_NONE)
1082         {
1083             otLogDebgPlat("Transmit failed ErrorCode=%d", sTransmitError);
1084         }
1085
1086         sState = OT_RADIO_STATE_RECEIVE;
1087 #if OPENTHREAD_CONFIG_DIAG_ENABLE
1088         if (otPlatDiagModeGet())
1089         {
1090             otPlatDiagRadioTransmitDone(aInstance, &sTransmitFrame, sTransmitError);
1091         }
1092         else
1093 #endif
1094             if (((sTransmitFrame.mPsdu[0] & IEEE802154_ACK_REQUEST) == 0) || (sTransmitError != OT_ERROR_NONE))
1095         {
1096             otPlatRadioTxDone(aInstance, &sTransmitFrame, NULL, sTransmitError);
1097         }
1098         else
1099         {
1100             otPlatRadioTxDone(aInstance, &sTransmitFrame, &sReceiveFrame, sTransmitError);
1101         }
1102
1103 #if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT
1104         sRailDebugCounters.mRailPlatRadioTxDoneCbCount++;
1105 #endif
1106
1107         otSysEventSignalPending();
1108     }
1109     else if (sEnergyScanMode == ENERGY_SCAN_MODE_ASYNC && sEnergyScanStatus == ENERGY_SCAN_STATUS_COMPLETED)
1110     {
1111         sEnergyScanStatus = ENERGY_SCAN_STATUS_IDLE;
1112         otPlatRadioEnergyScanDone(aInstance, sEnergyScanResultDbm);
1113         otSysEventSignalPending();
1114
1115 #if RADIO_CONFIG_DEBUG_COUNTERS_SUPPORT
1116         sRailDebugCounters.mRailEventEnergyScanCompleted++;
1117 #endif
1118     }
1119 }
1120
1121 otError otPlatRadioGetTransmitPower(otInstance *aInstance, int8_t *aPower)
1122 {
1123     OT_UNUSED_VARIABLE(aInstance);
1124
1125     otError error = OT_ERROR_NONE;
1126
1127     otEXPECT_ACTION(aPower != NULL, error = OT_ERROR_INVALID_ARGS);
1128     *aPower = sTxPowerDbm;
1129
1130 exit:
1131     return error;
1132 }
1133
1134 otError otPlatRadioSetTransmitPower(otInstance *aInstance, int8_t aPower)
1135 {
1136     OT_UNUSED_VARIABLE(aInstance);
1137
1138     RAIL_Status_t status;
1139
1140     status = RAIL_SetTxPowerDbm(gRailHandle, ((RAIL_TxPower_t)aPower) * 10);
1141     assert(status == RAIL_STATUS_NO_ERROR);
1142
1143     sTxPowerDbm = aPower;
1144
1145     return OT_ERROR_NONE;
1146 }
1147
1148 otError otPlatRadioGetCcaEnergyDetectThreshold(otInstance *aInstance, int8_t *aThreshold)
1149 {
1150     OT_UNUSED_VARIABLE(aInstance);
1151
1152     otError error = OT_ERROR_NONE;
1153     otEXPECT_ACTION(aThreshold != NULL, error = OT_ERROR_INVALID_ARGS);
1154
1155     *aThreshold = sCcaThresholdDbm;
1156
1157 exit:
1158     return error;
1159 }
1160
1161 otError otPlatRadioSetCcaEnergyDetectThreshold(otInstance *aInstance, int8_t aThreshold)
1162 {
1163     OT_UNUSED_VARIABLE(aInstance);
1164
1165     sCcaThresholdDbm = aThreshold;
1166
1167     return OT_ERROR_NONE;
1168 }
1169
1170 int8_t otPlatRadioGetReceiveSensitivity(otInstance *aInstance)
1171 {
1172     OT_UNUSED_VARIABLE(aInstance);
1173
1174     return EFR32_RECEIVE_SENSITIVITY;
1175 }