1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2007 INRIA
4  *               2009,2010 Contributors
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation;
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  *
19  * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
20  * Contributors: Thomas Waldecker <twaldecker@rocketmail.com>
21  *               Martín Giachino <martin.giachino@gmail.com>
22  *
23  * Brief description: Implementation of a ns2 movement trace file reader.
24  *
25  * This implementation is based on the ns2 movement documentation of ns2
26  * as described in http://www.isi.edu/nsnam/ns/doc/node172.html
27  *
28  * Valid trace files use the following ns2 statements:
29  *
30  * $node set X_ x1
31  * $node set Y_ y1
32  * $node set Z_ z1
33  * $ns at $time $node setdest x2 y2 speed
34  * $ns at $time $node set X_ x1
35  * $ns at $time $node set Y_ Y1
36  * $ns at $time $node set Z_ Z1
37  *
38  */
39 
40 
41 #include <fstream>
42 #include <sstream>
43 #include <map>
44 #include "ns3/log.h"
45 #include "ns3/unused.h"
46 #include "ns3/simulator.h"
47 #include "ns3/node-list.h"
48 #include "ns3/node.h"
49 #include "ns3/constant-velocity-mobility-model.h"
50 #include "ns2-mobility-helper.h"
51 
52 namespace ns3 {
53 
54 NS_LOG_COMPONENT_DEFINE ("Ns2MobilityHelper");
55 
56 // Constants definitions
57 #define  NS2_AT       "at"
58 #define  NS2_X_COORD  "X_"
59 #define  NS2_Y_COORD  "Y_"
60 #define  NS2_Z_COORD  "Z_"
61 #define  NS2_SETDEST  "setdest"
62 #define  NS2_SET      "set"
63 #define  NS2_NODEID   "$node_("
64 #define  NS2_NS_SCH   "$ns_"
65 
66 
67 /**
68  * Type to maintain line parsed and its values
69  */
70 struct ParseResult
71 {
72   std::vector<std::string> tokens; //!< tokens from a line
73   std::vector<int> ivals;     //!< int values for each tokens
74   std::vector<bool> has_ival; //!< points if a tokens has an int value
75   std::vector<double> dvals;  //!< double values for each tokens
76   std::vector<bool> has_dval; //!< points if a tokens has a double value
77   std::vector<std::string> svals;  //!< string value for each token
78 };
79 /**
80  * Keeps last movement schedule. If new movement occurs during
81  * a current one, node stopping must be cancels (stored in a proper
82  * event ID), actually reached point must be calculated and new
83  * velocity must be calculated in accordance with actually reached
84  * destination.
85  */
86 struct DestinationPoint
87 {
88   Vector m_startPosition;     //!< Start position of last movement
89   Vector m_speed;             //!< Speed of the last movement (needed to derive reached destination at next schedule = start + velocity * actuallyTravelled)
90   Vector m_finalPosition;     //!< Final destination to be reached before next schedule. Replaced with actually reached if needed.
91   EventId m_stopEvent;        //!< Event scheduling node's stop. May be canceled if needed.
92   double m_travelStartTime;   //!< Travel start time is needed to calculate actually traveled time
93   double m_targetArrivalTime; //!< When a station arrives to a destination
DestinationPointns3::DestinationPoint94   DestinationPoint () :
95     m_startPosition (Vector (0,0,0)),
96     m_speed (Vector (0,0,0)),
97     m_finalPosition (Vector (0,0,0)),
98     m_travelStartTime (0),
99     m_targetArrivalTime (0)
100   {};
101 };
102 
103 
104 /**
105  * Parses a line of ns2 mobility
106  * \param str the string to parse
107  * \returns The parsed line
108  */
109 static ParseResult ParseNs2Line (const std::string& str);
110 
111 /**
112  * Put out blank spaces at the start and end of a line
113  * \param str input line
114  * \returns the line trimmed
115  */
116 static std::string TrimNs2Line (const std::string& str);
117 
118 /**
119  * Checks if a string represents a number or it has others characters than digits and point.
120  * \param s the string to check
121  * \returns true if the string represents a number
122  */
123 static bool IsNumber (const std::string& s);
124 
125 /**
126  * Check if s string represents a numeric value
127  * \param str string to check
128  * \param ret numeric value to return
129  * \return true if string represents a numeric value
130  */
131 template<class T>
132 static bool IsVal (const std::string& str, T& ret);
133 
134 /**
135  * Checks if the value between brackets is a correct nodeId number
136  * \param str string to check
137  * \returns true if the string represents a nodeId number
138  */
139 static bool HasNodeIdNumber (std::string str);
140 
141 /**
142  * Gets nodeId number in string format from the string like $node_(4)
143  * \param str string to de-tokenize
144  * \returns A string with the nodeId number
145  */
146 static std::string GetNodeIdFromToken (std::string str);
147 
148 /**
149  * Get node id number in int format
150  * \param pr the ParseResult to analyze
151  * \returns the node ID (as an int)
152  */
153 static int GetNodeIdInt (ParseResult pr);
154 
155 /**
156  * Get node id number in string format
157  * \param pr the ParseResult to analyze
158  * \returns the node ID (as a string)
159  */
160 static std::string GetNodeIdString (ParseResult pr);
161 
162 /**
163  * Add one coord to a vector position
164  * \param actPos actual position (overwritten)
165  * \param coord coordinate (x, y, or z)
166  * \param value value of the coordinate
167  * \return The vector of the position
168  */
169 static Vector SetOneInitialCoord (Vector actPos, std::string& coord, double value);
170 
171 /**
172  * Check if this corresponds to a line like this: $node_(0) set X_ 123
173  * \param pr the ParseResult to analyze
174  * \returns true if the ParseResult looks like a coordinate without a scheduled time
175  */
176 static bool IsSetInitialPos (ParseResult pr);
177 
178 /**
179  * Check if this corresponds to a line like this: $ns_ at 1 "$node_(0) setdest 2 3 4"
180  * \param pr the ParseResult to analyze
181  * \returns true if the ParseResult looks like a coordinate with a scheduled time and destionation
182  */
183 static bool IsSchedSetPos (ParseResult pr);
184 
185 /**
186  * Check if this corresponds to a line like this: $ns_ at 1 "$node_(0) set X_ 2"
187  * \param pr the ParseResult to analyze
188  * \returns true if the ParseResult looks like a coordinate with a scheduled time
189  */
190 static bool IsSchedMobilityPos (ParseResult pr);
191 
192 /**
193  * Set waypoints and speed for movement.
194  * \param model mobility model
195  * \param lastPos last position
196  * \param at initial movement time
197  * \param xFinalPosition final position (X axis)
198  * \param yFinalPosition final position (Y axis)
199  * \param speed movement speed
200  * \returns A descriptor of the movement
201  */
202 static DestinationPoint SetMovement (Ptr<ConstantVelocityMobilityModel> model, Vector lastPos, double at,
203                                      double xFinalPosition, double yFinalPosition, double speed);
204 
205 /**
206  * Set initial position for a node
207  * \param model mobility model
208  * \param coord coordinate (x, y, or z)
209  * \param coordVal value of the coordinate
210  * \return The vector of the position
211  */
212 static Vector SetInitialPosition (Ptr<ConstantVelocityMobilityModel> model, std::string coord, double coordVal);
213 
214 /**
215  * Schedule a set of position for a node
216  * \param model mobility model
217  * \param at initial movement time
218  * \param coord coordinate (x, y, or z)
219  * \param coordVal value of the coordinate
220  * \return The vector of the position at the given time
221  */
222 static Vector SetSchedPosition (Ptr<ConstantVelocityMobilityModel> model, double at, std::string coord, double coordVal);
223 
224 
Ns2MobilityHelper(std::string filename)225 Ns2MobilityHelper::Ns2MobilityHelper (std::string filename)
226   : m_filename (filename)
227 {
228   std::ifstream file (m_filename.c_str (), std::ios::in);
229   if (!(file.is_open ())) NS_FATAL_ERROR("Could not open trace file " << m_filename.c_str() << " for reading, aborting here \n");
230 }
231 
232 Ptr<ConstantVelocityMobilityModel>
GetMobilityModel(std::string idString,const ObjectStore & store) const233 Ns2MobilityHelper::GetMobilityModel (std::string idString, const ObjectStore &store) const
234 {
235   std::istringstream iss;
236   iss.str (idString);
237   uint32_t id (0);
238   iss >> id;
239   Ptr<Object> object = store.Get (id);
240   if (object == 0)
241     {
242       return 0;
243     }
244   Ptr<ConstantVelocityMobilityModel> model = object->GetObject<ConstantVelocityMobilityModel> ();
245   if (model == 0)
246     {
247       model = CreateObject<ConstantVelocityMobilityModel> ();
248       object->AggregateObject (model);
249     }
250   return model;
251 }
252 
253 
254 void
ConfigNodesMovements(const ObjectStore & store) const255 Ns2MobilityHelper::ConfigNodesMovements (const ObjectStore &store) const
256 {
257   std::map<int, DestinationPoint> last_pos;    // Stores previous movement scheduled for each node
258 
259   //*****************************************************************
260   // Parse the file the first time to get the initial node positions.
261   //*****************************************************************
262 
263   // Look through the whole the file for the the initial node
264   // positions to make this helper robust to handle trace files with
265   // the initial node positions at the end.
266   std::ifstream file (m_filename.c_str (), std::ios::in);
267   if (file.is_open ())
268     {
269       while (!file.eof () )
270         {
271           int         iNodeId = 0;
272           std::string nodeId;
273           std::string line;
274 
275           getline (file, line);
276 
277           // ignore empty lines
278           if (line.empty ())
279             {
280               continue;
281             }
282 
283           ParseResult pr = ParseNs2Line (line); // Parse line and obtain tokens
284 
285           // Check if the line corresponds with setting the initial
286           // node positions
287           if (pr.tokens.size () != 4)
288             {
289               continue;
290             }
291 
292           // Get the node Id
293           nodeId  = GetNodeIdString (pr);
294           iNodeId = GetNodeIdInt (pr);
295           if (iNodeId == -1)
296             {
297               NS_LOG_ERROR ("Node number couldn't be obtained (corrupted file?): " << line << "\n");
298               continue;
299             }
300 
301           // get mobility model of node
302           Ptr<ConstantVelocityMobilityModel> model = GetMobilityModel (nodeId,store);
303 
304           // if model not exists, continue
305           if (model == 0)
306             {
307               NS_LOG_ERROR ("Unknown node ID (corrupted file?): " << nodeId << "\n");
308               continue;
309             }
310 
311 
312           /*
313            * In this case a initial position is being seted
314            * line like $node_(0) set X_ 151.05190721688197
315            */
316           if (IsSetInitialPos (pr))
317             {
318               DestinationPoint point;
319               //                                                    coord         coord value
320               point.m_finalPosition = SetInitialPosition (model, pr.tokens[2], pr.dvals[3]);
321               last_pos[iNodeId] = point;
322 
323               // Log new position
324               NS_LOG_DEBUG ("Positions after parse for node " << iNodeId << " " << nodeId <<
325                             " position = " << last_pos[iNodeId].m_finalPosition);
326             }
327         }
328       file.close ();
329     }
330 
331   //*****************************************************************
332   // Parse the file a second time to get the rest of its values
333   //*****************************************************************
334 
335   // The reason the file is parsed again is to make this helper robust
336   // to handle trace files with the initial node positions at the end.
337   file.open (m_filename.c_str (), std::ios::in);
338   if (file.is_open ())
339     {
340       while (!file.eof () )
341         {
342           int         iNodeId = 0;
343           std::string nodeId;
344           std::string line;
345 
346           getline (file, line);
347 
348           // ignore empty lines
349           if (line.empty ())
350             {
351               continue;
352             }
353 
354           ParseResult pr = ParseNs2Line (line); // Parse line and obtain tokens
355 
356           // Check if the line corresponds with one of the three types of line
357           if (pr.tokens.size () != 4 && pr.tokens.size () != 7 && pr.tokens.size () != 8)
358             {
359               NS_LOG_ERROR ("Line has not correct number of parameters (corrupted file?): " << line << "\n");
360               continue;
361             }
362 
363           // Get the node Id
364           nodeId  = GetNodeIdString (pr);
365           iNodeId = GetNodeIdInt (pr);
366           if (iNodeId == -1)
367             {
368               NS_LOG_ERROR ("Node number couldn't be obtained (corrupted file?): " << line << "\n");
369               continue;
370             }
371 
372           // get mobility model of node
373           Ptr<ConstantVelocityMobilityModel> model = GetMobilityModel (nodeId,store);
374 
375           // if model not exists, continue
376           if (model == 0)
377             {
378               NS_LOG_ERROR ("Unknown node ID (corrupted file?): " << nodeId << "\n");
379               continue;
380             }
381 
382 
383           /*
384            * In this case a initial position is being seted
385            * line like $node_(0) set X_ 151.05190721688197
386            */
387           if (IsSetInitialPos (pr))
388             {
389               // This is the second time this file has been parsed,
390               // and the initial node positions were already set the
391               // first time.  So, do nothing this time with this line.
392               continue;
393             }
394 
395           else // NOW EVENTS TO BE SCHEDULED
396             {
397 
398               // This is a scheduled event, so time at should be present
399               double at;
400 
401               if (!IsNumber (pr.tokens[2]))
402                 {
403                   NS_LOG_WARN ("Time is not a number: " << pr.tokens[2]);
404                   continue;
405                 }
406 
407               at = pr.dvals[2]; // set time at
408 
409               if ( at < 0 )
410                 {
411                   NS_LOG_WARN ("Time is less than cero: " << at);
412                   continue;
413                 }
414 
415 
416 
417               /*
418                * In this case a new waypoint is added
419                * line like $ns_ at 1 "$node_(0) setdest 2 3 4"
420                */
421               if (IsSchedMobilityPos (pr))
422                 {
423                   if (last_pos[iNodeId].m_targetArrivalTime > at)
424                     {
425                       NS_LOG_LOGIC ("Did not reach a destination! stoptime = " << last_pos[iNodeId].m_targetArrivalTime << ", at = "<<  at);
426                       double actuallytraveled = at - last_pos[iNodeId].m_travelStartTime;
427                       Vector reached = Vector (
428                           last_pos[iNodeId].m_startPosition.x + last_pos[iNodeId].m_speed.x * actuallytraveled,
429                           last_pos[iNodeId].m_startPosition.y + last_pos[iNodeId].m_speed.y * actuallytraveled,
430                           0
431                           );
432                       NS_LOG_LOGIC ("Final point = " << last_pos[iNodeId].m_finalPosition << ", actually reached = " << reached);
433                       last_pos[iNodeId].m_stopEvent.Cancel ();
434                       last_pos[iNodeId].m_finalPosition = reached;
435                     }
436                   //                                     last position     time  X coord     Y coord      velocity
437                   last_pos[iNodeId] = SetMovement (model, last_pos[iNodeId].m_finalPosition, at, pr.dvals[5], pr.dvals[6], pr.dvals[7]);
438 
439                   // Log new position
440                   NS_LOG_DEBUG ("Positions after parse for node " << iNodeId << " " << nodeId << " position =" << last_pos[iNodeId].m_finalPosition);
441                 }
442 
443 
444               /*
445                * Scheduled set position
446                * line like $ns_ at 4.634906291962 "$node_(0) set X_ 28.675920486450"
447                */
448               else if (IsSchedSetPos (pr))
449                 {
450                   //                                         time  coordinate   coord value
451                   last_pos[iNodeId].m_finalPosition = SetSchedPosition (model, at, pr.tokens[5], pr.dvals[6]);
452                   if (last_pos[iNodeId].m_targetArrivalTime > at)
453                     {
454                       last_pos[iNodeId].m_stopEvent.Cancel ();
455                     }
456                   last_pos[iNodeId].m_targetArrivalTime = at;
457                   last_pos[iNodeId].m_travelStartTime = at;
458                   // Log new position
459                   NS_LOG_DEBUG ("Positions after parse for node " << iNodeId << " " << nodeId <<
460                                 " position =" << last_pos[iNodeId].m_finalPosition);
461                 }
462               else
463                 {
464                   NS_LOG_WARN ("Format Line is not correct: " << line << "\n");
465                 }
466             }
467         }
468       file.close ();
469     }
470 }
471 
472 
473 ParseResult
ParseNs2Line(const std::string & str)474 ParseNs2Line (const std::string& str)
475 {
476   ParseResult ret;
477   std::istringstream s;
478   std::string line;
479 
480   // ignore comments (#)
481   size_t pos_sharp = str.find_first_of ('#');
482   if (pos_sharp != std::string::npos)
483     {
484       line = str.substr (0, pos_sharp);
485     }
486   else
487     {
488       line = str;
489     }
490 
491   line = TrimNs2Line (line);
492 
493   // If line hasn't a correct node Id
494   if (!HasNodeIdNumber (line))
495     {
496       NS_LOG_WARN ("Line has no node Id: " << line);
497       return ret;
498     }
499 
500   s.str (line);
501 
502   while (!s.eof ())
503     {
504       std::string x;
505       s >> x;
506       if (x.length () == 0)
507         {
508           continue;
509         }
510       ret.tokens.push_back (x);
511       int ii (0);
512       double d (0);
513       if (HasNodeIdNumber (x))
514         {
515           x = GetNodeIdFromToken (x);
516         }
517       ret.has_ival.push_back (IsVal<int> (x, ii));
518       ret.ivals.push_back (ii);
519       ret.has_dval.push_back (IsVal<double> (x, d));
520       ret.dvals.push_back (d);
521       ret.svals.push_back (x);
522     }
523 
524   size_t tokensLength   = ret.tokens.size ();                 // number of tokens in line
525   size_t lasTokenLength = ret.tokens[tokensLength - 1].size (); // length of the last token
526 
527   // if it is a scheduled set _[XYZ] or a setdest I need to remove the last "
528   // and re-calculate values
529   if ( (tokensLength == 7 || tokensLength == 8)
530        && (ret.tokens[tokensLength - 1][lasTokenLength - 1] == '"') )
531     {
532 
533       // removes " from the last position
534       ret.tokens[tokensLength - 1] = ret.tokens[tokensLength - 1].substr (0,lasTokenLength - 1);
535 
536       std::string x;
537       x = ret.tokens[tokensLength - 1];
538 
539       if (HasNodeIdNumber (x))
540         {
541           x = GetNodeIdFromToken (x);
542         }
543 
544       // Re calculate values
545       int ii (0);
546       double d (0);
547       ret.has_ival[tokensLength - 1] = IsVal<int> (x, ii);
548       ret.ivals[tokensLength - 1] = ii;
549       ret.has_dval[tokensLength - 1] = IsVal<double> (x, d);
550       ret.dvals[tokensLength - 1] = d;
551       ret.svals[tokensLength - 1] = x;
552 
553     }
554   else if ( (tokensLength == 9 && ret.tokens[tokensLength - 1] == "\"")
555             || (tokensLength == 8 && ret.tokens[tokensLength - 1] == "\""))
556     {
557       // if the line has the " character in this way: $ns_ at 1 "$node_(0) setdest 2 2 1  "
558       // or in this: $ns_ at 4 "$node_(0) set X_ 2  " we need to ignore this last token
559 
560       ret.tokens.erase (ret.tokens.begin () + tokensLength - 1);
561       ret.has_ival.erase (ret.has_ival.begin () + tokensLength - 1);
562       ret.ivals.erase (ret.ivals.begin () + tokensLength - 1);
563       ret.has_dval.erase (ret.has_dval.begin () + tokensLength - 1);
564       ret.dvals.erase (ret.dvals.begin () + tokensLength - 1);
565       ret.svals.erase (ret.svals.begin () + tokensLength - 1);
566 
567     }
568 
569 
570 
571   return ret;
572 }
573 
574 
575 std::string
TrimNs2Line(const std::string & s)576 TrimNs2Line (const std::string& s)
577 {
578   std::string ret = s;
579 
580   while (ret.size () > 0 && isblank (ret[0]))
581     {
582       ret.erase (0, 1);    // Removes blank spaces at the beginning of the line
583     }
584 
585   while (ret.size () > 0 && (isblank (ret[ret.size () - 1]) || (ret[ret.size () - 1] == ';')))
586     {
587       ret.erase (ret.size () - 1, 1); // Removes blank spaces from at end of line
588     }
589 
590   return ret;
591 }
592 
593 
594 bool
IsNumber(const std::string & s)595 IsNumber (const std::string& s)
596 {
597   char *endp;
598   double v = strtod (s.c_str (), &endp); // declared with warn_unused_result
599   NS_UNUSED (v); // suppress "set but not used" compiler warning
600   return endp == s.c_str () + s.size ();
601 }
602 
603 
604 template<class T>
IsVal(const std::string & str,T & ret)605 bool IsVal (const std::string& str, T& ret)
606 {
607   if (str.size () == 0)
608     {
609       return false;
610     }
611   else if (IsNumber (str))
612     {
613       std::string s2 = str;
614       std::istringstream s (s2);
615       s >> ret;
616       return true;
617     }
618   else
619     {
620       return false;
621     }
622 }
623 
624 
625 bool
HasNodeIdNumber(std::string str)626 HasNodeIdNumber (std::string str)
627 {
628 
629   // find brackets
630   std::string::size_type startNodeId = str.find_first_of ("("); // index of left bracket
631   std::string::size_type endNodeId   = str.find_first_of (")"); // index of right bracket
632 
633   // Get de nodeId in a string and in a int value
634   std::string nodeId;     // node id
635 
636   // if no brackets, continue!
637   if (startNodeId == std::string::npos || endNodeId == std::string::npos)
638     {
639       return false;
640     }
641 
642   nodeId = str.substr (startNodeId + 1, endNodeId - (startNodeId + 1)); // set node id
643 
644   //   is number              is integer                                       is not negative
645   if (IsNumber (nodeId) && (nodeId.find_first_of (".") == std::string::npos) && (nodeId[0] != '-'))
646     {
647       return true;
648     }
649   else
650     {
651       return false;
652     }
653 }
654 
655 
656 std::string
GetNodeIdFromToken(std::string str)657 GetNodeIdFromToken (std::string str)
658 {
659   if (HasNodeIdNumber (str))
660     {
661       // find brackets
662       std::string::size_type startNodeId = str.find_first_of ("(");     // index of left bracket
663       std::string::size_type endNodeId   = str.find_first_of (")");     // index of right bracket
664 
665       return str.substr (startNodeId + 1, endNodeId - (startNodeId + 1)); // set node id
666     }
667   else
668     {
669       return "";
670     }
671 }
672 
673 
674 int
GetNodeIdInt(ParseResult pr)675 GetNodeIdInt (ParseResult pr)
676 {
677   int result = -1;
678   switch (pr.tokens.size ())
679     {
680     case 4:   // line like $node_(0) set X_ 11
681       result = pr.ivals[0];
682       break;
683     case 7:   // line like $ns_ at 4 "$node_(0) set X_ 28"
684       result = pr.ivals[3];
685       break;
686     case 8:   // line like $ns_ at 1 "$node_(0) setdest 2 3 4"
687       result = pr.ivals[3];
688       break;
689     default:
690       result = -1;
691     }
692   return result;
693 }
694 
695 // Get node id number in string format
696 std::string
GetNodeIdString(ParseResult pr)697 GetNodeIdString (ParseResult pr)
698 {
699   switch (pr.tokens.size ())
700     {
701     case 4:   // line like $node_(0) set X_ 11
702       return pr.svals[0];
703       break;
704     case 7:   // line like $ns_ at 4 "$node_(0) set X_ 28"
705       return pr.svals[3];
706       break;
707     case 8:   // line like $ns_ at 1 "$node_(0) setdest 2 3 4"
708       return pr.svals[3];
709       break;
710     default:
711       return "";
712     }
713 }
714 
715 
716 Vector
SetOneInitialCoord(Vector position,std::string & coord,double value)717 SetOneInitialCoord (Vector position, std::string& coord, double value)
718 {
719 
720   // set the position for the coord.
721   if (coord == NS2_X_COORD)
722     {
723       position.x = value;
724       NS_LOG_DEBUG ("X=" << value);
725     }
726   else if (coord == NS2_Y_COORD)
727     {
728       position.y = value;
729       NS_LOG_DEBUG ("Y=" << value);
730     }
731   else if (coord == NS2_Z_COORD)
732     {
733       position.z = value;
734       NS_LOG_DEBUG ("Z=" << value);
735     }
736   return position;
737 }
738 
739 
740 bool
IsSetInitialPos(ParseResult pr)741 IsSetInitialPos (ParseResult pr)
742 {
743   //        number of tokens         has $node_( ?                        has "set"           has doble for position?
744   return pr.tokens.size () == 4 && HasNodeIdNumber (pr.tokens[0]) && pr.tokens[1] == NS2_SET && pr.has_dval[3]
745          // coord name is X_, Y_ or Z_ ?
746          && (pr.tokens[2] == NS2_X_COORD || pr.tokens[2] == NS2_Y_COORD || pr.tokens[2] == NS2_Z_COORD);
747 
748 }
749 
750 
751 bool
IsSchedSetPos(ParseResult pr)752 IsSchedSetPos (ParseResult pr)
753 {
754   //      correct number of tokens,    has $ns_                   and at
755   return pr.tokens.size () == 7 && pr.tokens[0] == NS2_NS_SCH && pr.tokens[1] == NS2_AT
756          && pr.tokens[4] == NS2_SET && pr.has_dval[2] && pr.has_dval[3]   // has set and double value for time and nodeid
757          && ( pr.tokens[5] == NS2_X_COORD || pr.tokens[5] == NS2_Y_COORD || pr.tokens[5] == NS2_Z_COORD) // has X_, Y_ or Z_?
758          && pr.has_dval[2]; // time is a number
759 }
760 
761 bool
IsSchedMobilityPos(ParseResult pr)762 IsSchedMobilityPos (ParseResult pr)
763 {
764   //     number of tokens      and    has $ns_                and    has at
765   return pr.tokens.size () == 8 && pr.tokens[0] == NS2_NS_SCH && pr.tokens[1] == NS2_AT
766          //    time             x coord          y coord          velocity are numbers?
767          && pr.has_dval[2] && pr.has_dval[5] && pr.has_dval[6] && pr.has_dval[7]
768          && pr.tokens[4] == NS2_SETDEST; // and has setdest
769 
770 }
771 
772 DestinationPoint
SetMovement(Ptr<ConstantVelocityMobilityModel> model,Vector last_pos,double at,double xFinalPosition,double yFinalPosition,double speed)773 SetMovement (Ptr<ConstantVelocityMobilityModel> model, Vector last_pos, double at,
774              double xFinalPosition, double yFinalPosition, double speed)
775 {
776   DestinationPoint retval;
777   retval.m_startPosition = last_pos;
778   retval.m_finalPosition = last_pos;
779   retval.m_travelStartTime = at;
780   retval.m_targetArrivalTime = at;
781 
782   if (speed == 0)
783     {
784       // We have to maintain last position, and stop the movement
785       retval.m_stopEvent = Simulator::Schedule (Seconds (at), &ConstantVelocityMobilityModel::SetVelocity, model,
786                                                 Vector (0, 0, 0));
787       return retval;
788     }
789   if (speed > 0)
790     {
791       // first calculate the time; time = distance / speed
792       double time = std::sqrt (std::pow (xFinalPosition - retval.m_finalPosition.x, 2) + std::pow (yFinalPosition - retval.m_finalPosition.y, 2)) / speed;
793       NS_LOG_DEBUG ("at=" << at << " time=" << time);
794       if (time == 0)
795         {
796           return retval;
797         }
798       // now calculate the xSpeed = distance / time
799       double xSpeed = (xFinalPosition - retval.m_finalPosition.x) / time;
800       double ySpeed = (yFinalPosition - retval.m_finalPosition.y) / time; // & same with ySpeed
801       retval.m_speed = Vector (xSpeed, ySpeed, 0);
802 
803       // quick and dirty set zSpeed = 0
804       double zSpeed = 0;
805 
806       NS_LOG_DEBUG ("Calculated Speed: X=" << xSpeed << " Y=" << ySpeed << " Z=" << zSpeed);
807 
808       // Set the Values
809       Simulator::Schedule (Seconds (at), &ConstantVelocityMobilityModel::SetVelocity, model, Vector (xSpeed, ySpeed, zSpeed));
810       retval.m_stopEvent = Simulator::Schedule (Seconds (at + time), &ConstantVelocityMobilityModel::SetVelocity, model, Vector (0, 0, 0));
811       retval.m_finalPosition.x += xSpeed * time;
812       retval.m_finalPosition.y += ySpeed * time;
813       retval.m_targetArrivalTime += time;
814     }
815   return retval;
816 }
817 
818 
819 Vector
SetInitialPosition(Ptr<ConstantVelocityMobilityModel> model,std::string coord,double coordVal)820 SetInitialPosition (Ptr<ConstantVelocityMobilityModel> model, std::string coord, double coordVal)
821 {
822   model->SetPosition (SetOneInitialCoord (model->GetPosition (), coord, coordVal));
823 
824   Vector position;
825   position.x = model->GetPosition ().x;
826   position.y = model->GetPosition ().y;
827   position.z = model->GetPosition ().z;
828 
829   return position;
830 }
831 
832 // Schedule a set of position for a node
833 Vector
SetSchedPosition(Ptr<ConstantVelocityMobilityModel> model,double at,std::string coord,double coordVal)834 SetSchedPosition (Ptr<ConstantVelocityMobilityModel> model, double at, std::string coord, double coordVal)
835 {
836   // update position
837   model->SetPosition (SetOneInitialCoord (model->GetPosition (), coord, coordVal));
838 
839   Vector position;
840   position.x = model->GetPosition ().x;
841   position.y = model->GetPosition ().y;
842   position.z = model->GetPosition ().z;
843 
844   // Chedule next positions
845   Simulator::Schedule (Seconds (at), &ConstantVelocityMobilityModel::SetPosition, model,position);
846 
847   return position;
848 }
849 
850 void
Install(void) const851 Ns2MobilityHelper::Install (void) const
852 {
853   Install (NodeList::Begin (), NodeList::End ());
854 }
855 
856 } // namespace ns3
857