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