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