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