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