1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
/*******************************************************************************
Eurecom OpenAirInterface
Copyright(c) 1999 - 2011 Eurecom
This program is free software; you can redistribute it and/or modify it
under the terms and conditions of the GNU General Public License,
version 2, as published by the Free Software Foundation.
This program is distributed in the hope it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
The full GNU General Public License is included in this distribution in
the file called "COPYING".
Contact Information
Openair Admin: openair_admin@eurecom.fr
Openair Tech : openair_tech@eurecom.fr
Forums : http://forums.eurecom.fsr/openairinterface
Address : Eurecom, 2229, route des crêtes, 06560 Valbonne Sophia Antipolis, France
*******************************************************************************/
/*! \file sumo.c
* \brief The OMG interface to SUMO (Simulation of Urban Mobility)
* \author S. Uppoor, J. Harri
* \date 2012
* \version 0.1
* \company INRIA, Eurecom
* \email: sandesh.uppor@inria.fr, haerri@eurecom.fr
* \note
* \warning
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <math.h>
#include <string.h>
#include <signal.h>
#include "sumo.h"
#include "client_traci_OMG.h"
int
start_sumo_generator (omg_global_param omg_param_list)
{
char sumo_line[300];
int n_id;
static int id = 0;
// sprintf(sumo_line, "%s -c %s -b %d -e %d --remote-port %d --step-length %d -v ",omg_param_list.sumo_command, omg_param_list.sumo_config, omg_param_list.sumo_start, omg_param_list.sumo_end, omg_param_list.sumo_port, omg_param_list.sumo_step);
sprintf (sumo_line, "%s -c %s ", omg_param_list.sumo_command,
omg_param_list.sumo_config);
printf ("%s\n", sumo_line);
if ((pid = fork ()) == 0)
{
// Start SUMO in the child process
system (sumo_line);
//childs addresss space
}
//still in the parent process
// Talk to SUMO
targetTime = 1;
departed = NULL;
arrived = NULL;
// switch on error to return to OAI
handshake (omg_param_list.sumo_host, omg_param_list.sumo_port);
init (omg_param_list.sumo_end - omg_param_list.sumo_start);
int max_node_SUMO = 100; //commandGetMaxSUMONodesVariable(); TODO method not implemented in TraCI server..must find another solution
// printf("received Number of nodes %d\n", max_node_SUMO);
// create the OAI/SUMO ID manager
id_manager = create_IDManager ();
node_struct *node = NULL;
mobility_struct *mobility = NULL;
active_nodes = NULL; // container to return a subset of only ACTIVE OAI nodes in SUMO
last_update_time = 0.0;
// just check for faulty values
if (omg_param_list.nodes <= 0)
{
#ifdef STANDALONE
printf ("Number of nodes has not been set\n");
#else
LOG_W (OMG, "Number of nodes has not been set\n");
#endif
return (-1);
}
#ifdef STANDALONE
printf ("Number of OAI-equipped nodes in SUMO has been set to %d\n",
omg_param_list.nodes);
printf ("Number of SUMO simulated nodes has been set to %d\n",
max_node_SUMO);
#else
LOG_I (OMG, "Number of OAI-equipped nodes in SUMO has been set to %d\n",
omg_param_list.nodes);
LOG_I (OMG, "Number of SUMO simulated nodes has been set to %d\n",
max_node_SUMO);
#endif
// check and match number of nodes in mobility file provided
if (omg_param_list.nodes > max_node_SUMO)
{
#ifdef STANDALONE
printf ("Not all OAI nodes will be moving according to SUMO.\n");
#else
LOG_I (OMG, "Not all OAI nodes will be moving according to SUMO.\n");
#endif
}
else
{
#ifdef STANDALONE
printf ("OAI nodes will be mapped to a subset of SUMO nodes\n");
#else
LOG_I (OMG, "OAI nodes will be mapped to a subset of SUMO nodes\n");
#endif
}
if (omg_param_list.nodes_type == eNB)
{
#ifdef STANDALONE
printf ("Node type has been set to eNB\n");
#else
LOG_I (OMG, "Node type has been set to eNB\n");
#endif
}
else if (omg_param_list.nodes_type == UE)
{
#ifdef STANDALONE
printf ("Node type has been set to UE\n");
#else
LOG_I (OMG, "Node type has been set to UE\n");
#endif
}
for (n_id = id; n_id < omg_param_list.nodes + id; n_id++)
{
node = create_node ();
mobility = create_mobility ();
node->mobile = 0; // 0 means inactive in SUMO; 1 means active in SUMO; as long as a mapping between OAI-SUMO has not been created, nodes are inactive and do not move
node->id = n_id; // this is OAI ID, not SUMO
node->type = omg_param_list.nodes_type; // UE eNB...
node->generator = SUMO; // SUMO
node->mob = mobility;
node_vector_end[SUMO] =
(node_list *) add_entry (node, node_vector_end[SUMO]);
if (node_vector[SUMO] == NULL)
node_vector[SUMO] = node_vector_end[SUMO];
}
id += omg_param_list.nodes;
update_IDs (); // update the mapping between departed and arrived nodes in SUMO.
return (0);
}
void
update_IDs (void)
{
#ifdef STANDALONE
printf ("Updating the ID mapping between SUMO and OAI\n");
#else
LOG_D (OMG, "Updating the ID mapping between SUMO and OAI\n");
#endif
string_list *tmp_arrived, *tmp_departed;
if (arrived == NULL)
{
printf ("arrived vehicles is NULL \n");
return;
}
tmp_arrived = arrived;
tmp_departed = departed;
if (departed == NULL)
{
printf ("departed vehicles is NULL \n");
return;
}
if (tmp_departed->string != NULL)
{
char *tmp_string = malloc (sizeof (strlen (tmp_departed->string)));
strcpy (tmp_string, tmp_departed->string);
//printf("OMG - 2 head is not null and value is: %s\n",tmp_string);
int OAI_ID = get_oaiID_by_SUMO (tmp_string, id_manager);
if (OAI_ID == -1)
{
if (!activate_and_map (tmp_string))
{
// printf("Reached the Maximum of OAI nodes to be mapped to SUMO\n");
// LOG_I(OMG, "Reached the Maximum of OAI nodes to be mapped to SUMO\n");
return; // stopping mapping as the maximum of OAI nodes has been reached;
}
}
}
while (tmp_departed->next != NULL)
{
// printf("OMG - 2 main is not null \n");
//char tmp_string [strlen(tmp_departed->string)];
char *tmp_string = malloc (sizeof (strlen (tmp_departed->string)));
strcpy (tmp_string, tmp_departed->string);
//char *tmp_string = tmp_departed->string;
int OAI_ID = get_oaiID_by_SUMO (tmp_string, id_manager);
if (OAI_ID == -1)
{
if (!activate_and_map (tmp_string))
{
//printf("Reached the Maximum of OAI nodes to be mapped to SUMO\n");
//LOG_I(OMG, "Reached the Maximum of OAI nodes to be mapped to SUMO\n");
return; // stopping mapping as the maximum of OAI nodes has been reached;
}
}
tmp_departed = tmp_departed->next;
}
departed = clear_string_list (departed);
if (tmp_arrived->string != NULL)
{
char *tmp_string = tmp_arrived->string;
//printf("OMG - 3 head is not null and value is: %s\n",tmp_arrived->string);
if (!desactivate_and_unmap (tmp_string))
{
printf ("Could not locate the OAI node ID %s \n", tmp_string);
//LOG_I(OMG, "Could not locate the OAI node ID %s \n", tmp_string);
}
}
while (tmp_arrived->next != NULL)
{
char *tmp_string = tmp_arrived->string;
if (!desactivate_and_unmap (tmp_string))
{
printf ("Could not locate the OAI node\n");
// LOG_I(OMG, "Could not locate the OAI node\n");
}
tmp_arrived = tmp_arrived->next;
}
arrived = clear_string_list (arrived);
}
bool
desactivate_and_unmap (char *sumo_id)
{
#ifdef STANDALONE
printf ("desactivating node %s \n", sumo_id);
#else
LOG_I (OMG, "desactivating node %s \n", sumo_id);
#endif
int OAI_ID = get_oaiID_by_SUMO (sumo_id, id_manager);
remove_oaiID_by_SUMO (sumo_id, id_manager);
if (OAI_ID != -1)
{
//TODO generalize to UE and eNB (must change the method)
node_struct *node = find_node (node_vector[SUMO], OAI_ID, UE);
if (node == NULL)
node = find_node (node_vector[SUMO], OAI_ID, eNB);
if (node != NULL)
{
node->mobile = 0; // this node is now inactive;
active_nodes = remove_node_entry (node, active_nodes);
return true;
}
}
#ifdef STANDALONE
printf
("Could not desactive an OAI node, as the SUMO-OAI mapping could not be found for the SUMO node ID %s \n",
sumo_id);
#else
LOG_I (OMG,
"Could not desactive an OAI node, as the SUMO-OAI mapping could not be found for the SUMO node ID %s \n",
sumo_id);
#endif
return false;
}
bool
activate_and_map (char *sumo_id)
{
MapPtr map = create_map ();
#ifdef STANDALONE
printf ("activating node %s \n", sumo_id);
#else
LOG_I (OMG, "activating node %s \n", sumo_id);
#endif
// TODO: So far, only UE can be SUMO mobile, but could change
node_struct *active_node =
get_first_inactive_OAI_node (node_vector[SUMO], UE);
if (active_node != NULL)
{ // found an inactive OAI node; will be mapped to SUMO
active_node->mobile = 1; // now node is active in SUMO
active_nodes = add_entry (active_node, active_nodes);
map->oai_id = active_node->id;
map->sumo_id = malloc (sizeof ((int) strlen (sumo_id)));
strcpy (map->sumo_id, sumo_id);
#ifdef STANDALONE
printf ("added a mapping between oai ID: %d and SUMO ID: %s \n",
map->oai_id, map->sumo_id);
#else
LOG_I (OMG, "added a mapping between oai ID: %d and SUMO ID: %s \n",
map->oai_id, map->sumo_id);
#endif
// TODO fusion the two lists...leads to data inconsistency
id_manager->map_sumo2oai =
add_map_entry (map, id_manager->map_sumo2oai);
id_manager->map_oai2sumo = add_map_entry (map, id_manager->map_oai2sumo); //map_sumo2oai
return true;
}
else
{
#ifdef STANDALONE
printf
("All OAI Nodes are already active in SUMO; cannot control this SUMO node in OAI\n");
#else
LOG_I (OMG,
"All OAI Nodes are already active in SUMO; cannot control this SUMO node in OAI\n");
#endif
return false;
}
}
void
update_sumo_nodes (double cur_time)
{
if ((cur_time - last_update_time) < MIN_SUMO_STEP)
{ // the min time interval for SUMO must be 100ms or more
printf ("--------Update Step too small--------\n");
return;
}
last_update_time = cur_time; // keeps track of the last update time to get the update interval
// commandSimulationStep(1.0);// Advance the SUMO simulation by cur_time units
commandSimulationStep (cur_time); // Advance the SUMO simulation by cur_time units
LOG_I (OMG, "--------Updated SUMO positions by %f [ms]--------\n",
cur_time);
update_IDs (); // both are in the traCI client
}
void
update_sumo_positions (node_struct * node)
{
#ifdef STANDALONE
printf ("--------GET SUMO Mobility for a single node--------\n");
#else
LOG_D (OMG, "--------GET SUMO Mobility for a single node--------\n");
#endif
Map_list tmp = id_manager->map_oai2sumo;
char *sumo_id = get_sumo_entry (node->id, tmp);
if (sumo_id != NULL)
{
//printf(" OAI ID is: %d and SUMO ID is %s \n",node->ID, sumo_id);
GetPosition (node, sumo_id);
GetSpeed (node, sumo_id);
}
}
node_list *
get_sumo_positions_updated (double cur_time)
{
#ifdef STANDALONE
printf
("--------GET SUMO Mobility for a group of ACTIVE OAI nodes--------\n");
#else
LOG_I (OMG,
"--------GET SUMO Mobility for a group of ACTIVE OAI nodes--------\n");
#endif
if (node_vector[SUMO] != NULL)
{
node_list *tmp = node_vector[SUMO];
while (tmp != NULL)
{
if ((tmp->node->generator == SUMO) && (tmp->node->mobile == 1))
{ // OAI node MUST be active
LOG_I (OMG, "found an active node with id %d \n",
tmp->node->id);
LOG_I (OMG, "Old Positions \n");
//printf("Old Positions \n");
display_node_position (tmp->node->id, tmp->node->generator,
tmp->node->type, tmp->node->mobile,
tmp->node->x_pos, tmp->node->y_pos);
update_sumo_positions (tmp->node);
//printf("New Positions \n");
LOG_I (OMG, "New Positions \n");
display_node_position (tmp->node->id, tmp->node->generator,
tmp->node->type, tmp->node->mobile,
tmp->node->x_pos, tmp->node->y_pos);
}
tmp = tmp->next;
}
}
return active_nodes;
}
node_struct *
get_first_inactive_OAI_node (node_list * list, int node_type)
{
node_list *current;
if (list != NULL)
{ //start search
current = list;
while (current->next != NULL)
{
if ((current->node->mobile == 0)
&& (current->node->type == node_type))
{
return current->node;
}
current = current->next;
}
}
return NULL; // all nodes are active already..reached the maximum number of OAI nodes
}
bool
stop_sumo_generator (void)
{
#ifdef STANDALONE
printf
(" --------Destructor for SUMO: closing the TraCI socket and killing SUMO ---- \n");
#else
LOG_I (OMG,
" --------Destructor for SUMO: closing the TraCI socket and killing SUMO ---- \n");
#endif
commandClose (); // closing the connection with SUMO via TraCI
close_connection (); // closing the socket connection
kill (pid, SIGKILL); // killing SUMO in case it could not close by itself
return true;
}