pre-ci tests passed git-svn-id: http://svn.eurecom.fr/openair4G/trunk@4401 818b1a75-f10b-46b9-bf7c-635c3b92a50f
413 lines
13 KiB
C
413 lines
13 KiB
C
/*******************************************************************************
|
|
|
|
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];
|
|
|
|
// 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();
|
|
|
|
NodePtr node = NULL;
|
|
MobilityPtr 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
|
|
}
|
|
|
|
int n_id = 0;
|
|
for ( n_id = 0; n_id< omg_param_list.nodes; n_id++) {
|
|
|
|
node = (NodePtr) create_node();
|
|
mobility = (MobilityPtr) 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 = omg_param_list.mobility_type; // SUMO
|
|
node->mob = mobility;
|
|
|
|
Node_Vector[SUMO] = (Node_list) add_entry(node, Node_Vector[SUMO]);
|
|
}
|
|
|
|
update_IDs(); // update the mapping between departed and arrived nodes in SUMO.
|
|
|
|
return(0);
|
|
}
|
|
|
|
void update_IDs() {
|
|
#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)
|
|
NodePtr 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
|
|
NodePtr 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(NodePtr 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;
|
|
}
|
|
|
|
NodePtr 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() {
|
|
#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;
|
|
}
|