/******************************************************************************* OpenAirInterface Copyright(c) 1999 - 2014 Eurecom OpenAirInterface is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. OpenAirInterface is distributed in the hope that 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 OpenAirInterface.The full GNU General Public License is included in this distribution in the file called "COPYING". If not, see <http://www.gnu.org/licenses/>. Contact Information OpenAirInterface Admin: openair_admin@eurecom.fr OpenAirInterface Tech : openair_tech@eurecom.fr OpenAirInterface Dev : openair4g-devel@eurecom.fr Address : Eurecom, Compus SophiaTech 450, route des chappes, 06451 Biot, 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; }