• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     sAckFrame.mInfo.mTxInfo.mIeInfo = NULL;
424 
425     for (size_t i = 0; i <= kMaxChannel - kMinChannel; i++)
426     {
427         sChannelMaxTransmitPower[i] = OT_RADIO_POWER_INVALID;
428     }
429 
430 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
431     otLinkMetricsInit(SIM_RECEIVE_SENSITIVITY);
432 #endif
433 }
434 
otPlatRadioIsEnabled(otInstance * aInstance)435 bool otPlatRadioIsEnabled(otInstance *aInstance)
436 {
437     OT_UNUSED_VARIABLE(aInstance);
438 
439     return (sState != OT_RADIO_STATE_DISABLED) ? true : false;
440 }
441 
otPlatRadioEnable(otInstance * aInstance)442 otError otPlatRadioEnable(otInstance *aInstance)
443 {
444     if (!otPlatRadioIsEnabled(aInstance))
445     {
446         sState = OT_RADIO_STATE_SLEEP;
447     }
448 
449     return OT_ERROR_NONE;
450 }
451 
otPlatRadioDisable(otInstance * aInstance)452 otError otPlatRadioDisable(otInstance *aInstance)
453 {
454     otError error = OT_ERROR_NONE;
455 
456     otEXPECT(otPlatRadioIsEnabled(aInstance));
457     otEXPECT_ACTION(sState == OT_RADIO_STATE_SLEEP, error = OT_ERROR_INVALID_STATE);
458 
459     sState = OT_RADIO_STATE_DISABLED;
460 
461 exit:
462     return error;
463 }
464 
otPlatRadioSleep(otInstance * aInstance)465 otError otPlatRadioSleep(otInstance *aInstance)
466 {
467     OT_UNUSED_VARIABLE(aInstance);
468 
469     assert(aInstance != NULL);
470 
471     otError error = OT_ERROR_INVALID_STATE;
472 
473     if (sState == OT_RADIO_STATE_SLEEP || sState == OT_RADIO_STATE_RECEIVE)
474     {
475         error  = OT_ERROR_NONE;
476         sState = OT_RADIO_STATE_SLEEP;
477     }
478 
479     return error;
480 }
481 
otPlatRadioReceive(otInstance * aInstance,uint8_t aChannel)482 otError otPlatRadioReceive(otInstance *aInstance, uint8_t aChannel)
483 {
484     OT_UNUSED_VARIABLE(aInstance);
485 
486     assert(aInstance != NULL);
487 
488     otError error = OT_ERROR_INVALID_STATE;
489 
490     if (sState != OT_RADIO_STATE_DISABLED)
491     {
492         error                  = OT_ERROR_NONE;
493         sState                 = OT_RADIO_STATE_RECEIVE;
494         sTxWait                = false;
495         sReceiveFrame.mChannel = aChannel;
496         sCurrentChannel        = aChannel;
497     }
498 
499     return error;
500 }
501 
otPlatRadioTransmit(otInstance * aInstance,otRadioFrame * aFrame)502 otError otPlatRadioTransmit(otInstance *aInstance, otRadioFrame *aFrame)
503 {
504     OT_UNUSED_VARIABLE(aInstance);
505     OT_UNUSED_VARIABLE(aFrame);
506 
507     assert(aInstance != NULL);
508     assert(aFrame != NULL);
509 
510     otError error = OT_ERROR_INVALID_STATE;
511 
512     if (sState == OT_RADIO_STATE_RECEIVE)
513     {
514         error           = OT_ERROR_NONE;
515         sState          = OT_RADIO_STATE_TRANSMIT;
516         sCurrentChannel = aFrame->mChannel;
517     }
518 
519     return error;
520 }
521 
otPlatRadioGetTransmitBuffer(otInstance * aInstance)522 otRadioFrame *otPlatRadioGetTransmitBuffer(otInstance *aInstance)
523 {
524     OT_UNUSED_VARIABLE(aInstance);
525 
526     assert(aInstance != NULL);
527 
528     return &sTransmitFrame;
529 }
530 
otPlatRadioGetRssi(otInstance * aInstance)531 int8_t otPlatRadioGetRssi(otInstance *aInstance)
532 {
533     OT_UNUSED_VARIABLE(aInstance);
534     assert(aInstance != NULL);
535 
536     return GetRssi(sReceiveFrame.mChannel);
537 }
538 
GetRssi(uint16_t aChannel)539 static int8_t GetRssi(uint16_t aChannel)
540 {
541     int8_t   rssi = SIM_LOW_RSSI_SAMPLE;
542     uint32_t probabilityThreshold;
543 
544     otEXPECT((SIM_RADIO_CHANNEL_MIN <= aChannel) && aChannel <= (SIM_RADIO_CHANNEL_MAX));
545 
546     // To emulate a simple interference model, we return either a high or
547     // a low  RSSI value with a fixed probability per each channel. The
548     // probability is increased per channel by a constant.
549 
550     probabilityThreshold = (aChannel - SIM_RADIO_CHANNEL_MIN) * SIM_HIGH_RSSI_PROB_INC_PER_CHANNEL;
551 
552     if (otRandomNonCryptoGetUint16() < (probabilityThreshold * 0xffff / 100))
553     {
554         rssi = SIM_HIGH_RSSI_SAMPLE;
555     }
556 
557 exit:
558     return rssi;
559 }
560 
otPlatRadioGetCaps(otInstance * aInstance)561 otRadioCaps otPlatRadioGetCaps(otInstance *aInstance)
562 {
563     OT_UNUSED_VARIABLE(aInstance);
564 
565     assert(aInstance != NULL);
566 
567     return gRadioCaps;
568 }
569 
otPlatRadioGetPromiscuous(otInstance * aInstance)570 bool otPlatRadioGetPromiscuous(otInstance *aInstance)
571 {
572     OT_UNUSED_VARIABLE(aInstance);
573 
574     assert(aInstance != NULL);
575 
576     return sPromiscuous;
577 }
578 
radioReceive(otInstance * aInstance)579 static void radioReceive(otInstance *aInstance)
580 {
581     bool isTxDone = false;
582     bool isAck    = otMacFrameIsAck(&sReceiveFrame);
583 
584     otEXPECT(sReceiveFrame.mChannel == sReceiveMessage.mChannel);
585     otEXPECT(sState == OT_RADIO_STATE_RECEIVE || sState == OT_RADIO_STATE_TRANSMIT);
586 
587     // Unable to simulate SFD, so use the rx done timestamp instead.
588     sReceiveFrame.mInfo.mRxInfo.mTimestamp = otPlatTimeGet();
589 
590     if (sTxWait)
591     {
592         if (otMacFrameIsAckRequested(&sTransmitFrame))
593         {
594             uint8_t rxSeq;
595             uint8_t txSeq;
596 
597             isTxDone = isAck && otMacFrameGetSequence(&sReceiveFrame, &rxSeq) == OT_ERROR_NONE &&
598                        otMacFrameGetSequence(&sTransmitFrame, &txSeq) == OT_ERROR_NONE && rxSeq == txSeq;
599         }
600 #if OPENTHREAD_SIMULATION_VIRTUAL_TIME
601         // Simulate tx done when receiving the echo frame.
602         else
603         {
604             isTxDone = !isAck && sTransmitFrame.mLength == sReceiveFrame.mLength &&
605                        memcmp(sTransmitFrame.mPsdu, sReceiveFrame.mPsdu, sTransmitFrame.mLength) == 0;
606         }
607 #endif
608     }
609 
610     if (isTxDone)
611     {
612         sState  = OT_RADIO_STATE_RECEIVE;
613         sTxWait = false;
614 
615 #if OPENTHREAD_CONFIG_DIAG_ENABLE
616 
617         if (otPlatDiagModeGet())
618         {
619             otPlatDiagRadioTransmitDone(aInstance, &sTransmitFrame, OT_ERROR_NONE);
620         }
621         else
622 #endif
623         {
624             otPlatRadioTxDone(aInstance, &sTransmitFrame, (isAck ? &sReceiveFrame : NULL), OT_ERROR_NONE);
625         }
626     }
627     else if (!isAck || sPromiscuous)
628     {
629         radioProcessFrame(aInstance);
630     }
631 
632 exit:
633     return;
634 }
635 
radioComputeCrc(struct RadioMessage * aMessage,uint16_t aLength)636 static void radioComputeCrc(struct RadioMessage *aMessage, uint16_t aLength)
637 {
638     uint16_t crc        = 0;
639     uint16_t crc_offset = aLength - sizeof(uint16_t);
640 
641     for (uint16_t i = 0; i < crc_offset; i++)
642     {
643         crc = crc16_citt(crc, aMessage->mPsdu[i]);
644     }
645 
646     aMessage->mPsdu[crc_offset]     = crc & 0xff;
647     aMessage->mPsdu[crc_offset + 1] = crc >> 8;
648 }
649 
radioSendMessage(otInstance * aInstance)650 void radioSendMessage(otInstance *aInstance)
651 {
652     // This block should be called in SFD ISR
653     {
654         uint64_t sfdTxTime = otPlatTimeGet();
655 
656         otEXPECT(otMacFrameProcessTxSfd(&sTransmitFrame, sfdTxTime, &sRadioContext) == OT_ERROR_NONE);
657     }
658 
659     sTransmitMessage.mChannel = sTransmitFrame.mChannel;
660     otPlatRadioTxStarted(aInstance, &sTransmitFrame);
661     radioComputeCrc(&sTransmitMessage, sTransmitFrame.mLength);
662     radioTransmit(&sTransmitMessage, &sTransmitFrame);
663 
664 #if OPENTHREAD_SIMULATION_VIRTUAL_TIME == 0
665     sTxWait = otMacFrameIsAckRequested(&sTransmitFrame);
666 
667     if (!sTxWait)
668     {
669         sState = OT_RADIO_STATE_RECEIVE;
670 
671 #if OPENTHREAD_CONFIG_DIAG_ENABLE
672 
673         if (otPlatDiagModeGet())
674         {
675             otPlatDiagRadioTransmitDone(aInstance, &sTransmitFrame, OT_ERROR_NONE);
676         }
677         else
678 #endif
679         {
680             otPlatRadioTxDone(aInstance, &sTransmitFrame, NULL, OT_ERROR_NONE);
681         }
682     }
683 #else
684     // Wait for echo radio in virtual time mode.
685     sTxWait = true;
686 #endif // OPENTHREAD_SIMULATION_VIRTUAL_TIME
687 exit:
688     return;
689 }
690 
platformRadioIsTransmitPending(void)691 bool platformRadioIsTransmitPending(void) { return sState == OT_RADIO_STATE_TRANSMIT && !sTxWait; }
692 
693 #if OPENTHREAD_SIMULATION_VIRTUAL_TIME
platformRadioReceive(otInstance * aInstance,uint8_t * aBuf,uint16_t aBufLength)694 void platformRadioReceive(otInstance *aInstance, uint8_t *aBuf, uint16_t aBufLength)
695 {
696     assert(sizeof(sReceiveMessage) >= aBufLength);
697 
698     memcpy(&sReceiveMessage, aBuf, aBufLength);
699 
700     sReceiveFrame.mLength = (uint8_t)(aBufLength - 1);
701 
702     radioReceive(aInstance);
703 }
704 #else
platformRadioUpdateFdSet(fd_set * aReadFdSet,fd_set * aWriteFdSet,struct timeval * aTimeout,int * aMaxFd)705 void platformRadioUpdateFdSet(fd_set *aReadFdSet, fd_set *aWriteFdSet, struct timeval *aTimeout, int *aMaxFd)
706 {
707     if (sState != OT_RADIO_STATE_TRANSMIT || sTxWait)
708     {
709         utilsAddSocketRxFd(&sSocket, aReadFdSet, aMaxFd);
710     }
711 
712     if (platformRadioIsTransmitPending())
713     {
714         utilsAddSocketTxFd(&sSocket, aWriteFdSet, aMaxFd);
715     }
716 
717     if (sEnergyScanning)
718     {
719         struct timeval tv  = {0, 0};
720         uint32_t       now = otPlatAlarmMilliGetNow();
721 
722         if (IsTimeAfterOrEqual(sEnergyScanEndTime, now))
723         {
724             uint32_t remaining = sEnergyScanEndTime - now;
725 
726             tv.tv_sec  = remaining / OT_MS_PER_S;
727             tv.tv_usec = (remaining % OT_MS_PER_S) * OT_US_PER_MS;
728         }
729 
730         if (timercmp(&tv, aTimeout, <))
731         {
732             *aTimeout = tv;
733         }
734     }
735 }
736 
737 // no need to close in virtual time mode.
platformRadioDeinit(void)738 void platformRadioDeinit(void) { utilsDeinitSocket(&sSocket); }
739 #endif // OPENTHREAD_SIMULATION_VIRTUAL_TIME
740 
platformRadioProcess(otInstance * aInstance,const fd_set * aReadFdSet,const fd_set * aWriteFdSet)741 void platformRadioProcess(otInstance *aInstance, const fd_set *aReadFdSet, const fd_set *aWriteFdSet)
742 {
743     OT_UNUSED_VARIABLE(aReadFdSet);
744     OT_UNUSED_VARIABLE(aWriteFdSet);
745 
746 #if !OPENTHREAD_SIMULATION_VIRTUAL_TIME
747     if (utilsCanSocketReceive(&sSocket, aReadFdSet))
748     {
749         uint16_t senderNodeId;
750         uint16_t len;
751 
752         len = utilsReceiveFromSocket(&sSocket, &sReceiveMessage, sizeof(sReceiveMessage), &senderNodeId);
753 
754         if (NodeIdFilterIsConnectable(senderNodeId))
755         {
756             sReceiveFrame.mLength = len - 1;
757             radioReceive(aInstance);
758         }
759     }
760 #endif
761 
762     if (platformRadioIsTransmitPending())
763     {
764         radioSendMessage(aInstance);
765     }
766 
767     if (sEnergyScanning && IsTimeAfterOrEqual(otPlatAlarmMilliGetNow(), sEnergyScanEndTime))
768     {
769         sEnergyScanning = false;
770         otPlatRadioEnergyScanDone(aInstance, sEnergyScanResult);
771     }
772 }
773 
radioTransmit(struct RadioMessage * aMessage,const struct otRadioFrame * aFrame)774 void radioTransmit(struct RadioMessage *aMessage, const struct otRadioFrame *aFrame)
775 {
776 #if !OPENTHREAD_SIMULATION_VIRTUAL_TIME
777     utilsSendOverSocket(&sSocket, aMessage, aFrame->mLength + 1); // + 1 is for `mChannel`
778 #else
779     struct Event event;
780 
781     event.mDelay      = 1; // 1us for now
782     event.mEvent      = OT_SIM_EVENT_RADIO_RECEIVED;
783     event.mDataLength = 1 + aFrame->mLength; // include channel in first byte
784     memcpy(event.mData, aMessage, event.mDataLength);
785     otSimSendEvent(&event);
786 #endif
787 }
788 
radioSendAck(void)789 void radioSendAck(void)
790 {
791     if (
792 #if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
793         // Determine if frame pending should be set
794         ((otMacFrameIsVersion2015(&sReceiveFrame) && otMacFrameIsCommand(&sReceiveFrame)) ||
795          otMacFrameIsData(&sReceiveFrame) || otMacFrameIsDataRequest(&sReceiveFrame))
796 #else
797         otMacFrameIsDataRequest(&sReceiveFrame)
798 #endif
799         && hasFramePending(&sReceiveFrame))
800     {
801         sReceiveFrame.mInfo.mRxInfo.mAckedWithFramePending = true;
802     }
803 
804 #if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
805     // Use enh-ack for 802.15.4-2015 frames
806     if (otMacFrameIsVersion2015(&sReceiveFrame))
807     {
808         uint8_t  linkMetricsDataLen = 0;
809         uint8_t *dataPtr            = NULL;
810 
811 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
812         uint8_t      linkMetricsData[OT_ENH_PROBING_IE_DATA_MAX_SIZE];
813         otMacAddress macAddress;
814 
815         otEXPECT(otMacFrameGetSrcAddr(&sReceiveFrame, &macAddress) == OT_ERROR_NONE);
816 
817         linkMetricsDataLen = otLinkMetricsEnhAckGenData(&macAddress, sReceiveFrame.mInfo.mRxInfo.mLqi,
818                                                         sReceiveFrame.mInfo.mRxInfo.mRssi, linkMetricsData);
819 
820         if (linkMetricsDataLen > 0)
821         {
822             dataPtr = linkMetricsData;
823         }
824 #endif
825 
826         sAckIeDataLength = generateAckIeData(dataPtr, linkMetricsDataLen);
827 
828         otEXPECT(otMacFrameGenerateEnhAck(&sReceiveFrame, sReceiveFrame.mInfo.mRxInfo.mAckedWithFramePending,
829                                           sAckIeData, sAckIeDataLength, &sAckFrame) == OT_ERROR_NONE);
830         otEXPECT(otMacFrameProcessTxSfd(&sAckFrame, otPlatTimeGet(), &sRadioContext) == OT_ERROR_NONE);
831     }
832     else
833 #endif
834     {
835         otMacFrameGenerateImmAck(&sReceiveFrame, sReceiveFrame.mInfo.mRxInfo.mAckedWithFramePending, &sAckFrame);
836     }
837 
838     sAckMessage.mChannel = sReceiveFrame.mChannel;
839 
840     radioComputeCrc(&sAckMessage, sAckFrame.mLength);
841     radioTransmit(&sAckMessage, &sAckFrame);
842 
843 #if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
844 exit:
845 #endif
846     return;
847 }
848 
radioProcessFrame(otInstance * aInstance)849 void radioProcessFrame(otInstance *aInstance)
850 {
851     otError      error = OT_ERROR_NONE;
852     otMacAddress macAddress;
853     OT_UNUSED_VARIABLE(macAddress);
854 
855     sReceiveFrame.mInfo.mRxInfo.mRssi = -20;
856     sReceiveFrame.mInfo.mRxInfo.mLqi  = OT_RADIO_LQI_NONE;
857 
858     sReceiveFrame.mInfo.mRxInfo.mAckedWithFramePending = false;
859     sReceiveFrame.mInfo.mRxInfo.mAckedWithSecEnhAck    = false;
860 
861     otEXPECT(sPromiscuous == false);
862 
863     otEXPECT_ACTION(otMacFrameDoesAddrMatchAny(&sReceiveFrame, sPanid, sRadioContext.mShortAddress,
864                                                sRadioContext.mAlternateShortAddress, &sRadioContext.mExtAddress),
865                     error = OT_ERROR_ABORT);
866 
867 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
868     otEXPECT_ACTION(otMacFrameGetSrcAddr(&sReceiveFrame, &macAddress) == OT_ERROR_NONE, error = OT_ERROR_PARSE);
869 #endif
870 
871     // generate acknowledgment
872     if (otMacFrameIsAckRequested(&sReceiveFrame))
873     {
874         radioSendAck();
875 #if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
876         if (otMacFrameIsSecurityEnabled(&sAckFrame))
877         {
878             sReceiveFrame.mInfo.mRxInfo.mAckedWithSecEnhAck = true;
879             sReceiveFrame.mInfo.mRxInfo.mAckFrameCounter    = otMacFrameGetFrameCounter(&sAckFrame);
880         }
881 #endif // OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
882     }
883 
884 exit:
885 
886     if (error != OT_ERROR_ABORT)
887     {
888 #if OPENTHREAD_CONFIG_DIAG_ENABLE
889         if (otPlatDiagModeGet())
890         {
891             otPlatDiagRadioReceiveDone(aInstance, error == OT_ERROR_NONE ? &sReceiveFrame : NULL, error);
892         }
893         else
894 #endif
895         {
896             otPlatRadioReceiveDone(aInstance, error == OT_ERROR_NONE ? &sReceiveFrame : NULL, error);
897         }
898     }
899 }
900 
otPlatRadioEnableSrcMatch(otInstance * aInstance,bool aEnable)901 void otPlatRadioEnableSrcMatch(otInstance *aInstance, bool aEnable)
902 {
903     OT_UNUSED_VARIABLE(aInstance);
904 
905     assert(aInstance != NULL);
906 
907     sSrcMatchEnabled = aEnable;
908 }
909 
otPlatRadioEnergyScan(otInstance * aInstance,uint8_t aScanChannel,uint16_t aScanDuration)910 otError otPlatRadioEnergyScan(otInstance *aInstance, uint8_t aScanChannel, uint16_t aScanDuration)
911 {
912     OT_UNUSED_VARIABLE(aInstance);
913     OT_UNUSED_VARIABLE(aScanChannel);
914 
915     otError error = OT_ERROR_NONE;
916 
917     assert(aInstance != NULL);
918     assert(aScanChannel >= SIM_RADIO_CHANNEL_MIN && aScanChannel <= SIM_RADIO_CHANNEL_MAX);
919     assert(aScanDuration > 0);
920 
921     otEXPECT_ACTION((gRadioCaps & OT_RADIO_CAPS_ENERGY_SCAN), error = OT_ERROR_NOT_IMPLEMENTED);
922     otEXPECT_ACTION(!sEnergyScanning, error = OT_ERROR_BUSY);
923 
924     sEnergyScanResult  = GetRssi(aScanChannel);
925     sEnergyScanning    = true;
926     sEnergyScanEndTime = otPlatAlarmMilliGetNow() + aScanDuration;
927 
928 exit:
929     return error;
930 }
931 
otPlatRadioGetTransmitPower(otInstance * aInstance,int8_t * aPower)932 otError otPlatRadioGetTransmitPower(otInstance *aInstance, int8_t *aPower)
933 {
934     OT_UNUSED_VARIABLE(aInstance);
935 
936     int8_t maxPower = sChannelMaxTransmitPower[sCurrentChannel - kMinChannel];
937 
938     assert(aInstance != NULL);
939 
940     *aPower = sTxPower < maxPower ? sTxPower : maxPower;
941 
942     return OT_ERROR_NONE;
943 }
944 
otPlatRadioSetTransmitPower(otInstance * aInstance,int8_t aPower)945 otError otPlatRadioSetTransmitPower(otInstance *aInstance, int8_t aPower)
946 {
947     OT_UNUSED_VARIABLE(aInstance);
948 
949     assert(aInstance != NULL);
950 
951     sTxPower = aPower;
952 
953     return OT_ERROR_NONE;
954 }
955 
otPlatRadioGetCcaEnergyDetectThreshold(otInstance * aInstance,int8_t * aThreshold)956 otError otPlatRadioGetCcaEnergyDetectThreshold(otInstance *aInstance, int8_t *aThreshold)
957 {
958     OT_UNUSED_VARIABLE(aInstance);
959 
960     assert(aInstance != NULL);
961 
962     *aThreshold = sCcaEdThresh;
963 
964     return OT_ERROR_NONE;
965 }
966 
otPlatRadioSetCcaEnergyDetectThreshold(otInstance * aInstance,int8_t aThreshold)967 otError otPlatRadioSetCcaEnergyDetectThreshold(otInstance *aInstance, int8_t aThreshold)
968 {
969     OT_UNUSED_VARIABLE(aInstance);
970 
971     assert(aInstance != NULL);
972 
973     sCcaEdThresh = aThreshold;
974 
975     return OT_ERROR_NONE;
976 }
977 
otPlatRadioGetFemLnaGain(otInstance * aInstance,int8_t * aGain)978 otError otPlatRadioGetFemLnaGain(otInstance *aInstance, int8_t *aGain)
979 {
980     OT_UNUSED_VARIABLE(aInstance);
981 
982     assert(aInstance != NULL && aGain != NULL);
983 
984     *aGain = sLnaGain;
985 
986     return OT_ERROR_NONE;
987 }
988 
otPlatRadioSetFemLnaGain(otInstance * aInstance,int8_t aGain)989 otError otPlatRadioSetFemLnaGain(otInstance *aInstance, int8_t aGain)
990 {
991     OT_UNUSED_VARIABLE(aInstance);
992 
993     assert(aInstance != NULL);
994 
995     sLnaGain = aGain;
996 
997     return OT_ERROR_NONE;
998 }
999 
otPlatRadioGetReceiveSensitivity(otInstance * aInstance)1000 int8_t otPlatRadioGetReceiveSensitivity(otInstance *aInstance)
1001 {
1002     OT_UNUSED_VARIABLE(aInstance);
1003 
1004     assert(aInstance != NULL);
1005 
1006     return SIM_RECEIVE_SENSITIVITY;
1007 }
1008 
otPlatRadioGetState(otInstance * aInstance)1009 otRadioState otPlatRadioGetState(otInstance *aInstance)
1010 {
1011     OT_UNUSED_VARIABLE(aInstance);
1012 
1013     return sState;
1014 }
1015 
1016 #if OPENTHREAD_CONFIG_PLATFORM_RADIO_COEX_ENABLE
otPlatRadioSetCoexEnabled(otInstance * aInstance,bool aEnabled)1017 otError otPlatRadioSetCoexEnabled(otInstance *aInstance, bool aEnabled)
1018 {
1019     OT_UNUSED_VARIABLE(aInstance);
1020 
1021     assert(aInstance != NULL);
1022 
1023     sRadioCoexEnabled = aEnabled;
1024     return OT_ERROR_NONE;
1025 }
1026 
otPlatRadioIsCoexEnabled(otInstance * aInstance)1027 bool otPlatRadioIsCoexEnabled(otInstance *aInstance)
1028 {
1029     OT_UNUSED_VARIABLE(aInstance);
1030 
1031     assert(aInstance != NULL);
1032 
1033     return sRadioCoexEnabled;
1034 }
1035 
otPlatRadioGetCoexMetrics(otInstance * aInstance,otRadioCoexMetrics * aCoexMetrics)1036 otError otPlatRadioGetCoexMetrics(otInstance *aInstance, otRadioCoexMetrics *aCoexMetrics)
1037 {
1038     OT_UNUSED_VARIABLE(aInstance);
1039 
1040     otError error = OT_ERROR_NONE;
1041 
1042     assert(aInstance != NULL);
1043     otEXPECT_ACTION(aCoexMetrics != NULL, error = OT_ERROR_INVALID_ARGS);
1044 
1045     memset(aCoexMetrics, 0, sizeof(otRadioCoexMetrics));
1046 
1047     aCoexMetrics->mStopped                            = false;
1048     aCoexMetrics->mNumGrantGlitch                     = 1;
1049     aCoexMetrics->mNumTxRequest                       = 2;
1050     aCoexMetrics->mNumTxGrantImmediate                = 3;
1051     aCoexMetrics->mNumTxGrantWait                     = 4;
1052     aCoexMetrics->mNumTxGrantWaitActivated            = 5;
1053     aCoexMetrics->mNumTxGrantWaitTimeout              = 6;
1054     aCoexMetrics->mNumTxGrantDeactivatedDuringRequest = 7;
1055     aCoexMetrics->mNumTxDelayedGrant                  = 8;
1056     aCoexMetrics->mAvgTxRequestToGrantTime            = 9;
1057     aCoexMetrics->mNumRxRequest                       = 10;
1058     aCoexMetrics->mNumRxGrantImmediate                = 11;
1059     aCoexMetrics->mNumRxGrantWait                     = 12;
1060     aCoexMetrics->mNumRxGrantWaitActivated            = 13;
1061     aCoexMetrics->mNumRxGrantWaitTimeout              = 14;
1062     aCoexMetrics->mNumRxGrantDeactivatedDuringRequest = 15;
1063     aCoexMetrics->mNumRxDelayedGrant                  = 16;
1064     aCoexMetrics->mAvgRxRequestToGrantTime            = 17;
1065     aCoexMetrics->mNumRxGrantNone                     = 18;
1066 
1067 exit:
1068     return error;
1069 }
1070 #endif
1071 
otPlatRadioGetNow(otInstance * aInstance)1072 uint64_t otPlatRadioGetNow(otInstance *aInstance)
1073 {
1074     OT_UNUSED_VARIABLE(aInstance);
1075 
1076     return otPlatTimeGet();
1077 }
1078 
1079 #if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
generateAckIeData(uint8_t * aLinkMetricsIeData,uint8_t aLinkMetricsIeDataLen)1080 static uint8_t generateAckIeData(uint8_t *aLinkMetricsIeData, uint8_t aLinkMetricsIeDataLen)
1081 {
1082     OT_UNUSED_VARIABLE(aLinkMetricsIeData);
1083     OT_UNUSED_VARIABLE(aLinkMetricsIeDataLen);
1084 
1085     uint8_t offset = 0;
1086 
1087 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
1088     if (sRadioContext.mCslPeriod > 0)
1089     {
1090         offset += otMacFrameGenerateCslIeTemplate(sAckIeData);
1091     }
1092 #endif
1093 
1094 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
1095     if (aLinkMetricsIeData != NULL && aLinkMetricsIeDataLen > 0)
1096     {
1097         offset += otMacFrameGenerateEnhAckProbingIe(sAckIeData, aLinkMetricsIeData, aLinkMetricsIeDataLen);
1098     }
1099 #endif
1100 
1101     return offset;
1102 }
1103 #endif
1104 
1105 #if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
otPlatRadioEnableCsl(otInstance * aInstance,uint32_t aCslPeriod,otShortAddress aShortAddr,const otExtAddress * aExtAddr)1106 otError otPlatRadioEnableCsl(otInstance         *aInstance,
1107                              uint32_t            aCslPeriod,
1108                              otShortAddress      aShortAddr,
1109                              const otExtAddress *aExtAddr)
1110 {
1111     OT_UNUSED_VARIABLE(aInstance);
1112     OT_UNUSED_VARIABLE(aShortAddr);
1113     OT_UNUSED_VARIABLE(aExtAddr);
1114 
1115     assert(aCslPeriod < UINT16_MAX);
1116     sRadioContext.mCslPeriod = (uint16_t)aCslPeriod;
1117 
1118     return OT_ERROR_NONE;
1119 }
1120 
otPlatRadioResetCsl(otInstance * aInstance)1121 otError otPlatRadioResetCsl(otInstance *aInstance)
1122 {
1123     OT_UNUSED_VARIABLE(aInstance);
1124 
1125     sRadioContext.mCslPeriod = 0;
1126 
1127     return OT_ERROR_NONE;
1128 }
1129 
otPlatRadioUpdateCslSampleTime(otInstance * aInstance,uint32_t aCslSampleTime)1130 void otPlatRadioUpdateCslSampleTime(otInstance *aInstance, uint32_t aCslSampleTime)
1131 {
1132     OT_UNUSED_VARIABLE(aInstance);
1133 
1134     sRadioContext.mCslSampleTime = aCslSampleTime;
1135 }
1136 
otPlatRadioGetCslAccuracy(otInstance * aInstance)1137 uint8_t otPlatRadioGetCslAccuracy(otInstance *aInstance)
1138 {
1139     OT_UNUSED_VARIABLE(aInstance);
1140 
1141     return 0;
1142 }
1143 #endif // OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
1144 
otPlatRadioSetMacKey(otInstance * aInstance,uint8_t aKeyIdMode,uint8_t aKeyId,const otMacKeyMaterial * aPrevKey,const otMacKeyMaterial * aCurrKey,const otMacKeyMaterial * aNextKey,otRadioKeyType aKeyType)1145 void otPlatRadioSetMacKey(otInstance             *aInstance,
1146                           uint8_t                 aKeyIdMode,
1147                           uint8_t                 aKeyId,
1148                           const otMacKeyMaterial *aPrevKey,
1149                           const otMacKeyMaterial *aCurrKey,
1150                           const otMacKeyMaterial *aNextKey,
1151                           otRadioKeyType          aKeyType)
1152 {
1153     OT_UNUSED_VARIABLE(aInstance);
1154     OT_UNUSED_VARIABLE(aKeyIdMode);
1155 
1156     otEXPECT(aPrevKey != NULL && aCurrKey != NULL && aNextKey != NULL);
1157 
1158     sRadioContext.mKeyId               = aKeyId;
1159     sRadioContext.mKeyType             = aKeyType;
1160     sRadioContext.mPrevMacFrameCounter = sRadioContext.mMacFrameCounter;
1161     sRadioContext.mMacFrameCounter     = 0;
1162 
1163     memcpy(&sRadioContext.mPrevKey, aPrevKey, sizeof(otMacKeyMaterial));
1164     memcpy(&sRadioContext.mCurrKey, aCurrKey, sizeof(otMacKeyMaterial));
1165     memcpy(&sRadioContext.mNextKey, aNextKey, sizeof(otMacKeyMaterial));
1166 
1167 exit:
1168     return;
1169 }
1170 
otPlatRadioSetMacFrameCounter(otInstance * aInstance,uint32_t aMacFrameCounter)1171 void otPlatRadioSetMacFrameCounter(otInstance *aInstance, uint32_t aMacFrameCounter)
1172 {
1173     OT_UNUSED_VARIABLE(aInstance);
1174 
1175     sRadioContext.mMacFrameCounter = aMacFrameCounter;
1176 }
1177 
otPlatRadioSetChannelMaxTransmitPower(otInstance * aInstance,uint8_t aChannel,int8_t aMaxPower)1178 otError otPlatRadioSetChannelMaxTransmitPower(otInstance *aInstance, uint8_t aChannel, int8_t aMaxPower)
1179 {
1180     OT_UNUSED_VARIABLE(aInstance);
1181 
1182     otError error = OT_ERROR_NONE;
1183 
1184     otEXPECT_ACTION(aChannel >= kMinChannel && aChannel <= kMaxChannel, error = OT_ERROR_INVALID_ARGS);
1185     sChannelMaxTransmitPower[aChannel - kMinChannel] = aMaxPower;
1186 
1187 exit:
1188     return error;
1189 }
1190 
1191 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
otPlatRadioConfigureEnhAckProbing(otInstance * aInstance,otLinkMetrics aLinkMetrics,const otShortAddress aShortAddress,const otExtAddress * aExtAddress)1192 otError otPlatRadioConfigureEnhAckProbing(otInstance          *aInstance,
1193                                           otLinkMetrics        aLinkMetrics,
1194                                           const otShortAddress aShortAddress,
1195                                           const otExtAddress  *aExtAddress)
1196 {
1197     OT_UNUSED_VARIABLE(aInstance);
1198 
1199     return otLinkMetricsConfigureEnhAckProbing(aShortAddress, aExtAddress, aLinkMetrics);
1200 }
1201 #endif
1202 
otPlatRadioSetRegion(otInstance * aInstance,uint16_t aRegionCode)1203 otError otPlatRadioSetRegion(otInstance *aInstance, uint16_t aRegionCode)
1204 {
1205     OT_UNUSED_VARIABLE(aInstance);
1206 
1207     sRegionCode = aRegionCode;
1208     return OT_ERROR_NONE;
1209 }
1210 
otPlatRadioGetRegion(otInstance * aInstance,uint16_t * aRegionCode)1211 otError otPlatRadioGetRegion(otInstance *aInstance, uint16_t *aRegionCode)
1212 {
1213     OT_UNUSED_VARIABLE(aInstance);
1214     otError error = OT_ERROR_NONE;
1215 
1216     otEXPECT_ACTION(aRegionCode != NULL, error = OT_ERROR_INVALID_ARGS);
1217 
1218     *aRegionCode = sRegionCode;
1219 exit:
1220     return error;
1221 }
1222 
parseFromEnvAsUint16(const char * aEnvName,uint16_t * aValue)1223 void parseFromEnvAsUint16(const char *aEnvName, uint16_t *aValue)
1224 {
1225     char *env = getenv(aEnvName);
1226 
1227     if (env)
1228     {
1229         char *endptr;
1230 
1231         *aValue = (uint16_t)strtol(env, &endptr, 0);
1232 
1233         if (*endptr != '\0')
1234         {
1235             fprintf(stderr, "Invalid %s: %s\n", aEnvName, env);
1236             DieNow(OT_EXIT_FAILURE);
1237         }
1238     }
1239 }
1240