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