• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2016-2019, The OpenThread Authors.
3  *  All rights reserved.
4  *
5  *  Redistribution and use in source and binary forms, with or without
6  *  modification, are permitted provided that the following conditions are met:
7  *  1. Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  *  2. Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *  3. Neither the name of the copyright holder nor the
13  *     names of its contributors may be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  *  POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include "platform-simulation.h"
30 
31 #include <errno.h>
32 #include <sys/time.h>
33 
34 #include <openthread/cli.h>
35 #include <openthread/dataset.h>
36 #include <openthread/link.h>
37 #include <openthread/random_noncrypto.h>
38 #include <openthread/platform/alarm-micro.h>
39 #include <openthread/platform/alarm-milli.h>
40 #include <openthread/platform/diag.h>
41 #include <openthread/platform/radio.h>
42 #include <openthread/platform/time.h>
43 
44 #include "simul_utils.h"
45 #include "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