146 MakeUintegerAccessor (&Node::m_id), |
147 MakeUintegerAccessor (&Node::m_id), |
147 MakeUintegerChecker<uint32_t> ()) |
148 MakeUintegerChecker<uint32_t> ()) |
148 ; |
149 ; |
149 return tid; |
150 return tid; |
150 } |
151 } |
151 @end verbatim |
152 @end example |
152 |
153 @end smallformat |
153 Look at the TypeId of an ns-3 @code{Object} class as an extended form of run |
154 |
154 time type information (RTTI). The C++ language includes simple kind of RTTI |
155 Consider the TypeId of an ns-3 @code{Object} class as an extended form of run |
|
156 time type information (RTTI). The C++ language includes a simple kind of RTTI |
155 in order to support @code{dynamic_cast} and @code{typeid} operators. |
157 in order to support @code{dynamic_cast} and @code{typeid} operators. |
156 |
158 |
157 The ``@code{.SetParent<Object> ()}'' call in the declaration above is used in |
159 The ``@code{.SetParent<Object> ()}'' call in the declaration above is used in |
158 conjunction with our object aggregation mechanisms to allow safe up- and |
160 conjunction with our object aggregation mechanisms to allow safe up- and |
159 down-casing in inheritance trees during @code{GetObject}. |
161 down-casting in inheritance trees during @code{GetObject}. |
160 |
162 |
161 The ``@code{.AddConstructor<Node> ()}'' call is used in conjunction with our |
163 The ``@code{.AddConstructor<Node> ()}'' call is used in conjunction with our |
162 abstract object factory mechanisms to allow us to construct C++ objects without |
164 abstract object factory mechanisms to allow us to construct C++ objects without |
163 forcing a user to know the concrete class of the object she is building. |
165 forcing a user to know the concrete class of the object she is building. |
164 |
166 |
293 strings such as "MaxPackets" and TypeId strings. In the next |
297 strings such as "MaxPackets" and TypeId strings. In the next |
294 section, we will provide an example script that shows how users |
298 section, we will provide an example script that shows how users |
295 may manipulate these values. |
299 may manipulate these values. |
296 |
300 |
297 Note that initialization of the attribute relies on the macro |
301 Note that initialization of the attribute relies on the macro |
298 NS_OBJECT_ENSURE_REGISTERED (DropTailQueue) being called; if you leave |
302 @code{NS_OBJECT_ENSURE_REGISTERED} (DropTailQueue) being called; if you leave |
299 this out of your new class implementation, your attributes will not be |
303 this out of your new class implementation, your attributes will not be |
300 initialized correctly. |
304 initialized correctly. |
301 |
305 |
302 @subsection Basic usage |
306 While we have described how to create attributes, we still haven't |
|
307 described how to access and manage these values. For instance, there is no |
|
308 @code{globals.h} header file where these are stored; attributes are |
|
309 stored with their classes. Questions that naturally arise are how |
|
310 do users easily learn about all of the attributes of their models, and |
|
311 how does a user access these attributes, or document their values |
|
312 as part of the record of their simulation? |
|
313 |
|
314 @subsection Default values and command-line arguments |
303 |
315 |
304 Let's look at how a user script might access these values. |
316 Let's look at how a user script might access these values. |
305 This is based on the script found at @code{samples/main-attribute-value.cc}, |
317 This is based on the script found at @code{samples/main-attribute-value.cc}, |
306 with some details stripped out. |
318 with some details stripped out. |
307 @verbatim |
319 @verbatim |
339 |
351 |
340 Now, we will create a few objects using the low-level API; here, |
352 Now, we will create a few objects using the low-level API; here, |
341 our newly created queues will not have a m_maxPackets initialized to |
353 our newly created queues will not have a m_maxPackets initialized to |
342 100 packets but to 80 packets, because of what we did above with |
354 100 packets but to 80 packets, because of what we did above with |
343 default values. |
355 default values. |
344 @verbatim |
356 @smallformat |
|
357 @example |
345 Ptr<Node> n0 = CreateObject<Node> (); |
358 Ptr<Node> n0 = CreateObject<Node> (); |
346 |
359 |
347 Ptr<PointToPointNetDevice> net0 = CreateObject<PointToPointNetDevice> (); |
360 Ptr<PointToPointNetDevice> net0 = CreateObject<PointToPointNetDevice> (); |
348 n0->AddDevice (net0); |
361 n0->AddDevice (net0); |
349 |
362 |
350 Ptr<Queue> q = CreateObject<DropTailQueue> (); |
363 Ptr<Queue> q = CreateObject<DropTailQueue> (); |
351 net0->AddQueue(q); |
364 net0->AddQueue(q); |
352 @end verbatim |
365 @end example |
|
366 @end smallformat |
353 |
367 |
354 At this point, we have created a single node (Node 0) and a |
368 At this point, we have created a single node (Node 0) and a |
355 single PointToPointNetDevice (NetDevice 0) and added a |
369 single PointToPointNetDevice (NetDevice 0) and added a |
356 DropTailQueue to it. |
370 DropTailQueue to it. |
357 |
371 |
358 Now, we can manipulate the MaxPackets value of the already |
372 Now, we can manipulate the MaxPackets value of the already |
359 instantiated DropTailQueue. Here are various ways to do that. |
373 instantiated DropTailQueue. Here are various ways to do that. |
360 |
374 |
361 @subsubsection Pointer-based access |
375 @subsection Pointer-based access |
362 |
376 |
363 We assume that a smart pointer (Ptr) to a relevant network device is |
377 We assume that a smart pointer (Ptr) to a relevant network device is |
364 in hand; here, it is the net0 pointer. |
378 in hand; in the current example, it is the @code{net0} pointer. |
365 |
379 |
366 One way to change the value is to access a pointer to the |
380 One way to change the value is to access a pointer to the |
367 underlying queue and modify its attribute. |
381 underlying queue and modify its attribute. |
368 |
382 |
369 First, we observe that we can get a pointer to the (base class) |
383 First, we observe that we can get a pointer to the (base class) |
370 queue via the PointToPointNetDevice attributes, where it is called |
384 queue via the PointToPointNetDevice attributes, where it is called |
371 TxQueue |
385 TxQueue |
372 @verbatim |
386 @example |
373 PointerValue tmp; |
387 PointerValue tmp; |
374 net0->GetAttribute ("TxQueue", tmp); |
388 net0->GetAttribute ("TxQueue", tmp); |
375 Ptr<Object> txQueue = tmp.GetObject (); |
389 Ptr<Object> txQueue = tmp.GetObject (); |
376 @end verbatim |
390 @end example |
377 |
391 |
378 Using the GetObject function, we can perform a safe downcast |
392 Using the GetObject function, we can perform a safe downcast |
379 to a DropTailQueue, where MaxPackets is a member |
393 to a DropTailQueue, where MaxPackets is a member |
380 @verbatim |
394 @verbatim |
381 Ptr<DropTailQueue> dtq = txQueue->GetObject <DropTailQueue> (); |
395 Ptr<DropTailQueue> dtq = txQueue->GetObject <DropTailQueue> (); |
407 txQueue->SetAttribute("MaxPackets", UintegerValue (60)); |
421 txQueue->SetAttribute("MaxPackets", UintegerValue (60)); |
408 txQueue->GetAttribute ("MaxPackets", limit); |
422 txQueue->GetAttribute ("MaxPackets", limit); |
409 NS_LOG_INFO ("3. txQueue limit changed: " << limit.Get () << " packets"); |
423 NS_LOG_INFO ("3. txQueue limit changed: " << limit.Get () << " packets"); |
410 @end verbatim |
424 @end verbatim |
411 |
425 |
412 @subsubsection Namespace-based access |
426 @subsection Namespace-based access |
413 |
427 |
414 An alternative way to get at the attribute is to use the configuration namespace. |
428 An alternative way to get at the attribute is to use the configuration namespace. |
415 Here, this attribute resides on a known path in this namespace; this approach |
429 Here, this attribute resides on a known path in this namespace; this approach |
416 is useful if one doesn't have access to the underlying pointers and would like |
430 is useful if one doesn't have access to the underlying pointers and would like |
417 to configure a specific attribute with a single statement. |
431 to configure a specific attribute with a single statement. |
418 |
432 |
419 @verbatim |
433 @smallformat |
|
434 @example |
420 Config::Set ("/NodeList/0/DeviceList/0/TxQueue/MaxPackets", UintegerValue (25)); |
435 Config::Set ("/NodeList/0/DeviceList/0/TxQueue/MaxPackets", UintegerValue (25)); |
421 txQueue->GetAttribute ("MaxPackets", limit); |
436 txQueue->GetAttribute ("MaxPackets", limit); |
422 NS_LOG_INFO ("4. txQueue limit changed through namespace: " << |
437 NS_LOG_INFO ("4. txQueue limit changed through namespace: " << |
423 limit.Get () << " packets"); |
438 limit.Get () << " packets"); |
424 @end verbatim |
439 @end example |
|
440 @end smallformat |
425 |
441 |
426 We could have also used wildcards to set this value for all nodes and all net |
442 We could have also used wildcards to set this value for all nodes and all net |
427 devices (which in this simple example has the same effect as the previous Set()) |
443 devices (which in this simple example has the same effect as the previous Set()) |
428 @verbatim |
444 @smallformat |
|
445 @example |
429 Config::Set ("/NodeList/*/DeviceList/*/TxQueue/MaxPackets", UintegerValue (15)); |
446 Config::Set ("/NodeList/*/DeviceList/*/TxQueue/MaxPackets", UintegerValue (15)); |
430 txQueue->GetAttribute ("MaxPackets", limit); |
447 txQueue->GetAttribute ("MaxPackets", limit); |
431 NS_LOG_INFO ("5. txQueue limit changed through wildcarded namespace: " << |
448 NS_LOG_INFO ("5. txQueue limit changed through wildcarded namespace: " << |
432 limit.Get () << " packets"); |
449 limit.Get () << " packets"); |
433 @end verbatim |
450 @end example |
434 |
451 @end smallformat |
435 @subsubsection Object Name Service-based access |
452 |
|
453 @subsection Object Name Service-based access |
436 |
454 |
437 Another way to get at the attribute is to use the object name service facility. |
455 Another way to get at the attribute is to use the object name service facility. |
438 Here, this attribute is found using a name string. This approach is useful if |
456 Here, this attribute is found using a name string. This approach is useful if |
439 one doesn't have access to the underlying pointers and it is difficult to |
457 one doesn't have access to the underlying pointers and it is difficult to |
440 determine the required concrete configuration namespaced path. |
458 determine the required concrete configuration namespaced path. |
441 |
459 |
442 @verbatim |
460 @smallformat |
|
461 @example |
443 Names::Add ("server", serverNode); |
462 Names::Add ("server", serverNode); |
444 Names::Add ("server/eth0", serverDevice); |
463 Names::Add ("server/eth0", serverDevice); |
445 |
464 |
446 ... |
465 ... |
447 |
466 |
448 Config::Set ("/Names/server/eth0/TxQueue/MaxPackets", UintegerValue (25)); |
467 Config::Set ("/Names/server/eth0/TxQueue/MaxPackets", UintegerValue (25)); |
449 @end verbatim |
468 @end example |
|
469 @end smallformat |
|
470 |
|
471 @xref{Object names} for a fuller treatment of the ns-3 configuration namespace. |
450 |
472 |
451 @subsection Setting through constructors helper classes |
473 @subsection Setting through constructors helper classes |
452 |
474 |
453 Arbitrary combinations of attributes can be set and fetched from |
475 Arbitrary combinations of attributes can be set and fetched from |
454 the helper and low-level APIs; either from the constructors themselves: |
476 the helper and low-level APIs; either from the constructors themselves: |
464 "DeltaY", DoubleValue (20.0), |
486 "DeltaY", DoubleValue (20.0), |
465 "GridWidth", UintegerValue (20), |
487 "GridWidth", UintegerValue (20), |
466 "LayoutType", StringValue ("RowFirst")); |
488 "LayoutType", StringValue ("RowFirst")); |
467 @end verbatim |
489 @end verbatim |
468 |
490 |
469 @subsection Value classes |
491 @subsection Implementation details |
|
492 @subsubsection Value classes |
470 Readers will note the new FooValue classes which are subclasses of the |
493 Readers will note the new FooValue classes which are subclasses of the |
471 AttributeValue base class. These can be thought of as |
494 AttributeValue base class. These can be thought of as |
472 an intermediate class that can be used to convert from raw types to the |
495 an intermediate class that can be used to convert from raw types to the |
473 Values that are used by the attribute system. Recall that this database is holding |
496 Values that are used by the attribute system. Recall that this database is holding |
474 objects of many types with a single generic type. Conversions to this |
497 objects of many types with a single generic type. Conversions to this |
487 @itemize @bullet |
510 @itemize @bullet |
488 @item ATTRIBUTE_HELPER_HEADER |
511 @item ATTRIBUTE_HELPER_HEADER |
489 @item ATTRIBUTE_HELPER_CPP |
512 @item ATTRIBUTE_HELPER_CPP |
490 @end itemize |
513 @end itemize |
491 |
514 |
492 @subsection Initialization order |
515 @subsubsection Initialization order |
493 |
516 |
494 In general, the attribute code to assign values to the underlying |
517 In general, the attribute code to assign values to the underlying |
495 class member variables is executed after an object is constructed. |
518 class member variables is executed after an object is constructed. |
496 But what if you need the values assigned before the constructor |
519 But what if you need the values assigned before the constructor |
497 body executes, because you need them in the logic of the constructor? |
520 body executes, because you need them in the logic of the constructor? |
498 There is a way to do this, used for example in the class |
521 There is a way to do this, used for example in the class |
499 @code{ns3::ConfigStore}: call @code{ObjectBase::ConstructSelf()} |
522 @code{ns3::ConfigStore}: call @code{ObjectBase::ConstructSelf ()} |
500 as follows: |
523 as follows: |
501 |
524 |
502 @verbatim |
525 @verbatim |
503 ConfigStore::ConfigStore () |
526 ConfigStore::ConfigStore () |
504 { |
527 { |
610 double xMin; |
637 double xMin; |
611 double xMax; |
638 double xMax; |
612 double yMin; |
639 double yMin; |
613 double yMax; |
640 double yMax; |
614 }; |
641 }; |
615 @end verbatim |
642 @end example |
|
643 @end smallformat |
616 |
644 |
617 One macro call and two operators, must be added below the class declaration |
645 One macro call and two operators, must be added below the class declaration |
618 in order to turn a Rectangle into a value usable by the @code{Attribute} |
646 in order to turn a Rectangle into a value usable by the @code{Attribute} |
619 system: |
647 system: |
620 |
648 |
621 @verbatim |
649 @smallformat |
|
650 @example |
622 std::ostream &operator << (std::ostream &os, const Rectangle &rectangle); |
651 std::ostream &operator << (std::ostream &os, const Rectangle &rectangle); |
623 std::istream &operator >> (std::istream &is, Rectangle &rectangle); |
652 std::istream &operator >> (std::istream &is, Rectangle &rectangle); |
624 |
653 |
625 ATTRIBUTE_HELPER_HEADER (Rectangle); |
654 ATTRIBUTE_HELPER_HEADER (Rectangle); |
626 @end verbatim |
655 @end example |
627 |
656 @end smallformat |
|
657 |
|
658 @subsection Implementation file |
628 In the class definition (@code{.cc} file), the code looks like this: |
659 In the class definition (@code{.cc} file), the code looks like this: |
629 |
660 |
630 @verbatim |
661 @smallformat |
|
662 @example |
631 ATTRIBUTE_HELPER_CPP (Rectangle); |
663 ATTRIBUTE_HELPER_CPP (Rectangle); |
632 |
664 |
633 std::ostream & |
665 std::ostream & |
634 operator << (std::ostream &os, const Rectangle &rectangle) |
666 operator << (std::ostream &os, const Rectangle &rectangle) |
635 { |
667 { |
636 os << rectangle.xMin << "|" << rectangle.xMax << "|" << rectangle.yMin << "|" << rectangle.yMax; |
668 os << rectangle.xMin << "|" << rectangle.xMax << "|" << rectangle.yMin << "|" |
|
669 << rectangle.yMax; |
637 return os; |
670 return os; |
638 } |
671 } |
639 std::istream & |
672 std::istream & |
640 operator >> (std::istream &is, Rectangle &rectangle) |
673 operator >> (std::istream &is, Rectangle &rectangle) |
641 { |
674 { |
642 char c1, c2, c3; |
675 char c1, c2, c3; |
643 is >> rectangle.xMin >> c1 >> rectangle.xMax >> c2 >> rectangle.yMin >> c3 >> rectangle.yMax; |
676 is >> rectangle.xMin >> c1 >> rectangle.xMax >> c2 >> rectangle.yMin >> c3 |
|
677 >> rectangle.yMax; |
644 if (c1 != '|' || |
678 if (c1 != '|' || |
645 c2 != '|' || |
679 c2 != '|' || |
646 c3 != '|') |
680 c3 != '|') |
647 { |
681 { |
648 is.setstate (std::ios_base::failbit); |
682 is.setstate (std::ios_base::failbit); |
649 } |
683 } |
650 return is; |
684 return is; |
651 } |
685 } |
652 @end verbatim |
686 @end example |
|
687 @end smallformat |
653 |
688 |
654 These stream operators simply convert from a string representation of the |
689 These stream operators simply convert from a string representation of the |
655 Rectangle ("xMin|xMax|yMin|yMax") to the underlying Rectangle, and the |
690 Rectangle ("xMin|xMax|yMin|yMax") to the underlying Rectangle, and the |
656 modeler must specify these operators and the string syntactical representation |
691 modeler must specify these operators and the string syntactical representation |
657 of an instance of the new class. |
692 of an instance of the new class. |
703 output data. The FileFormat (default "RawText") governs whether |
740 output data. The FileFormat (default "RawText") governs whether |
704 the ConfigStore format is Xml or RawText format. |
741 the ConfigStore format is Xml or RawText format. |
705 |
742 |
706 So, using the above modified program, try executing the following |
743 So, using the above modified program, try executing the following |
707 waf command and |
744 waf command and |
708 @verbatim |
745 @smallformat |
709 ./waf --command-template="%s --ns3::ConfigStore::Filename=csma-bridge-config.xml --ns3::ConfigStore::Mode=Save --ns3::ConfigStore::FileFormat=Xml" --run scratch/csma-bridge |
746 @example |
710 @end verbatim |
747 ./waf --command-template="%s --ns3::ConfigStore::Filename=csma-bridge-config.xml |
|
748 --ns3::ConfigStore::Mode=Save --ns3::ConfigStore::FileFormat=Xml" --run scratch/csma-bridge |
|
749 @end example |
|
750 @end smallformat |
711 After running, you can open the csma-bridge-config.xml file and it will |
751 After running, you can open the csma-bridge-config.xml file and it will |
712 display the configuration that was applied to your simulation; e.g. |
752 display the configuration that was applied to your simulation; e.g. |
713 @verbatim |
753 @smallformat |
|
754 @example |
714 <?xml version="1.0" encoding="UTF-8"?> |
755 <?xml version="1.0" encoding="UTF-8"?> |
715 <ns3> |
756 <ns3> |
716 <default name="ns3::V4Ping::Remote" value="102.102.102.102"/> |
757 <default name="ns3::V4Ping::Remote" value="102.102.102.102"/> |
717 <default name="ns3::MsduStandardAggregator::MaxAmsduSize" value="7935"/> |
758 <default name="ns3::MsduStandardAggregator::MaxAmsduSize" value="7935"/> |
718 <default name="ns3::EdcaTxopN::MinCw" value="31"/> |
759 <default name="ns3::EdcaTxopN::MinCw" value="31"/> |
721 <default name="ns3::QstaWifiMac::ProbeRequestTimeout" value="50000000ns"/> |
762 <default name="ns3::QstaWifiMac::ProbeRequestTimeout" value="50000000ns"/> |
722 <default name="ns3::QstaWifiMac::AssocRequestTimeout" value="500000000ns"/> |
763 <default name="ns3::QstaWifiMac::AssocRequestTimeout" value="500000000ns"/> |
723 <default name="ns3::QstaWifiMac::MaxMissedBeacons" value="10"/> |
764 <default name="ns3::QstaWifiMac::MaxMissedBeacons" value="10"/> |
724 <default name="ns3::QstaWifiMac::ActiveProbing" value="false"/> |
765 <default name="ns3::QstaWifiMac::ActiveProbing" value="false"/> |
725 ... |
766 ... |
726 @end verbatim |
767 @end example |
|
768 @end smallformat |
|
769 |
727 This file can be archived with your simulation script and output data. |
770 This file can be archived with your simulation script and output data. |
728 |
771 |
729 While it is possible to generate a sample config file and lightly |
772 While it is possible to generate a sample config file and lightly |
730 edit it to change a couple of values, there are cases where this |
773 edit it to change a couple of values, there are cases where this |
731 process will not work because the same value on the same object |
774 process will not work because the same value on the same object |
747 "input-defaults.xml", and write out the resulting attributes to a |
790 "input-defaults.xml", and write out the resulting attributes to a |
748 separate file called "output-attributes.xml". (Note-- to get this |
791 separate file called "output-attributes.xml". (Note-- to get this |
749 input xml file to begin with, it is sometimes helpful to run the |
792 input xml file to begin with, it is sometimes helpful to run the |
750 program to generate an output xml file first, then hand-edit that |
793 program to generate an output xml file first, then hand-edit that |
751 file and re-input it for the next simulation run). |
794 file and re-input it for the next simulation run). |
752 @verbatim |
795 @smallformat |
|
796 @example |
753 #include "contrib-module.h" |
797 #include "contrib-module.h" |
754 ... |
798 ... |
755 int main (...) |
799 int main (...) |
756 { |
800 { |
757 |
801 |
792 @verbatim |
837 @verbatim |
793 sudo apt-get install libgtk2.0-0 libgtk2.0-dev |
838 sudo apt-get install libgtk2.0-0 libgtk2.0-dev |
794 @end verbatim |
839 @end verbatim |
795 To check whether it is configured or not, check the output of the |
840 To check whether it is configured or not, check the output of the |
796 ./waf configure step: |
841 ./waf configure step: |
797 @verbatim |
842 @smallformat |
|
843 @example |
798 ---- Summary of optional NS-3 features: |
844 ---- Summary of optional NS-3 features: |
799 Threading Primitives : enabled |
845 Threading Primitives : enabled |
800 Real Time Simulator : enabled |
846 Real Time Simulator : enabled |
801 GtkConfigStore : not enabled (library 'gtk+-2.0 >= 2.12' not found) |
847 GtkConfigStore : not enabled (library 'gtk+-2.0 >= 2.12' not found) |
802 @end verbatim |
848 @end example |
|
849 @end smallformat |
803 |
850 |
804 In the above example, it was not enabled, so it cannot be used until a |
851 In the above example, it was not enabled, so it cannot be used until a |
805 suitable version is installed and ./waf configure; ./waf is rerun. |
852 suitable version is installed and ./waf configure; ./waf is rerun. |
806 |
853 |
807 Usage is almost the same as the non-GTK-based version, but there |
854 Usage is almost the same as the non-GTK-based version, but there |
808 are no ConfigStore attributes involved: |
855 are no ConfigStore attributes involved: |
809 @verbatim |
856 @smallformat |
|
857 @example |
810 // Invoke just before entering Simulator::Run () |
858 // Invoke just before entering Simulator::Run () |
811 GtkConfigStore config; |
859 GtkConfigStore config; |
812 config.ConfigureDefaults (); |
860 config.ConfigureDefaults (); |
813 config.ConfigureAttributes (); |
861 config.ConfigureAttributes (); |
814 @end verbatim |
862 @end example |
|
863 @end smallformat |
815 |
864 |
816 Now, when you run the script, a GUI should pop up, allowing you to open |
865 Now, when you run the script, a GUI should pop up, allowing you to open |
817 menus of attributes on different nodes/objects, and then launch the |
866 menus of attributes on different nodes/objects, and then launch the |
818 simulation execution when you are done. |
867 simulation execution when you are done. |
819 |
868 |