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