1 /*
2 * Copyright (c) 2016, 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 /**
30 * @file
31 * @brief
32 * This file includes the platform-specific initializers.
33 */
34
35 #include "platform-simulation.h"
36
37 #if OPENTHREAD_SIMULATION_VIRTUAL_TIME == 0
38
39 #include <arpa/inet.h>
40 #include <assert.h>
41 #include <errno.h>
42 #include <getopt.h>
43 #include <libgen.h>
44 #include <stddef.h>
45 #include <stdint.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <sys/types.h>
50
51 #include <openthread/tasklet.h>
52 #include <openthread/platform/alarm-milli.h>
53 #include <openthread/platform/radio.h>
54
55 #include "simul_utils.h"
56
57 uint32_t gNodeId = 1;
58
59 extern bool gPlatformPseudoResetWasRequested;
60 extern otRadioCaps gRadioCaps;
61
62 static volatile bool gTerminate = false;
63
handleSignal(int aSignal)64 static void handleSignal(int aSignal)
65 {
66 OT_UNUSED_VARIABLE(aSignal);
67
68 gTerminate = true;
69 }
70
71 /**
72 * Defines the argument return values.
73 */
74 enum
75 {
76 OT_SIM_OPT_HELP = 'h',
77 OT_SIM_OPT_ENABLE_ENERGY_SCAN = 'E',
78 OT_SIM_OPT_LOCAL_INTERFACE = 'L',
79 OT_SIM_OPT_SLEEP_TO_TX = 't',
80 OT_SIM_OPT_TIME_SPEED = 's',
81 OT_SIM_OPT_LOG_FILE = 'l',
82 OT_SIM_OPT_UNKNOWN = '?',
83 };
84
PrintUsage(const char * aProgramName,int aExitCode)85 static void PrintUsage(const char *aProgramName, int aExitCode)
86 {
87 fprintf(stderr,
88 "Syntax:\n"
89 " %s [Options] NodeId\n"
90 "Options:\n"
91 " -h --help Display this usage information.\n"
92 " -L --local-interface=val The address or name of the netif to simulate Thread radio.\n"
93 " -E --enable-energy-scan Enable energy scan capability.\n"
94 " -t --sleep-to-tx Let radio support direct transition from sleep to TX with CSMA.\n"
95 " -s --time-speed=val Speed up the time in simulation.\n"
96 #if (OPENTHREAD_CONFIG_LOG_OUTPUT == OPENTHREAD_CONFIG_LOG_OUTPUT_PLATFORM_DEFINED)
97 " -l --log-file=name File name to write logs.\n"
98 #endif
99 ,
100 aProgramName);
101
102 exit(aExitCode);
103 }
104
otSysInit(int aArgCount,char * aArgVector[])105 void otSysInit(int aArgCount, char *aArgVector[])
106 {
107 char *endptr;
108 uint32_t speedUpFactor = 1;
109
110 static const struct option long_options[] = {
111 {"help", no_argument, 0, OT_SIM_OPT_HELP},
112 {"enable-energy-scan", no_argument, 0, OT_SIM_OPT_ENABLE_ENERGY_SCAN},
113 {"sleep-to-tx", no_argument, 0, OT_SIM_OPT_SLEEP_TO_TX},
114 {"time-speed", required_argument, 0, OT_SIM_OPT_TIME_SPEED},
115 {"local-interface", required_argument, 0, OT_SIM_OPT_LOCAL_INTERFACE},
116 #if (OPENTHREAD_CONFIG_LOG_OUTPUT == OPENTHREAD_CONFIG_LOG_OUTPUT_PLATFORM_DEFINED)
117 {"log-file", required_argument, 0, OT_SIM_OPT_LOG_FILE},
118 #endif
119 {0, 0, 0, 0},
120 };
121
122 #if (OPENTHREAD_CONFIG_LOG_OUTPUT == OPENTHREAD_CONFIG_LOG_OUTPUT_PLATFORM_DEFINED)
123 static const char options[] = "Ehts:L:l:";
124 #else
125 static const char options[] = "Ehts:L:";
126 #endif
127
128 if (gPlatformPseudoResetWasRequested)
129 {
130 gPlatformPseudoResetWasRequested = false;
131 return;
132 }
133
134 optind = 1;
135
136 while (true)
137 {
138 int c = getopt_long(aArgCount, aArgVector, options, long_options, NULL);
139
140 if (c == -1)
141 {
142 break;
143 }
144
145 switch (c)
146 {
147 case OT_SIM_OPT_UNKNOWN:
148 PrintUsage(aArgVector[0], EXIT_FAILURE);
149 break;
150 case OT_SIM_OPT_HELP:
151 PrintUsage(aArgVector[0], EXIT_SUCCESS);
152 break;
153 case OT_SIM_OPT_ENABLE_ENERGY_SCAN:
154 gRadioCaps |= OT_RADIO_CAPS_ENERGY_SCAN;
155 break;
156 case OT_SIM_OPT_SLEEP_TO_TX:
157 gRadioCaps |= OT_RADIO_CAPS_SLEEP_TO_TX;
158 break;
159 case OT_SIM_OPT_LOCAL_INTERFACE:
160 gLocalInterface = optarg;
161 break;
162 case OT_SIM_OPT_TIME_SPEED:
163 speedUpFactor = (uint32_t)strtol(optarg, &endptr, 10);
164 if (*endptr != '\0' || speedUpFactor == 0)
165 {
166 fprintf(stderr, "Invalid value for TimerSpeedUpFactor: %s\n", optarg);
167 exit(EXIT_FAILURE);
168 }
169 break;
170 #if OPENTHREAD_CONFIG_LOG_OUTPUT == OPENTHREAD_CONFIG_LOG_OUTPUT_PLATFORM_DEFINED
171 case OT_SIM_OPT_LOG_FILE:
172 platformLoggingSetFileName(optarg);
173 break;
174 #endif
175 default:
176 break;
177 }
178 }
179
180 if (optind != aArgCount - 1)
181 {
182 PrintUsage(aArgVector[0], EXIT_FAILURE);
183 }
184
185 gNodeId = (uint32_t)strtol(aArgVector[optind], &endptr, 0);
186
187 if (*endptr != '\0' || gNodeId < 1 || gNodeId > MAX_NETWORK_SIZE)
188 {
189 fprintf(stderr, "Invalid NodeId: %s\n", aArgVector[optind]);
190 exit(EXIT_FAILURE);
191 }
192
193 signal(SIGTERM, &handleSignal);
194 signal(SIGHUP, &handleSignal);
195
196 platformLoggingInit(basename(aArgVector[0]));
197 platformAlarmInit(speedUpFactor);
198 platformRadioInit();
199 #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
200 platformTrelInit(speedUpFactor);
201 #endif
202 #if OPENTHREAD_SIMULATION_IMPLEMENT_INFRA_IF && OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
203 platformInfraIfInit();
204 #endif
205 platformRandomInit();
206 }
207
otSysPseudoResetWasRequested(void)208 bool otSysPseudoResetWasRequested(void) { return gPlatformPseudoResetWasRequested; }
209
otSysDeinit(void)210 void otSysDeinit(void)
211 {
212 platformRadioDeinit();
213 #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
214 platformTrelDeinit();
215 #endif
216 #if OPENTHREAD_SIMULATION_IMPLEMENT_INFRA_IF && OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
217 platformInfraIfDeinit();
218 #endif
219 platformLoggingDeinit();
220 }
221
otSysProcessDrivers(otInstance * aInstance)222 void otSysProcessDrivers(otInstance *aInstance)
223 {
224 fd_set read_fds;
225 fd_set write_fds;
226 fd_set error_fds;
227 int max_fd = -1;
228 struct timeval timeout;
229 int rval;
230
231 FD_ZERO(&read_fds);
232 FD_ZERO(&write_fds);
233 FD_ZERO(&error_fds);
234
235 platformUartUpdateFdSet(&read_fds, &write_fds, &error_fds, &max_fd);
236 platformAlarmUpdateTimeout(&timeout);
237 platformRadioUpdateFdSet(&read_fds, &write_fds, &timeout, &max_fd);
238 #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
239 platformTrelUpdateFdSet(&read_fds, &write_fds, &timeout, &max_fd);
240 #endif
241 #if OPENTHREAD_SIMULATION_IMPLEMENT_INFRA_IF && OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
242 platformInfraIfUpdateFdSet(&read_fds, &write_fds, &max_fd);
243 #endif
244 #if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE && OPENTHREAD_SIMULATION_MDNS_SOCKET_IMPLEMENT_POSIX
245 platformMdnsSocketUpdateFdSet(&read_fds, &max_fd);
246 #endif
247
248 #if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE
249 platformBleUpdateFdSet(&read_fds, &write_fds, &timeout, &max_fd);
250 #endif
251
252 if (otTaskletsArePending(aInstance))
253 {
254 timeout.tv_sec = 0;
255 timeout.tv_usec = 0;
256 }
257
258 rval = select(max_fd + 1, &read_fds, &write_fds, &error_fds, &timeout);
259
260 if (rval >= 0)
261 {
262 platformUartProcess();
263 platformRadioProcess(aInstance, &read_fds, &write_fds);
264 #if OPENTHREAD_CONFIG_BLE_TCAT_ENABLE
265 platformBleProcess(aInstance, &read_fds, &write_fds);
266 #endif
267 }
268 else if (errno != EINTR)
269 {
270 perror("select");
271 exit(EXIT_FAILURE);
272 }
273
274 platformAlarmProcess(aInstance);
275 #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
276 platformTrelProcess(aInstance, &read_fds, &write_fds);
277 #endif
278 #if OPENTHREAD_SIMULATION_IMPLEMENT_INFRA_IF && OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
279 platformInfraIfProcess(aInstance, &read_fds, &write_fds);
280 #endif
281 #if OPENTHREAD_CONFIG_MULTICAST_DNS_ENABLE && OPENTHREAD_SIMULATION_MDNS_SOCKET_IMPLEMENT_POSIX
282 platformMdnsSocketProcess(aInstance, &read_fds);
283 #endif
284
285 if (gTerminate)
286 {
287 exit(0);
288 }
289 }
290
291 #endif // OPENTHREAD_SIMULATION_VIRTUAL_TIME == 0
292