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