1 /*
2 * Copyright (c) 2018, 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
38
39 #include <assert.h>
40 #include <errno.h>
41 #include <inttypes.h>
42 #include <libgen.h>
43 #include <stddef.h>
44 #include <stdint.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <syslog.h>
48
49 #include <openthread/tasklet.h>
50 #include <openthread/platform/alarm-milli.h>
51
52 #include "lib/platform/exit_code.h"
53 #include "utils/uart.h"
54
55 uint32_t gNodeId = 1;
56
57 extern bool gPlatformPseudoResetWasRequested;
58 static volatile bool gTerminate = false;
59
60 int gArgumentsCount = 0;
61 char **gArguments = NULL;
62
63 uint64_t sNow = 0; // microseconds
64 int sSockFd;
65 uint16_t sPortBase = 9000;
66 uint16_t sPortOffset;
67
handleSignal(int aSignal)68 static void handleSignal(int aSignal)
69 {
70 OT_UNUSED_VARIABLE(aSignal);
71
72 gTerminate = true;
73 }
74
otSimSendEvent(const struct Event * aEvent)75 void otSimSendEvent(const struct Event *aEvent)
76 {
77 ssize_t rval;
78 struct sockaddr_in sockaddr;
79
80 memset(&sockaddr, 0, sizeof(sockaddr));
81 sockaddr.sin_family = AF_INET;
82 inet_pton(AF_INET, "127.0.0.1", &sockaddr.sin_addr);
83 sockaddr.sin_port = htons(sPortBase + sPortOffset);
84
85 rval = sendto(sSockFd, aEvent, offsetof(struct Event, mData) + aEvent->mDataLength, 0, (struct sockaddr *)&sockaddr,
86 sizeof(sockaddr));
87
88 if (rval < 0)
89 {
90 perror("sendto");
91 DieNow(OT_EXIT_ERROR_ERRNO);
92 }
93 }
94
receiveEvent(otInstance * aInstance)95 static void receiveEvent(otInstance *aInstance)
96 {
97 struct Event event;
98 ssize_t rval = recvfrom(sSockFd, (char *)&event, sizeof(event), 0, NULL, NULL);
99
100 if (rval < 0 || (uint16_t)rval < offsetof(struct Event, mData))
101 {
102 perror("recvfrom");
103 DieNow(OT_EXIT_ERROR_ERRNO);
104 }
105
106 platformAlarmAdvanceNow(event.mDelay);
107
108 switch (event.mEvent)
109 {
110 case OT_SIM_EVENT_ALARM_FIRED:
111 break;
112
113 case OT_SIM_EVENT_RADIO_RECEIVED:
114 platformRadioReceive(aInstance, event.mData, event.mDataLength);
115 break;
116
117 case OT_SIM_EVENT_UART_WRITE:
118 otPlatUartReceived(event.mData, event.mDataLength);
119 break;
120
121 default:
122 assert(false);
123 }
124 }
125
platformSendSleepEvent(void)126 static void platformSendSleepEvent(void)
127 {
128 struct Event event;
129
130 assert(platformAlarmGetNext() > 0);
131
132 event.mDelay = platformAlarmGetNext();
133 event.mEvent = OT_SIM_EVENT_ALARM_FIRED;
134 event.mDataLength = 0;
135
136 otSimSendEvent(&event);
137 }
138
139 #if OPENTHREAD_SIMULATION_VIRTUAL_TIME_UART
platformUartRestore(void)140 void platformUartRestore(void) {}
141
otPlatUartEnable(void)142 otError otPlatUartEnable(void) { return OT_ERROR_NONE; }
143
otPlatUartDisable(void)144 otError otPlatUartDisable(void) { return OT_ERROR_NONE; }
145
otPlatUartSend(const uint8_t * aData,uint16_t aLength)146 otError otPlatUartSend(const uint8_t *aData, uint16_t aLength)
147 {
148 otError error = OT_ERROR_NONE;
149 struct Event event;
150
151 event.mDelay = 0;
152 event.mEvent = OT_SIM_EVENT_UART_WRITE;
153 event.mDataLength = aLength;
154
155 memcpy(event.mData, aData, aLength);
156
157 otSimSendEvent(&event);
158
159 otPlatUartSendDone();
160
161 return error;
162 }
163
otPlatUartFlush(void)164 otError otPlatUartFlush(void) { return OT_ERROR_NONE; }
165 #endif // OPENTHREAD_SIMULATION_VIRTUAL_TIME_UART
166
socket_init(void)167 static void socket_init(void)
168 {
169 struct sockaddr_in sockaddr;
170 memset(&sockaddr, 0, sizeof(sockaddr));
171 sockaddr.sin_family = AF_INET;
172
173 parseFromEnvAsUint16("PORT_BASE", &sPortBase);
174
175 parseFromEnvAsUint16("PORT_OFFSET", &sPortOffset);
176 sPortOffset *= (MAX_NETWORK_SIZE + 1);
177
178 sockaddr.sin_port = htons((uint16_t)(sPortBase + sPortOffset + gNodeId));
179 sockaddr.sin_addr.s_addr = INADDR_ANY;
180
181 sSockFd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
182
183 if (sSockFd == -1)
184 {
185 perror("socket");
186 DieNow(OT_EXIT_ERROR_ERRNO);
187 }
188
189 if (bind(sSockFd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) == -1)
190 {
191 perror("bind");
192 DieNow(OT_EXIT_ERROR_ERRNO);
193 }
194 }
195
otSysInit(int argc,char * argv[])196 void otSysInit(int argc, char *argv[])
197 {
198 char *endptr;
199
200 if (gPlatformPseudoResetWasRequested)
201 {
202 gPlatformPseudoResetWasRequested = false;
203 return;
204 }
205
206 if (argc != 2)
207 {
208 DieNow(OT_EXIT_FAILURE);
209 }
210
211 openlog(basename(argv[0]), LOG_PID, LOG_USER);
212 setlogmask(setlogmask(0) & LOG_UPTO(LOG_NOTICE));
213
214 gArgumentsCount = argc;
215 gArguments = argv;
216
217 gNodeId = (uint32_t)strtol(argv[1], &endptr, 0);
218
219 if (*endptr != '\0' || gNodeId < 1 || gNodeId > MAX_NETWORK_SIZE)
220 {
221 fprintf(stderr, "Invalid NodeId: %s\n", argv[1]);
222 DieNow(OT_EXIT_FAILURE);
223 }
224
225 socket_init();
226
227 platformAlarmInit(1);
228 platformRadioInit();
229 platformRandomInit();
230
231 signal(SIGTERM, &handleSignal);
232 signal(SIGHUP, &handleSignal);
233 }
234
otSysPseudoResetWasRequested(void)235 bool otSysPseudoResetWasRequested(void) { return gPlatformPseudoResetWasRequested; }
236
otSysDeinit(void)237 void otSysDeinit(void) { close(sSockFd); }
238
otSysProcessDrivers(otInstance * aInstance)239 void otSysProcessDrivers(otInstance *aInstance)
240 {
241 fd_set read_fds;
242 fd_set write_fds;
243 fd_set error_fds;
244 int max_fd = -1;
245 int rval;
246
247 if (gTerminate)
248 {
249 exit(0);
250 }
251
252 FD_ZERO(&read_fds);
253 FD_ZERO(&write_fds);
254 FD_ZERO(&error_fds);
255
256 FD_SET(sSockFd, &read_fds);
257 max_fd = sSockFd;
258
259 #if OPENTHREAD_SIMULATION_VIRTUAL_TIME_UART == 0
260 platformUartUpdateFdSet(&read_fds, &write_fds, &error_fds, &max_fd);
261 #endif
262
263 if (!otTaskletsArePending(aInstance) && platformAlarmGetNext() > 0 && !platformRadioIsTransmitPending())
264 {
265 platformSendSleepEvent();
266
267 rval = select(max_fd + 1, &read_fds, &write_fds, &error_fds, NULL);
268
269 if ((rval < 0) && (errno != EINTR))
270 {
271 perror("select");
272 DieNow(OT_EXIT_ERROR_ERRNO);
273 }
274
275 if (rval > 0 && FD_ISSET(sSockFd, &read_fds))
276 {
277 receiveEvent(aInstance);
278 }
279 }
280
281 platformAlarmProcess(aInstance);
282 platformRadioProcess(aInstance, &read_fds, &write_fds);
283 #if OPENTHREAD_SIMULATION_VIRTUAL_TIME_UART == 0
284 platformUartProcess();
285 #endif
286 }
287
288 #if OPENTHREAD_CONFIG_OTNS_ENABLE
289
otPlatOtnsStatus(const char * aStatus)290 void otPlatOtnsStatus(const char *aStatus)
291 {
292 struct Event event;
293 uint16_t statusLength = (uint16_t)strlen(aStatus);
294
295 assert(statusLength < sizeof(event.mData));
296
297 memcpy(event.mData, aStatus, statusLength);
298 event.mDataLength = statusLength;
299 event.mDelay = 0;
300 event.mEvent = OT_SIM_EVENT_OTNS_STATUS_PUSH;
301
302 otSimSendEvent(&event);
303 }
304
305 #endif // OPENTHREAD_CONFIG_OTNS_ENABLE
306
307 #endif // OPENTHREAD_SIMULATION_VIRTUAL_TIME
308