1 /*
2  *  Copyright (c) 2016-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"
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 #include "platform-simulation.h"
30 
31 #include <errno.h>
32 #include <sys/time.h>
33 
34 #include <openthread/cli.h>
35 #include <openthread/dataset.h>
36 #include <openthread/link.h>
37 #include <openthread/random_noncrypto.h>
38 #include <openthread/platform/alarm-micro.h>
39 #include <openthread/platform/alarm-milli.h>
40 #include <openthread/platform/diag.h>
41 #include <openthread/platform/radio.h>
42 #include <openthread/platform/time.h>
43 
44 #include "simul_utils.h"
45 #include "lib/platform/exit_code.h"
46 #include "utils/code_utils.h"
47 #include "utils/link_metrics.h"
48 #include "utils/mac_frame.h"
49 #include "utils/soft_source_match_table.h"
50 
51 enum
52 {
53     IEEE802154_ACK_LENGTH = 5,
54 
55     IEEE802154_FRAME_TYPE_ACK = 2 << 0,
56 
57     IEEE802154_FRAME_PENDING = 1 << 4,
58 };
59 
60 enum
61 {
62     SIM_RECEIVE_SENSITIVITY = -100, // dBm
63 
64     SIM_HIGH_RSSI_SAMPLE               = -30, // dBm
65     SIM_LOW_RSSI_SAMPLE                = -98, // dBm
66     SIM_HIGH_RSSI_PROB_INC_PER_CHANNEL = 5,
67 };
68 
69 #if OPENTHREAD_SIMULATION_VIRTUAL_TIME
70 extern int      sSockFd;
71 extern uint16_t sPortBase;
72 extern uint16_t sPortOffset;
73 #else
74 static utilsSocket sSocket;
75 static uint16_t    sPortBase   = 9000;
76 static uint16_t    sPortOffset = 0;
77 #endif
78 
79 static int8_t   sEnergyScanResult  = OT_RADIO_RSSI_INVALID;
80 static bool     sEnergyScanning    = false;
81 static uint32_t sEnergyScanEndTime = 0;
82 
83 enum
84 {
85     SIM_RADIO_CHANNEL_MIN = OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MIN,
86     SIM_RADIO_CHANNEL_MAX = OT_RADIO_2P4GHZ_OQPSK_CHANNEL_MAX,
87 };
88 
89 OT_TOOL_PACKED_BEGIN
90 struct RadioMessage
91 {
92     uint8_t mChannel;
93     uint8_t mPsdu[OT_RADIO_FRAME_MAX_SIZE];
94 } OT_TOOL_PACKED_END;
95 
96 static void radioTransmit(struct RadioMessage *aMessage, const struct otRadioFrame *aFrame);
97 static void radioSendMessage(otInstance *aInstance);
98 static void radioSendAck(void);
99 static void radioProcessFrame(otInstance *aInstance);
100 #if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
101 static uint8_t generateAckIeData(uint8_t *aLinkMetricsIeData, uint8_t aLinkMetricsIeDataLen);
102 #endif
103 
104 static otRadioState        sState = OT_RADIO_STATE_DISABLED;
105 static struct RadioMessage sReceiveMessage;
106 static struct RadioMessage sTransmitMessage;
107 static struct RadioMessage sAckMessage;
108 static otRadioFrame        sReceiveFrame;
109 static otRadioFrame        sTransmitFrame;
110 static otRadioFrame        sAckFrame;
111 
112 #if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT
113 static otRadioIeInfo sTransmitIeInfo;
114 #endif
115 
116 static otPanId  sPanid;
117 static bool     sPromiscuous = false;
118 static bool     sTxWait      = false;
119 static int8_t   sTxPower     = 0;
120 static int8_t   sCcaEdThresh = -74;
121 static int8_t   sLnaGain     = 0;
122 static uint16_t sRegionCode  = 0;
123 
124 enum
125 {
126     kMinChannel = 11,
127     kMaxChannel = 26,
128 };
129 static int8_t  sChannelMaxTransmitPower[kMaxChannel - kMinChannel + 1];
130 static uint8_t sCurrentChannel = kMinChannel;
131 
132 static bool sSrcMatchEnabled = false;
133 
134 #if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
135 static uint8_t sAckIeData[OT_ACK_IE_MAX_SIZE];
136 static uint8_t sAckIeDataLength = 0;
137 #endif
138 
139 #if OPENTHREAD_CONFIG_PLATFORM_RADIO_COEX_ENABLE
140 static bool sRadioCoexEnabled = true;
141 #endif
142 
143 otRadioCaps gRadioCaps =
144 #if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
145     OT_RADIO_CAPS_TRANSMIT_SEC;
146 #else
147     OT_RADIO_CAPS_NONE;
148 #endif
149 
150 static otRadioContext sRadioContext;
151 
152 static int8_t GetRssi(uint16_t aChannel);
153 
154 #if OPENTHREAD_SIMULATION_VIRTUAL_TIME == 0
155 
156 static enum {
157     kFilterOff,
158     kFilterDenyList,
159     kFilterAllowList,
160 } sFilterMode = kFilterOff;
161 
162 static uint8_t sFilterNodeIdsBitVector[(MAX_NETWORK_SIZE + 7) / 8];
163 
FilterContainsId(uint16_t aNodeId)164 static bool FilterContainsId(uint16_t aNodeId)
165 {
166     uint16_t index = aNodeId - 1;
167 
168     return (sFilterNodeIdsBitVector[index / 8] & (0x80 >> (index % 8))) != 0;
169 }
170 
NodeIdFilterIsConnectable(uint16_t aNodeId)171 static bool NodeIdFilterIsConnectable(uint16_t aNodeId)
172 {
173     bool isConnectable = true;
174 
175     otEXPECT_ACTION(aNodeId != gNodeId, isConnectable = false);
176 
177     switch (sFilterMode)
178     {
179     case kFilterOff:
180         break;
181     case kFilterDenyList:
182         isConnectable = !FilterContainsId(aNodeId);
183         break;
184     case kFilterAllowList:
185         isConnectable = FilterContainsId(aNodeId);
186         break;
187     }
188 
189 exit:
190     return isConnectable;
191 }
192 
AddNodeIdToFilter(uint16_t aNodeId)193 static void AddNodeIdToFilter(uint16_t aNodeId)
194 {
195     uint16_t index = aNodeId - 1;
196 
197     sFilterNodeIdsBitVector[index / 8] |= 0x80 >> (index % 8);
198 }
199 
otCliOutputFormat(const char * aFmt,...)200 OT_TOOL_WEAK void otCliOutputFormat(const char *aFmt, ...) { OT_UNUSED_VARIABLE(aFmt); }
201 
ProcessNodeIdFilter(void * aContext,uint8_t aArgsLength,char * aArgs[])202 otError ProcessNodeIdFilter(void *aContext, uint8_t aArgsLength, char *aArgs[])
203 {
204     OT_UNUSED_VARIABLE(aContext);
205 
206     otError error = OT_ERROR_NONE;
207     bool    deny  = false;
208 
209     if (aArgsLength == 0)
210     {
211         switch (sFilterMode)
212         {
213         case kFilterOff:
214             otCliOutputFormat("off");
215             break;
216         case kFilterDenyList:
217             otCliOutputFormat("deny-list");
218             break;
219         case kFilterAllowList:
220             otCliOutputFormat("allow-list");
221             break;
222         }
223 
224         for (uint16_t nodeId = 0; nodeId <= (uint16_t)MAX_NETWORK_SIZE; nodeId++)
225         {
226             if (FilterContainsId(nodeId))
227             {
228                 otCliOutputFormat(" %d", nodeId);
229             }
230         }
231 
232         otCliOutputFormat("\r\n");
233     }
234     else if (!strcmp(aArgs[0], "clear"))
235     {
236         otEXPECT_ACTION(aArgsLength == 1, error = OT_ERROR_INVALID_ARGS);
237 
238         memset(sFilterNodeIdsBitVector, 0, sizeof(sFilterNodeIdsBitVector));
239         sFilterMode = kFilterOff;
240     }
241     else if ((deny = !strcmp(aArgs[0], "deny")) || !strcmp(aArgs[0], "allow"))
242     {
243         uint16_t nodeId;
244         char    *endptr;
245 
246         otEXPECT_ACTION(aArgsLength == 2, error = OT_ERROR_INVALID_ARGS);
247 
248         nodeId = (uint16_t)strtol(aArgs[1], &endptr, 0);
249 
250         otEXPECT_ACTION(*endptr == '\0', error = OT_ERROR_INVALID_ARGS);
251         otEXPECT_ACTION(1 <= nodeId && nodeId <= MAX_NETWORK_SIZE, error = OT_ERROR_INVALID_ARGS);
252 
253         otEXPECT_ACTION(sFilterMode != (deny ? kFilterAllowList : kFilterDenyList), error = OT_ERROR_INVALID_STATE);
254 
255         AddNodeIdToFilter(nodeId);
256         sFilterMode = deny ? kFilterDenyList : kFilterAllowList;
257     }
258     else
259     {
260         error = OT_ERROR_INVALID_COMMAND;
261     }
262 
263 exit:
264     return error;
265 }
266 #else
ProcessNodeIdFilter(void * aContext,uint8_t aArgsLength,char * aArgs[])267 otError ProcessNodeIdFilter(void *aContext, uint8_t aArgsLength, char *aArgs[])
268 {
269     OT_UNUSED_VARIABLE(aContext);
270     OT_UNUSED_VARIABLE(aArgsLength);
271     OT_UNUSED_VARIABLE(aArgs);
272 
273     return OT_ERROR_NOT_IMPLEMENTED;
274 }
275 #endif // OPENTHREAD_SIMULATION_VIRTUAL_TIME == 0
276 
IsTimeAfterOrEqual(uint32_t aTimeA,uint32_t aTimeB)277 static bool IsTimeAfterOrEqual(uint32_t aTimeA, uint32_t aTimeB) { return (aTimeA - aTimeB) < (1U << 31); }
278 
ReverseExtAddress(otExtAddress * aReversed,const otExtAddress * aOrigin)279 static void ReverseExtAddress(otExtAddress *aReversed, const otExtAddress *aOrigin)
280 {
281     for (size_t i = 0; i < sizeof(*aReversed); i++)
282     {
283         aReversed->m8[i] = aOrigin->m8[sizeof(*aOrigin) - 1 - i];
284     }
285 }
286 
hasFramePending(const otRadioFrame * aFrame)287 static bool hasFramePending(const otRadioFrame *aFrame)
288 {
289     bool         rval = false;
290     otMacAddress src;
291 
292     otEXPECT_ACTION(sSrcMatchEnabled, rval = true);
293     otEXPECT(otMacFrameGetSrcAddr(aFrame, &src) == OT_ERROR_NONE);
294 
295     switch (src.mType)
296     {
297     case OT_MAC_ADDRESS_TYPE_SHORT:
298         rval = utilsSoftSrcMatchShortFindEntry(src.mAddress.mShortAddress) >= 0;
299         break;
300     case OT_MAC_ADDRESS_TYPE_EXTENDED:
301     {
302         otExtAddress extAddr;
303 
304         ReverseExtAddress(&extAddr, &src.mAddress.mExtAddress);
305         rval = utilsSoftSrcMatchExtFindEntry(&extAddr) >= 0;
306         break;
307     }
308     default:
309         break;
310     }
311 
312 exit:
313     return rval;
314 }
315 
crc16_citt(uint16_t aFcs,uint8_t aByte)316 static uint16_t crc16_citt(uint16_t aFcs, uint8_t aByte)
317 {
318     // CRC-16/CCITT, CRC-16/CCITT-TRUE, CRC-CCITT
319     // width=16 poly=0x1021 init=0x0000 refin=true refout=true xorout=0x0000 check=0x2189 name="KERMIT"
320     // http://reveng.sourceforge.net/crc-catalogue/16.htm#crc.cat.kermit
321     static const uint16_t sFcsTable[256] = {
322         0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5,
323         0xe97e, 0xf8f7, 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, 0x9cc9, 0x8d40, 0xbfdb, 0xae52,
324         0xdaed, 0xcb64, 0xf9ff, 0xe876, 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, 0xad4a, 0xbcc3,
325         0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
326         0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9,
327         0x2732, 0x36bb, 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, 0x5285, 0x430c, 0x7197, 0x601e,
328         0x14a1, 0x0528, 0x37b3, 0x263a, 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, 0x6306, 0x728f,
329         0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
330         0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862,
331         0x9af9, 0x8b70, 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, 0x0840, 0x19c9, 0x2b52, 0x3adb,
332         0x4e64, 0x5fed, 0x6d76, 0x7cff, 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, 0x18c1, 0x0948,
333         0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
334         0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226,
335         0xd0bd, 0xc134, 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, 0xc60c, 0xd785, 0xe51e, 0xf497,
336         0x8028, 0x91a1, 0xa33a, 0xb2b3, 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, 0xd68d, 0xc704,
337         0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
338         0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb,
339         0x0e70, 0x1ff9, 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, 0x7bc7, 0x6a4e, 0x58d5, 0x495c,
340         0x3de3, 0x2c6a, 0x1ef1, 0x0f78};
341     return (aFcs >> 8) ^ sFcsTable[(aFcs ^ aByte) & 0xff];
342 }
343 
otPlatRadioGetIeeeEui64(otInstance * aInstance,uint8_t * aIeeeEui64)344 void otPlatRadioGetIeeeEui64(otInstance *aInstance, uint8_t *aIeeeEui64)
345 {
346     OT_UNUSED_VARIABLE(aInstance);
347 
348     aIeeeEui64[0] = 0x18;
349     aIeeeEui64[1] = 0xb4;
350     aIeeeEui64[2] = 0x30;
351     aIeeeEui64[3] = 0x00;
352     aIeeeEui64[4] = (gNodeId >> 24) & 0xff;
353     aIeeeEui64[5] = (gNodeId >> 16) & 0xff;
354     aIeeeEui64[6] = (gNodeId >> 8) & 0xff;
355     aIeeeEui64[7] = gNodeId & 0xff;
356 }
357 
otPlatRadioSetPanId(otInstance * aInstance,otPanId aPanid)358 void otPlatRadioSetPanId(otInstance *aInstance, otPanId aPanid)
359 {
360     OT_UNUSED_VARIABLE(aInstance);
361 
362     assert(aInstance != NULL);
363 
364     sPanid = aPanid;
365     utilsSoftSrcMatchSetPanId(aPanid);
366 }
367 
otPlatRadioSetExtendedAddress(otInstance * aInstance,const otExtAddress * aExtAddress)368 void otPlatRadioSetExtendedAddress(otInstance *aInstance, const otExtAddress *aExtAddress)
369 {
370     OT_UNUSED_VARIABLE(aInstance);
371 
372     assert(aInstance != NULL);
373 
374     ReverseExtAddress(&sRadioContext.mExtAddress, aExtAddress);
375 }
376 
otPlatRadioSetShortAddress(otInstance * aInstance,otShortAddress aShortAddress)377 void otPlatRadioSetShortAddress(otInstance *aInstance, otShortAddress aShortAddress)
378 {
379     OT_UNUSED_VARIABLE(aInstance);
380 
381     assert(aInstance != NULL);
382 
383     sRadioContext.mShortAddress = aShortAddress;
384 }
385 
otPlatRadioSetAlternateShortAddress(otInstance * aInstance,otShortAddress aShortAddress)386 void otPlatRadioSetAlternateShortAddress(otInstance *aInstance, otShortAddress aShortAddress)
387 {
388     OT_UNUSED_VARIABLE(aInstance);
389 
390     assert(aInstance != NULL);
391 
392     sRadioContext.mAlternateShortAddress = aShortAddress;
393 }
394 
otPlatRadioSetPromiscuous(otInstance * aInstance,bool aEnable)395 void otPlatRadioSetPromiscuous(otInstance *aInstance, bool aEnable)
396 {
397     OT_UNUSED_VARIABLE(aInstance);
398 
399     assert(aInstance != NULL);
400 
401     sPromiscuous = aEnable;
402 }
403 
platformRadioInit(void)404 void platformRadioInit(void)
405 {
406 #if !OPENTHREAD_SIMULATION_VIRTUAL_TIME
407     parseFromEnvAsUint16("PORT_BASE", &sPortBase);
408     parseFromEnvAsUint16("PORT_OFFSET", &sPortOffset);
409     sPortOffset *= (MAX_NETWORK_SIZE + 1);
410 
411     utilsInitSocket(&sSocket, sPortBase + sPortOffset);
412 #endif
413 
414     sReceiveFrame.mPsdu  = sReceiveMessage.mPsdu;
415     sTransmitFrame.mPsdu = sTransmitMessage.mPsdu;
416     sAckFrame.mPsdu      = sAckMessage.mPsdu;
417 
418 #if OPENTHREAD_CONFIG_MAC_HEADER_IE_SUPPORT
419     sTransmitFrame.mInfo.mTxInfo.mIeInfo = &sTransmitIeInfo;
420 #else
421     sTransmitFrame.mInfo.mTxInfo.mIeInfo = NULL;
422 #endif
423 
424     for (size_t i = 0; i <= kMaxChannel - kMinChannel; i++)
425     {
426         sChannelMaxTransmitPower[i] = OT_RADIO_POWER_INVALID;
427     }
428 
429 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
430     otLinkMetricsInit(SIM_RECEIVE_SENSITIVITY);
431 #endif
432 }
433 
otPlatRadioIsEnabled(otInstance * aInstance)434 bool otPlatRadioIsEnabled(otInstance *aInstance)
435 {
436     OT_UNUSED_VARIABLE(aInstance);
437 
438     return (sState != OT_RADIO_STATE_DISABLED) ? true : false;
439 }
440 
otPlatRadioEnable(otInstance * aInstance)441 otError otPlatRadioEnable(otInstance *aInstance)
442 {
443     if (!otPlatRadioIsEnabled(aInstance))
444     {
445         sState = OT_RADIO_STATE_SLEEP;
446     }
447 
448     return OT_ERROR_NONE;
449 }
450 
otPlatRadioDisable(otInstance * aInstance)451 otError otPlatRadioDisable(otInstance *aInstance)
452 {
453     otError error = OT_ERROR_NONE;
454 
455     otEXPECT(otPlatRadioIsEnabled(aInstance));
456     otEXPECT_ACTION(sState == OT_RADIO_STATE_SLEEP, error = OT_ERROR_INVALID_STATE);
457 
458     sState = OT_RADIO_STATE_DISABLED;
459 
460 exit:
461     return error;
462 }
463 
otPlatRadioSleep(otInstance * aInstance)464 otError otPlatRadioSleep(otInstance *aInstance)
465 {
466     OT_UNUSED_VARIABLE(aInstance);
467 
468     assert(aInstance != NULL);
469 
470     otError error = OT_ERROR_INVALID_STATE;
471 
472     if (sState == OT_RADIO_STATE_SLEEP || sState == OT_RADIO_STATE_RECEIVE)
473     {
474         error  = OT_ERROR_NONE;
475         sState = OT_RADIO_STATE_SLEEP;
476     }
477 
478     return error;
479 }
480 
otPlatRadioReceive(otInstance * aInstance,uint8_t aChannel)481 otError otPlatRadioReceive(otInstance *aInstance, uint8_t aChannel)
482 {
483     OT_UNUSED_VARIABLE(aInstance);
484 
485     assert(aInstance != NULL);
486 
487     otError error = OT_ERROR_INVALID_STATE;
488 
489     if (sState != OT_RADIO_STATE_DISABLED)
490     {
491         error                  = OT_ERROR_NONE;
492         sState                 = OT_RADIO_STATE_RECEIVE;
493         sTxWait                = false;
494         sReceiveFrame.mChannel = aChannel;
495         sCurrentChannel        = aChannel;
496     }
497 
498     return error;
499 }
500 
otPlatRadioTransmit(otInstance * aInstance,otRadioFrame * aFrame)501 otError otPlatRadioTransmit(otInstance *aInstance, otRadioFrame *aFrame)
502 {
503     OT_UNUSED_VARIABLE(aInstance);
504     OT_UNUSED_VARIABLE(aFrame);
505 
506     assert(aInstance != NULL);
507     assert(aFrame != NULL);
508 
509     otError error = OT_ERROR_INVALID_STATE;
510 
511     if (sState == OT_RADIO_STATE_RECEIVE)
512     {
513         error           = OT_ERROR_NONE;
514         sState          = OT_RADIO_STATE_TRANSMIT;
515         sCurrentChannel = aFrame->mChannel;
516     }
517 
518     return error;
519 }
520 
otPlatRadioGetTransmitBuffer(otInstance * aInstance)521 otRadioFrame *otPlatRadioGetTransmitBuffer(otInstance *aInstance)
522 {
523     OT_UNUSED_VARIABLE(aInstance);
524 
525     assert(aInstance != NULL);
526 
527     return &sTransmitFrame;
528 }
529 
otPlatRadioGetRssi(otInstance * aInstance)530 int8_t otPlatRadioGetRssi(otInstance *aInstance)
531 {
532     OT_UNUSED_VARIABLE(aInstance);
533     assert(aInstance != NULL);
534 
535     return GetRssi(sReceiveFrame.mChannel);
536 }
537 
GetRssi(uint16_t aChannel)538 static int8_t GetRssi(uint16_t aChannel)
539 {
540     int8_t   rssi = SIM_LOW_RSSI_SAMPLE;
541     uint32_t probabilityThreshold;
542 
543     otEXPECT((SIM_RADIO_CHANNEL_MIN <= aChannel) && aChannel <= (SIM_RADIO_CHANNEL_MAX));
544 
545     // To emulate a simple interference model, we return either a high or
546     // a low  RSSI value with a fixed probability per each channel. The
547     // probability is increased per channel by a constant.
548 
549     probabilityThreshold = (aChannel - SIM_RADIO_CHANNEL_MIN) * SIM_HIGH_RSSI_PROB_INC_PER_CHANNEL;
550 
551     if (otRandomNonCryptoGetUint16() < (probabilityThreshold * 0xffff / 100))
552     {
553         rssi = SIM_HIGH_RSSI_SAMPLE;
554     }
555 
556 exit:
557     return rssi;
558 }
559 
otPlatRadioGetCaps(otInstance * aInstance)560 otRadioCaps otPlatRadioGetCaps(otInstance *aInstance)
561 {
562     OT_UNUSED_VARIABLE(aInstance);
563 
564     assert(aInstance != NULL);
565 
566     return gRadioCaps;
567 }
568 
otPlatRadioGetPromiscuous(otInstance * aInstance)569 bool otPlatRadioGetPromiscuous(otInstance *aInstance)
570 {
571     OT_UNUSED_VARIABLE(aInstance);
572 
573     assert(aInstance != NULL);
574 
575     return sPromiscuous;
576 }
577 
radioReceive(otInstance * aInstance)578 static void radioReceive(otInstance *aInstance)
579 {
580     bool isTxDone = false;
581     bool isAck    = otMacFrameIsAck(&sReceiveFrame);
582 
583     otEXPECT(sReceiveFrame.mChannel == sReceiveMessage.mChannel);
584     otEXPECT(sState == OT_RADIO_STATE_RECEIVE || sState == OT_RADIO_STATE_TRANSMIT);
585 
586     // Unable to simulate SFD, so use the rx done timestamp instead.
587     sReceiveFrame.mInfo.mRxInfo.mTimestamp = otPlatTimeGet();
588 
589     if (sTxWait)
590     {
591         if (otMacFrameIsAckRequested(&sTransmitFrame))
592         {
593             uint8_t rxSeq;
594             uint8_t txSeq;
595 
596             isTxDone = isAck && otMacFrameGetSequence(&sReceiveFrame, &rxSeq) == OT_ERROR_NONE &&
597                        otMacFrameGetSequence(&sTransmitFrame, &txSeq) == OT_ERROR_NONE && rxSeq == txSeq;
598         }
599 #if OPENTHREAD_SIMULATION_VIRTUAL_TIME
600         // Simulate tx done when receiving the echo frame.
601         else
602         {
603             isTxDone = !isAck && sTransmitFrame.mLength == sReceiveFrame.mLength &&
604                        memcmp(sTransmitFrame.mPsdu, sReceiveFrame.mPsdu, sTransmitFrame.mLength) == 0;
605         }
606 #endif
607     }
608 
609     if (isTxDone)
610     {
611         sState  = OT_RADIO_STATE_RECEIVE;
612         sTxWait = false;
613 
614 #if OPENTHREAD_CONFIG_DIAG_ENABLE
615 
616         if (otPlatDiagModeGet())
617         {
618             otPlatDiagRadioTransmitDone(aInstance, &sTransmitFrame, OT_ERROR_NONE);
619         }
620         else
621 #endif
622         {
623             otPlatRadioTxDone(aInstance, &sTransmitFrame, (isAck ? &sReceiveFrame : NULL), OT_ERROR_NONE);
624         }
625     }
626     else if (!isAck || sPromiscuous)
627     {
628         radioProcessFrame(aInstance);
629     }
630 
631 exit:
632     return;
633 }
634 
radioComputeCrc(struct RadioMessage * aMessage,uint16_t aLength)635 static void radioComputeCrc(struct RadioMessage *aMessage, uint16_t aLength)
636 {
637     uint16_t crc        = 0;
638     uint16_t crc_offset = aLength - sizeof(uint16_t);
639 
640     for (uint16_t i = 0; i < crc_offset; i++)
641     {
642         crc = crc16_citt(crc, aMessage->mPsdu[i]);
643     }
644 
645     aMessage->mPsdu[crc_offset]     = crc & 0xff;
646     aMessage->mPsdu[crc_offset + 1] = crc >> 8;
647 }
648 
radioSendMessage(otInstance * aInstance)649 void radioSendMessage(otInstance *aInstance)
650 {
651     // This block should be called in SFD ISR
652     {
653         uint64_t sfdTxTime = otPlatTimeGet();
654 
655         otEXPECT(otMacFrameProcessTxSfd(&sTransmitFrame, sfdTxTime, &sRadioContext) == OT_ERROR_NONE);
656     }
657 
658     sTransmitMessage.mChannel = sTransmitFrame.mChannel;
659     otPlatRadioTxStarted(aInstance, &sTransmitFrame);
660     radioComputeCrc(&sTransmitMessage, sTransmitFrame.mLength);
661     radioTransmit(&sTransmitMessage, &sTransmitFrame);
662 
663 #if OPENTHREAD_SIMULATION_VIRTUAL_TIME == 0
664     sTxWait = otMacFrameIsAckRequested(&sTransmitFrame);
665 
666     if (!sTxWait)
667     {
668         sState = OT_RADIO_STATE_RECEIVE;
669 
670 #if OPENTHREAD_CONFIG_DIAG_ENABLE
671 
672         if (otPlatDiagModeGet())
673         {
674             otPlatDiagRadioTransmitDone(aInstance, &sTransmitFrame, OT_ERROR_NONE);
675         }
676         else
677 #endif
678         {
679             otPlatRadioTxDone(aInstance, &sTransmitFrame, NULL, OT_ERROR_NONE);
680         }
681     }
682 #else
683     // Wait for echo radio in virtual time mode.
684     sTxWait = true;
685 #endif // OPENTHREAD_SIMULATION_VIRTUAL_TIME
686 exit:
687     return;
688 }
689 
platformRadioIsTransmitPending(void)690 bool platformRadioIsTransmitPending(void) { return sState == OT_RADIO_STATE_TRANSMIT && !sTxWait; }
691 
692 #if OPENTHREAD_SIMULATION_VIRTUAL_TIME
platformRadioReceive(otInstance * aInstance,uint8_t * aBuf,uint16_t aBufLength)693 void platformRadioReceive(otInstance *aInstance, uint8_t *aBuf, uint16_t aBufLength)
694 {
695     assert(sizeof(sReceiveMessage) >= aBufLength);
696 
697     memcpy(&sReceiveMessage, aBuf, aBufLength);
698 
699     sReceiveFrame.mLength = (uint8_t)(aBufLength - 1);
700 
701     radioReceive(aInstance);
702 }
703 #else
platformRadioUpdateFdSet(fd_set * aReadFdSet,fd_set * aWriteFdSet,struct timeval * aTimeout,int * aMaxFd)704 void platformRadioUpdateFdSet(fd_set *aReadFdSet, fd_set *aWriteFdSet, struct timeval *aTimeout, int *aMaxFd)
705 {
706     if (sState != OT_RADIO_STATE_TRANSMIT || sTxWait)
707     {
708         utilsAddSocketRxFd(&sSocket, aReadFdSet, aMaxFd);
709     }
710 
711     if (platformRadioIsTransmitPending())
712     {
713         utilsAddSocketTxFd(&sSocket, aWriteFdSet, aMaxFd);
714     }
715 
716     if (sEnergyScanning)
717     {
718         struct timeval tv  = {0, 0};
719         uint32_t       now = otPlatAlarmMilliGetNow();
720 
721         if (IsTimeAfterOrEqual(sEnergyScanEndTime, now))
722         {
723             uint32_t remaining = sEnergyScanEndTime - now;
724 
725             tv.tv_sec  = remaining / OT_MS_PER_S;
726             tv.tv_usec = (remaining % OT_MS_PER_S) * OT_US_PER_MS;
727         }
728 
729         if (timercmp(&tv, aTimeout, <))
730         {
731             *aTimeout = tv;
732         }
733     }
734 }
735 
736 // no need to close in virtual time mode.
platformRadioDeinit(void)737 void platformRadioDeinit(void) { utilsDeinitSocket(&sSocket); }
738 #endif // OPENTHREAD_SIMULATION_VIRTUAL_TIME
739 
platformRadioProcess(otInstance * aInstance,const fd_set * aReadFdSet,const fd_set * aWriteFdSet)740 void platformRadioProcess(otInstance *aInstance, const fd_set *aReadFdSet, const fd_set *aWriteFdSet)
741 {
742     OT_UNUSED_VARIABLE(aReadFdSet);
743     OT_UNUSED_VARIABLE(aWriteFdSet);
744 
745 #if !OPENTHREAD_SIMULATION_VIRTUAL_TIME
746     if (utilsCanSocketReceive(&sSocket, aReadFdSet))
747     {
748         uint16_t senderNodeId;
749         uint16_t len;
750 
751         len = utilsReceiveFromSocket(&sSocket, &sReceiveMessage, sizeof(sReceiveMessage), &senderNodeId);
752 
753         if (NodeIdFilterIsConnectable(senderNodeId))
754         {
755             sReceiveFrame.mLength = len - 1;
756             radioReceive(aInstance);
757         }
758     }
759 #endif
760 
761     if (platformRadioIsTransmitPending())
762     {
763         radioSendMessage(aInstance);
764     }
765 
766     if (sEnergyScanning && IsTimeAfterOrEqual(otPlatAlarmMilliGetNow(), sEnergyScanEndTime))
767     {
768         sEnergyScanning = false;
769         otPlatRadioEnergyScanDone(aInstance, sEnergyScanResult);
770     }
771 }
772 
radioTransmit(struct RadioMessage * aMessage,const struct otRadioFrame * aFrame)773 void radioTransmit(struct RadioMessage *aMessage, const struct otRadioFrame *aFrame)
774 {
775 #if !OPENTHREAD_SIMULATION_VIRTUAL_TIME
776     utilsSendOverSocket(&sSocket, aMessage, aFrame->mLength + 1); // + 1 is for `mChannel`
777 #else
778     struct Event event;
779 
780     event.mDelay      = 1; // 1us for now
781     event.mEvent      = OT_SIM_EVENT_RADIO_RECEIVED;
782     event.mDataLength = 1 + aFrame->mLength; // include channel in first byte
783     memcpy(event.mData, aMessage, event.mDataLength);
784     otSimSendEvent(&event);
785 #endif
786 }
787 
radioSendAck(void)788 void radioSendAck(void)
789 {
790     if (
791 #if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
792         // Determine if frame pending should be set
793         ((otMacFrameIsVersion2015(&sReceiveFrame) && otMacFrameIsCommand(&sReceiveFrame)) ||
794          otMacFrameIsData(&sReceiveFrame) || otMacFrameIsDataRequest(&sReceiveFrame))
795 #else
796         otMacFrameIsDataRequest(&sReceiveFrame)
797 #endif
798         && hasFramePending(&sReceiveFrame))
799     {
800         sReceiveFrame.mInfo.mRxInfo.mAckedWithFramePending = true;
801     }
802 
803 #if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
804     // Use enh-ack for 802.15.4-2015 frames
805     if (otMacFrameIsVersion2015(&sReceiveFrame))
806     {
807         uint8_t  linkMetricsDataLen = 0;
808         uint8_t *dataPtr            = NULL;
809 
810 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
811         uint8_t      linkMetricsData[OT_ENH_PROBING_IE_DATA_MAX_SIZE];
812         otMacAddress macAddress;
813 
814         otEXPECT(otMacFrameGetSrcAddr(&sReceiveFrame, &macAddress) == OT_ERROR_NONE);
815 
816         linkMetricsDataLen = otLinkMetricsEnhAckGenData(&macAddress, sReceiveFrame.mInfo.mRxInfo.mLqi,
817                                                         sReceiveFrame.mInfo.mRxInfo.mRssi, linkMetricsData);
818 
819         if (linkMetricsDataLen > 0)
820         {
821             dataPtr = linkMetricsData;
822         }
823 #endif
824 
825         sAckIeDataLength = generateAckIeData(dataPtr, linkMetricsDataLen);
826 
827         otEXPECT(otMacFrameGenerateEnhAck(&sReceiveFrame, sReceiveFrame.mInfo.mRxInfo.mAckedWithFramePending,
828                                           sAckIeData, sAckIeDataLength, &sAckFrame) == OT_ERROR_NONE);
829         otEXPECT(otMacFrameProcessTxSfd(&sAckFrame, otPlatTimeGet(), &sRadioContext) == OT_ERROR_NONE);
830     }
831     else
832 #endif
833     {
834         otMacFrameGenerateImmAck(&sReceiveFrame, sReceiveFrame.mInfo.mRxInfo.mAckedWithFramePending, &sAckFrame);
835     }
836 
837     sAckMessage.mChannel = sReceiveFrame.mChannel;
838 
839     radioComputeCrc(&sAckMessage, sAckFrame.mLength);
840     radioTransmit(&sAckMessage, &sAckFrame);
841 
842 #if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
843 exit:
844 #endif
845     return;
846 }
847 
radioProcessFrame(otInstance * aInstance)848 void radioProcessFrame(otInstance *aInstance)
849 {
850     otError      error = OT_ERROR_NONE;
851     otMacAddress macAddress;
852     OT_UNUSED_VARIABLE(macAddress);
853 
854     sReceiveFrame.mInfo.mRxInfo.mRssi = -20;
855     sReceiveFrame.mInfo.mRxInfo.mLqi  = OT_RADIO_LQI_NONE;
856 
857     sReceiveFrame.mInfo.mRxInfo.mAckedWithFramePending = false;
858     sReceiveFrame.mInfo.mRxInfo.mAckedWithSecEnhAck    = false;
859 
860     otEXPECT(sPromiscuous == false);
861 
862     otEXPECT_ACTION(otMacFrameDoesAddrMatchAny(&sReceiveFrame, sPanid, sRadioContext.mShortAddress,
863                                                sRadioContext.mAlternateShortAddress, &sRadioContext.mExtAddress),
864                     error = OT_ERROR_ABORT);
865 
866 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
867     otEXPECT_ACTION(otMacFrameGetSrcAddr(&sReceiveFrame, &macAddress) == OT_ERROR_NONE, error = OT_ERROR_PARSE);
868 #endif
869 
870     // generate acknowledgment
871     if (otMacFrameIsAckRequested(&sReceiveFrame))
872     {
873         radioSendAck();
874 #if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
875         if (otMacFrameIsSecurityEnabled(&sAckFrame))
876         {
877             sReceiveFrame.mInfo.mRxInfo.mAckedWithSecEnhAck = true;
878             sReceiveFrame.mInfo.mRxInfo.mAckFrameCounter    = otMacFrameGetFrameCounter(&sAckFrame);
879         }
880 #endif // OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
881     }
882 
883 exit:
884 
885     if (error != OT_ERROR_ABORT)
886     {
887 #if OPENTHREAD_CONFIG_DIAG_ENABLE
888         if (otPlatDiagModeGet())
889         {
890             otPlatDiagRadioReceiveDone(aInstance, error == OT_ERROR_NONE ? &sReceiveFrame : NULL, error);
891         }
892         else
893 #endif
894         {
895             otPlatRadioReceiveDone(aInstance, error == OT_ERROR_NONE ? &sReceiveFrame : NULL, error);
896         }
897     }
898 }
899 
otPlatRadioEnableSrcMatch(otInstance * aInstance,bool aEnable)900 void otPlatRadioEnableSrcMatch(otInstance *aInstance, bool aEnable)
901 {
902     OT_UNUSED_VARIABLE(aInstance);
903 
904     assert(aInstance != NULL);
905 
906     sSrcMatchEnabled = aEnable;
907 }
908 
otPlatRadioEnergyScan(otInstance * aInstance,uint8_t aScanChannel,uint16_t aScanDuration)909 otError otPlatRadioEnergyScan(otInstance *aInstance, uint8_t aScanChannel, uint16_t aScanDuration)
910 {
911     OT_UNUSED_VARIABLE(aInstance);
912     OT_UNUSED_VARIABLE(aScanChannel);
913 
914     otError error = OT_ERROR_NONE;
915 
916     assert(aInstance != NULL);
917     assert(aScanChannel >= SIM_RADIO_CHANNEL_MIN && aScanChannel <= SIM_RADIO_CHANNEL_MAX);
918     assert(aScanDuration > 0);
919 
920     otEXPECT_ACTION((gRadioCaps & OT_RADIO_CAPS_ENERGY_SCAN), error = OT_ERROR_NOT_IMPLEMENTED);
921     otEXPECT_ACTION(!sEnergyScanning, error = OT_ERROR_BUSY);
922 
923     sEnergyScanResult  = GetRssi(aScanChannel);
924     sEnergyScanning    = true;
925     sEnergyScanEndTime = otPlatAlarmMilliGetNow() + aScanDuration;
926 
927 exit:
928     return error;
929 }
930 
otPlatRadioGetTransmitPower(otInstance * aInstance,int8_t * aPower)931 otError otPlatRadioGetTransmitPower(otInstance *aInstance, int8_t *aPower)
932 {
933     OT_UNUSED_VARIABLE(aInstance);
934 
935     int8_t maxPower = sChannelMaxTransmitPower[sCurrentChannel - kMinChannel];
936 
937     assert(aInstance != NULL);
938 
939     *aPower = sTxPower < maxPower ? sTxPower : maxPower;
940 
941     return OT_ERROR_NONE;
942 }
943 
otPlatRadioSetTransmitPower(otInstance * aInstance,int8_t aPower)944 otError otPlatRadioSetTransmitPower(otInstance *aInstance, int8_t aPower)
945 {
946     OT_UNUSED_VARIABLE(aInstance);
947 
948     assert(aInstance != NULL);
949 
950     sTxPower = aPower;
951 
952     return OT_ERROR_NONE;
953 }
954 
otPlatRadioGetCcaEnergyDetectThreshold(otInstance * aInstance,int8_t * aThreshold)955 otError otPlatRadioGetCcaEnergyDetectThreshold(otInstance *aInstance, int8_t *aThreshold)
956 {
957     OT_UNUSED_VARIABLE(aInstance);
958 
959     assert(aInstance != NULL);
960 
961     *aThreshold = sCcaEdThresh;
962 
963     return OT_ERROR_NONE;
964 }
965 
otPlatRadioSetCcaEnergyDetectThreshold(otInstance * aInstance,int8_t aThreshold)966 otError otPlatRadioSetCcaEnergyDetectThreshold(otInstance *aInstance, int8_t aThreshold)
967 {
968     OT_UNUSED_VARIABLE(aInstance);
969 
970     assert(aInstance != NULL);
971 
972     sCcaEdThresh = aThreshold;
973 
974     return OT_ERROR_NONE;
975 }
976 
otPlatRadioGetFemLnaGain(otInstance * aInstance,int8_t * aGain)977 otError otPlatRadioGetFemLnaGain(otInstance *aInstance, int8_t *aGain)
978 {
979     OT_UNUSED_VARIABLE(aInstance);
980 
981     assert(aInstance != NULL && aGain != NULL);
982 
983     *aGain = sLnaGain;
984 
985     return OT_ERROR_NONE;
986 }
987 
otPlatRadioSetFemLnaGain(otInstance * aInstance,int8_t aGain)988 otError otPlatRadioSetFemLnaGain(otInstance *aInstance, int8_t aGain)
989 {
990     OT_UNUSED_VARIABLE(aInstance);
991 
992     assert(aInstance != NULL);
993 
994     sLnaGain = aGain;
995 
996     return OT_ERROR_NONE;
997 }
998 
otPlatRadioGetReceiveSensitivity(otInstance * aInstance)999 int8_t otPlatRadioGetReceiveSensitivity(otInstance *aInstance)
1000 {
1001     OT_UNUSED_VARIABLE(aInstance);
1002 
1003     assert(aInstance != NULL);
1004 
1005     return SIM_RECEIVE_SENSITIVITY;
1006 }
1007 
otPlatRadioGetState(otInstance * aInstance)1008 otRadioState otPlatRadioGetState(otInstance *aInstance)
1009 {
1010     OT_UNUSED_VARIABLE(aInstance);
1011 
1012     return sState;
1013 }
1014 
1015 #if OPENTHREAD_CONFIG_PLATFORM_RADIO_COEX_ENABLE
otPlatRadioSetCoexEnabled(otInstance * aInstance,bool aEnabled)1016 otError otPlatRadioSetCoexEnabled(otInstance *aInstance, bool aEnabled)
1017 {
1018     OT_UNUSED_VARIABLE(aInstance);
1019 
1020     assert(aInstance != NULL);
1021 
1022     sRadioCoexEnabled = aEnabled;
1023     return OT_ERROR_NONE;
1024 }
1025 
otPlatRadioIsCoexEnabled(otInstance * aInstance)1026 bool otPlatRadioIsCoexEnabled(otInstance *aInstance)
1027 {
1028     OT_UNUSED_VARIABLE(aInstance);
1029 
1030     assert(aInstance != NULL);
1031 
1032     return sRadioCoexEnabled;
1033 }
1034 
otPlatRadioGetCoexMetrics(otInstance * aInstance,otRadioCoexMetrics * aCoexMetrics)1035 otError otPlatRadioGetCoexMetrics(otInstance *aInstance, otRadioCoexMetrics *aCoexMetrics)
1036 {
1037     OT_UNUSED_VARIABLE(aInstance);
1038 
1039     otError error = OT_ERROR_NONE;
1040 
1041     assert(aInstance != NULL);
1042     otEXPECT_ACTION(aCoexMetrics != NULL, error = OT_ERROR_INVALID_ARGS);
1043 
1044     memset(aCoexMetrics, 0, sizeof(otRadioCoexMetrics));
1045 
1046     aCoexMetrics->mStopped                            = false;
1047     aCoexMetrics->mNumGrantGlitch                     = 1;
1048     aCoexMetrics->mNumTxRequest                       = 2;
1049     aCoexMetrics->mNumTxGrantImmediate                = 3;
1050     aCoexMetrics->mNumTxGrantWait                     = 4;
1051     aCoexMetrics->mNumTxGrantWaitActivated            = 5;
1052     aCoexMetrics->mNumTxGrantWaitTimeout              = 6;
1053     aCoexMetrics->mNumTxGrantDeactivatedDuringRequest = 7;
1054     aCoexMetrics->mNumTxDelayedGrant                  = 8;
1055     aCoexMetrics->mAvgTxRequestToGrantTime            = 9;
1056     aCoexMetrics->mNumRxRequest                       = 10;
1057     aCoexMetrics->mNumRxGrantImmediate                = 11;
1058     aCoexMetrics->mNumRxGrantWait                     = 12;
1059     aCoexMetrics->mNumRxGrantWaitActivated            = 13;
1060     aCoexMetrics->mNumRxGrantWaitTimeout              = 14;
1061     aCoexMetrics->mNumRxGrantDeactivatedDuringRequest = 15;
1062     aCoexMetrics->mNumRxDelayedGrant                  = 16;
1063     aCoexMetrics->mAvgRxRequestToGrantTime            = 17;
1064     aCoexMetrics->mNumRxGrantNone                     = 18;
1065 
1066 exit:
1067     return error;
1068 }
1069 #endif
1070 
otPlatRadioGetNow(otInstance * aInstance)1071 uint64_t otPlatRadioGetNow(otInstance *aInstance)
1072 {
1073     OT_UNUSED_VARIABLE(aInstance);
1074 
1075     return otPlatTimeGet();
1076 }
1077 
1078 #if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
generateAckIeData(uint8_t * aLinkMetricsIeData,uint8_t aLinkMetricsIeDataLen)1079 static uint8_t generateAckIeData(uint8_t *aLinkMetricsIeData, uint8_t aLinkMetricsIeDataLen)
1080 {
1081     OT_UNUSED_VARIABLE(aLinkMetricsIeData);
1082     OT_UNUSED_VARIABLE(aLinkMetricsIeDataLen);
1083 
1084     uint8_t offset = 0;
1085 
1086 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
1087     if (sRadioContext.mCslPeriod > 0)
1088     {
1089         offset += otMacFrameGenerateCslIeTemplate(sAckIeData);
1090     }
1091 #endif
1092 
1093 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
1094     if (aLinkMetricsIeData != NULL && aLinkMetricsIeDataLen > 0)
1095     {
1096         offset += otMacFrameGenerateEnhAckProbingIe(sAckIeData, aLinkMetricsIeData, aLinkMetricsIeDataLen);
1097     }
1098 #endif
1099 
1100     return offset;
1101 }
1102 #endif
1103 
1104 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
otPlatRadioEnableCsl(otInstance * aInstance,uint32_t aCslPeriod,otShortAddress aShortAddr,const otExtAddress * aExtAddr)1105 otError otPlatRadioEnableCsl(otInstance         *aInstance,
1106                              uint32_t            aCslPeriod,
1107                              otShortAddress      aShortAddr,
1108                              const otExtAddress *aExtAddr)
1109 {
1110     OT_UNUSED_VARIABLE(aInstance);
1111     OT_UNUSED_VARIABLE(aShortAddr);
1112     OT_UNUSED_VARIABLE(aExtAddr);
1113 
1114     assert(aCslPeriod < UINT16_MAX);
1115     sRadioContext.mCslPeriod = (uint16_t)aCslPeriod;
1116 
1117     return OT_ERROR_NONE;
1118 }
1119 
otPlatRadioResetCsl(otInstance * aInstance)1120 otError otPlatRadioResetCsl(otInstance *aInstance)
1121 {
1122     OT_UNUSED_VARIABLE(aInstance);
1123 
1124     sRadioContext.mCslPeriod = 0;
1125 
1126     return OT_ERROR_NONE;
1127 }
1128 
otPlatRadioUpdateCslSampleTime(otInstance * aInstance,uint32_t aCslSampleTime)1129 void otPlatRadioUpdateCslSampleTime(otInstance *aInstance, uint32_t aCslSampleTime)
1130 {
1131     OT_UNUSED_VARIABLE(aInstance);
1132 
1133     sRadioContext.mCslSampleTime = aCslSampleTime;
1134 }
1135 
otPlatRadioGetCslAccuracy(otInstance * aInstance)1136 uint8_t otPlatRadioGetCslAccuracy(otInstance *aInstance)
1137 {
1138     OT_UNUSED_VARIABLE(aInstance);
1139 
1140     return 0;
1141 }
1142 #endif // OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
1143 
otPlatRadioSetMacKey(otInstance * aInstance,uint8_t aKeyIdMode,uint8_t aKeyId,const otMacKeyMaterial * aPrevKey,const otMacKeyMaterial * aCurrKey,const otMacKeyMaterial * aNextKey,otRadioKeyType aKeyType)1144 void otPlatRadioSetMacKey(otInstance             *aInstance,
1145                           uint8_t                 aKeyIdMode,
1146                           uint8_t                 aKeyId,
1147                           const otMacKeyMaterial *aPrevKey,
1148                           const otMacKeyMaterial *aCurrKey,
1149                           const otMacKeyMaterial *aNextKey,
1150                           otRadioKeyType          aKeyType)
1151 {
1152     OT_UNUSED_VARIABLE(aInstance);
1153     OT_UNUSED_VARIABLE(aKeyIdMode);
1154 
1155     otEXPECT(aPrevKey != NULL && aCurrKey != NULL && aNextKey != NULL);
1156 
1157     sRadioContext.mKeyId               = aKeyId;
1158     sRadioContext.mKeyType             = aKeyType;
1159     sRadioContext.mPrevMacFrameCounter = sRadioContext.mMacFrameCounter;
1160     sRadioContext.mMacFrameCounter     = 0;
1161 
1162     memcpy(&sRadioContext.mPrevKey, aPrevKey, sizeof(otMacKeyMaterial));
1163     memcpy(&sRadioContext.mCurrKey, aCurrKey, sizeof(otMacKeyMaterial));
1164     memcpy(&sRadioContext.mNextKey, aNextKey, sizeof(otMacKeyMaterial));
1165 
1166 exit:
1167     return;
1168 }
1169 
otPlatRadioSetMacFrameCounter(otInstance * aInstance,uint32_t aMacFrameCounter)1170 void otPlatRadioSetMacFrameCounter(otInstance *aInstance, uint32_t aMacFrameCounter)
1171 {
1172     OT_UNUSED_VARIABLE(aInstance);
1173 
1174     sRadioContext.mMacFrameCounter = aMacFrameCounter;
1175 }
1176 
otPlatRadioSetChannelMaxTransmitPower(otInstance * aInstance,uint8_t aChannel,int8_t aMaxPower)1177 otError otPlatRadioSetChannelMaxTransmitPower(otInstance *aInstance, uint8_t aChannel, int8_t aMaxPower)
1178 {
1179     OT_UNUSED_VARIABLE(aInstance);
1180 
1181     otError error = OT_ERROR_NONE;
1182 
1183     otEXPECT_ACTION(aChannel >= kMinChannel && aChannel <= kMaxChannel, error = OT_ERROR_INVALID_ARGS);
1184     sChannelMaxTransmitPower[aChannel - kMinChannel] = aMaxPower;
1185 
1186 exit:
1187     return error;
1188 }
1189 
1190 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
otPlatRadioConfigureEnhAckProbing(otInstance * aInstance,otLinkMetrics aLinkMetrics,const otShortAddress aShortAddress,const otExtAddress * aExtAddress)1191 otError otPlatRadioConfigureEnhAckProbing(otInstance          *aInstance,
1192                                           otLinkMetrics        aLinkMetrics,
1193                                           const otShortAddress aShortAddress,
1194                                           const otExtAddress  *aExtAddress)
1195 {
1196     OT_UNUSED_VARIABLE(aInstance);
1197 
1198     return otLinkMetricsConfigureEnhAckProbing(aShortAddress, aExtAddress, aLinkMetrics);
1199 }
1200 #endif
1201 
otPlatRadioSetRegion(otInstance * aInstance,uint16_t aRegionCode)1202 otError otPlatRadioSetRegion(otInstance *aInstance, uint16_t aRegionCode)
1203 {
1204     OT_UNUSED_VARIABLE(aInstance);
1205 
1206     sRegionCode = aRegionCode;
1207     return OT_ERROR_NONE;
1208 }
1209 
otPlatRadioGetRegion(otInstance * aInstance,uint16_t * aRegionCode)1210 otError otPlatRadioGetRegion(otInstance *aInstance, uint16_t *aRegionCode)
1211 {
1212     OT_UNUSED_VARIABLE(aInstance);
1213     otError error = OT_ERROR_NONE;
1214 
1215     otEXPECT_ACTION(aRegionCode != NULL, error = OT_ERROR_INVALID_ARGS);
1216 
1217     *aRegionCode = sRegionCode;
1218 exit:
1219     return error;
1220 }
1221 
parseFromEnvAsUint16(const char * aEnvName,uint16_t * aValue)1222 void parseFromEnvAsUint16(const char *aEnvName, uint16_t *aValue)
1223 {
1224     char *env = getenv(aEnvName);
1225 
1226     if (env)
1227     {
1228         char *endptr;
1229 
1230         *aValue = (uint16_t)strtol(env, &endptr, 0);
1231 
1232         if (*endptr != '\0')
1233         {
1234             fprintf(stderr, "Invalid %s: %s\n", aEnvName, env);
1235             DieNow(OT_EXIT_FAILURE);
1236         }
1237     }
1238 }
1239