xref: /aosp_15_r20/external/openthread/examples/platforms/simulation/system.c (revision cfb92d1480a9e65faed56933e9c12405f45898b4)
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